~diresu/blender/blender-command-port

« back to all changes in this revision

Viewing changes to release/scripts/ac3d_import.py

  • Committer: theeth
  • Date: 2008-10-14 16:52:04 UTC
  • Revision ID: vcs-imports@canonical.com-20081014165204-r32w2gm6s0osvdhn
copy back trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!BPY
 
2
 
 
3
""" Registration info for Blender menus:
 
4
Name: 'AC3D (.ac)...'
 
5
Blender: 243
 
6
Group: 'Import'
 
7
Tip: 'Import an AC3D (.ac) file.'
 
8
"""
 
9
 
 
10
__author__ = "Willian P. Germano"
 
11
__url__ = ("blender", "blenderartists.org", "AC3D's homepage, http://www.ac3d.org",
 
12
        "PLib 3d gaming lib, http://plib.sf.net")
 
13
__version__ = "2.43.1 2007-02-21"
 
14
 
 
15
__bpydoc__ = """\
 
16
This script imports AC3D models into Blender.
 
17
 
 
18
AC3D is a simple and affordable commercial 3d modeller also built with OpenGL.
 
19
The .ac file format is an easy to parse text format well supported,
 
20
for example, by the PLib 3d gaming library.
 
21
 
 
22
Supported:<br>
 
23
    UV-textured meshes with hierarchy (grouping) information.
 
24
 
 
25
Missing:<br>
 
26
    The url tag is irrelevant for Blender.
 
27
 
 
28
Known issues:<br>
 
29
    - Some objects may be imported with wrong normals due to wrong information in the model itself. This can be noticed by strange shading, like darker than expected parts in the model. To fix this, select the mesh with wrong normals, enter edit mode and tell Blender to recalculate the normals, either to make them point outside (the usual case) or inside.<br>
 
30
 
 
31
Config Options:<br>
 
32
    - display transp (toggle): if "on", objects that have materials with alpha < 1.0 are shown with translucency (transparency) in the 3D View.<br>
 
33
    - subdiv (toggle): if "on", ac3d objects meant to be subdivided receive a SUBSURF modifier in Blender.<br>
 
34
    - textures dir (string): if non blank, when imported texture paths are
 
35
wrong in the .ac file, Blender will also look for them at this dir.
 
36
 
 
37
Notes:<br>
 
38
   - When looking for assigned textures, Blender tries in order: the actual
 
39
paths from the .ac file, the .ac file's dir and the default textures dir path
 
40
users can configure (see config options above).
 
41
"""
 
42
 
 
43
# $Id: ac3d_import.py 14530 2008-04-23 14:04:05Z campbellbarton $
 
44
#
 
45
# --------------------------------------------------------------------------
 
46
# AC3DImport version 2.43.1 Feb 21, 2007
 
47
# Program versions: Blender 2.43 and AC3Db files (means version 0xb)
 
48
# changed: better triangulation of ngons, more fixes to support bad .ac files,
 
49
# option to display transp mats in 3d view, support "subdiv" tag (via SUBSURF modifier)
 
50
# --------------------------------------------------------------------------
 
51
# Thanks: Melchior Franz for extensive bug testing and reporting, making this
 
52
# version cope much better with old or bad .ac files, among other improvements;
 
53
# Stewart Andreason for reporting a serious crash.
 
54
# --------------------------------------------------------------------------
 
55
# ***** BEGIN GPL LICENSE BLOCK *****
 
56
#
 
57
# Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br
 
58
#
 
59
# This program is free software; you can redistribute it and/or
 
60
# modify it under the terms of the GNU General Public License
 
61
# as published by the Free Software Foundation; either version 2
 
62
# of the License, or (at your option) any later version.
 
63
#
 
64
# This program is distributed in the hope that it will be useful,
 
65
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
66
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
67
# GNU General Public License for more details.
 
68
#
 
69
# You should have received a copy of the GNU General Public License
 
70
# along with this program; if not, write to the Free Software Foundation,
 
71
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
72
#
 
73
# ***** END GPL LICENCE BLOCK *****
 
74
# --------------------------------------------------------------------------
 
75
 
 
76
from math import radians
 
77
 
 
78
import Blender
 
79
from Blender import Scene, Object, Mesh, Lamp, Registry, sys as bsys, Window, Image, Material, Modifier
 
80
from Blender.sys import dirsep
 
81
from Blender.Mathutils import Vector, Matrix, Euler
 
