-= Collisions -=
[blender.git] / release / scripts / flt_import.py
1 #!BPY
2 """ Registration info for Blender menus:
3 Name: 'OpenFlight (.flt)...'
4 Blender: 245
5 Group: 'Import'
6 Tip: 'Import OpenFlight (.flt)'
7 """
8
9
10
11 __author__ = "Greg MacDonald, Campbell Barton, Geoffrey Bantle"
12 __version__ = "2.0 11/21/07"
13 __url__ = ("blender", "blenderartists.org", "Author's homepage, http://sourceforge.net/projects/blight/")
14 __bpydoc__ = """\
15 This script imports OpenFlight files into Blender. OpenFlight is a
16 registered trademark of MultiGen-Paradigm, Inc.
17
18 Feature overview and more availible at:
19 http://wiki.blender.org/index.php/Scripts/Manual/Import/openflight_flt
20
21 Note: This file is a grab-bag of old and new code. It needs some cleanup still.
22 """
23
24 # flt_import.py is an OpenFlight importer for blender.
25 # Copyright (C) 2005 Greg MacDonald, 2007  Blender Foundation
26 #
27 # This program is free software; you can redistribute it and/or
28 # modify it under the terms of the GNU General Public License
29 # as published by the Free Software Foundation; either version 2
30 # of the License, or (at your option) any later version.
31 #
32 # This program is distributed in the hope that it will be useful,
33 # but WITHOUT ANY WARRANTY; without even the implied warranty of
34 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35 # GNU General Public License for more details.
36 #
37 # You should have received a copy of the GNU General Public License
38 # along with this program; if not, write to the Free Software
39 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
40
41 import Blender
42 import os
43 import BPyMesh
44 import BPyImage
45 import flt_filewalker 
46 import flt_properties
47 reload(flt_properties)
48 from flt_properties import *
49
50 #Globals. Should Clean these up and minimize their usage.
51
52 typecodes = ['c','C','s','S','i','I','f','d','t']
53 records = dict()
54
55 FLTBaseLabel = None
56 FLTBaseString = None
57 FLTBaseChooser = None
58 FLTExport = None
59 FLTClose = None
60 FLTDoXRef = None
61 FLTScale = None
62 FLTShadeImport = None
63 FLTAttrib = None
64 FLTWarn = None
65
66 Vector= Blender.Mathutils.Vector
67 FLOAT_TOLERANCE = 0.01
68
69 FF = flt_filewalker.FileFinder()
70 current_layer = 0x01
71
72 global_prefs = dict()
73 global_prefs['verbose']= 4
74 global_prefs['get_texture'] = True
75 global_prefs['get_diffuse'] = True
76 global_prefs['get_specular'] = False
77 global_prefs['get_emissive'] = False
78 global_prefs['get_alpha'] = True
79 global_prefs['get_ambient'] = False
80 global_prefs['get_shininess'] = True
81 global_prefs['color_from_face'] = True
82 global_prefs['fltfile']= ''
83 global_prefs['smoothshading'] = 1
84 global_prefs['doxrefs'] = 1
85 global_prefs['scale'] = 1.0
86 global_prefs['attrib'] = 0
87 msg_once = False
88
89 reg = Blender.Registry.GetKey('flt_import',1)
90 if reg:
91         for key in global_prefs:
92                 if reg.has_key(key):
93                         global_prefs[key] = reg[key]
94                 
95
96
97 throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63,111] # Opcodes that indicate its time to return control to parent.
98 do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125]
99
100 #Process FLT record definitions
101 for record in FLT_Records:
102         props = dict()
103         for prop in FLT_Records[record]:
104                 position = ''
105                 slice = 0
106                 (format,name) = prop.split('!')
107                 for i in format:
108                         if i not in typecodes:
109                                 position = position + i
110                                 slice = slice + 1
111                         else:
112                                 break
113                 type = format[slice:]
114                 length = type[1:] 
115                 if len(length) == 0:
116                         length = 1
117                 else:
118                         type = type[0]
119                         length = int(length)
120                 
121                 props[int(position)] = (type,length,prop)
122         records[record] = props
123
124 def col_to_gray(c):
125         return 0.3*c[0] + 0.59*c[1] + 0.11*c[2]
126 class MaterialDesc:
127         # Was going to use int(f*1000.0) instead of round(f,3), but for some reason
128         # round produces better results, as in less dups.
129         def make_key(self):
130                 key = list()
131                 if global_prefs['get_texture']:
132                         if self.tex0:
133                                 key.append(self.tex0.getName())
134                         else:
135                                 key.append(None)
136                 
137                 if global_prefs['get_alpha']:
138                         key.append(round(self.alpha, 3))
139                 else:
140                         key.append(None)
141                         
142                 if global_prefs['get_shininess']:
143                         key.append(round(self.shininess, 3))
144                 else:
145                         key.append(None)
146                 
147                 if global_prefs['get_emissive']:
148                         key.append(round(self.emissive, 3))
149                 else:
150                         key.append(None)
151                 
152                 if global_prefs['get_ambient']:
153                         key.append(round(self.ambient, 3))
154                 else:
155                         key.append(None)
156                 
157                 if global_prefs['get_specular']:
158                         for n in self.specular:
159                                 key.append(round(n, 3))
160                 else:
161                         key.extend([None, None, None])
162                 
163                 if global_prefs['get_diffuse']:
164                         for n in self.diffuse:
165                                 key.append(round(n, 3))
166                 else:
167                         key.extend([None, None, None])
168                 
169 #        key.extend(self.face_props.values())
170                 
171                 return tuple(key)
172
173         def __init__(self):
174                 self.name = 'Material'
175                 # Colors, List of 3 floats.
176                 self.diffuse = [1.0, 1.0, 1.0]
177                 self.specular = [1.0, 1.0, 1.0]
178
179                 # Scalars
180                 self.ambient = 0.0 # [0.0, 1.0]
181                 self.emissive = 0.0 # [0.0, 1.0]
182                 self.shininess = 0.5 # Range is [0.0, 2.0]
183                 self.alpha = 1.0 # Range is [0.0, 1.0]
184
185                 self.tex0 = None
186                 
187                 # OpenFlight Face attributes
188                 self.face_props = dict.fromkeys(['comment', 'ir color', 'priority', 
189                                                         'draw type', 'texture white', 'template billboard',
190                                                         'smc', 'fid', 'ir material', 'lod generation control',
191                                                         'flags', 'light mode'])
192
193 class VertexDesc:
194         def make_key(self):
195                 return round(self.x, 6), round(self.y, 6), round(self.z, 6)
196                 
197         def __init__(self):
198                 
199                 # Assign later, save memory, all verts have a loc
200                 self.x = 0.0
201                 self.y = 0.0
202                 self.z = 0.0
203                 
204                 
205                 self.nx = 0.0
206                 self.ny = 0.0
207                 self.nz = 0.0
208                 
209                 self.uv= Vector(0,0)
210                 self.cindex = 127 #default/lowest
211                 self.cnorm = False        
212
213 class LightPointAppDesc:
214         def make_key(self):
215                 d = dict(self.props)
216                 del d['id']
217                 del d['type']
218                 
219                 if d['directionality'] != 0: # not omni
220                         d['nx'] = 0.0
221                         d['ny'] = 0.0
222                         d['nz'] = 0.0
223                 
224                 return tuple(d.values())
225                 
226         def __init__(self):
227                 self.props = dict()
228                 self.props.update({'type': 'LPA'})
229                 self.props.update({'id': 'ap'})
230                 # Attribs not found in inline lightpoint.
231                 self.props.update({'visibility range': 0.0})
232                 self.props.update({'fade range ratio': 0.0})
233                 self.props.update({'fade in duration': 0.0})
234                 self.props.update({'fade out duration': 0.0})
235                 self.props.update({'LOD range ratio': 0.0})
236                 self.props.update({'LOD scale': 0.0})
237
238 class GlobalResourceRepository:
239         def request_lightpoint_app(self, desc, scene):
240                 match = self.light_point_app.get(desc.make_key())
241                 
242                 if match:
243                         return match.getName()
244                 else:
245                         # Create empty and fill with properties.
246                         name = desc.props['type'] + ': ' + desc.props['id']
247                         object = Blender.Object.New('Empty', name)
248                         scene.objects.link(object)
249                         object.Layers= current_layer
250                         object.sel= 1
251                         
252                         # Attach properties
253                         for name, value in desc.props.iteritems():
254                                 object.addProperty(name, value)
255                         
256                         self.light_point_app.update({desc.make_key(): object})
257                         
258                         return object.getName()
259         
260         # Dont use request_vert - faster to make it from the vector direct.
261         """
262         def request_vert(self, desc):
263                 match = self.vert_dict.get(desc.make_key())
264
265                 if match:
266                         return match
267                 else:
268                         vert = Blender.Mathutils.Vector(desc.x, desc.y, desc.z)
269                         ''' IGNORE_NORMALS
270                         vert.no[0] = desc.nx
271                         vert.no[1] = desc.ny
272                         vert.no[2] = desc.nz
273                         '''
274                         self.vert_dict.update({desc.make_key(): vert})
275                         return vert
276         """
277         def request_mat(self, mat_desc):
278                 match = self.mat_dict.get(mat_desc.make_key())
279                 if match: return match
280                 
281                 mat = Blender.Material.New(mat_desc.name)
282
283                 if mat_desc.tex0 != None:
284                         mat.setTexture(0, mat_desc.tex0, Blender.Texture.TexCo.UV)
285
286                 mat.setAlpha(mat_desc.alpha)
287                 mat.setSpec(mat_desc.shininess)
288                 mat.setHardness(255)
289                 mat.setEmit(mat_desc.emissive)
290                 mat.setAmb(mat_desc.ambient)
291                 mat.setSpecCol(mat_desc.specular)
292                 mat.setRGBCol(mat_desc.diffuse)
293                 
294                 # Create a text object to store openflight face attribs until
295                 # user properties can be set on materials.
296 #        t = Blender.Text.New('FACE: ' + mat.getName())
297 #
298 #        for name, value in mat_desc.face_props.items():
299 #            t.write(name + '\n' + str(value) + '\n\n')    
300                                 
301                 self.mat_dict.update({mat_desc.make_key(): mat})
302
303                 return mat
304                 
305         def request_image(self, filename_with_path):
306                 if not global_prefs['get_texture']: return None
307                 return BPyImage.comprehensiveImageLoad(filename_with_path, global_prefs['fltfile']) # Use join in case of spaces 
308                 
309         def request_texture(self, image):
310                 if not global_prefs['get_texture']:
311                         return None
312
313                 tex = self.tex_dict.get(image.filename)
314                 if tex: return tex
315                 
316                 tex = Blender.Texture.New(Blender.sys.basename(image.filename))
317                 tex.setImage(image)
318                 tex.setType('Image')
319                 self.tex_dict.update({image.filename: tex})
320                 return tex
321                 
322         def __init__(self):
323                 
324                 #list of scenes xrefs belong to.
325                 self.xrefs = dict()
326                 # material
327                 self.mat_dict = dict()
328                 mat_lst = Blender.Material.Get()
329                 for mat in mat_lst:
330                         mat_desc = MaterialDesc()
331                         mapto_lst = mat.getTextures()
332                         if mapto_lst[0]:
333                                 mat_desc.tex0 = mapto_lst[0].tex
334                         else:
335                                 mat_desc.tex0 = None
336                         mat_desc.alpha = mat.getAlpha()
337                         mat_desc.shininess = mat.getSpec()
338                         mat_desc.emissive = mat.getEmit()
339                         mat_desc.ambient = mat.getAmb()
340                         mat_desc.specular = mat.getSpecCol()
341                         mat_desc.diffuse = mat.getRGBCol()
342                         
343                         self.mat_dict.update({mat_desc.make_key(): mat})
344                         
345                 # texture
346                 self.tex_dict = dict()
347                 tex_lst = Blender.Texture.Get()
348                 
349                 for tex in tex_lst:
350                         img = tex.getImage()
351                         # Only interested in textures with images.
352                         if img:
353                                 self.tex_dict.update({img.filename: tex})
354                         
355                 # vertex
356                 # self.vert_dict = dict()
357                 
358                 # light point
359                 self.light_point_app = dict()
360                 
361 class Handler:
362         def in_throw_back_lst(self, opcode):
363                 return opcode in self.throw_back_lst
364                 
365         def handle(self, opcode):
366                 return self.handler[opcode]()
367         
368         def handles(self, opcode):
369                 return opcode in self.handler.iterkeys()
370         
371         def throws_back_all_unhandled(self):
372                 return self.throw_back_unhandled
373                 
374         def set_throw_back_lst(self, a):
375                 self.throw_back_lst = a
376                 
377         def set_throw_back_all_unhandled(self):
378                 self.throw_back_unhandled = True
379                 
380         def set_only_throw_back_specified(self):
381                 self.throw_back_unhandled = False
382                 
383         def set_handler(self, d):
384                 self.handler = d
385                 
386         def __init__(self):
387                 # Dictionary of opcodes to handler methods.
388                 self.handler = dict()
389                 # Send all opcodes not handled to the parent node.
390                 self.throw_back_unhandled = False
391                 # If throw_back_unhandled is False then only throw back
392                 # if the opcodes in throw_back are encountered.
393                 self.throw_back_lst = list()
394                 
395 class Node:
396         def blender_import(self):
397                 if self.opcode in opcode_name and global_prefs['verbose'] >= 2:
398                         for i in xrange(self.get_level()):
399                                 print ' ',
400                         print opcode_name[self.opcode],
401                         print '-', self.props['id'],
402                         print '-', self.props['comment'],
403
404                         print
405                 
406                 for child in self.children:
407                         child.blender_import()
408                         
409 # Import comment.
410 #        if self.props['comment'] != '':
411 #            name = 'COMMENT: ' + self.props['id']
412 #            t = Blender.Text.New(name)
413 #            t.write(self.props['comment'])
414 #            self.props['comment'] = name
415                 
416         # Always ignore extensions and anything in between them.
417         def parse_push_extension(self):
418                 self.saved_handler = self.active_handler
419                 self.active_handler = self.extension_handler
420                 return True
421         
422         def parse_pop_extension(self):
423                 self.active_handler = self.saved_handler
424                 return True
425         
426         def parse_push(self):
427                 self.header.fw.up_level()
428                 # Ignore unknown children.
429                 self.ignore_unhandled = True
430                 # Don't do child records that might overwrite parent info. ex: longid
431                 self.active_handler = self.child_handler
432                 return True
433                 
434         def parse_pop(self):
435                 self.header.fw.down_level()
436                 
437                 if self.header.fw.get_level() == self.level:
438                         return False
439                 
440                 return True
441         
442         def parse(self):
443                 while self.header.fw.begin_record():
444                         opcode = self.header.fw.get_opcode()
445
446                         # Print out info on opcode and tree level.
447                         if global_prefs['verbose'] >= 3:
448                                 p = ''
449                                 for i in xrange(self.header.fw.get_level()):
450                                         p = p + '  '
451                                 if opcode in opcode_name:
452                                         p = p + opcode_name[opcode]
453                                 else:
454                                         if global_prefs['verbose'] >= 1:
455                                                 print 'undocumented opcode', opcode
456                                         continue
457                                                         
458                         if self.global_handler.handles(opcode):
459                                 if global_prefs['verbose'] >= 3:
460                                         print p + ' handled globally'
461                                 if self.global_handler.handle(opcode) == False:
462                                         break
463                                         
464                         elif self.active_handler.handles(opcode):
465                                 if global_prefs['verbose'] >= 4:
466                                         print p + ' handled'
467                                 if self.active_handler.handle(opcode) == False:
468                                         break
469                                         
470                         else:
471                                 if self.active_handler.throws_back_all_unhandled():
472                                         if global_prefs['verbose'] >= 3:
473                                                 print p + ' handled elsewhere'              
474                                         self.header.fw.repeat_record()
475                                         break
476
477                                 elif self.active_handler.in_throw_back_lst(opcode):
478                                         if global_prefs['verbose'] >= 3:
479                                                 print p + ' handled elsewhere'              
480                                         self.header.fw.repeat_record()
481                                         break
482
483                                 else:
484                                         if global_prefs['verbose'] >= 3:
485                                                 print p + ' ignored'
486                                         elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name:   
487                                                 print 'not handled'
488                                         
489         def get_level(self):
490                 return self.level
491                 
492         def parse_long_id(self):
493                 self.props['id'] = self.header.fw.read_string(self.header.fw.get_length()-4)
494                 return True
495
496         def parse_comment(self):
497                 self.props['comment'] = self.header.fw.read_string(self.header.fw.get_length()-4)
498                 return True
499         
500         def parse_extension(self):
501                 extension = dict()
502                 props = records[100]
503                 propkeys = props.keys()
504                 propkeys.sort()
505                 for position in propkeys:
506                         (type,length,name) = props[position]
507                         extension[name] = read_prop(self.header.fw,type,length)
508                 #read extension data.
509                 dstring = list()
510                 for i in xrange(self.header.fw.get_length()-24):
511                         dstring.append(self.header.fw.read_char())
512                 extension['data'] = dstring
513                 self.extension = extension
514         def parse_record(self):
515                 self.props['type'] = self.opcode
516                 props = records[self.opcode]
517                 propkeys = props.keys()
518                 propkeys.sort()
519                 for position in propkeys:
520                         (type,length,name) = props[position]
521                         self.props[name] = read_prop(self.header.fw,type,length)
522                 try: #remove me!
523                         self.props['id'] = self.props['3t8!id']
524                 except:
525                         pass
526         def __init__(self, parent, header):
527                 self.root_handler = Handler()
528                 self.child_handler = Handler()
529                 self.extension_handler = Handler()
530                 self.global_handler = Handler()
531                 
532                 self.global_handler.set_handler({21: self.parse_push_extension})
533                 self.active_handler = self.root_handler
534                 
535                 # used by parse_*_extension
536                 self.extension_handler.set_handler({22: self.parse_pop_extension})
537                 self.saved_handler = None
538                 
539                 self.header = header
540                 self.children = list()
541
542                 self.parent = parent
543
544                 if parent:
545                         parent.children.append(self)
546
547                 self.level = self.header.fw.get_level()
548                 self.opcode = self.header.fw.get_opcode()
549
550                 self.props = {'id': 'unnamed', 'comment': '', 'type': 'untyped'}
551
552 class VertexPalette(Node):
553         def __init__(self, parent):
554                 Node.__init__(self, parent, parent.header)
555                 self.root_handler.set_handler({68: self.parse_vertex_c,
556                                                                            69: self.parse_vertex_cn,
557                                                                            70: self.parse_vertex_cnuv,
558                                                                            71: self.parse_vertex_cuv})
559                 self.root_handler.set_throw_back_all_unhandled()
560
561                 self.vert_desc_lst = list()
562                 self.blender_verts = list()
563                 self.offset = 8
564                 # Used to create a map from byte offset to vertex index.
565                 self.index = dict()
566         
567         
568         def blender_import(self):
569                 self.blender_verts.extend([Vector(vert_desc.x, vert_desc.y, vert_desc.z) for vert_desc in self.vert_desc_lst ])
570
571         def parse_vertex_common(self):
572                 # Add this vertex to an offset to index dictionary.
573                 #self.index_lst.append( (self.offset, self.next_index) )
574                 self.index[self.offset]= len(self.index)
575                 
576                 # Get ready for next record.
577                 self.offset += self.header.fw.get_length()
578
579                 v = VertexDesc()
580
581                 self.header.fw.read_ahead(2)
582                 v.flags = self.header.fw.read_short()
583
584                 v.x = self.header.fw.read_double()
585                 v.y = self.header.fw.read_double()
586                 v.z = self.header.fw.read_double()
587
588                 return v
589
590         def parse_vertex_post_common(self, v):
591                 #if not v.flags & 0x2000: # 0x2000 = no color
592                         #if v.flags & 0x1000: # 0x1000 = packed color
593                         #       v.a = self.header.fw.read_uchar()
594                         #       v.b = self.header.fw.read_uchar()
595                         #       v.g = self.header.fw.read_uchar()
596                         #       v.r = self.header.fw.read_uchar()
597                         #else:
598                 self.header.fw.read_ahead(4) #skip packed color
599                 v.cindex = self.header.fw.read_uint()
600                 self.vert_desc_lst.append(v)
601                 return True
602
603         def parse_vertex_c(self):
604                 v = self.parse_vertex_common()
605
606                 self.parse_vertex_post_common(v)
607                 
608                 return True
609
610         def parse_vertex_cn(self):
611                 v = self.parse_vertex_common()
612                 v.cnorm = True
613                 v.nx = self.header.fw.read_float()
614                 v.ny = self.header.fw.read_float()
615                 v.nz = self.header.fw.read_float()
616                 
617                 self.parse_vertex_post_common(v)
618                 
619                 return True
620
621         def parse_vertex_cuv(self):
622                 v = self.parse_vertex_common()
623
624                 v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float()
625
626                 self.parse_vertex_post_common(v)
627                 
628                 return True
629
630         def parse_vertex_cnuv(self):
631                 v = self.parse_vertex_common()
632                 v.cnorm = True
633                 v.nx = self.header.fw.read_float()
634                 v.ny = self.header.fw.read_float()
635                 v.nz = self.header.fw.read_float()
636                 
637                 v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float()
638
639                 self.parse_vertex_post_common(v)
640                 
641                 return True
642
643         def parse(self): # Run once per import
644                 Node.parse(self)
645
646
647 class InterNode(Node):
648         def __init__(self):
649                 self.object = None
650                 self.mesh = None
651                 self.swapmesh = None
652                 self.hasMesh = False
653                 self.faceLs= []
654                 self.matrix = None
655                 self.vis = True
656                 self.hasmtex = False
657                 self.uvlayers = dict()
658                 self.blayernames = dict()
659                 self.subfacelevel = 0
660                 self.extension = None
661                 
662                 mask = 2147483648
663                 for i in xrange(7):
664                         self.uvlayers[mask] = False
665                         mask = mask / 2
666                 
667         #######################################################
668         ##              Begin Remove Doubles Replacement     ##
669         #######################################################
670         def __xvertsort(self,__a,__b):
671                 (__vert, __x1) = __a
672                 (__vert2,__x2) = __b
673                 
674                 if __x1 > __x2:
675                         return 1
676                 elif __x1 < __x2:
677                         return -1
678                 return 0        
679         def __calcFaceNorm(self,__face):
680                 if len(__face) == 3:
681                         return Blender.Mathutils.TriangleNormal(__face[0].co, __face[1].co, __face[2].co)
682                 elif len(__face) == 4:
683                         return Blender.Mathutils.QuadNormal(__face[0].co, __face[1].co, __face[2].co, __face[3].co)
684                         
685         def __replaceFaceVert(self,__weldface, __oldvert, __newvert):
686                 __index = None
687                 for __i, __v in enumerate(__weldface):
688                         if __v == __oldvert:
689                                 __index = __i
690                                 break
691                 __weldface[__index] = __newvert
692         
693         def __matchEdge(self,__weldmesh, __edge1, __edge2):
694                 if __edge1[0] in __weldmesh['Vertex Disk'][__edge2[1]] and __edge1[1] in __weldmesh['Vertex Disk'][__edge2[0]]:
695                         return True
696                 return False
697         #have to compare original faces!
698         def __faceWinding(self, __weldmesh, __face1, __face2):
699                 
700                 __f1edges = list()
701                 __f2edges = list()
702                 
703                 __f1edges.append((__face1.verts[0], __face1.verts[1]))
704                 __f1edges.append((__face1.verts[1], __face1.verts[2]))
705                 if len(__face1.verts) == 3:
706                         __f1edges.append((__face1.verts[2], __face1.verts[0]))
707                 else:
708                         __f1edges.append((__face1.verts[2], __face1.verts[3]))
709                         __f1edges.append((__face1.verts[3], __face1.verts[0]))
710
711                 __f2edges.append((__face2.verts[0], __face2.verts[1]))
712                 __f2edges.append((__face2.verts[1], __face2.verts[2]))
713                 if len(__face2.verts) == 3:
714                         __f2edges.append((__face2.verts[2], __face2.verts[0]))
715                 else:
716                         __f2edges.append((__face2.verts[2], __face2.verts[3]))
717                         __f2edges.append((__face2.verts[3], __face2.verts[0]))
718
719                         
720                 #find a matching edge
721                 for __edge1 in __f1edges:
722                         for __edge2 in __f2edges:
723                                 if self.__matchEdge(__weldmesh, __edge1, __edge2): #no more tests nessecary
724                                         return True
725                 
726                 return False
727                 
728         def __floatcompare(self, __f1, __f2):
729                 epsilon = 0.1
730                 if ((__f1 + epsilon) > __f2) and ((__f1 - epsilon) < __f2):
731                         return True
732                 return False
733         def __testFace(self,__weldmesh,__v1face, __v2face, __v1bface, __v2bface):
734                 limit = 0.01
735                 __matchvert = None
736                 #frst test (for real this time!). Are the faces the same face?
737                 if __v1face == __v2face:
738                         return False
739                 
740                 #first test: Do the faces possibly geometrically share more than two vertices? we should be comparing original faces for this? - Yes.....
741                 __match = 0
742                 for __vert in __v1bface.verts:
743                         for __vert2 in __v2bface.verts:
744                                 #if (abs(__vert.co[0] - __vert2.co[0]) <= limit) and (abs(__vert.co[1] - __vert2.co[1]) <= limit) and (abs(__vert.co[2] - __vert2.co[2]) <= limit): #this needs to be fixed!
745                                 if __vert2 in __weldmesh['Vertex Disk'][__vert] or __vert == __vert2:
746                                         __match += 1
747                                         __matchvert = __vert2
748                 #avoid faces sharing more than two verts
749                 if __match > 2:
750                         return False
751
752                 #consistent winding for face normals
753                 if __match == 2:
754                         if not self.__faceWinding(__weldmesh, __v1bface, __v2bface):
755                                 return False
756
757                 #second test: Compatible normals.Anything beyond almost exact opposite is 'ok'
758                 __v1facenorm = self.__calcFaceNorm(__v1face)
759                 __v2facenorm = self.__calcFaceNorm(__v2face)
760
761                 #dont even mess with zero length faces
762                 if __v1facenorm.length < limit:
763                         return False
764                 if __v2facenorm.length < limit:
765                         return False
766
767                 __v1facenorm.normalize()
768                 __v2facenorm.normalize()
769
770                 if __match == 1:
771                         #special case, look for comparison of normals angle
772                         __angle = Blender.Mathutils.AngleBetweenVecs(__v1facenorm, __v2facenorm)
773                         if __angle > 70.0:
774                                 return False    
775
776
777
778                 __v2facenorm = __v2facenorm.negate()
779
780                 if self.__floatcompare(__v1facenorm[0], __v2facenorm[0]) and self.__floatcompare(__v1facenorm[1], __v2facenorm[1]) and self.__floatcompare(__v1facenorm[2], __v2facenorm[2]):
781                         return False
782
783                 #next test: dont weld a subface to a non-subface!
784                 if __v1bface.getProperty("FLT_SFLEVEL") != __v2bface.getProperty("FLT_SFLEVEL"):
785                         return False    
786                         
787                 #final test: edge test - We dont want to create a non-manifold edge through our weld operation  
788         
789                 return True
790
791         def __copyFaceData(self, __source, __target):
792                 #copy vcolor layers.
793                 __actColLayer = self.mesh.activeColorLayer
794                 for __colorlayer in self.mesh.getColorLayerNames():
795                         self.mesh.activeColorLayer = __colorlayer
796                         for __i, __col in enumerate(__source.col):
797                                 __target.col[__i].r = __col.r
798                                 __target.col[__i].g = __col.g
799                                 __target.col[__i].b = __col.b                   
800                         
801                 self.mesh.activeColorLayer = __actColLayer
802                 #copy uv layers.
803                 __actUVLayer = self.mesh.activeUVLayer
804                 for __uvlayer in self.mesh.getUVLayerNames():
805                         self.mesh.activeUVLayer = __uvlayer
806                         __target.image = __source.image
807                         __target.mode = __source.mode
808                         __target.smooth = __source.smooth
809                         __target.transp = __source.transp
810                         for __i, __uv in enumerate(__source.uv):
811                                 __target.uv[__i][0] = __uv[0]
812                                 __target.uv[__i][1] = __uv[1]
813                         
814                 self.mesh.activeUVLayer = __actUVLayer
815                 #copy property layers
816                 for __property in self.mesh.faces.properties:
817                         __target.setProperty(__property, __source.getProperty(__property))      
818
819         def findDoubles(self):
820                 limit = 0.01
821                 sortblock = list()
822                 double = dict()
823                 for vert in self.mesh.verts:
824                         double[vert] = None
825                         sortblock.append((vert, vert.co[0] + vert.co[1] + vert.co[2]))
826                 sortblock.sort(self.__xvertsort)
827                 
828                 a = 0
829                 while a < len(self.mesh.verts):
830                         (vert,xsort) = sortblock[a]
831                         b = a+1
832                         if not double[vert]:
833                                 while b < len(self.mesh.verts):
834                                         (vert2, xsort2) = sortblock[b]
835                                         if not double[vert2]:
836                                                 #first test, simple distance
837                                                 if (xsort2 - xsort) > limit: 
838                                                         break
839                                                 #second test, more expensive
840                                                 if (abs(vert.co[0] - vert2.co[0]) <= limit) and (abs(vert.co[1] - vert2.co[1]) <= limit) and (abs(vert.co[2] - vert2.co[2]) <= limit):
841                                                         double[vert2] = vert
842                                         b+=1                            
843                         a+=1
844         
845                 return double
846
847         def buildWeldMesh(self):
848                 
849                 weldmesh = dict()
850                 weldmesh['Vertex Disk'] = dict() #this is geometric adjacency
851                 weldmesh['Vertex Faces'] = dict() #topological adjacency
852                 
853                 #find the doubles for this mesh
854                 double = self.findDoubles()
855                 
856                 for vert in self.mesh.verts:
857                         weldmesh['Vertex Faces'][vert] = list()
858         
859                 #create weld faces      
860                 weldfaces = list()
861                 originalfaces = list()
862                 for face in self.mesh.faces:
863                         weldface = list()
864                         for vert in face.verts:
865                                 weldface.append(vert)
866                         weldfaces.append(weldface)
867                         originalfaces.append(face)
868                 for i, weldface in enumerate(weldfaces):
869                         for vert in weldface:
870                                 weldmesh['Vertex Faces'][vert].append(i)
871                 weldmesh['Weld Faces'] = weldfaces
872                 weldmesh['Original Faces'] = originalfaces
873                 
874                 #Now we need to build the vertex disk data. first we do just the 'target' vertices
875                 for vert in self.mesh.verts:
876                         if not double[vert]: #its a target
877                                 weldmesh['Vertex Disk'][vert] = list()
878                 for vert in self.mesh.verts:
879                         if double[vert]: #its a double
880                                 weldmesh['Vertex Disk'][double[vert]].append(vert)
881                                 
882                 #Now we need to create the disk information for the remaining vertices
883                 targets = weldmesh['Vertex Disk'].keys()
884                 for target in targets:
885                         for doublevert in weldmesh['Vertex Disk'][target]:
886                                 weldmesh['Vertex Disk'][doublevert] = [target]
887                                 for othervert in weldmesh['Vertex Disk'][target]:
888                                         if othervert != doublevert:
889                                                 weldmesh['Vertex Disk'][doublevert].append(othervert)           
890                 
891                 return weldmesh                 
892
893         def weldFuseFaces(self,weldmesh):
894
895                 #retain original loose vertices
896                 looseverts = dict()
897                 for vert in self.mesh.verts:
898                         looseverts[vert] = 0
899                 for edge in self.mesh.edges:
900                         looseverts[edge.v1] += 1
901                         looseverts[edge.v2] += 1
902
903
904
905                 #slight modification here: we need to walk around the mesh as many times as it takes to have no more matches
906                 done = 0
907                 while not done:
908                         done = 1
909                         for windex, weldface in enumerate(weldmesh['Weld Faces']):
910                                 for vertex in weldface:
911                                         #we walk around the faces of the doubles of this vertex and if possible, we weld them.
912                                         for doublevert in weldmesh['Vertex Disk'][vertex]:
913                                                 removeFaces = list() #list of faces to remove from doubleverts face list
914                                                 for doublefaceindex in weldmesh['Vertex Faces'][doublevert]:
915                                                         doubleface = weldmesh['Weld Faces'][doublefaceindex]
916                                                         oface1 = self.mesh.faces[windex]
917                                                         oface2 = self.mesh.faces[doublefaceindex]
918                                                         ok = self.__testFace(weldmesh, weldface, doubleface, oface1, oface2)
919                                                         if ok:
920                                                                 done = 0
921                                                                 removeFaces.append(doublefaceindex)
922                                                                 self.__replaceFaceVert(doubleface, doublevert, vertex)
923                                                 for doublefaceindex in removeFaces:
924                                                         weldmesh['Vertex Faces'][doublevert].remove(doublefaceindex)
925                 #old faces first
926                 oldindices = list()
927                 for face in self.mesh.faces:
928                         oldindices.append(face.index)
929                 #make our new faces.
930                 newfaces = list()
931                 for weldface in weldmesh['Weld Faces']:
932                         newfaces.append(weldface)
933                 newindices = self.mesh.faces.extend(newfaces, indexList=True, ignoreDups=True)
934                 #copy custom data over
935                 for i, newindex in enumerate(newindices):
936                         try:
937                                 self.__copyFaceData(self.mesh.faces[oldindices[i]], self.mesh.faces[newindex])
938                         except:
939                                 print "warning, could not copy face data!"
940                 #delete the old faces
941                 self.mesh.faces.delete(1, oldindices)
942                 
943                 #Clean up stray vertices
944                 vertuse = dict()
945                 for vert in self.mesh.verts:
946                         vertuse[vert] = 0
947                 for face in self.mesh.faces:
948                         for vert in face.verts:
949                                 vertuse[vert] += 1
950                 delverts = list()
951                 for vert in self.mesh.verts:
952                         if not vertuse[vert] and vert.index != 0 and looseverts[vert]:
953                                 delverts.append(vert)
954                 
955                 self.mesh.verts.delete(delverts)        
956
957
958         #######################################################
959         ##             End Remove Doubles Replacement        ##
960         #######################################################
961
962         def blender_import_my_faces(self):
963
964                 # Add the verts onto the mesh
965                 blender_verts= self.header.vert_pal.blender_verts
966                 vert_desc_lst= self.header.vert_pal.vert_desc_lst
967                 
968                 vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices] #splitting faces apart. Is this a good thing?
969                 face_edges= []
970                 face_verts= []
971                 self.mesh.verts.extend([blender_verts[i] for i in vert_list])
972                 
973                 new_faces= []
974                 new_faces_props= []
975                 ngon= BPyMesh.ngon
976                 vert_index= 1
977                 
978                 #add vertex color layer for baked face colors.
979                 self.mesh.addColorLayer("FLT_Fcol")
980                 self.mesh.activeColorLayer = "FLT_Fcol"
981                 
982                 FLT_OrigIndex = 0
983                 for flt_face in self.faceLs:
984                         if flt_face.tex_index != -1:
985                                 try:
986                                         image= self.header.tex_pal[flt_face.tex_index][1]
987                                 except KeyError:
988                                         image= None
989                         else:
990                                 image= None
991                         face_len= len(flt_face.indices)
992                         
993                         #create dummy uvert dicts
994                         if len(flt_face.uverts) == 0:
995                                 for i in xrange(face_len):
996                                         flt_face.uverts.append(dict())
997                         #May need to patch up MTex info
998                         if self.hasmtex:
999                                 #For every layer in mesh, there should be corresponding layer in the face
1000                                 for mask in self.uvlayers.keys():
1001                                         if self.uvlayers[mask]:
1002                                                 if not flt_face.uvlayers.has_key(mask): #Does the face have this layer?
1003                                                         #Create Layer info for this face
1004                                                         flt_face.uvlayers[mask] = dict()
1005                                                         flt_face.uvlayers[mask]['texture index'] = -1
1006                                                         flt_face.uvlayers[mask]['texture enviorment'] = 3
1007                                                         flt_face.uvlayers[mask]['texture mapping'] = 0
1008                                                         flt_face.uvlayers[mask]['texture data'] = 0
1009                                                         
1010                                                         #now go through and create dummy uvs for this layer
1011                                                         for uvert in flt_face.uverts:
1012                                                                         uv = Vector(0.0,0.0)
1013                                                                         uvert[mask] = uv
1014
1015                         # Get the indicies in reference to the mesh.
1016                         uvs= [vert_desc_lst[j].uv for j in flt_face.indices]
1017                         if face_len == 1:
1018                                 pass
1019                         elif face_len == 2:
1020                                 face_edges.append((vert_index, vert_index+1))
1021                         elif flt_face.props['draw type'] == 2 or flt_face.props['draw type'] == 3:
1022                                 i = 0
1023                                 while i < (face_len-1):
1024                                         face_edges.append((vert_index + i, vert_index + i + 1))
1025                                         i = i + 1
1026                                 if flt_face.props['draw type'] == 2:
1027                                         face_edges.append((vert_index + i,vert_index)) 
1028                         elif face_len == 3 or face_len == 4: # tri or quad
1029                                 #if face_len == 1:
1030                                 #       pass
1031                                 #if face_len == 2:
1032                                 #       face_edges.append((vert_index, vert_index+1))
1033                                 new_faces.append( [i+vert_index for i in xrange(face_len)] )
1034                                 new_faces_props.append((None, image, uvs, flt_face.uverts, flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,0, flt_face.subfacelevel))
1035                         
1036                         else: # fgon
1037                                 mesh_face_indicies = [i+vert_index for i in xrange(face_len)]
1038                                 tri_ngons= ngon(self.mesh, mesh_face_indicies)
1039                                 new_faces.extend([ [mesh_face_indicies[t] for t in tri] for tri in tri_ngons])
1040                                 new_faces_props.extend( [ (None, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]), [flt_face.uverts[tri[0]], flt_face.uverts[tri[1]], flt_face.uverts[tri[2]]], flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,1, flt_face.subfacelevel) for tri in tri_ngons ])
1041                         
1042                         vert_index+= face_len
1043                         FLT_OrigIndex+=1
1044                 
1045                 self.mesh.faces.extend(new_faces)
1046                 self.mesh.edges.extend(face_edges)
1047                 
1048                 #add in the FLT_ORIGINDEX layer
1049                 if len(self.mesh.faces):
1050                         try:    self.mesh.faceUV= True
1051                         except: pass
1052                 
1053                         if self.mesh.faceUV == True:
1054                                 self.mesh.renameUVLayer(self.mesh.activeUVLayer, 'Layer0')
1055                 
1056                         #create name layer for faces
1057                         self.mesh.faces.addPropertyLayer("FLT_ID",Blender.Mesh.PropertyTypes["STRING"])
1058                         #create layer for face color indices
1059                         self.mesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"])
1060                         #create index layer for faces. This is needed by both FGONs and subfaces
1061                         self.mesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"])
1062                         #create temporary FGON flag layer. Delete after remove doubles
1063                         self.mesh.faces.addPropertyLayer("FLT_FGON",Blender.Mesh.PropertyTypes["INT"])
1064                         self.mesh.faces.addPropertyLayer("FLT_SFLEVEL", Blender.Mesh.PropertyTypes["INT"])
1065                         
1066                         for i, f in enumerate(self.mesh.faces):
1067                                 props = new_faces_props[i]
1068                                 if props[6]['template billboard'] > 0:
1069                                         f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"]
1070                                         if props[6]['template billboard'] == 2:
1071                                                 f.mode |=  Blender.Mesh.FaceModes["BILLBOARD"]
1072                                         f.mode |= Blender.Mesh.FaceModes["LIGHT"]
1073                                 if props[6]['draw type'] == 1:
1074                                         f.mode |= Blender.Mesh.FaceModes["TWOSIDE"]
1075                                 
1076                                 #f.mat = props[0]
1077                                 f.image = props[1]
1078                                 f.uv = props[2]
1079                                 #set vertex colors
1080                                 color = self.header.get_color(props[5])
1081                                 if not color:
1082                                         color = [255,255,255,255]
1083                                 for mcol in f.col:
1084                                         mcol.a = color[3]
1085                                         mcol.r = color[0]
1086                                         mcol.g = color[1]
1087                                         mcol.b = color[2]
1088                                 
1089                                 f.setProperty("FLT_SFLEVEL", props[9])
1090                                 f.setProperty("FLT_ORIGINDEX",i)
1091                                 f.setProperty("FLT_ID",props[6]['id'])
1092                                 #if props[5] > 13199:
1093                                 #       print "Warning, invalid color index read in! Using default!"
1094                                 #       f.setProperty("FLT_COL",127)
1095                                 #else:
1096                                 if(1):                  #uh oh....
1097                                         value = struct.unpack('>i',struct.pack('>I',props[5]))[0]
1098                                         f.setProperty("FLT_COL",value)
1099                                 
1100                                 #if props[8]: 
1101                                 #       f.setProperty("FLT_FGON",1)
1102                                 #else:
1103                                 #       f.setProperty("FLT_FGON",0)
1104                         
1105                         
1106                         #Create multitex layers, if present.
1107                         actuvlayer = self.mesh.activeUVLayer
1108                         if(self.hasmtex):
1109                                 #For every multi-tex layer, we have to add a new UV layer to the mesh
1110                                 for i,mask in enumerate(reversed(sorted(self.uvlayers))):
1111                                         if self.uvlayers[mask]:
1112                                                 self.blayernames[mask] = "Layer" + str(i+1)
1113                                                 self.mesh.addUVLayer(self.blayernames[mask])
1114                                 
1115                                 #Cycle through availible multi-tex layers and add face UVS
1116                                 for mask in self.uvlayers:
1117                                         if self.uvlayers[mask]:
1118                                                 self.mesh.activeUVLayer = self.blayernames[mask]
1119                                                 for j, f in enumerate(self.mesh.faces):
1120                                                         if props[6]['draw type'] == 1:
1121                                                                 f.mode |= Blender.Mesh.FaceModes["TWOSIDE"]
1122                                                         f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"]
1123                                                         f.mode |= Blender.Mesh.FaceModes["LIGHT"]
1124                                                         props = new_faces_props[j]
1125                                                         uvlayers = props[4]
1126                                                         if uvlayers.has_key(mask): #redundant
1127                                                                 uverts = props[3]
1128                                                                 for k, uv in enumerate(f.uv):
1129                                                                         uv[0] = uverts[k][mask][0]
1130                                                                         uv[1] = uverts[k][mask][1]
1131                                 
1132                                                                 uvlayer = uvlayers[mask]
1133                                                                 tex_index = uvlayer['texture index']
1134                                                                 if tex_index != -1:
1135                                                                         try:
1136                                                                                 f.image = self.header.tex_pal[tex_index][1]
1137                                                                         except KeyError:
1138                                                                                 f.image = None
1139                                                                         
1140                         if global_prefs['smoothshading'] == True and len(self.mesh.faces):
1141                                 #We need to store per-face vertex normals in the faces as UV layers and delete them later.
1142                                 self.mesh.addUVLayer("FLTNorm1")
1143                                 self.mesh.addUVLayer("FLTNorm2")
1144                                 self.mesh.activeUVLayer = "FLTNorm1"
1145                                 for f in self.mesh.faces:
1146                                         f.smooth = 1
1147                                         #grab the X and Y components of normal and store them in UV 
1148                                         for i, uv in enumerate(f.uv):
1149                                                 vert = f.v[i].index
1150                                                 vert_desc = vert_desc_lst[vert_list[vert-1]]
1151                                                 if vert_desc.cnorm:
1152                                                         uv[0] = vert_desc.nx
1153                                                         uv[1] = vert_desc.ny
1154                                                 else:
1155                                                         uv[0] = 0.0
1156                                                         uv[1] = 0.0
1157                                 
1158                                 #Now go through and populate the second UV Layer with the z component
1159                                 self.mesh.activeUVLayer = "FLTNorm2"
1160                                 for f in self.mesh.faces:
1161                                         for i, uv in enumerate(f.uv):
1162                                                 vert = f.v[i].index
1163                                                 vert_desc = vert_desc_lst[vert_list[vert-1]]
1164                                                 if vert_desc.cnorm:
1165                                                         uv[0] = vert_desc.nz
1166                                                         uv[1] = 0.0
1167                                                 else:
1168                                                         uv[0] = 0.0
1169                                                         uv[1] = 0.0
1170                         
1171                                 
1172                                 
1173                         #Finally, go through, remove dummy vertex, remove doubles and add edgesplit modifier.
1174                         Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX'])
1175                         self.mesh.sel= 1
1176                         self.header.scene.update(1) #slow!
1177                         
1178                         #self.mesh.remDoubles(0.0001)
1179                         weldmesh = self.buildWeldMesh()
1180                         welded = self.weldFuseFaces(weldmesh)
1181                         self.mesh.verts.delete(0) # remove the dummy vert
1182                         
1183                         edgeHash = dict()
1184
1185                         for edge in self.mesh.edges:
1186                                 edgeHash[edge.key] = edge.index
1187
1188
1189                         if global_prefs['smoothshading'] == True and len(self.mesh.faces):
1190                                 
1191                                 #rip out the custom vertex normals from the mesh and place them in a face aligned list. Easier to compare this way.
1192                                 facenorms = []
1193                                 self.mesh.activeUVLayer = "FLTNorm1"
1194                                 for face in self.mesh.faces:
1195                                         facenorm = []
1196                                         for uv in face.uv:
1197                                                 facenorm.append(Vector(uv[0],uv[1],0.0))
1198                                         facenorms.append(facenorm)
1199                                 self.mesh.activeUVLayer = "FLTNorm2"
1200                                 for i, face in enumerate(self.mesh.faces):
1201                                         facenorm = facenorms[i]
1202                                         for j, uv in enumerate(face.uv):
1203                                                 facenorm[j][2] = uv[0]
1204                                 self.mesh.removeUVLayer("FLTNorm1")
1205                                 self.mesh.removeUVLayer("FLTNorm2")
1206
1207                                 #find hard edges
1208                                 #store edge data for lookup by faces
1209                                 #edgeHash = dict()
1210                                 #for edge in self.mesh.edges:
1211                                 #       edgeHash[edge.key] = edge.index
1212
1213                                 edgeNormHash = dict()
1214                                 #make sure to align the edgenormals to key value!
1215                                 for i, face in enumerate(self.mesh.faces):
1216                                         
1217                                         facenorm = facenorms[i]
1218                                         faceEdges = []
1219                                         faceEdges.append((face.v[0].index,face.v[1].index,facenorm[0],facenorm[1],face.edge_keys[0]))
1220                                         faceEdges.append((face.v[1].index,face.v[2].index,facenorm[1],facenorm[2],face.edge_keys[1]))
1221                                         if len(face.v) == 3:
1222                                                 faceEdges.append((face.v[2].index,face.v[0].index,facenorm[2],facenorm[0],face.edge_keys[2]))
1223                                         elif len(face.v) == 4:
1224                                                 faceEdges.append((face.v[2].index,face.v[3].index,facenorm[2],facenorm[3],face.edge_keys[2]))
1225                                                 faceEdges.append((face.v[3].index,face.v[0].index,facenorm[3],facenorm[0],face.edge_keys[3]))
1226                                         
1227                                         #check to see if edgeNormal has been placed in the edgeNormHash yet
1228                                         #this is a redundant test, and should be optimized to not be called as often as it is.
1229                                         for j, faceEdge in enumerate(faceEdges):
1230                                                 #the value we are looking for is (faceEdge[2],faceEdge[3])
1231                                                 hashvalue = (faceEdge[2],faceEdge[3])
1232                                                 if (faceEdge[0],faceEdge[1]) != faceEdge[4]:
1233                                                         hashvalue = (hashvalue[1],hashvalue[0])
1234                                                         assert (faceEdge[1],faceEdge[0]) == faceEdge[4]
1235                                                 if edgeNormHash.has_key(faceEdge[4]):
1236                                                         #compare value in the hash, if different, mark as sharp
1237                                                         edgeNorm = edgeNormHash[faceEdge[4]]
1238                                                         if\
1239                                                         abs(hashvalue[0][0] - edgeNorm[0][0]) > FLOAT_TOLERANCE or\
1240                                                         abs(hashvalue[0][1] - edgeNorm[0][1]) > FLOAT_TOLERANCE or\
1241                                                         abs(hashvalue[0][2] - edgeNorm[0][2]) > FLOAT_TOLERANCE or\
1242                                                         abs(hashvalue[1][0] - edgeNorm[1][0]) > FLOAT_TOLERANCE or\
1243                                                         abs(hashvalue[1][1] - edgeNorm[1][1]) > FLOAT_TOLERANCE or\
1244                                                         abs(hashvalue[1][2] - edgeNorm[1][2]) > FLOAT_TOLERANCE:
1245                                                                 edge = self.mesh.edges[edgeHash[faceEdge[4]]]
1246                                                                 edge.flag |= Blender.Mesh.EdgeFlags.SHARP
1247                                                                 
1248                                                 else:
1249                                                         edgeNormHash[faceEdge[4]] = hashvalue
1250                                 
1251                                 #add in edgesplit modifier
1252                                 mod = self.object.modifiers.append(Blender.Modifier.Types.EDGESPLIT)
1253                                 mod[Blender.Modifier.Settings.EDGESPLIT_FROM_SHARP] = True
1254                                 mod[Blender.Modifier.Settings.EDGESPLIT_FROM_ANGLE] = False
1255
1256                         if(actuvlayer):
1257                                 self.mesh.activeUVLayer = actuvlayer
1258                 
1259         def blender_import(self):
1260                 if self.vis and self.parent.object:
1261                         self.vis = self.parent.vis
1262                 name = self.props['id']
1263                 
1264
1265                 if self.hasMesh:
1266                         self.mesh = Blender.Mesh.New()
1267                         self.mesh.name = 'FLT_FaceList'
1268                         self.mesh.fakeUser = True
1269                         self.mesh.verts.extend( Vector()) #DUMMYVERT
1270                         self.object = self.header.scene.objects.new(self.mesh)
1271                 else:
1272                         self.object = self.header.scene.objects.new('Empty')
1273
1274                 self.object.name = name
1275                 self.header.group.objects.link(self.object)
1276
1277                 #id props import
1278                 self.object.properties['FLT'] = dict()
1279                 for key in self.props:
1280                         try:
1281                                 self.object.properties['FLT'][key] = self.props[key]
1282                         except: #horrible...
1283                                 pass
1284                 
1285
1286                 if self.extension:
1287                         self.object.properties['FLT']['EXT'] = dict()
1288                         for key in self.extension:
1289                                 self.object.properties['FLT']['EXT'][key] = self.extension[key]
1290                 
1291                 if self.parent and self.parent.object and (self.header.scene == self.parent.header.scene):
1292                                 self.parent.object.makeParent([self.object],1)
1293
1294                 if self.matrix:
1295                         self.object.setMatrix(self.matrix)
1296                 
1297                 if self.vis == False:
1298                         self.object.restrictDisplay = True
1299                         self.object.restrictRender = True
1300                 
1301                 else: #check for LOD children and set the proper flags
1302                         lodlist = list()
1303                         for child in self.children:
1304                                 if child.props.has_key('type') and child.props['type'] == 73:
1305                                         if child.props['6d!switch out'] != 0.0:
1306                                                 child.vis = False
1307                                         #lodlist.append(child)
1308                         
1309                         #def LODmin(a,b):
1310                         #       if a.props['5d!switch in'] < b.props['5d!switch in']:
1311                         #               return a 
1312                         #       return b
1313                 
1314                         #min= None
1315                         #if len(lodlist) > 1:
1316                         #       for lod in lodlist:
1317                         #               lod.vis = False
1318                         #       min = lodlist[0]
1319                         #       for i in xrange(len(lodlist)):
1320                         #               min= LODmin(min,lodlist[i])
1321                         #       min.vis = True
1322                                 
1323                         
1324                 Node.blender_import(self) # Attach faces to self.faceLs
1325                 
1326                 if self.hasMesh:
1327                         # Add all my faces into the mesh at once
1328                         self.blender_import_my_faces()
1329                         
1330         def parse_face(self):
1331                 child = Face(self, self.subfacelevel)
1332                 child.parse()
1333                 return True
1334
1335         def parse_group(self):
1336                 child = Group(self)
1337                 child.parse()
1338                 return True
1339
1340         def move_to_next_layer(self):
1341                 global current_layer
1342                 current_layer = current_layer << 1
1343                 if current_layer > 0x80000:
1344                         current_layer = 1
1345
1346         def parse_lod(self):
1347                 child = LOD(self)
1348                 child.parse()
1349                 return True
1350
1351         def parse_unhandled(self):
1352                 child = Unhandled(self)
1353                 child.parse()
1354                 return True
1355
1356         def parse_object(self):
1357                 child = Object(self)
1358                 child.parse()
1359                 return True
1360         
1361         def parse_xref(self):
1362                 child = XRef(self)
1363                 child.parse()
1364                 return True
1365
1366         def parse_dof(self):
1367                 child = DOF(self)
1368                 child.parse()
1369                 return True
1370
1371         def parse_indexed_light_point(self):
1372                 child = IndexedLightPoint(self)
1373                 child.parse()
1374                 return True
1375                 
1376         def parse_inline_light_point(self):
1377                 child = InlineLightPoint(self)
1378                 child.parse()
1379                 return True
1380                 
1381         def parse_matrix(self):
1382                 m = list()
1383                 for i in xrange(4):
1384                         m.append([])
1385                         for j in xrange(4):
1386                                 f = self.header.fw.read_float()
1387                                 m[i].append(f)
1388                 self.matrix = Blender.Mathutils.Matrix(m[0], m[1], m[2], m[3])
1389                 
1390         def parse_subpush(self):
1391                 self.parse_push()
1392                 self.subfacelevel+= 1
1393                 return True
1394         def  parse_subpop(self):
1395                 self.parse_pop()
1396                 self.subfacelevel -= 1
1397                 return True
1398
1399                 
1400                 
1401 class Face(Node):
1402         def __init__(self, parent,subfacelevel):
1403                 Node.__init__(self, parent, parent.header)
1404                 self.root_handler.set_handler({31: self.parse_comment,
1405                                                                            10: self.parse_push,
1406                                                                            52: self.parse_multitex})
1407                 self.root_handler.set_throw_back_lst(throw_back_opcodes)
1408                 
1409                 self.child_handler.set_handler({72: self.parse_vertex_list,
1410                                                                                 10: self.parse_push,
1411                                                                                 11: self.parse_pop,
1412                                                                                 53: self.parse_uvlist})
1413                 
1414                 if parent:
1415                         parent.hasMesh = True
1416
1417                 self.subfacelevel = subfacelevel
1418                 self.indices =  list()  # face verts here
1419                 self.uvlayers = dict()  # MultiTexture layers keyed to layer bitmask.
1420                 self.uverts = list()    # Vertex aligned list of dictionaries keyed to layer bitmask.
1421                 self.uvmask = 0                 # Bitfield read from MTex record
1422                 
1423                 self.comment = ''
1424                 self.props = dict()             
1425                 self.props['id'] = self.header.fw.read_string(8)
1426                 # Load face.
1427                 self.props['ir color'] = self.header.fw.read_int()
1428                 self.props['priority'] = self.header.fw.read_short()
1429                 self.props['draw type'] = self.header.fw.read_char()
1430                 self.props['texture white'] = self.header.fw.read_char()
1431                 self.header.fw.read_ahead(4) # color name indices
1432                 self.header.fw.read_ahead(1) # reserved
1433                 self.props['template billboard'] = self.header.fw.read_uchar()
1434                 self.detail_tex_index = self.header.fw.read_short()
1435                 self.tex_index = self.header.fw.read_short()
1436                 self.mat_index = self.header.fw.read_short()
1437                 self.props['smc'] = self.header.fw.read_short()
1438                 self.props['fid'] = self.header.fw.read_short()
1439                 self.props['ir material'] = self.header.fw.read_int()
1440                 self.alpha = 1.0 - float(self.header.fw.read_ushort()) / 65535.0
1441                 self.props['lod generation control'] = self.header.fw.read_uchar()
1442                 self.header.fw.read_ahead(1) # line style index
1443                 self.props['flags'] = self.header.fw.read_int()
1444                 self.props['light mode'] = self.header.fw.read_uchar()
1445                 self.header.fw.read_ahead(7)
1446                 a = self.header.fw.read_uchar()
1447                 b = self.header.fw.read_uchar()
1448                 g = self.header.fw.read_uchar()
1449                 r = self.header.fw.read_uchar()
1450                 self.packed_color = [r, g, b, a]
1451                 a = self.header.fw.read_uchar()
1452                 b = self.header.fw.read_uchar()
1453                 g = self.header.fw.read_uchar()
1454                 r = self.header.fw.read_uchar()
1455                 self.alt_packed_color = [r, g, b, a]
1456                 self.tex_map_index = self.header.fw.read_short()
1457                 self.header.fw.read_ahead(2)
1458                 self.color_index = self.header.fw.read_uint()
1459                 self.alt_color_index = self.header.fw.read_uint()
1460                 #self.header.fw.read_ahead(2)
1461                 #self.shader_index = self.header.fw.read_short()
1462
1463         def parse_comment(self):
1464                 self.comment = self.header.fw.read_string(self.header.fw.get_length()-4)
1465                 return True
1466                 
1467         def blender_import(self):
1468                 vert_count = len(self.indices)
1469                 if vert_count < 1:
1470                         if global_prefs['verbose'] >= 2:
1471                                 print 'Warning: Ignoring face with no vertices.'
1472                         return
1473                 
1474                 # Assign material and image
1475                 
1476                 self.parent.faceLs.append(self)
1477                 #need to store comment in mesh prop layer!
1478                 
1479                 # Store comment info in parent.
1480                 #if self.comment != '':
1481                 #       if self.parent.props['comment'] != '':
1482                 #               self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment
1483                 #       else:
1484                 #               self.parent.props['comment'] = self.comment
1485                 
1486                 if self.uvlayers:
1487                         #Make sure that the mesh knows about the layers that this face uses
1488                         self.parent.hasmtex = True
1489                         for mask in self.uvlayers.keys():
1490                                 self.parent.uvlayers[mask] = True
1491                         
1492         def parse_vertex_list(self):
1493                 length = self.header.fw.get_length()
1494                 fw = self.header.fw
1495                 vert_pal = self.header.vert_pal
1496
1497                 count = (length-4)/4
1498                 
1499                 # If this ever fails the chunk below does error checking
1500                 self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)]
1501                 '''
1502                 for i in xrange(count):
1503                         byte_offset = fw.read_int()
1504                         if byte_offset in vert_pal.index:
1505                                 index = vert_pal.index[byte_offset]
1506                                 self.indices.append(index)
1507                         elif global_prefs['verbose'] >= 1:
1508                                 print 'Warning: Unable to map byte offset %s' + \
1509                                           ' to vertex index.' % byte_offset
1510                 '''
1511                 return True
1512         
1513         def parse_multitex(self):
1514                 #Parse  MultiTex Record.
1515                 length = self.header.fw.get_length()
1516                 fw = self.header.fw
1517                 #num layers == (length - 8) / 4
1518                 uvmask = fw.read_uint()
1519                 mask = 2147483648
1520                 for i in xrange(7):
1521                         if mask & uvmask:
1522                                 uvlayer = dict()
1523                                 self.uvlayers[mask] = uvlayer
1524                         mask = mask / 2
1525                 
1526                 #read in record for each individual layer.
1527                 for key in reversed(sorted(self.uvlayers)):
1528                         uvlayer = self.uvlayers[key]
1529                         uvlayer['texture index'] = fw.read_ushort()
1530                         uvlayer['texture enviorment'] = fw.read_ushort()
1531                         uvlayer['texture mapping'] = fw.read_ushort()
1532                         uvlayer['texture data'] = fw.read_ushort()
1533                 
1534                         self.uvmask = uvmask
1535                 
1536         def parse_uvlist(self):
1537                 #for each uvlayer, add uv vertices
1538                 length = self.header.fw.get_length()
1539                 fw = self.header.fw
1540                 uvmask = fw.read_uint()
1541                 if uvmask != self.uvmask: #This should never happen!
1542                         fw.read_ahead(self.length -  4) #potentially unnessecary?
1543                 else:   
1544                         #need to store in uvverts dictionary for each vertex.
1545                         totverts = len(self.indices)
1546                         for i in xrange(totverts):
1547                                 uvert = dict()
1548                                 for key in reversed(sorted(self.uvlayers)):
1549                                         uv = Vector(0.0,0.0)
1550                                         uv[0] = fw.read_float()
1551                                         uv[1] = fw.read_float()
1552                                         uvert[key] = uv
1553                                 self.uverts.append(uvert)
1554                                 
1555 class Object(InterNode):
1556         def __init__(self, parent):
1557                 Node.__init__(self, parent, parent.header)
1558                 InterNode.__init__(self)
1559                 
1560                 self.root_handler.set_handler({33: self.parse_long_id,
1561                                                                         21: self.parse_push_extension,
1562                                                                         31: self.parse_comment,
1563                                                                         10: self.parse_push,
1564                                                                         49: self.parse_matrix})
1565                 self.root_handler.set_throw_back_lst(throw_back_opcodes)
1566                 
1567                 self.child_handler.set_handler({5: self.parse_face,
1568                                                                                 19: self.parse_subpush,
1569                                                                                 20: self.parse_subpop,
1570                                                                                 111: self.parse_inline_light_point,
1571                                                                                 10: self.parse_push,
1572                                                                                 11: self.parse_pop})
1573                 self.extension_handler.set_handler({22: self.parse_pop_extension,
1574                                                                 100: self.parse_extension})
1575                 
1576                 self.extension = dict()
1577                 self.props = dict()             
1578                 self.props['comment'] = ''
1579                 self.parse_record()
1580
1581 class Group(InterNode):
1582         def __init__(self, parent):
1583                 Node.__init__(self, parent, parent.header)
1584                 InterNode.__init__(self)
1585                 
1586                 self.root_handler.set_handler({33: self.parse_long_id,
1587                                                                            31: self.parse_comment,
1588                                                                            10: self.parse_push,
1589                                                                            49: self.parse_matrix,
1590                                                                            21: self.parse_push_extension})
1591                 self.root_handler.set_throw_back_lst(throw_back_opcodes)
1592                 
1593                 self.child_handler.set_handler({5: self.parse_face,
1594                                                                                 19: self.parse_subpush,
1595                                                                                 20: self.parse_subpop,
1596                                                                                 111: self.parse_inline_light_point,
1597                                                                                 2: self.parse_group,
1598                                                                                 73: self.parse_lod,
1599                                                                                 4: self.parse_object,
1600                                                                                 10: self.parse_push,
1601                                                                                 11: self.parse_pop,
1602                                                                                 96: self.parse_unhandled,
1603                                                                                 14: self.parse_dof,
1604                                                                                 91: self.parse_unhandled,
1605                                                                                 98: self.parse_unhandled,
1606                                                                                 63: self.parse_xref})
1607                                                                                 
1608                 self.extension_handler.set_handler({22: self.parse_pop_extension,
1609                                                                 100: self.parse_extension})
1610                                                                 
1611                 self.props = dict.fromkeys(['type', 'id', 'comment', 'priority', 'flags', 'special1',
1612                                                                         'special2', 'significance', 'layer code', 'loop count',
1613                                                                         'loop duration', 'last frame duration'])
1614                 
1615                 self.props['comment'] = ''
1616                 self.parse_record()
1617                 
1618                 #self.props['type'] = str(self.opcode) + ':' + opcode_name[self.opcode]
1619                 #props = records[self.opcode]
1620                 #propkeys = props.keys()
1621                 #propkeys.sort()
1622                 #for position in propkeys:
1623                 #       (type,length,name) = props[position]
1624                 #       self.props[name] = read_prop(self.header.fw,type,length)
1625                 #self.props['id'] = self.props['3t8!id']
1626
1627 class DOF(InterNode):
1628         def blender_import(self):
1629                 InterNode.blender_import(self)
1630
1631         def __init__(self, parent):
1632                 Node.__init__(self, parent, parent.header)
1633                 InterNode.__init__(self)
1634                 
1635                 self.root_handler.set_handler({33: self.parse_long_id,
1636                                                                            31: self.parse_comment,
1637                                                                            10: self.parse_push,
1638                                                                            49: self.parse_matrix,
1639                                                                            21: self.parse_push_extension})
1640                 self.root_handler.set_throw_back_lst(throw_back_opcodes)
1641                 
1642                 self.child_handler.set_handler({#130: self.parse_indexed_light_point,
1643                                                                                 111: self.parse_inline_light_point,
1644                                                                                 2: self.parse_group,
1645                                                                                 73: self.parse_lod,
1646                                                                                 4: self.parse_object,
1647                                                                                 10: self.parse_push,
1648                                                                                 11: self.parse_pop,
1649                                                                                 96: self.parse_unhandled,
1650                                                                                 14: self.parse_dof,
1651                                                                                 91: self.parse_unhandled,
1652                                                                                 98: self.parse_unhandled,
1653                                                                                 63: self.parse_xref})
1654                 self.extension_handler.set_handler({22: self.parse_pop_extension,
1655                                                                                 100: self.parse_extension})
1656                 self.props = dict()             
1657                 self.props['comment'] = ''
1658                 self.parse_record()
1659
1660
1661 class XRef(InterNode):
1662         def parse(self):
1663                 if self.xref:
1664                         self.xref.parse()
1665                 Node.parse(self)
1666
1667         def __init__(self, parent):
1668                 Node.__init__(self, parent, parent.header)
1669                 InterNode.__init__(self)
1670                 
1671                 self.root_handler.set_handler({49: self.parse_matrix})
1672                 self.root_handler.set_throw_back_lst(throw_back_opcodes)
1673                 
1674                 self.props = dict()             
1675                 self.props['comment'] = ''
1676                 self.parse_record()
1677
1678                 xref_filename = self.props['3t200!filename'] #I dont even think there is a reason to keep this around...
1679                 
1680                 if not os.path.isabs(xref_filename):
1681                         absname = os.path.join(os.path.dirname(self.header.filename), xref_filename) 
1682                 else:
1683                         absname = xref_filename 
1684                 
1685                 self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(xref_filename))[0] #this is really wrong as well....
1686                 
1687                 if global_prefs['doxrefs'] and os.path.exists(absname) and not self.header.grr.xrefs.has_key(xref_filename):
1688                         self.xref = Database(absname, self.header.grr, self)
1689                         self.header.grr.xrefs[xref_filename] = self.xref
1690                 else:
1691                         self.xref = None
1692                 
1693
1694         def blender_import(self):
1695                 #name = self.props['type'] + ': ' + self.props['id']
1696                 name = self.props['id']
1697                 self.object = self.header.scene.objects.new('Empty')
1698                 self.object.name = name
1699                 self.object.enableDupGroup = True
1700                 self.header.group.objects.link(self.object)
1701                 
1702                 #for broken links its ok to leave this empty! they purely for visual purposes anyway.....
1703                 try:
1704                         self.object.DupGroup = self.header.grr.xrefs[self.props['3t200!filename']].group
1705                 except:
1706                         pass
1707                         
1708
1709
1710
1711                 if self.parent and self.parent.object:
1712                         self.parent.object.makeParent([self.object],1)
1713
1714                 if self.matrix:
1715                         self.object.setMatrix(self.matrix)
1716
1717
1718                 #id props import
1719                 self.object.properties['FLT'] = dict()
1720                 for key in self.props:
1721                         try:
1722                                 self.object.properties['FLT'][key] = self.props[key]
1723                         except: #horrible...
1724                                 pass
1725
1726                 self.object.Layer = current_layer
1727                 self.object.sel = 1
1728
1729                 Node.blender_import(self)
1730                 
1731                 
1732 class LOD(InterNode):
1733         def blender_import(self):
1734                 #self.move_to_next_layer()
1735                 InterNode.blender_import(self)
1736                 #self.object.properties['FLT'] = self.props.copy()
1737                 
1738         def __init__(self, parent):
1739                 Node.__init__(self, parent, parent.header)
1740                 InterNode.__init__(self)
1741
1742                 self.root_handler.set_handler({33: self.parse_long_id,
1743                                                                            31: self.parse_comment,
1744                                                                            10: self.parse_push,
1745                                                                            49: self.parse_matrix,
1746                                                                            21: self.parse_push_extension})
1747                 self.root_handler.set_throw_back_lst(throw_back_opcodes)
1748                 
1749                 self.child_handler.set_handler({2: self.parse_group,
1750                                                                                 111: self.parse_inline_light_point,
1751                                                                                 73: self.parse_lod,
1752                                                                                 4: self.parse_object,
1753                                                                                 10: self.parse_push,
1754                                                                                 11: self.parse_pop,
1755                                                                                 96: self.parse_unhandled, # switch
1756                                                                                 14: self.parse_dof, # DOF
1757                                                                                 91: self.parse_unhandled, # sound
1758                                                                                 98: self.parse_unhandled, # clip
1759                                                                                 63: self.parse_xref})
1760                 self.extension_handler.set_handler({22: self.parse_pop_extension,
1761                                                                 100: self.parse_extension})
1762
1763
1764                 self.props = dict()             
1765                 self.props['comment'] = ''
1766                 self.parse_record()
1767
1768 class InlineLightPoint(InterNode):
1769         def __init__(self, parent):
1770                 Node.__init__(self, parent, parent.header)
1771                 InterNode.__init__(self)
1772                 self.root_handler.set_handler({33: self.parse_long_id,
1773                                                                            31: self.parse_comment,
1774                                                                            10: self.parse_push,
1775                                                                            21: self.parse_push_extension,
1776                                                                            49: self.parse_matrix})
1777                 self.root_handler.set_throw_back_lst(throw_back_opcodes)
1778                 
1779                 self.child_handler.set_handler({72: self.parse_vertex_list,
1780                                                                                 10: self.parse_push,
1781                                                                                 11: self.parse_pop})
1782                 self.extension_handler.set_handler({22: self.parse_pop_extension,
1783                                                                 100: self.parse_extension})
1784                 
1785                 self.indices = list()
1786                 self.props = dict()             
1787                 self.props['comment'] = ''
1788                 self.parse_record()
1789
1790                 
1791         def blender_import(self):
1792                 
1793
1794                 name = self.props['id']
1795                 self.mesh= Blender.Mesh.New()
1796                 self.mesh.name = 'FLT_LP'
1797                 self.object = self.header.scene.objects.new(self.mesh)
1798                 self.object.name = name
1799                 #self.mesh.verts.extend(Vector() ) # DUMMYVERT
1800                 self.object.Layer = current_layer
1801                 self.object.sel= 1
1802         
1803                 self.object.properties['FLT'] = dict()
1804                 for key in self.props:
1805                         try:
1806                                 self.object.properties['FLT'][key] = self.props[key]
1807                         except: #horrible...
1808                                 pass
1809
1810                 if self.extension:
1811                         self.object.properties['FLT']['EXT'] = dict()
1812                         for key in self.extension:
1813                                 self.object.properties['FLT']['EXT'][key] = self.extension[key]
1814
1815                 if self.parent and self.parent.object and self.header.scene == self.parent.header.scene:
1816                         self.parent.object.makeParent([self.object])
1817
1818                 if self.matrix:
1819                         self.object.setMatrix(self.matrix)
1820
1821                 self.mesh.verts.extend([self.header.vert_pal.blender_verts[i] for i in self.indices])
1822                 
1823                 #add color index information.
1824                 self.mesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"])
1825                 for i, vindex in enumerate(self.indices):
1826                         vdesc = self.header.vert_pal.vert_desc_lst[vindex]
1827                         v = self.mesh.verts[i]
1828                         v.setProperty("FLT_VCOL",vdesc.cindex)
1829                 #for i, v in enumerate(self.mesh.verts):
1830                 #       vdesc = self.header.vert_pal.vert_desc_lst[i]
1831                 #       v.setProperty("FLT_VCOL",vdesc.cindex)
1832                 self.mesh.update()
1833                                 
1834         def parse_vertex_list(self):
1835                 length = self.header.fw.get_length()
1836                 fw = self.header.fw
1837                 vert_pal = self.header.vert_pal
1838
1839                 count = (length-4)/4
1840                 
1841                 # If this ever fails the chunk below does error checking
1842                 self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)]
1843                 
1844                 '''
1845                 for i in xrange(count):
1846                         byte_offset = fw.read_int()
1847                         if byte_offset in vert_pal.index:
1848                                 index = vert_pal.index[byte_offset]
1849                                 self.indices.append(index)
1850                         elif global_prefs['verbose'] >= 1:
1851                                 print 'Warning: Unable to map byte offset %s' + \
1852                                           ' to vertex index.' % byte_offset
1853                 '''
1854                 
1855                 return True
1856                 
1857
1858
1859 class IndexedLightPoint(InterNode):
1860         # return dictionary: lp_app name => index list
1861         def group_points(self, props):
1862                 
1863                 name_to_indices = {}
1864                 
1865                 for i in self.indices:
1866                         vert_desc = self.header.vert_pal.vert_desc_lst[i]
1867                         app_desc = LightPointAppDesc()
1868                         app_desc.props.update(props)
1869                         # add vertex normal and color
1870                         app_desc.props.update({'nx': vert_desc.nx})
1871                         app_desc.props.update({'ny': vert_desc.ny})
1872                         app_desc.props.update({'nz': vert_desc.nz})
1873                         
1874                         app_desc.props.update({'r': vert_desc.r})
1875                         app_desc.props.update({'g': vert_desc.g})
1876                         app_desc.props.update({'b': vert_desc.b})
1877                         app_desc.props.update({'a': vert_desc.a})
1878                         
1879                         app_name = self.header.grr.request_lightpoint_app(app_desc, self.header.scene)
1880
1881                         if name_to_indices.get(app_name):
1882                                 name_to_indices[app_name].append(i)
1883                         else:
1884                                 name_to_indices.update({app_name: [i]})
1885                         
1886                 return name_to_indices
1887                 
1888         def blender_import(self):
1889                 name = self.props['type'] + ': ' + self.props['id']
1890                 
1891                 name_to_indices = self.group_points(self.header.lightpoint_appearance_pal[self.index])
1892                 
1893                 for app_name, indices in name_to_indices.iteritems():        
1894                         self.object = Blender.Object.New('Mesh', name)
1895                         self.mesh= Blender.Mesh.New()
1896                         self.mesh.verts.extend( Vector() ) # DUMMYVERT
1897                         self.object.link(self.mesh)
1898                         
1899                         if self.parent:
1900                                 self.parent.object.makeParent([self.object])
1901                                 
1902                         for i in indices:
1903                                 vert = self.header.vert_pal.blender_verts[i]
1904                                 self.mesh.verts.append(vert)
1905                         
1906                         self.header.scene.objects.link(self.object)
1907         
1908                         self.object.Layer = current_layer
1909                         
1910                         if self.matrix:
1911                                 self.object.setMatrix(self.matrix)
1912                                 
1913                         # Import comment.
1914                         if self.props['comment'] != '':
1915                                 name = 'COMMENT: ' + self.props['id']
1916                                 t = Blender.Text.New(name)
1917                                 t.write(self.props['comment'])
1918                                 self.props['comment'] = name
1919                                 
1920                         # Attach properties.
1921                         self.props.update({'appearance': app_name})
1922                         for name, value in self.props.iteritems():
1923                                 self.object.addProperty(name, value)
1924                         
1925                         self.mesh.update()
1926                         
1927         def parse_vertex_list(self):
1928                 length = self.header.fw.get_length()
1929                 fw = self.header.fw
1930                 vert_pal = self.header.vert_pal
1931
1932                 count = (length-4)/4
1933                 
1934                 # If this ever fails the chunk below does error checking
1935                 self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)]
1936                 
1937                 '''
1938                 for i in xrange(count):
1939                         byte_offset = fw.read_int()
1940                         if byte_offset in vert_pal.index:
1941                                 index = vert_pal.index[byte_offset]
1942                                 self.indices.append(index)
1943                         elif global_prefs['verbose'] >= 1:
1944                                 print 'Warning: Unable to map byte offset %s' + \
1945                                           ' to vertex index.' % byte_offset
1946                 '''
1947                 return True
1948                 
1949         def __init__(self, parent):
1950                 Node.__init__(self, parent, parent.header)
1951                 InterNode.__init__(self)
1952                 self.root_handler.set_handler({33: self.parse_long_id,
1953                                                                            31: self.parse_comment,
1954                                                                            10: self.parse_push,
1955                                                                            49: self.parse_matrix})
1956                 self.root_handler.set_throw_back_lst(throw_back_opcodes)
1957                 
1958                 self.child_handler.set_handler({72: self.parse_vertex_list,
1959                                                                                 10: self.parse_push,
1960                                                                                 11: self.parse_pop})
1961
1962                 self.indices = list()
1963                 
1964                 self.props = dict.fromkeys(['id', 'type', 'comment', 'draw order', 'appearance'])
1965                 self.props['comment'] = ''
1966                 self.props['type'] = 'Light Point'
1967                 self.props['id'] = self.header.fw.read_string(8)
1968                 self.index = self.header.fw.read_int()
1969                 self.header.fw.read_ahead(4) # animation index
1970                 self.props['draw order'] = self.header.fw.read_int()        
1971
1972 class Unhandled(InterNode):
1973         def __init__(self, parent):
1974                 Node.__init__(self, parent, parent.header)
1975                 InterNode.__init__(self)
1976                 
1977                 self.root_handler.set_handler({33: self.parse_long_id,
1978                                                                            31: self.parse_comment,
1979                                                                            10: self.parse_push,
1980                                                                            49: self.parse_matrix})
1981                 self.root_handler.set_throw_back_lst(throw_back_opcodes)
1982                 
1983                 self.child_handler.set_handler({2: self.parse_group,
1984                                                                                 73: self.parse_lod,
1985                                                                                 4: self.parse_object,
1986                                                                                 10: self.parse_push,
1987                                                                                 11: self.parse_pop,
1988                                                                                 96: self.parse_unhandled, # switch
1989                                                                                 14: self.parse_dof, # DOF
1990                                                                                 91: self.parse_unhandled, # sound
1991                                                                                 98: self.parse_unhandled, # clip
1992                                                                                 63: self.parse_xref})
1993
1994                 self.props['id'] = self.header.fw.read_string(8)
1995
1996 class Database(InterNode):
1997         def blender_import(self):
1998                 for key in self.tex_pal.keys():
1999                         path_filename= FF.find(self.tex_pal[key][0])
2000                         if path_filename != None:
2001                                 img = self.grr.request_image(path_filename)
2002                                 if img:
2003                                         self.tex_pal[key][1] = img
2004                         elif global_prefs['verbose'] >= 1:
2005                                 print 'Warning: Unable to find', self.tex_pal[key][0]
2006                 
2007                 self.scene.properties['FLT'] = dict()
2008                 for key in self.props:
2009                         try:
2010                                 self.scene.properties['FLT'][key] = self.props[key]
2011                         except: #horrible...
2012                                 pass
2013                 
2014                 self.scene.properties['FLT']['Main'] = 0
2015                 self.scene.properties['FLT']['Filename'] = self.bname
2016                 
2017                 for child in self.children:
2018                         if child.props.has_key('type') and child.props['type'] == 73:
2019                                 if child.props['6d!switch out'] != 0.0:
2020                                                 child.vis = False
2021                 
2022                 #import color palette
2023                 carray = list()
2024                 for color in self.col_pal:
2025                         carray.append(struct.unpack('>i',struct.pack('>BBBB',color[0],color[1],color[2],color[3]))[0])
2026                 self.scene.properties['FLT']['Color Palette'] = carray
2027                 Node.blender_import(self)
2028
2029         def parse_appearance_palette(self):
2030                 props = dict()
2031                 self.fw.read_ahead(4) # reserved
2032                 props.update({'id': self.fw.read_string(256)})
2033                 index = self.fw.read_int()
2034                 props.update({'smc': self.fw.read_short()})
2035                 props.update({'fid': self.fw.read_short()})
2036                 props.update({'back color: a': self.fw.read_uchar()})
2037                 props.update({'back color: b': self.fw.read_uchar()})
2038                 props.update({'back color: g': self.fw.read_uchar()})
2039                 props.update({'back color: r': self.fw.read_uchar()})
2040                 props.update({'display mode': self.fw.read_int()})
2041                 props.update({'intensity': self.fw.read_float()})
2042                 props.update({'back intensity': self.fw.read_float()})
2043                 props.update({'minimum defocus': self.fw.read_float()})
2044                 props.update({'maximum defocus': self.fw.read_float()})
2045                 props.update({'fading mode': self.fw.read_int()})
2046                 props.update({'fog punch mode': self.fw.read_int()})
2047                 props.update({'directional mode': self.fw.read_int()})
2048                 props.update({'range mode': self.fw.read_int()})
2049                 props.update({'min pixel size': self.fw.read_float()})
2050                 props.update({'max pixel size': self.fw.read_float()})
2051                 props.update({'actual size': self.fw.read_float()})
2052                 props.update({'trans falloff pixel size': self.fw.read_float()})
2053                 props.update({'trans falloff exponent': self.fw.read_float()})
2054                 props.update({'trans falloff scalar': self.fw.read_float()})
2055                 props.update({'trans falloff clamp': self.fw.read_float()})
2056                 props.update({'fog scalar': self.fw.read_float()})
2057                 props.update({'fog intensity': self.fw.read_float()})
2058                 props.update({'size threshold': self.fw.read_float()})
2059                 props.update({'directionality': self.fw.read_int()})
2060                 props.update({'horizontal lobe angle': self.fw.read_float()})
2061                 props.update({'vertical lobe angle': self.fw.read_float()})
2062                 props.update({'lobe roll angle': self.fw.read_float()})
2063                 props.update({'dir falloff exponent': self.fw.read_float()})
2064                 props.update({'dir ambient intensity': self.fw.read_float()})
2065                 props.update({'significance': self.fw.read_float()})
2066                 props.update({'flags': self.fw.read_int()})
2067                 props.update({'visibility range': self.fw.read_float()})
2068                 props.update({'fade range ratio': self.fw.read_float()})
2069                 props.update({'fade in duration': self.fw.read_float()})
2070                 props.update({'fade out duration': self.fw.read_float()})
2071                 props.update({'LOD range ratio': self.fw.read_float()})
2072                 props.update({'LOD scale': self.fw.read_float()})
2073                 
2074                 self.lightpoint_appearance_pal.update({index: props})
2075                 
2076         def parse_header(self):
2077                 self.props['type'] = 'Header'
2078                 self.props['comment'] = ''
2079                 self.props['id'] = self.fw.read_string(8)
2080                 self.props['version'] = self.fw.read_int()
2081                 self.fw.read_ahead(46)
2082                 self.props['units'] = self.fw.read_char()
2083                 self.props['set white'] = bool(self.fw.read_char())
2084                 self.props['flags'] = self.fw.read_int()
2085                 self.fw.read_ahead(24)
2086                 self.props['projection type'] = self.fw.read_int()
2087                 self.fw.read_ahead(36)
2088                 self.props['sw x'] = self.fw.read_double()
2089                 self.props['sw y'] = self.fw.read_double()
2090                 self.props['dx'] = self.fw.read_double()
2091                 self.props['dy'] = self.fw.read_double()
2092                 self.fw.read_ahead(24)
2093                 self.props['sw lat'] = self.fw.read_double()
2094                 self.props['sw lon'] = self.fw.read_double()
2095                 self.props['ne lat'] = self.fw.read_double()
2096                 self.props['ne lon'] = self.fw.read_double()
2097                 self.props['origin lat'] = self.fw.read_double()
2098                 self.props['origin lon'] = self.fw.read_double()
2099                 self.props['lambert lat1'] = self.fw.read_double()
2100                 self.props['lambert lat2'] = self.fw.read_double()
2101                 self.fw.read_ahead(16)
2102                 self.props['ellipsoid model'] = self.fw.read_int()
2103                 self.fw.read_ahead(4)
2104                 self.props['utm zone'] = self.fw.read_short()
2105                 self.fw.read_ahead(6)
2106                 self.props['dz'] = self.fw.read_double()
2107                 self.props['radius'] = self.fw.read_double()
2108                 self.fw.read_ahead(8)
2109                 self.props['major axis'] = self.fw.read_double()
2110                 self.props['minor axis'] = self.fw.read_double()
2111                 
2112                 if global_prefs['verbose'] >= 1:
2113                         print 'OpenFlight Version:', float(self.props['version']) / 100.0
2114                         print
2115                         
2116                 return True
2117
2118         def parse_mat_palette(self):
2119                 mat_desc = MaterialDesc()
2120                 index = self.fw.read_int()
2121
2122                 name = self.fw.read_string(12)
2123                 if len(mat_desc.name) > 0:
2124                         mat_desc.name = name
2125
2126                 flag = self.fw.read_int()
2127                 # skip material if not used
2128                 if not flag & 0x80000000:
2129                         return True
2130
2131                 ambient_col = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()]
2132                 mat_desc.diffuse = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()]
2133                 mat_desc.specular = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()]
2134                 emissive_col = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()]
2135
2136                 mat_desc.shininess = self.fw.read_float() / 64.0 # [0.0, 128.0] => [0.0, 2.0]
2137                 mat_desc.alpha = self.fw.read_float()
2138
2139                 # Convert ambient and emissive colors into intensitities.
2140                 mat_desc.ambient = col_to_gray(ambient_col)
2141                 mat_desc.emissive = col_to_gray(emissive_col)
2142
2143                 self.mat_desc_pal_lst.append( (index, mat_desc) )
2144                 
2145                 return True
2146         
2147         def get_color(self, color_index):
2148                 color = None
2149                 index = color_index / 128
2150                 intensity = float(color_index - 128.0 * index) / 127.0
2151                 
2152                 if index >= 0 and index <= 1023:
2153                         brightest = self.col_pal[index]
2154                         r = int(brightest[0] * intensity)
2155                         g = int(brightest[1] * intensity)
2156                         b = int(brightest[2] * intensity)
2157                         a = int(brightest[3])
2158                         
2159                         color = [r, g, b, a]
2160                 
2161                 return color
2162         
2163         def parse_color_palette(self):
2164                 self.header.fw.read_ahead(128)
2165                 for i in xrange(1024):
2166                         a = self.header.fw.read_uchar()
2167                         b = self.header.fw.read_uchar()
2168                         g = self.header.fw.read_uchar()
2169                         r = self.header.fw.read_uchar()
2170                         self.col_pal.append((r, g, b, a))
2171                 return True
2172                 
2173         def parse_vertex_palette(self):
2174                 self.vert_pal = VertexPalette(self)
2175                 self.vert_pal.parse()
2176                 return True
2177                 
2178         def parse_texture_palette(self):
2179                 name = self.fw.read_string(200)
2180                 index = self.fw.read_int()
2181                 self.tex_pal[index]= [name, None]
2182                 return True
2183         
2184         def read_attribute_files(self):
2185                 for tex in self.tex_pal.keys():
2186                         [name,image] = self.tex_pal[tex]
2187                         basename = os.path.basename(name)
2188                         if(image):
2189                                 basename = basename + ".attr"
2190                                 dirname = os.path.dirname(Blender.sys.expandpath(image.getFilename())) #can't rely on original info stored in pallette since it might be relative link
2191                                 newpath = os.path.join(dirname, basename)
2192                                 if os.path.exists(newpath) and not image.properties.has_key('FLT'):
2193                                         fw = flt_filewalker.FltIn(newpath)
2194                                         fw.read_ahead(8) #We dont care what the attribute file says about x/y dimensions
2195                                         image.properties['FLT']={}
2196                                         
2197                                         #need to steal code from parse records....
2198                                         props = records['Image']
2199                                         propkeys = props.keys()
2200                                         propkeys.sort()
2201                                         for position in propkeys:
2202                                                 (type,length,name) = props[position]
2203                                                 image.properties['FLT'][name] = read_prop(fw,type,length)
2204                                         fw.close_file()
2205                                         
2206                                         #copy clamp settings
2207                                         wrap = image.properties['FLT']['10i!Wrap']
2208                                         wrapu = image.properties['FLT']['11i!WrapU']
2209                                         wrapv = image.properties['FLT']['12i!WrapV']
2210                                         
2211                                         if wrapu == 3 or wrapv == 3:
2212                                                 wrapuv = (wrap,wrap)
2213                                         else:
2214                                                 wrapuv = (wrapu, wrapv)
2215                                         image.clampX = wrapuv[0]
2216                                         image.clampY = wrapuv[1]
2217                                         
2218                                 elif not os.path.exists(newpath):
2219                                         print "Cannot read attribute file:" + newpath
2220                                         
2221         def __init__(self, filename, grr, parent=None):
2222                 if global_prefs['verbose'] >= 1:
2223                         print 'Parsing:', filename
2224                         print
2225                 
2226                 #check to see if filename is a relative path
2227                 #filename = os.path.abspath(filename)
2228                 
2229                 self.fw = flt_filewalker.FltIn(filename)
2230                 self.filename = filename
2231                 self.bname = os.path.splitext(os.path.basename(filename))[0]
2232                 self.grr = grr
2233                 
2234                 Node.__init__(self, parent, self)
2235                 InterNode.__init__(self)
2236                 
2237                 self.root_handler.set_handler({1: self.parse_header,
2238                                                                            67: self.parse_vertex_palette,
2239                                                                            33: self.parse_long_id,
2240                                                                            31: self.parse_comment,
2241                                                                            64: self.parse_texture_palette,
2242                                                                            32: self.parse_color_palette,
2243                                                                            113: self.parse_mat_palette,
2244                                                                            128: self.parse_appearance_palette,
2245                                                                            10: self.parse_push})
2246                 if parent:
2247                         self.root_handler.set_throw_back_lst(throw_back_opcodes)
2248
2249                 self.child_handler.set_handler({#130: self.parse_indexed_light_point,
2250                                                                                 111: self.parse_inline_light_point,
2251                                                                                 2: self.parse_group,
2252                                                                                 73: self.parse_lod,
2253                                                                                 4: self.parse_object,
2254                                                                                 10: self.parse_push,
2255                                                                                 11: self.parse_pop,
2256                                                                                 96: self.parse_unhandled,
2257                                                                                 14: self.parse_dof,
2258                                                                                 91: self.parse_unhandled,
2259                                                                                 98: self.parse_unhandled,
2260                                                                                 63: self.parse_xref})
2261                 
2262                 self.scene = Blender.Scene.New(self.bname)
2263                 self.group = Blender.Group.New(self.bname)
2264
2265                 self.vert_pal = None
2266                 self.lightpoint_appearance_pal = dict()
2267                 self.tex_pal = dict()
2268                 #self.tex_pal_lst = list()
2269                 #self.bl_tex_pal = dict()
2270                 self.col_pal = list()
2271                 self.mat_desc_pal_lst = list()
2272                 self.mat_desc_pal = dict()
2273                 self.props = dict.fromkeys(['id', 'type', 'comment', 'version', 'units', 'set white',
2274                         'flags', 'projection type', 'sw x', 'sw y', 'dx', 'dy', 'dz', 'sw lat',
2275                         'sw lon', 'ne lat', 'ne lon', 'origin lat', 'origin lon', 'lambert lat1',
2276                         'lambert lat2', 'ellipsoid model', 'utm zone', 'radius', 'major axis', 'minor axis'])
2277
2278
2279 def clearparent(root,childhash):
2280         for child in childhash[root]:
2281                 clearparent(child,childhash)
2282         root.clrParent(2,0)
2283
2284 def fixscale(root,childhash):   
2285         for child in childhash[root]:
2286                 fixscale(child,childhash)
2287         location = Blender.Mathutils.Vector(root.getLocation('worldspace'))
2288         if location[0] != 0.0 or location[1] != 0.0 or location[2] != 0.0:
2289                 #direction = Blender.Mathutils.Vector(0-location[0],0-location[1],0-location[2]) #reverse vector
2290                 smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4)
2291                 root.setLocation(location * smat)
2292         #if its a mesh, we need to scale all of its vertices too
2293         if root.type == 'Mesh':
2294                 smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4)
2295                 rmesh = root.getData(mesh=True)
2296                 for v in rmesh.verts:
2297                         v.co = v.co * smat
2298         
2299         
2300 def reparent(root,childhash,sce):
2301         for child in childhash[root]:
2302                 reparent(child,childhash,sce)
2303         
2304         root.makeParent(childhash[root])
2305         sce.update(1)
2306         
2307 def update_scene(root,sdone):
2308         for object in root.objects:
2309                 if object.DupGroup:
2310                         try:
2311                                 child = Blender.Scene.Get(object.DupGroup.name)
2312                         except:
2313                                 child = None
2314                         if child and child not in sdone:
2315                                 update_scene(child,sdone)
2316         root.makeCurrent()
2317         #create a list of children for each object
2318         childhash = dict()
2319         for object in root.objects:
2320                 childhash[object] = list()
2321                 
2322         for object in root.objects:
2323                 if object.parent:
2324                         childhash[object.parent].append(object)
2325         
2326         for object in root.objects:
2327                 if not object.parent:
2328                         #recursivley go through and clear all the children of their transformation, starting at deepest level first.
2329                         clearparent(object,childhash)
2330                         #now fix the location of everything
2331                         fixscale(object,childhash)
2332                         #now fix the parenting
2333                         reparent(object,childhash,root)
2334         
2335         for object in root.objects:
2336                 object.makeDisplayList()
2337         root.update(1)
2338         sdone.append(root)
2339
2340
2341 def select_file(filename, grr):
2342         if not Blender.sys.exists(filename):
2343                 msg = 'Error: File ' + filename + ' does not exist.'
2344                 Blender.Draw.PupMenu(msg)
2345                 return
2346         
2347         if not filename.lower().endswith('.flt'):
2348                 msg = 'Error: Not a flight file.'
2349                 Blender.Draw.PupMenu(msg)
2350                 print msg
2351                 print
2352                 return
2353         
2354         global_prefs['fltfile']= filename
2355         global_prefs['verbose']= 1
2356         global_prefs['get_texture'] = True
2357         global_prefs['get_diffuse'] = True
2358         global_prefs['get_specular'] = False
2359         global_prefs['get_emissive'] = False
2360         global_prefs['get_alpha'] = True
2361         global_prefs['get_ambient'] = False
2362         global_prefs['get_shininess'] = True
2363         global_prefs['color_from_face'] = True
2364         global_prefs['log to blender'] = True
2365         
2366         
2367         
2368         Blender.Window.WaitCursor(True)
2369         Blender.Window.EditMode(0)
2370         
2371         
2372         FF.add_file_to_search_path(filename)
2373         
2374         if global_prefs['verbose'] >= 1:
2375                 print 'Pass 1: Loading.'
2376                 print
2377
2378         load_time = Blender.sys.time()    
2379         db = Database(filename,grr)
2380         db.parse()
2381         load_time = Blender.sys.time() - load_time
2382
2383         if global_prefs['verbose'] >= 1:
2384                 print
2385                 print 'Pass 2: Importing to Blender.'
2386                 print
2387
2388         import_time = Blender.sys.time()
2389         db.blender_import()
2390         
2391         if global_prefs['attrib']:
2392                 print "reading attribute files"
2393                 db.read_attribute_files()
2394         
2395         Blender.Window.ViewLayer(range(1,21))
2396         
2397         update_scene(db.scene,[])
2398         import_time = Blender.sys.time() - import_time
2399         if global_prefs['verbose'] >= 1:
2400                 print 'Done.'
2401                 print
2402                 print 'Time to parse file: %.3f seconds' % load_time
2403                 print 'Time to import to blender: %.3f seconds' % import_time
2404                 print 'Total time: %.3f seconds' % (load_time + import_time)
2405         
2406         Blender.Window.WaitCursor(False)
2407
2408 def setimportscale(ID,val):
2409         global global_prefs
2410         global_prefs['scale'] = val
2411 def setBpath(fname):
2412         global_prefs['fltfile'] = fname
2413         d = dict()
2414         for key in global_prefs:
2415                 d[key] = global_prefs[key]
2416                 Blender.Registry.SetKey('flt_import', d, 1) 
2417
2418 def event(evt,val):
2419         pass
2420
2421 from Blender.BGL import *
2422 from Blender import Draw
2423
2424 def but_event(evt):
2425         
2426         global FLTBaseLabel
2427         global FLTBaseString
2428         global FLTBaseChooser
2429
2430         global FLTExport
2431         global FLTClose
2432         
2433         global FLTDoXRef
2434         global FLTShadeImport
2435         global FLTAttrib
2436         
2437         global FLTWarn
2438         
2439         #Import DB
2440         if evt == 1:
2441                 if global_prefs['verbose'] >= 1:
2442                         print
2443                         print 'OpenFlight Importer'
2444                         print 'Version:', __version__
2445                         print 'Author: Greg MacDonald, Campbell Barton, Geoffrey Bantle'
2446                         print __url__[2]
2447                         print
2448                 
2449                 GRR = GlobalResourceRepository()
2450                 
2451                 try:
2452                         select_file(global_prefs['fltfile'], GRR)
2453                 except:
2454                         import traceback
2455                         FLTWarn = Draw.PupBlock("Export Error", ["See console for output!"])
2456                         traceback.print_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)
2457         
2458         #choose base path for export
2459         if evt == 4:
2460                 Blender.Window.FileSelector(setBpath, "DB Root", global_prefs['fltfile'])
2461         #Import custom shading?
2462         if evt == 9:
2463                 global_prefs['smoothshading'] = FLTShadeImport.val
2464         #Import Image attribute files
2465         if evt == 10:
2466                 global_prefs['attrib'] = FLTAttrib.val
2467         #export XRefs
2468         if evt == 13:
2469                 global_prefs['doxrefs'] = FLTDoXRef.val
2470         
2471         if evt == 2:
2472                 Draw.Exit()
2473         
2474         d = dict()
2475         for key in global_prefs:
2476                 d[key] = global_prefs[key]
2477                 Blender.Registry.SetKey('flt_import', d, 1) 
2478
2479 def gui():
2480         
2481         global FLTBaseLabel
2482         global FLTBaseString
2483         global FLTBaseChooser
2484
2485         global FLTExport
2486         global FLTClose
2487         
2488         global FLTDoXRef
2489         global FLTShadeImport
2490         
2491         global FLTAttrib
2492         
2493         
2494         glClearColor(0.772,0.832,0.847,1.0)
2495         glClear(GL_COLOR_BUFFER_BIT)
2496         
2497         areas = Blender.Window.GetScreenInfo()
2498         curarea = Blender.Window.GetAreaID()
2499         curRect = None
2500         
2501         for area in areas:
2502                 if area['id'] == curarea:
2503                         curRect = area['vertices']
2504                         break
2505         
2506         width = curRect[2] - curRect[0]
2507         height = curRect[3] - curRect[1]
2508         cx = 50
2509         cy = height - 80
2510
2511         FLTBaseLabel = Draw.Label("Base file:",cx,cy,100,20)
2512         FLTBaseString = Draw.String("",3,cx+100,cy,300,20,global_prefs['fltfile'],255,"Root DB file")
2513         FLTBaseChooser = Draw.PushButton("...",4,cx+400,cy,20,20,"Choose Folder")
2514         
2515         cy = cy-40
2516         FLTScale = Draw.Number("Import Scale",14,cx,cy,220,20,global_prefs['scale'],0.0,100.0,"Export scaleing factor",setimportscale)
2517         
2518         cy = cy-40
2519         FLTDoXRef = Draw.Toggle("Import XRefs", 13,cx,cy,220,20,global_prefs['doxrefs'],"Import External references")
2520         
2521         cy = cy-40
2522         FLTShadeImport = Draw.Toggle("Import Custom Shading",9,cx,cy,220,20,global_prefs['smoothshading'],"Import custom shading via edgesplit modifiers")
2523         
2524         cy = cy-40
2525         FLTAttrib = Draw.Toggle("Import Attribute Files", 10,cx,cy,220,20,global_prefs['attrib'],"Import Image Attribute files")
2526         
2527         cy = cy - 40
2528         FLTExport = Draw.PushButton("Import",1,cx,20,100,20,"Import FLT Database")
2529         FLTClose = Draw.PushButton("Close",2,cx+120,20,100,20,"Close Window")
2530
2531         
2532         
2533 Draw.Register(gui,event,but_event)