82
from Blender.Geometry import PolyFill
 
83
 
 
84
# Default folder for AC3D textures, to override wrong paths, change to your
 
85
# liking or leave as "":
 
86
TEXTURES_DIR = ""
 
87
 
 
88
DISPLAY_TRANSP = True
 
89
 
 
90
SUBDIV = True
 
91
 
 
92
tooltips = {
 
93
        'DISPLAY_TRANSP': 'Turn transparency on in the 3d View for objects using materials with alpha < 1.0.',
 
94
        'SUBDIV': 'Apply a SUBSURF modifier to objects meant to appear subdivided.',
 
95
        'TEXTURES_DIR': 'Additional folder to look for missing textures.'
 
96
}
 
97
 
 
98
def update_registry():
 
99
        global TEXTURES_DIR, DISPLAY_TRANSP
 
100
        rd = dict([('tooltips', tooltips), ('TEXTURES_DIR', TEXTURES_DIR), ('DISPLAY_TRANSP', DISPLAY_TRANSP), ('SUBDIV', SUBDIV)])
 
101
        Registry.SetKey('ac3d_import', rd, True)
 
102
 
 
103
rd = Registry.GetKey('ac3d_import', True)
 
104
 
 
105
if rd:
 
106
        if 'GROUP' in rd:
 
107
                update_registry()
 
108
        try:
 
109
                TEXTURES_DIR = rd['TEXTURES_DIR']
 
110
                DISPLAY_TRANSP = rd['DISPLAY_TRANSP']
 
111
                SUBDIV = rd['SUBDIV']
 
112
        except:
 
113
                update_registry()
 
114
else: update_registry()
 
115
 
 
116
if TEXTURES_DIR:
 
117
        oldtexdir = TEXTURES_DIR
 
118
        if dirsep == '/': TEXTURES_DIR = TEXTURES_DIR.replace('\\', '/')
 
119
        if TEXTURES_DIR[-1] != dirsep: TEXTURES_DIR = "%s%s" % (TEXTURES_DIR, dirsep)
 
120
        if oldtexdir != TEXTURES_DIR: update_registry()
 
121
 
 
122
 
 
123
VERBOSE = True
 
124
rd = Registry.GetKey('General', True)
 
125
if rd:
 
126
        if rd.has_key('verbose'):
 
127
                VERBOSE = rd['verbose']
 
128
 
 
129
        
 
130
errmsg = ""
 
131
 
 
132
# Matrix to align ac3d's coordinate system with Blender's one,
 
133
# it's a -90 degrees rotation around the x axis:
 
134
AC_TO_BLEND_MATRIX = Matrix([1, 0, 0], [0, 0, 1], [0, -1, 0])
 
135
 
 
136
AC_WORLD = 0
 
137
AC_GROUP = 1
 
138
AC_POLY = 2
 
139
AC_LIGHT = 3
 
140
AC_OB_TYPES = {
 
141
        'world': AC_WORLD,
 
142
        'group': AC_GROUP,
 
143
        'poly':  AC_POLY,
 
144
        'light':  AC_LIGHT
 
145
        }
 
146
 
 
147
AC_OB_BAD_TYPES_LIST = [] # to hold references to unknown (wrong) ob types
 
148
 
 
149
def inform(msg):
 
150
        global VERBOSE
 
151
        if VERBOSE: print msg
 
152
 
 
153
def euler_in_radians(eul):
 
154
        "Used while there's a bug in the BPY API"
 
155
        eul.x = radians(eul.x)
 
156
        eul.y = radians(eul.y)
 
157
        eul.z = radians(eul.z)
 
158
        return eul
 
159
 
 
160
class Obj:
 
161
        
 
162
        def __init__(self, type):
 
163
                self.type = type
 
164
                self.dad = None
 
165
                self.name = ''
 
166
                self.data = ''
 
167
                self.tex = ''
 
168
                self.texrep = [1,1]
 
169
                self.texoff = None
 
170
                self.loc = []
 
171
                self.rot = []
 
172
                self.size = []
 
173
                self.crease = 30
 
174
                self.subdiv = 0
 
175
                self.vlist = []
 
176
                self.flist_cfg = []
 
177
                self.flist_v = []
 
178
                self.flist_uv = []
 
179
                self.elist = []
 
180
                self.matlist = []
 
181
                self.kids = 0
 
182
 
 
183
                self.bl_obj = None # the actual Blender object created from this data
 
184
 
 
185
class AC3DImport:
 
186
 
 
187
        def __init__(self, filename):
 
188
 
 
189
                global errmsg
 
190
 
 
191
                self.scene = Scene.GetCurrent()
 
192
 
 
193
                self.i = 0
 
194
                errmsg = ''
 
195
                self.importdir = bsys.dirname(filename)
 
196
                try:
 
197
                        file = open(filename, 'r')
 
198
                except IOError, (errno, strerror):
 
199
                        errmsg = "IOError #%s: %s" % (errno, strerror)
 
200
                        Blender.Draw.PupMenu('ERROR: %s' % errmsg)
 
201
                        inform(errmsg)
 
202
                        return None
 
203
                header = file.read(5)
 
204
                header, version = header[:4], header[-1]
 
205
                if header != 'AC3D':
 
206
                        file.close()
 
207
                        errmsg = 'AC3D header not found (invalid file)'
 
208
                        Blender.Draw.PupMenu('ERROR: %s' % errmsg)
 
209
                        inform(errmsg)
 
210
                        return None
 
211
                elif version != 'b':
 
212
                        inform('AC3D file version 0x%s.' % version)
 
213
                        inform('This importer is for version 0xb, so it may fail.')
 
214
 
 
215
                self.token = {'OBJECT':         self.parse_obj,
 
216
                                          'numvert':    self.parse_vert,
 
217
                                          'numsurf':    self.parse_surf,
 
218
                                          'name':               self.parse_name,
 
219
                                          'data':               self.parse_data,
 
220
                                          'kids':               self.parse_kids,
 
221
                                          'loc':                self.parse_loc,
 
222
                                          'rot':                self.parse_rot,
 
223
                                          'MATERIAL':   self.parse_mat,
 
224
                                          'texture':    self.parse_tex,
 
225
                                          'texrep':             self.parse_texrep,
 
226
                                          'texoff':             self.parse_texoff,
 
227
                                          'subdiv':             self.parse_subdiv,
 
228
                                          'crease':             self.parse_crease}
 
229
 
 
230
                self.objlist = []
 
231
                self.mlist = []
 
232
                self.kidsnumlist = []
 
233
                self.dad = None
 
234
 
 
235
                self.lines = file.readlines()
 
236
                self.lines.append('')
 
237
                self.parse_file()
 
238
                file.close()
 
239
                
 
240
                self.testAC3DImport()
 
241
                                
 
242
        def parse_obj(self, value):
 
243
                kidsnumlist = self.kidsnumlist
 
244
                if kidsnumlist:
 
245
                        while not kidsnumlist[-1]:
 
246
                                kidsnumlist.pop()
 
247
                                if kidsnumlist:
 
248
                                        self.dad = self.dad.dad
 
249
                                else:
 
250
                                        inform('Ignoring unexpected data at end of file.')
 
251
                                        return -1 # bad file with more objects than reported
 
252
                        kidsnumlist[-1] -= 1
 
253
                if value in AC_OB_TYPES:
 
254
                        new = Obj(AC_OB_TYPES[value])
 
255
                else:
 
256
                        if value not in AC_OB_BAD_TYPES_LIST:
 
257
                                AC_OB_BAD_TYPES_LIST.append(value)
 
258
                                inform('Unexpected object type keyword: "%s". Assuming it is of type: "poly".' % value)
 
259
                        new = Obj(AC_OB_TYPES['poly'])
 
260
                new.dad = self.dad
 
261
                new.name = value
 
262
                self.objlist.append(new)
 
263
 
 
264
        def parse_kids(self, value):
 
265
                kids = int(value)
 
266
                if kids:
 
267
                        self.kidsnumlist.append(kids)
 
268
                        self.dad = self.objlist[-1]
 
269
                self.objlist[-1].kids = kids
 
270
 
 
271
        def parse_name(self, value):
 
272
                name = value.split('"')[1]
 
273
                self.objlist[-1].name = name
 
274
 
 
275
        def parse_data(self, value):
 
276
                data = self.lines[self.i].strip()
 
277
                self.objlist[-1].data = data
 
278
 
 
279
        def parse_tex(self, value):
 
280
                line = self.lines[self.i - 1] # parse again to properly get paths with spaces
 
281
                texture = line.split('"')[1]
 
282
                self.objlist[-1].tex = texture
 
283
 
 
284
        def parse_texrep(self, trash):
 
285
                trep = self.lines[self.i - 1]
 
286
                trep = trep.split()
 
287
                trep = [float(trep[1]), float(trep[2])]
 
288
                self.objlist[-1].texrep = trep
 
289
                self.objlist[-1].texoff = [0, 0]
 
290
 
 
291
        def parse_texoff(self, trash):
 
292
                toff = self.lines[self.i - 1]
 
293
                toff = toff.split()
 
294
                toff = [float(toff[1]), float(toff[2])]
 
295
                self.objlist[-1].texoff = toff
 
296
                
 
297
        def parse_mat(self, value):
 
298
                i = self.i - 1
 
299
                lines = self.lines
 
300
                line = lines[i].split()
 
301
                mat_name = ''
 
302
                mat_col = mat_amb = mat_emit = mat_spec_col = [0,0,0]
 
303
                mat_alpha = 1
 
304
                mat_spec = 1.0
 
305
 
 
306
                while line[0] == 'MATERIAL':
 
307
                        mat_name = line[1].split('"')[1]
 
308
                        mat_col = map(float,[line[3],line[4],line[5]])
 
309
                        v = map(float,[line[7],line[8],line[9]])
 
310
                        mat_amb = (v[0]+v[1]+v[2]) / 3.0
 
311
                        v = map(float,[line[11],line[12],line[13]])
 
312
                        mat_emit = (v[0]+v[1]+v[2]) / 3.0
 
313
                        mat_spec_col = map(float,[line[15],line[16],line[17]])
 
314
                        mat_spec = float(line[19]) / 64.0
 
315
                        mat_alpha = float(line[-1])
 
316
                        mat_alpha = 1 - mat_alpha
 
317
                        self.mlist.append([mat_name, mat_col, mat_amb, mat_emit, mat_spec_col, mat_spec, mat_alpha])
 
318
                        i += 1
 
319
                        line = lines[i].split()
 
320
 
 
321
                self.i = i
 
322
 
 
323
        def parse_rot(self, trash):
 
324
                i = self.i - 1
 
325
                ob = self.objlist[-1]
 
326
                rot = self.lines[i].split(' ', 1)[1]
 
327
                rot = map(float, rot.split())
 
328
                matrix = Matrix(rot[:3], rot[3:6], rot[6:])
 
329
                ob.rot = matrix
 
330
                size = matrix.scalePart() # vector
 
331
                ob.size = size
 
332
 
 
333
        def parse_loc(self, trash):
 
334
                i = self.i - 1
 
335
                loc = self.lines[i].split(' ', 1)[1]
 
336
                loc = map(float, loc.split())
 
337
                self.objlist[-1].loc = Vector(loc)
 
338
 
 
339
        def parse_crease(self, value):
 
340
                # AC3D: range is [0.0, 180.0]; Blender: [1, 80]
 
341
                value = float(value)
 
342
                self.objlist[-1].crease = int(value)
 
343
 
 
344
        def parse_subdiv(self, value):
 
345
                self.objlist[-1].subdiv = int(value)
 
346
 
 
347
        def parse_vert(self, value):
 
348
                i = self.i
 
349
                lines = self.lines
 
350
                obj = self.objlist[-1]
 
351
                vlist = obj.vlist
 
352
                n = int(value)
 
353
 
 
354
                while n:
 
355
                        line = lines[i].split()
 
356
                        line = map(float, line)
 
357
                        vlist.append(line)
 
358
                        n -= 1
 
359
                        i += 1
 
360
 
 
361
                if vlist: # prepend a vertex at 1st position to deal with vindex 0 issues
 
362
                        vlist.insert(0, line)
 
363
 
 
364
                self.i = i
 
365
 
 
366
        def parse_surf(self, value):
 
367
                i = self.i
 
368
                is_smooth = 0
 
369
                double_sided = 0
 
370
                lines = self.lines
 
371
                obj = self.objlist[-1]
 
372
                vlist = obj.vlist
 
373
                matlist = obj.matlist
 
374
                numsurf = int(value)
 
375
                NUMSURF = numsurf
 
376
 
 
377
                badface_notpoly = badface_multirefs = 0
 
378
 
 
379
                while numsurf:
 
380
                        flags = lines[i].split()[1][2:]
 
381
                        if len(flags) > 1:
 
382
                                flaghigh = int(flags[0])
 
383
                                flaglow = int(flags[1])
 
384
                        else:
 
385
                                flaghigh = 0
 
386
                                flaglow = int(flags[0])
 
387
 
 
388
                        is_smooth = flaghigh & 1
 
389
                        twoside = flaghigh & 2
 
390
                        nextline = lines[i+1].split()
 
391
                        if nextline[0] != 'mat': # the "mat" line may be missing (found in one buggy .ac file)
 
392
                                matid = 0
 
393
                                if not matid in matlist: matlist.append(matid)
 
394
                                i += 2
 
395
                        else:
 
396
                                matid = int(nextline[1])
 
397
                                if not matid in matlist: matlist.append(matid)
 
398
                                nextline = lines[i+2].split()
 
399
                                i += 3
 
400
                        refs = int(nextline[1])
 
401
                        face = []
 
402
                        faces = []
 
403
                        edges = []
 
404
                        fuv = []
 
405
                        fuvs = []
 
406
                        rfs = refs
 
407
 
 
408
                        while rfs:
 
409
                                line = lines[i].split()
 
410
                                v = int(line[0]) + 1 # + 1 to avoid vindex == 0
 
411
                                uv = [float(line[1]), float(line[2])]
 
412
                                face.append(v)
 
413
                                fuv.append(Vector(uv))
 
414
                                rfs -= 1
 
415
                                i += 1
 
416
 
 
417
                        if flaglow: # it's a line or closed line, not a polygon
 
418
                                while len(face) >= 2:
 
419
                                        cut = face[:2]
 
420
                                        edges.append(cut)
 
421
                                        face = face[1:]
 
422
 
 
423
                                if flaglow == 1 and edges: # closed line
 
424
                                        face = [edges[-1][-1], edges[0][0]]
 
425
                                        edges.append(face)
 
426
 
 
427
                        else: # polygon
 
428
 
 
429
                                # check for bad face, that references same vertex more than once
 
430
                                lenface = len(face)
 
431
                                if lenface < 3:
 
432
                                        # less than 3 vertices, not a face
 
433
                                        badface_notpoly += 1
 
434
                                elif sum(map(face.count, face)) != lenface:
 
435
                                        # multiple references to the same vertex
 
436
                                        badface_multirefs += 1
 
437
                                else: # ok, seems fine
 
438
                                        if len(face) > 4: # ngon, triangulate it
 
439
                                                polyline = []
 
440
                                                for vi in face:
 
441
                                                        polyline.append(Vector(vlist[vi]))
 
442
                                                tris = PolyFill([polyline])
 
443
                                                for t in tris:
 
444
                                                        tri = [face[t[0]], face[t[1]], face[t[2]]]
 
445
                                                        triuvs = [fuv[t[0]], fuv[t[1]], fuv[t[2]]]
 
446
                                                        faces.append(tri)
 
447
                                                        fuvs.append(triuvs)
 
448
                                        else: # tri or quad
 
449
                                                faces.append(face)
 
450
                                                fuvs.append(fuv)
 
451
 
 
452
                        obj.flist_cfg.extend([[matid, is_smooth, twoside]] * len(faces))
 
453
                        obj.flist_v.extend(faces)
 
454
                        obj.flist_uv.extend(fuvs)
 
455
                        obj.elist.extend(edges) # loose edges
 
456
 
 
457
                        numsurf -= 1      
 
458
 
 
459
                if badface_notpoly or badface_multirefs:
 
460
                        inform('Object "%s" - ignoring bad faces:' % obj.name)
 
461
                        if badface_notpoly:
 
462
                                inform('\t%d face(s) with less than 3 vertices.' % badface_notpoly)
 
463
                        if badface_multirefs:
 
464
                                inform('\t%d face(s) with multiple references to a same vertex.' % badface_multirefs)
 
465
 
 
466
                self.i = i
 
467
 
 
468
        def parse_file(self):
 
469
                i = 1
 
470
                lines = self.lines
 
471
                line = lines[i].split()
 
472
 
 
473
                while line:
 
474
                        kw = ''
 
475
                        for k in self.token.keys():
 
476
                                if line[0] == k:
 
477
                                        kw = k
 
478
                                        break
 
479
                        i += 1
 
480
                        if kw:
 
481
                                self.i = i
 
482
                                result = self.token[kw](line[1])
 
483
                                if result:
 
484
                                        break # bad .ac file, stop parsing
 
485
                                i = self.i
 
486
                        line = lines[i].split()
 
487
 
 
488
        # for each group of meshes we try to find one that can be used as
 
489
        # parent of the group in Blender.
 
490
        # If not found, we can use an Empty as parent.
 
491
        def found_parent(self, groupname, olist):
 
492
                l = [o for o in olist if o.type == AC_POLY \
 
493
                                and not o.kids and not o.rot and not o.loc]
 
494
                if l:
 
495
                        for o in l:
 
496
                                if o.name == groupname:
 
497
                                        return o
 
498
                                #return l[0]
 
499
                return None
 
500
 
 
501
        def build_hierarchy(self):
 
502
                blmatrix = AC_TO_BLEND_MATRIX
 
503
 
 
504
                olist = self.objlist[1:]
 
505
                olist.reverse()
 
506
 
 
507
                scene = self.scene
 
508
 
 
509
                newlist = []
 
510
 
 
511
                for o in olist:
 
512
                        kids = o.kids
 
513
                        if kids:
 
514
                                children = newlist[-kids:]
 
515
                                newlist = newlist[:-kids]
 
516
                                if o.type == AC_GROUP:
 
517
                                        parent = self.found_parent(o.name, children)
 
518
                                        if parent:
 
519
                                                children.remove(parent)
 
520
                                                o.bl_obj = parent.bl_obj
 
521
                                        else: # not found, use an empty
 
522
                                                empty = scene.objects.new('Empty', o.name)
 
523
                                                o.bl_obj = empty
 
524
 
 
525
                                bl_children = [c.bl_obj for c in children if c.bl_obj != None]
 
526
                                
 
527
                                o.bl_obj.makeParent(bl_children, 0, 1)
 
528
                                for child in children:
 
529
                                        blob = child.bl_obj
 
530
                                        if not blob: continue
 
531
                                        if child.rot:
 
532
                                                eul = euler_in_radians(child.rot.toEuler())
 
533
                                                blob.setEuler(eul)
 
534
                                        if child.size:
 
535
                                                blob.size = child.size
 
536
                                        if not child.loc:
 
537
                                                child.loc = Vector(0.0, 0.0, 0.0)
 
538
                                        blob.setLocation(child.loc)
 
539
 
 
540
                        newlist.append(o)
 
541
 
 
542
                for o in newlist: # newlist now only has objs w/o parents
 
543
                        blob = o.bl_obj
 
544
                        if not blob:
 
545
                                continue
 
546
                        if o.size:
 
547
                                o.bl_obj.size = o.size
 
548
                        if not o.rot:
 
549
                                blob.setEuler([1.5707963267948966, 0, 0])
 
550
                        else:
 
551
                                matrix = o.rot * blmatrix
 
552
                                eul = euler_in_radians(matrix.toEuler())
 
553
                                blob.setEuler(eul)
 
554
                        if o.loc:
 
555
                                o.loc *= blmatrix
 
556
                        else:
 
557
                                o.loc = Vector(0.0, 0.0, 0.0)
 
558
                        blob.setLocation(o.loc) # forces DAG update, so we do it even for 0, 0, 0
 
559
 
 
560
                # XXX important: until we fix the BPy API so it doesn't increase user count
 
561
                # when wrapping a Blender object, this piece of code is needed for proper
 
562
                # object (+ obdata) deletion in Blender:
 
563
                for o in self.objlist:
 
564
                        if o.bl_obj:
 
565
                                o.bl_obj = None
 
566
 
 
567
        def testAC3DImport(self):
 
568
 
 
569
                FACE_TWOSIDE = Mesh.FaceModes['TWOSIDE']
 
570
                FACE_TEX = Mesh.FaceModes['TEX']
 
571
                MESH_AUTOSMOOTH = Mesh.Modes['AUTOSMOOTH']
 
572
 
 
573
                MAT_MODE_ZTRANSP = Material.Modes['ZTRANSP']
 
574
                MAT_MODE_TRANSPSHADOW = Material.Modes['TRANSPSHADOW']
 
575
 
 
576
                scene = self.scene
 
577
 
 
578
                bl_images = {} # loaded texture images
 
579
                missing_textures = [] # textures we couldn't find
 
580
 
 
581
                objlist = self.objlist[1:] # skip 'world'
 
582
 
 
583
                bmat = []
 
584
                has_transp_mats = False
 
585
                for mat in self.mlist:
 
586
                        name = mat[0]
 
587
                        m = Material.New(name)
 
588
                        m.rgbCol = (mat[1][0], mat[1][1], mat[1][2])
 
589
                        m.amb = mat[2]
 
590
                        m.emit = mat[3]
 
591
                        m.specCol = (mat[4][0], mat[4][1], mat[4][2])
 
592
                        m.spec = mat[5]
 
593
                        m.alpha = mat[6]
 
594
                        if m.alpha < 1.0:
 
595
                                m.mode |= MAT_MODE_ZTRANSP
 
596
                                has_transp_mats = True
 
597
                        bmat.append(m)
 
598
 
 
599
                if has_transp_mats:
 
600
                        for mat in bmat:
 
601
                                mat.mode |= MAT_MODE_TRANSPSHADOW
 
602
 
 
603
                obj_idx = 0 # index of current obj in loop
 
604
                for obj in objlist:
 
605
                        if obj.type == AC_GROUP:
 
606
                                continue
 
607
                        elif obj.type == AC_LIGHT:
 
608
                                light = Lamp.New('Lamp')
 
609
                                object = scene.objects.new(light, obj.name)
 
610
                                #object.select(True)
 
611
                                obj.bl_obj = object
 
612
                                if obj.data:
 
613
                                        light.name = obj.data
 
614
                                continue
 
615
 
 
616
                        # type AC_POLY:
 
617
 
 
618
                        # old .ac files used empty meshes as groups, convert to a real ac group
 
619
                        if not obj.vlist and obj.kids:
 
620
                                obj.type = AC_GROUP
 
621
                                continue
 
622
 
 
623
                        mesh = Mesh.New()
 
624
                        object = scene.objects.new(mesh, obj.name)
 
625
                        #object.select(True)
 
626
                        obj.bl_obj = object
 
627
                        if obj.data: mesh.name = obj.data
 
628
                        mesh.degr = obj.crease # will auto clamp to [1, 80]
 
629
 
 
630
                        if not obj.vlist: # no vertices? nothing more to do
 
631
                                continue
 
632
 
 
633
                        mesh.verts.extend(obj.vlist)
 
634
 
 
635
                        objmat_indices = []
 
636
                        for mat in bmat:
 
637
                                if bmat.index(mat) in obj.matlist:
 
638
                                        objmat_indices.append(bmat.index(mat))
 
639
                                        mesh.materials += [mat]
 
640
                                        if DISPLAY_TRANSP and mat.alpha < 1.0:
 
641
                                                object.transp = True
 
642
 
 
643
                        for e in obj.elist:
 
644
                                mesh.edges.extend(e)
 
645
 
 
646
                        if obj.flist_v:
 
647
                                mesh.faces.extend(obj.flist_v)
 
648
 
 
649
                                facesnum = len(mesh.faces)
 
650
 
 
651
                                if facesnum == 0: # shouldn't happen, of course
 
652
                                        continue
 
653
 
 
654
                                mesh.faceUV = True
 
655
 
 
656
                                # checking if the .ac file had duplicate faces (Blender ignores them)
 
657
                                if facesnum != len(obj.flist_v):
 
658
                                        # it has, ugh. Let's clean the uv list:
 
659
                                        lenfl = len(obj.flist_v)
 
660
                                        flist = obj.flist_v
 
661
                                        uvlist = obj.flist_uv
 
662
                                        cfglist = obj.flist_cfg
 
663
                                        for f in flist:
 
664
                                                f.sort()
 
665
                                        fi = lenfl
 
666
                                        while fi > 0: # remove data related to duplicates
 
667
                                                fi -= 1
 
668
                                                if flist[fi] in flist[:fi]:
 
669
                                                        uvlist.pop(fi)
 
670
                                                        cfglist.pop(fi)
 
671
 
 
672
                                img = None
 
673
                                if obj.tex != '':
 
674
                                        if obj.tex in bl_images.keys():
 
675
                                                img = bl_images[obj.tex]
 
676
                                        elif obj.tex not in missing_textures:
 
677
                                                texfname = None
 
678
                                                objtex = obj.tex
 
679
                                                baseimgname = bsys.basename(objtex)
 
680
                                                if bsys.exists(objtex) == 1:
 
681
                                                        texfname = objtex
 
682
                                                elif bsys.exists(bsys.join(self.importdir, objtex)):
 
683
                                                        texfname = bsys.join(self.importdir, objtex)
 
684
                                                else:
 
685
                                                        if baseimgname.find('\\') > 0:
 
686
                                                                baseimgname = bsys.basename(objtex.replace('\\','/'))
 
687
                                                        objtex = bsys.join(self.importdir, baseimgname)
 
688
                                                        if bsys.exists(objtex) == 1:
 
689
                                                                texfname = objtex
 
690
                                                        else:
 
691
                                                                objtex = bsys.join(TEXTURES_DIR, baseimgname)
 
692
                                                                if bsys.exists(objtex):
 
693
                                                                        texfname = objtex
 
694
                                                if texfname:
 
695
                                                        try:
 
696
                                                                img = Image.Load(texfname)
 
697
                                                                # Commented because it's unnecessary:
 
698
                                                                #img.xrep = int(obj.texrep[0])
 
699
                                                                #img.yrep = int(obj.texrep[1])
 
700
                                                                if img:
 
701
                                                                        bl_images[obj.tex] = img
 
702
                                                        except:
 
703
                                                                inform("Couldn't load texture: %s" % baseimgname)
 
704
                                                else:
 
705
                                                        missing_textures.append(obj.tex)
 
706
                                                        inform("Couldn't find texture: %s" % baseimgname)
 
707
 
 
708
                                for i in range(facesnum):
 
709
                                        f = obj.flist_cfg[i]
 
710
                                        fmat = f[0]
 
711
                                        is_smooth = f[1]
 
712
                                        twoside = f[2]
 
713
                                        bface = mesh.faces[i]
 
714
                                        bface.smooth = is_smooth
 
715
                                        if twoside: bface.mode |= FACE_TWOSIDE
 
716
                                        if img:
 
717
                                                bface.mode |= FACE_TEX
 
718
                                                bface.image = img
 
719
                                        bface.mat = objmat_indices.index(fmat)
 
720
                                        fuv = obj.flist_uv[i]
 
721
                                        if obj.texoff:
 
722
                                                uoff = obj.texoff[0]
 
723
                                                voff = obj.texoff[1]
 
724
                                                urep = obj.texrep[0]
 
725
                                                vrep = obj.texrep[1]
 
726
                                                for uv in fuv:
 
727
                                                        uv[0] *= urep
 
728
                                                        uv[1] *= vrep
 
729
                                                        uv[0] += uoff
 
730
                                                        uv[1] += voff
 
731
 
 
732
                                        mesh.faces[i].uv = fuv
 
733
 
 
734
                                # finally, delete the 1st vertex we added to prevent vindices == 0
 
735
                                mesh.verts.delete(0)
 
736
 
 
737
                                mesh.calcNormals()
 
738
 
 
739
                                mesh.mode = MESH_AUTOSMOOTH
 
740
 
 
741
                                # subdiv: create SUBSURF modifier in Blender
 
742
                                if SUBDIV and obj.subdiv > 0:
 
743
                                        subdiv = obj.subdiv
 
744
                                        subdiv_render = subdiv
 
745
                                        # just to be safe:
 
746
                                        if subdiv_render > 6: subdiv_render = 6
 
747
                                        if subdiv > 3: subdiv = 3
 
748
                                        modif = object.modifiers.append(Modifier.Types.SUBSURF)
 
749
                                        modif[Modifier.Settings.LEVELS] = subdiv
 
750
                                        modif[Modifier.Settings.RENDLEVELS] = subdiv_render
 
751
 
 
752
                        obj_idx += 1
 
753
 
 
754
                self.build_hierarchy()
 
755
                scene.update()
 
756
 
 
757
# End of class AC3DImport
 
758
 
 
759
def filesel_callback(filename):
 
760
 
 
761
        inform("\nTrying to import AC3D model(s) from:\n%s ..." % filename)
 
762
        Window.WaitCursor(1)
 
763
        starttime = bsys.time()
 
764
        test = AC3DImport(filename)
 
765
        Window.WaitCursor(0)
 
766
        endtime = bsys.time() - starttime
 
767
        inform('Done! Data imported in %.3f seconds.\n' % endtime)
 
768
 
 
769
Window.EditMode(0)
 
770
 
 
771
Window.FileSelector(filesel_callback, "Import AC3D", "*.ac")