~diresu/blender/blender-command-port

« back to all changes in this revision

Viewing changes to release/scripts/lightwave_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
Name: 'LightWave (.lwo)...'
 
4
Blender: 239
 
5
Group: 'Import'
 
6
Tooltip: 'Import LightWave Object File Format'
 
7
"""
 
8
 
 
9
__author__ = ["Alessandro Pirovano, Anthony D'Agostino (Scorpius)", "Campbell Barton (ideasman42)", "ZanQdo"]
 
10
__url__ = ("www.blender.org", "blenderartist.org",
 
11
"Anthony's homepage, http://www.redrival.com/scorpius", "Alessandro's homepage, http://uaraus.altervista.org")
 
12
 
 
13
importername = "lwo_import 0.4.0"
 
14
 
 
15
# +---------------------------------------------------------+
 
16
# | Save your work before and after use.                    |
 
17
# | Please report any useful comment to:                    |
 
18
# | uaraus-dem@yahoo.it                                     |
 
19
# | Thanks                                                  |
 
20
# +---------------------------------------------------------+
 
21
# +---------------------------------------------------------+
 
22
# | Copyright (c) 2002 Anthony D'Agostino                   |
 
23
# | http://www.redrival.com/scorpius                        |
 
24
# | scorpius@netzero.com                                    |
 
25
# | April 21, 2002                                          |
 
26
# | Import Export Suite v0.5                                |
 
27
# +---------------------------------------------------------+
 
28
# | Read and write LightWave Object File Format (*.lwo)     |
 
29
# +---------------------------------------------------------+
 
30
# +---------------------------------------------------------+
 
31
# | Alessandro Pirovano tweaked starting on March 2005      |
 
32
# | http://uaraus.altervista.org                            |
 
33
# +---------------------------------------------------------+
 
34
# +----------------------------------------------------------
 
35
# | GPL license block
 
36
# |
 
37
# | This program is free software; you can redistribute it and/or modify
 
38
# | it under the terms of the GNU General Public License as published by
 
39
# | the Free Software Foundation; either version 2 of the License, or
 
40
# | (at your option) any later version.
 
41
# |
 
42
# | This program is distributed in the hope that it will be useful,
 
43
# | but WITHOUT ANY WARRANTY; without even the implied warranty of
 
44
# | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
45
# | GNU General Public License for more details.
 
46
# |
 
47
# | You should have received a copy of the GNU General Public License
 
48
# | along with this program; if not, write to the Free Software
 
49
# | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
50
# +----------------------------------------------------------
 
51
# +---------------------------------------------------------+
 
52
# | Release log:                                            |
 
53
# | 0.4.0 : Updated for blender 2.44                        |
 
54
# |         ZanQdo - made the mesh import the right way up  |
 
55
# |         Ideasman42 - Updated functions for the bew API  |
 
56
# |           as well as removing the text object class     |
 
57
# | 0.2.2 : This code works with Blender 2.42 RC3           |
 
58
# |         Added a new PolyFill function for BPYMesh's     |
 
59
# |           ngon() to use, checked compatibility          |
 
60
# |           lightwaves ngons are imported as fgons        |
 
61
# |         Checked compatibility against 1711 lwo files    |
 
62
# | 0.2.1 : This code works with Blender 2.40 RC1           |
 
63
# |         modified material mode assignment to deal with  |
 
64
# |         Python API modification                         |
 
65
# |         Changed script license to GNU GPL               |
 
66
# | 0.2.0:  This code works with Blender 2.40a2 or up       |
 
67
# |         Major rewrite to deal with large meshes         |
 
68
# |         - 2 pass file parsing                           |
 
69
# |         - lower memory foot###if DEBUG: print                        |
 
70
# |           (as long as python gc allows)                 |
 
71
# |         2.40a2 - Removed subsurf settings patches=poly  |
 
72
# |         2.40a2 - Edge generation instead of 2vert faces |
 
73
# | 0.1.16: fixed (try 2) texture offset calculations       |
 
74
# |         added hint on axis mapping                      |
 
75
# |         added hint on texture blending mode             |
 
76
# |         added hint on texture transparency setting      |
 
77
# |         search images in original directory first       |
 
78
# |         fixed texture order application                 |
 
79
# | 0.1.15: added release log                               |
 
80
# |         fixed texture offset calculations (non-UV)      |
 
81
# |         fixed reverting vertex order in face generation |
 
82
# |         associate texture on game-engine settings       |
 
83
# |         vector math definitely based on mathutils       |
 
84
# |         search images in "Images" and "../Images" dir   |
 
85
# |         revised logging facility                        |
 
86
# |         fixed subsurf texture and material mappings     |
 
87
# | 0.1.14: patched missing mod_vector (not definitive)     |
 
88
# | 0.1.13: first public release                            |
 
89
# +---------------------------------------------------------+
 
90
 
 
91
#blender related import
 
92
import Blender
 
93
import bpy
 
94
 
 
95
# use for comprehensiveImageLoad
 
96
import BPyImage
 
97
 
 
98
# Use this ngon function
 
99
import BPyMesh
 
100
 
 
101
import BPyMessages
 
102
 
 
103
#python specific modules import
 
104
try:
 
105
        import struct, chunk, cStringIO
 
106
except:
 
107
        struct= chunk= cStringIO= None
 
108
 
 
109
### # Debuggin disabled in release.
 
110
### # do a search replace to enabe debug prints
 
111
### DEBUG = False
 
112
 
 
113
# ===========================================================
 
114
# === Utility Preamble ======================================
 
115
# ===========================================================
 
116
 
 
117
textname = None
 
118
#uncomment the following line to enable logging facility to the named text object
 
119
#textname = "lwo_log"
 
120
 
 
121
TXMTX = Blender.Mathutils.Matrix(\
 
122
[1, 0, 0, 0],\
 
123
[0, 0, 1, 0],\
 
124
[0, 1, 0, 0],\
 
125
[0, 0, 0, 1])
 
126
 
 
127
# ===========================================================
 
128
# === Make sure it is a string ... deal with strange chars ==
 
129
# ===========================================================
 
130
def safestring(st):
 
131
        myst = ""
 
132
        for ll in xrange(len(st)):
 
133
                if st[ll] < " ":
 
134
                        myst += "#"
 
135
                else:
 
136
                        myst += st[ll]
 
137
        return myst
 
138
 
 
139
# ===========================================================
 
140
# === Main read functions ===================================
 
141
# ===========================================================
 
142
 
 
143
# =============================
 
144
# === Read LightWave Format ===
 
145
# =============================
 
146
def read(filename):
 
147
        if BPyMessages.Error_NoFile(filename):
 
148
                return
 
149
 
 
150
        print "This is: %s" % importername
 
151
        print "Importing file:", filename
 
152
        bpy.data.scenes.active.objects.selected = []
 
153
        
 
154
        start = Blender.sys.time()
 
155
        file = open(filename, "rb")
 
156
        
 
157
        editmode = Blender.Window.EditMode()    # are we in edit mode?  If so ...
 
158
        if editmode: Blender.Window.EditMode(0) # leave edit mode before getting the mesh    # === LWO header ===
 
159
        
 
160
        try:
 
161
                form_id, form_size, form_type = struct.unpack(">4s1L4s",  file.read(12))
 
162
        except:
 
163
                Blender.Draw.PupMenu('Error%t|This is not a lightwave file')
 
164
                return
 
165
        
 
166
        if (form_type == "LWOB"):
 
167
                read_lwob(file, filename)
 
168
        elif (form_type == "LWO2"):
 
169
                read_lwo2(file, filename)
 
170
        else:
 
171
                print "Can't read a file with the form_type: %s" % form_type
 
172
                return
 
173
 
 
174
        Blender.Window.DrawProgressBar(1.0, "")    # clear progressbar
 
175
        file.close()
 
176
        end = Blender.sys.time()
 
177
        seconds = " in %.2f %s" % (end-start, "seconds")
 
178
        if form_type == "LWO2": fmt = " (v6.0 Format)"
 
179
        if form_type == "LWOB": fmt = " (v5.5 Format)"
 
180
        print "Successfully imported " + filename.split('\\')[-1].split('/')[-1] + fmt + seconds
 
181
        
 
182
        if editmode: Blender.Window.EditMode(1)  # optional, just being nice
 
183
        Blender.Redraw()
 
184
 
 
185
# enddef read
 
186
 
 
187
 
 
188
# =================================
 
189
# === Read LightWave 5.5 format ===
 
190
# =================================
 
191
def read_lwob(file, filename):
 
192
        #This function is directly derived from the LWO2 import routine
 
193
        #dropping all the material analysis parts
 
194
 
 
195
        ###if DEBUG: print "LightWave 5.5 format"
 
196
 
 
197
        dir_part = Blender.sys.dirname(filename)
 
198
        fname_part = Blender.sys.basename(filename)
 
199
        #ask_weird = 1
 
200
 
 
201
        #first initialization of data structures
 
202
        defaultname = Blender.sys.splitext(fname_part)[0]
 
203
        tag_list = []              #tag list: global for the whole file?
 
204
        surf_list = []             #surf list: global for the whole file?
 
205
        clip_list = []             #clip list: global for the whole file?
 
206
        object_index = 0
 
207
        object_list = None
 
208
        objspec_list = None
 
209
 
 
210
        #add default material for orphaned faces, if any
 
211
        surf_list.append({'NAME': "_Orphans", 'g_MAT': bpy.data.materials.new("_Orphans")})
 
212
 
 
213
        #pass 2: effectively generate objects
 
214
        ###if DEBUG: print "Pass 1: dry import"
 
215
        file.seek(0)
 
216
        objspec_list = ["imported", {}, [], [], {}, {}, 0, {}, {}]
 
217
        # === LWO header ===
 
218
        form_id, form_size, form_type = struct.unpack(">4s1L4s",  file.read(12))
 
219
        if (form_type != "LWOB"):
 
220
                ###if DEBUG: print "??? Inconsistent file type: %s" % form_type
 
221
                return
 
222
        while 1:
 
223
                try:
 
224
                        lwochunk = chunk.Chunk(file)
 
225
                except EOFError:
 
226
                        break
 
227
                ###if DEBUG: print ' ',
 
228
                if lwochunk.chunkname == "LAYR":
 
229
                        ###if DEBUG: print "---- LAYR",
 
230
                        objname = read_layr(lwochunk)
 
231
                        ###if DEBUG: print objname
 
232
                        if objspec_list != None: #create the object
 
233
                                create_objects(clip_list, objspec_list, surf_list)
 
234
                                update_material(clip_list, objspec_list, surf_list) #give it all the object
 
235
                        objspec_list = [objname, {}, [], [], {}, {}, 0, {}, {}]
 
236
                        object_index += 1
 
237
                elif lwochunk.chunkname == "PNTS":                         # Verts
 
238
                        ###if DEBUG: print "---- PNTS",
 
239
                        verts = read_verts(lwochunk)
 
240
                        objspec_list[2] = verts
 
241
                elif lwochunk.chunkname == "POLS": # Faces v5.5
 
242
                        ###if DEBUG: print "-------- POLS(5.5)"
 
243
                        faces = read_faces_5(lwochunk)
 
244
                        flag = 0
 
245
                        #flag is 0 for regular polygon, 1 for patches (= subsurf), 2 for anything else to be ignored
 
246
                        if flag<2:
 
247
                                if objspec_list[3] != []:
 
248
                                        #create immediately the object
 
249
                                        create_objects(clip_list, objspec_list, surf_list)
 
250
                                        update_material(clip_list, objspec_list, surf_list) #give it all the object
 
251
                                        #update with new data
 
252
                                        objspec_list = [objspec_list[0],                  #update name
 
253
                                                                        {},                               #init
 
254
                                                                        objspec_list[2],                  #same vertexes
 
255
                                                                        faces,                            #give it the new faces
 
256
                                                                        {},                               #no need to copy - filled at runtime
 
257
                                                                        {},                               #polygon tagging will follow
 
258
                                                                        flag,                             #patch flag
 
259
                                                                        objspec_list[7],                  #same uvcoords
 
260
                                                                        {}]                               #no vmad mapping
 
261
                                        object_index += 1
 
262
                                #end if already has a face list
 
263
                                objspec_list[3] = faces
 
264
                                objname = objspec_list[0]
 
265
                                if objname == None:
 
266
                                        objname = defaultname
 
267
                        #end if processing a valid poly type
 
268
                else:                                                       # Misc Chunks
 
269
                        ###if DEBUG: print "---- %s: skipping (definitely!)" % lwochunk.chunkname
 
270
                        lwochunk.skip()
 
271
                #uncomment here to log data structure as it is built
 
272
                # ###if DEBUG: print object_list
 
273
        #last object read
 
274
        create_objects(clip_list, objspec_list, surf_list)
 
275
        update_material(clip_list, objspec_list, surf_list) #give it all the object
 
276
        objspec_list = None
 
277
        surf_list = None
 
278
        clip_list = None
 
279
 
 
280
 
 
281
        ###if DEBUG: print "\nFound %d objects:" % object_index
 
282
 
 
283
# enddef read_lwob
 
284
 
 
285
 
 
286
# =============================
 
287
# === Read LightWave Format ===
 
288
# =============================
 
289
def read_lwo2(file, filename, typ="LWO2"):
 
290
 
 
291
        ###if DEBUG: print "LightWave 6 (and above) format"
 
292
 
 
293
        dir_part = Blender.sys.dirname(filename)
 
294
        fname_part = Blender.sys.basename(filename)
 
295
        ask_weird = 1
 
296
 
 
297
        #first initialization of data structures
 
298
        defaultname = Blender.sys.splitext(fname_part)[0]
 
299
        tag_list = []              #tag list: global for the whole file?
 
300
        surf_list = []             #surf list: global for the whole file?
 
301
        clip_list = []             #clip list: global for the whole file?
 
302
        object_index = 0
 
303
        object_list = None
 
304
        objspec_list = None
 
305
        # init value is: object_list = [[None, {}, [], [], {}, {}, 0, {}, {}]]
 
306
        #0 - objname                    #original name
 
307
        #1 - obj_dict = {TAG}           #objects created
 
308
        #2 - verts = []                 #object vertexes
 
309
        #3 - faces = []                 #object faces (associations poly -> vertexes)
 
310
        #4 - obj_dim_dict = {TAG}       #tuples size and pos in local object coords - used for NON-UV mappings
 
311
        #5 - polytag_dict = {TAG}       #tag to polygons mapping
 
312
        #6 - patch_flag                 #0 = surf; 1 = patch (subdivision surface) - it was the image list
 
313
        #7 - uvcoords_dict = {name}     #uvmap coordinates (mixed mode per vertex/per face)
 
314
        #8 - facesuv_dict = {name}      #vmad only coordinates associations poly & vertex -> uv tuples
 
315
 
 
316
        #pass 1: look in advance for materials
 
317
        ###if DEBUG: print "Starting Pass 1: hold on tight"
 
318
        while 1:
 
319
                try:
 
320
                        lwochunk = chunk.Chunk(file)
 
321
                except EOFError:
 
322
                        break
 
323
                ###if DEBUG: print ' ',
 
324
                if lwochunk.chunkname == "TAGS":                         # Tags
 
325
                        ###if DEBUG: print "---- TAGS"
 
326
                        tag_list.extend(read_tags(lwochunk))
 
327
                elif lwochunk.chunkname == "SURF":                         # surfaces
 
328
                        ###if DEBUG: print "---- SURF"
 
329
                        surf_list.append(read_surfs(lwochunk, surf_list, tag_list))
 
330
                elif lwochunk.chunkname == "CLIP":                         # texture images
 
331
                        ###if DEBUG: print "---- CLIP"
 
332
                        clip_list.append(read_clip(lwochunk, dir_part))
 
333
                        ###if DEBUG: print "read total %s clips up to now" % len(clip_list)
 
334
                else:                                                       # Misc Chunks
 
335
                        if ask_weird:
 
336
                                ckname = safestring(lwochunk.chunkname)
 
337
                                if "#" in ckname:
 
338
                                        choice = Blender.Draw.PupMenu("WARNING: file could be corrupted.%t|Import anyway|Give up")
 
339
                                        if choice != 1:
 
340
                                                ###if DEBUG: print "---- %s: Maybe file corrupted. Terminated by user" % lwochunk.chunkname
 
341
                                                return
 
342
                                        ask_weird = 0
 
343
                        ###if DEBUG: print "---- %s: skipping (maybe later)" % lwochunk.chunkname
 
344
                        lwochunk.skip()
 
345
 
 
346
        #add default material for orphaned faces, if any
 
347
        surf_list.append({'NAME': "_Orphans", 'g_MAT': bpy.data.materials.new("_Orphans")})
 
348
 
 
349
        #pass 2: effectively generate objects
 
350
        ###if DEBUG: print "Pass 2: now for the hard part"
 
351
        file.seek(0)
 
352
        # === LWO header ===
 
353
        form_id, form_size, form_type = struct.unpack(">4s1L4s",  file.read(12))
 
354
        if (form_type != "LWO2"):
 
355
                ###if DEBUG: print "??? Inconsistent file type: %s" % form_type
 
356
                return
 
357
        while 1:
 
358
                try:
 
359
                        lwochunk = chunk.Chunk(file)
 
360
                except EOFError:
 
361
                        break
 
362
                ###if DEBUG: print ' ',
 
363
                if lwochunk.chunkname == "LAYR":
 
364
                        ###if DEBUG: print "---- LAYR"
 
365
                        objname = read_layr(lwochunk)
 
366
                        ###if DEBUG: print objname
 
367
                        if objspec_list != None: #create the object
 
368
                                create_objects(clip_list, objspec_list, surf_list)
 
369
                                update_material(clip_list, objspec_list, surf_list) #give it all the object
 
370
                        objspec_list = [objname, {}, [], [], {}, {}, 0, {}, {}]
 
371
                        object_index += 1
 
372
                elif lwochunk.chunkname == "PNTS":                         # Verts
 
373
                        ###if DEBUG: print "---- PNTS"
 
374
                        verts = read_verts(lwochunk)
 
375
                        objspec_list[2] = verts
 
376
                elif lwochunk.chunkname == "VMAP":                         # MAPS (UV)
 
377
                        ###if DEBUG: print "---- VMAP"
 
378
                        #objspec_list[7] = read_vmap(objspec_list[7], len(objspec_list[2]), lwochunk)
 
379
                        read_vmap(objspec_list[7], len(objspec_list[2]), lwochunk)
 
380
                elif lwochunk.chunkname == "VMAD":                         # MAPS (UV) per-face
 
381
                        ###if DEBUG: print "---- VMAD"
 
382
                        #objspec_list[7], objspec_list[8] = read_vmad(objspec_list[7], objspec_list[8], len(objspec_list[3]), len(objspec_list[2]), lwochunk)
 
383
                        read_vmad(objspec_list[7], objspec_list[8], len(objspec_list[3]), len(objspec_list[2]), lwochunk)
 
384
                elif lwochunk.chunkname == "POLS": # Faces v6.0
 
385
                        ###if DEBUG: print "-------- POLS(6)"
 
386
                        faces, flag = read_faces_6(lwochunk)
 
387
                        #flag is 0 for regular polygon, 1 for patches (= subsurf), 2 for anything else to be ignored
 
388
                        if flag<2:
 
389
                                if objspec_list[3] != []:
 
390
                                        #create immediately the object
 
391
                                        create_objects(clip_list, objspec_list, surf_list)
 
392
                                        update_material(clip_list, objspec_list, surf_list) #give it all the object
 
393
                                        #update with new data
 
394
                                        objspec_list = [objspec_list[0],                  #update name
 
395
                                                                        {},                               #init
 
396
                                                                        objspec_list[2],                  #same vertexes
 
397
                                                                        faces,                            #give it the new faces
 
398
                                                                        {},                               #no need to copy - filled at runtime
 
399
                                                                        {},                               #polygon tagging will follow
 
400
                                                                        flag,                             #patch flag
 
401
                                                                        objspec_list[7],                  #same uvcoords
 
402
                                                                        {}]                               #no vmad mapping
 
403
                                        object_index += 1
 
404
                                #end if already has a face list
 
405
                                objspec_list[3] = faces
 
406
                                objname = objspec_list[0]
 
407
                                if objname == None:
 
408
                                        objname = defaultname
 
409
                        #end if processing a valid poly type
 
410
                elif lwochunk.chunkname == "PTAG":                         # PTags
 
411
                        ###if DEBUG: print "---- PTAG"
 
412
                        polytag_dict = read_ptags(lwochunk, tag_list)
 
413
                        for kk, polytag_dict_val in polytag_dict.iteritems(): objspec_list[5][kk] = polytag_dict_val
 
414
                else:                                                       # Misc Chunks
 
415
                        ###if DEBUG: print "---- %s: skipping (definitely!)" % lwochunk.chunkname
 
416
                        lwochunk.skip()
 
417
                #uncomment here to log data structure as it is built
 
418
                
 
419
        #last object read
 
420
        create_objects(clip_list, objspec_list, surf_list)
 
421
        update_material(clip_list, objspec_list, surf_list) #give it all the object
 
422
        objspec_list = None
 
423
        surf_list = None
 
424
        clip_list = None
 
425
 
 
426
        ###if DEBUG: print "\nFound %d objects:" % object_index
 
427
# enddef read_lwo2
 
428
 
 
429
 
 
430
 
 
431
 
 
432
 
 
433
 
 
434
# ===========================================================
 
435
# === File reading routines =================================
 
436
# ===========================================================
 
437
# ==================
 
438
# === Read Verts ===
 
439
# ==================
 
440
def read_verts(lwochunk):
 
441
        #data = cStringIO.StringIO(lwochunk.read())
 
442
        numverts = lwochunk.chunksize/12
 
443
        return [struct.unpack(">fff", lwochunk.read(12)) for i in xrange(numverts)]
 
444
# enddef read_verts
 
445
 
 
446
 
 
447
# =================
 
448
# === Read Name ===
 
449
# =================
 
450
# modified to deal with odd lenght strings
 
451
def read_name(file):
 
452
        name = ""
 
453
        while 1:
 
454
                char = file.read(1)
 
455
                if char == "\0": break
 
456
                else: name += char
 
457
        len_name = len(name) + 1 #count the trailing zero
 
458
        if len_name%2==1:
 
459
                char = file.read(1) #remove zero padding to even lenght
 
460
                len_name += 1
 
461
        return name, len_name
 
462
 
 
463
 
 
464
# ==================
 
465
# === Read Layer ===
 
466
# ==================
 
467
def read_layr(lwochunk):
 
468
        data = cStringIO.StringIO(lwochunk.read())
 
469
        idx, flags = struct.unpack(">hh", data.read(4))
 
470
        pivot = struct.unpack(">fff", data.read(12))
 
471
        layer_name, discard = read_name(data)
 
472
        if not layer_name: layer_name = "NoName"
 
473
        return layer_name
 
474
# enddef read_layr
 
475
 
 
476
 
 
477
# ======================
 
478
# === Read Faces 5.5 ===
 
479
# ======================
 
480
def read_faces_5(lwochunk):
 
481
        data = cStringIO.StringIO(lwochunk.read())
 
482
        faces = []
 
483
        i = 0
 
484
        while i < lwochunk.chunksize:
 
485
                #if not i%1000 and my_meshtools.show_progress:
 
486
                #   Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces")
 
487
                
 
488
                numfaceverts, = struct.unpack(">H", data.read(2))
 
489
                facev = [struct.unpack(">H", data.read(2))[0] for j in xrange(numfaceverts)]
 
490
                facev.reverse()
 
491
                faces.append(facev)
 
492
                surfaceindex, = struct.unpack(">H", data.read(2))
 
493
                if surfaceindex < 0:
 
494
                        ###if DEBUG: print "***Error. Referencing uncorrect surface index"
 
495
                        return
 
496
                i += (4+numfaceverts*2)
 
497
        return faces
 
498
 
 
499
 
 
500
# ==================================
 
501
# === Read Variable-Length Index ===
 
502
# ==================================
 
503
def read_vx(data):
 
504
        byte1, = struct.unpack(">B", data.read(1))
 
505
        if byte1 != 0xFF:    # 2-byte index
 
506
                byte2, = struct.unpack(">B", data.read(1))
 
507
                index = byte1*256 + byte2
 
508
                index_size = 2
 
509
        else:                # 4-byte index
 
510
                byte2, byte3, byte4 = struct.unpack(">3B", data.read(3))
 
511
                index = byte2*65536 + byte3*256 + byte4
 
512
                index_size = 4
 
513
        return index, index_size
 
514
 
 
515
 
 
516
# ======================
 
517
# === Read uvmapping ===
 
518
# ======================
 
519
def read_vmap(uvcoords_dict, maxvertnum, lwochunk):
 
520
        
 
521
        if maxvertnum == 0:
 
522
                ###if DEBUG: print "Found VMAP but no vertexes to map!"
 
523
                return uvcoords_dict
 
524
        data = cStringIO.StringIO(lwochunk.read())
 
525
        map_type = data.read(4)
 
526
        if map_type != "TXUV":
 
527
                ###if DEBUG: print "Reading VMAP: No Texture UV map Were Found. Map Type: %s" % map_type
 
528
                return uvcoords_dict
 
529
        dimension, = struct.unpack(">H", data.read(2))
 
530
        name, i = read_name(data) #i initialized with string lenght + zeros
 
531
        ###if DEBUG: print "TXUV %d %s" % (dimension, name)
 
532
        #note if there is already a VMAD it will be lost
 
533
        #it is assumed that VMAD will follow the corresponding VMAP
 
534
        Vector = Blender.Mathutils.Vector
 
535
        try: #if uvcoords_dict.has_key(name):
 
536
                my_uv_dict = uvcoords_dict[name]          #update existing
 
537
        except: #else:
 
538
                my_uv_dict = {}    #start a brand new: this could be made more smart
 
539
        while (i < lwochunk.chunksize - 6):      #4+2 header bytes already read
 
540
                vertnum, vnum_size = read_vx(data)
 
541
                uv = struct.unpack(">ff", data.read(8))
 
542
                if vertnum >= maxvertnum:
 
543
                        ###if DEBUG: print "Hem: more uvmap than vertexes? ignoring uv data for vertex %d" % vertnum
 
544
                        pass
 
545
                else:
 
546
                        my_uv_dict[vertnum] = Vector(uv)
 
547
                i += 8 + vnum_size
 
548
        #end loop on uv pairs
 
549
        uvcoords_dict[name] = my_uv_dict
 
550
        #this is a per-vertex mapping AND the uv tuple is vertex-ordered, so faces_uv is the same as faces
 
551
        #return uvcoords_dict
 
552
        return
 
553
 
 
554
# ========================
 
555
# === Read uvmapping 2 ===
 
556
# ========================
 
557
def read_vmad(uvcoords_dict, facesuv_dict, maxfacenum, maxvertnum, lwochunk):
 
558
        if maxvertnum == 0 or maxfacenum == 0:
 
559
                ###if DEBUG: print "Found VMAD but no vertexes to map!"
 
560
                return uvcoords_dict, facesuv_dict
 
561
        data = cStringIO.StringIO(lwochunk.read())
 
562
        map_type = data.read(4)
 
563
        if map_type != "TXUV":
 
564
                ###if DEBUG: print "Reading VMAD: No Texture UV map Were Found. Map Type: %s" % map_type
 
565
                return uvcoords_dict, facesuv_dict
 
566
        dimension, = struct.unpack(">H", data.read(2))
 
567
        name, i = read_name(data) #i initialized with string lenght + zeros
 
568
        ###if DEBUG: print "TXUV %d %s" % (dimension, name)
 
569
        try: #if uvcoords_dict.has_key(name):
 
570
                my_uv_dict = uvcoords_dict[name]          #update existing
 
571
        except: #else:
 
572
                my_uv_dict = {}    #start a brand new: this could be made more smart
 
573
        my_facesuv_list = []
 
574
        newindex = maxvertnum + 10 #why +10? Why not?
 
575
        #end variable initialization
 
576
        Vector = Blender.Mathutils.Vector
 
577
        while (i < lwochunk.chunksize - 6):  #4+2 header bytes already read
 
578
                vertnum, vnum_size = read_vx(data)
 
579
                i += vnum_size
 
580
                polynum, vnum_size = read_vx(data)
 
581
                i += vnum_size
 
582
                uv = struct.unpack(">ff", data.read(8))
 
583
                if polynum >= maxfacenum or vertnum >= maxvertnum:
 
584
                        ###if DEBUG: print "Hem: more uvmap than vertexes? ignorig uv data for vertex %d" % vertnum
 
585
                        pass
 
586
                else:
 
587
                        my_uv_dict[newindex] = Vector(uv)
 
588
                        my_facesuv_list.append([polynum, vertnum, newindex])
 
589
                        newindex += 1
 
590
                i += 8
 
591
        #end loop on uv pairs
 
592
        uvcoords_dict[name] = my_uv_dict
 
593
        facesuv_dict[name] = my_facesuv_list
 
594
        ###if DEBUG: print "updated %d vertexes data" % (newindex-maxvertnum-10)
 
595
        return
 
596
 
 
597
 
 
598
# =================
 
599
# === Read tags ===
 
600
# =================
 
601
def read_tags(lwochunk):
 
602
        data = cStringIO.StringIO(lwochunk.read())
 
603
        tag_list = []
 
604
        current_tag = ""
 
605
        i = 0
 
606
        while i < lwochunk.chunksize:
 
607
                char = data.read(1)
 
608
                if char == "\0":
 
609
                        tag_list.append(current_tag)
 
610
                        if (len(current_tag) % 2 == 0): char = data.read(1)
 
611
                        current_tag = ""
 
612
                else:
 
613
                        current_tag += char
 
614
                i += 1
 
615
        ###if DEBUG: print "read %d tags, list follows: %s" % (len(tag_list), tag_list)
 
616
        return tag_list
 
617
 
 
618
 
 
619
# ==================
 
620
# === Read Ptags ===
 
621
# ==================
 
622
def read_ptags(lwochunk, tag_list):
 
623
        data = cStringIO.StringIO(lwochunk.read())
 
624
        polygon_type = data.read(4)
 
625
        if polygon_type != "SURF":
 
626
                ###if DEBUG: print "No Surf Were Found. Polygon Type: %s" % polygon_type
 
627
                return {}
 
628
        ptag_dict = {}
 
629
        i = 0
 
630
        while(i < lwochunk.chunksize-4): #4 bytes polygon type already read
 
631
                #if not i%1000 and my_meshtools.show_progress:
 
632
                #   Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading PTAGS")
 
633
                poln, poln_size = read_vx(data)
 
634
                i += poln_size
 
635
                tag_index, = struct.unpack(">H", data.read(2))
 
636
                if tag_index > (len(tag_list)):
 
637
                        ###if DEBUG: print "Reading PTAG: Surf belonging to undefined TAG: %d. Skipping" % tag_index
 
638
                        return {}
 
639
                i += 2
 
640
                tag_key = tag_list[tag_index]
 
641
                try:
 
642
                        ptag_dict[tag_list[tag_index]].append(poln)
 
643
                except: #if not(ptag_dict.has_key(tag_key)):
 
644
                        ptag_dict[tag_list[tag_index]] = [poln]
 
645
        
 
646
        ###if DEBUG: for i, ptag_dict_val in ptag_dict.iteritems(): print "read %d polygons belonging to TAG %s" % (len(ptag_dict_val ), i)
 
647
        return ptag_dict
 
648
 
 
649
 
 
650
 
 
651
# ==================
 
652
# === Read Clips ===
 
653
# ==================
 
654
def read_clip(lwochunk, dir_part):
 
655
# img, IMG, g_IMG refers to blender image objects
 
656
# ima, IMAG, g_IMAG refers to clip dictionary 'ID' entries: refer to blok and surf
 
657
        clip_dict = {}
 
658
        data = cStringIO.StringIO(lwochunk.read())
 
659
        data_str = data.read(4)
 
660
        if len(data_str) < 4: # can be zero also??? :/
 
661
                # Should not happen but lw can import so we should too
 
662
                return 
 
663
        
 
664
        image_index, = struct.unpack(">L", data_str)
 
665
        clip_dict['ID'] = image_index
 
666
        i = 4
 
667
        while(i < lwochunk.chunksize):
 
668
                subchunkname, = struct.unpack("4s", data.read(4))
 
669
                subchunklen, = struct.unpack(">H", data.read(2))
 
670
                if subchunkname == "STIL":
 
671
                        ###if DEBUG: print "-------- STIL"
 
672
                        clip_name, k = read_name(data)
 
673
                        #now split text independently from platform
 
674
                        #depend on the system where image was saved. NOT the one where the script is run
 
675
                        no_sep = "\\"
 
676
                        if Blender.sys.sep == no_sep: no_sep ="/"
 
677
                        if (no_sep in clip_name):
 
678
                                clip_name = clip_name.replace(no_sep, Blender.sys.sep)
 
679
                        short_name = Blender.sys.basename(clip_name)
 
680
                        if clip_name == "" or short_name == "":
 
681
                                ###if DEBUG: print "Reading CLIP: Empty clip name not allowed. Skipping"
 
682
                                discard = data.read(subchunklen-k)
 
683
                        clip_dict['NAME'] = clip_name
 
684
                        clip_dict['BASENAME'] = short_name
 
685
                elif subchunkname == "XREF":                           #cross reference another image
 
686
                        ###if DEBUG: print "-------- XREF"
 
687
                        image_index, = struct.unpack(">L", data.read(4))
 
688
                        clip_name, k = read_name(data)
 
689
                        clip_dict['NAME'] = clip_name
 
690
                        clip_dict['XREF'] = image_index
 
691
                elif subchunkname == "NEGA":                           #negate texture effect
 
692
                        ###if DEBUG: print "-------- NEGA"
 
693
                        n, = struct.unpack(">H", data.read(2))
 
694
                        clip_dict['NEGA'] = n
 
695
                else:                                                       # Misc Chunks
 
696
                        ###if DEBUG: print "-------- CLIP:%s: skipping" % subchunkname
 
697
                        discard = data.read(subchunklen)
 
698
                i = i + 6 + subchunklen
 
699
        #end loop on surf chunks
 
700
        ###if DEBUG: print "read image:%s" % clip_dict
 
701
        if 'XREF' in clip_dict: # has_key
 
702
                ###if DEBUG: print "Cross-reference: no image pre-allocated."
 
703
                return clip_dict
 
704
        #look for images
 
705
        #img = load_image("",clip_dict['NAME'])
 
706
        NAME= BASENAME= None 
 
707
        
 
708
        try:
 
709
                NAME= clip_dict['NAME']
 
710
                BASENAME= clip_dict['BASENAME']
 
711
        except:
 
712
                clip_dict['g_IMG'] = None
 
713
                return
 
714
        # ###if DEBUG: print 'test', NAME, BASENAME
 
715
        img = BPyImage.comprehensiveImageLoad(NAME, dir_part, PLACE_HOLDER= False, RECURSIVE=False)
 
716
        if not img:
 
717
                ###if DEBUG: print "***No image %s found: trying LWO file subdir" % NAME
 
718
                img = BPyImage.comprehensiveImageLoad(BASENAME, dir_part, PLACE_HOLDER= False, RECURSIVE=False)
 
719
        
 
720
        ###if DEBUG: if not img: print "***No image %s found: giving up" % BASENAME
 
721
        #lucky we are: we have an image
 
722
        ###if DEBUG: print "Image pre-allocated."
 
723
        clip_dict['g_IMG'] = img
 
724
        
 
725
        return clip_dict
 
726
 
 
727
 
 
728
# ===========================
 
729
# === Read Surfaces Block ===
 
730
# ===========================
 
731
def read_surfblok(subchunkdata):
 
732
        lenght = len(subchunkdata)
 
733
        my_dict = {}
 
734
        my_uvname = ""
 
735
        data = cStringIO.StringIO(subchunkdata)
 
736
        ##############################################################
 
737
        # blok header sub-chunk
 
738
        ##############################################################
 
739
        subchunkname, = struct.unpack("4s", data.read(4))
 
740
        subchunklen, = struct.unpack(">h", data.read(2))
 
741
        accumulate_i = subchunklen + 6
 
742
        if subchunkname != 'IMAP':
 
743
                ###if DEBUG: print "---------- SURF: BLOK: %s: block aborting" % subchunkname
 
744
                return {}, ""
 
745
        ###if DEBUG: print "---------- IMAP"
 
746
        ordinal, i = read_name(data)
 
747
        my_dict['ORD'] = ordinal
 
748
        #my_dict['g_ORD'] = -1
 
749
        my_dict['ENAB'] = True
 
750
        while(i < subchunklen): # ---------left 6------------------------- loop on header parameters
 
751
                sub2chunkname, = struct.unpack("4s", data.read(4))
 
752
                sub2chunklen, = struct.unpack(">h", data.read(2))
 
753
                i = i + 6 + sub2chunklen
 
754
                if sub2chunkname == "CHAN":
 
755
                        ###if DEBUG: print "------------ CHAN"
 
756
                        sub2chunkname, = struct.unpack("4s", data.read(4))
 
757
                        my_dict['CHAN'] = sub2chunkname
 
758
                        sub2chunklen -= 4
 
759
                elif sub2chunkname == "ENAB":                             #only present if is to be disabled
 
760
                        ###if DEBUG: print "------------ ENAB"
 
761
                        ena, = struct.unpack(">h", data.read(2))
 
762
                        my_dict['ENAB'] = ena
 
763
                        sub2chunklen -= 2
 
764
                elif sub2chunkname == "NEGA":                             #only present if is to be enabled
 
765
                        ###if DEBUG: print "------------ NEGA"
 
766
                        ena, = struct.unpack(">h", data.read(2))
 
767
                        if ena == 1:
 
768
                                my_dict['NEGA'] = ena
 
769
                        sub2chunklen -= 2
 
770
                elif sub2chunkname == "OPAC":                             #only present if is to be disabled
 
771
                        ###if DEBUG: print "------------ OPAC"
 
772
                        opa, = struct.unpack(">h", data.read(2))
 
773
                        s, = struct.unpack(">f", data.read(4))
 
774
                        envelope, env_size = read_vx(data)
 
775
                        my_dict['OPAC'] = opa
 
776
                        my_dict['OPACVAL'] = s
 
777
                        sub2chunklen -= 6
 
778
                elif sub2chunkname == "AXIS":
 
779
                        ###if DEBUG: print "------------ AXIS"
 
780
                        ena, = struct.unpack(">h", data.read(2))
 
781
                        my_dict['DISPLAXIS'] = ena
 
782
                        sub2chunklen -= 2
 
783
                else:                                                       # Misc Chunks
 
784
                        ###if DEBUG: print "------------ SURF: BLOK: IMAP: %s: skipping" % sub2chunkname
 
785
                        discard = data.read(sub2chunklen)
 
786
        #end loop on blok header subchunks
 
787
        ##############################################################
 
788
        # blok attributes sub-chunk
 
789
        ##############################################################
 
790
        subchunkname, = struct.unpack("4s", data.read(4))
 
791
        subchunklen, = struct.unpack(">h", data.read(2))
 
792
        accumulate_i += subchunklen + 6
 
793
        if subchunkname != 'TMAP':
 
794
                ###if DEBUG: print "---------- SURF: BLOK: %s: block aborting" % subchunkname
 
795
                return {}, ""
 
796
        ###if DEBUG: print "---------- TMAP"
 
797
        i = 0
 
798
        while(i < subchunklen): # -----------left 6----------------------- loop on header parameters
 
799
                sub2chunkname, = struct.unpack("4s", data.read(4))
 
800
                sub2chunklen, = struct.unpack(">h", data.read(2))
 
801
                i = i + 6 + sub2chunklen
 
802
                if sub2chunkname == "CNTR":
 
803
                        ###if DEBUG: print "------------ CNTR"
 
804
                        x, y, z = struct.unpack(">fff", data.read(12))
 
805
                        envelope, env_size = read_vx(data)
 
806
                        my_dict['CNTR'] = [x, y, z]
 
807
                        sub2chunklen -= (12+env_size)
 
808
                elif sub2chunkname == "SIZE":
 
809
                        ###if DEBUG: print "------------ SIZE"
 
810
                        x, y, z = struct.unpack(">fff", data.read(12))
 
811
                        envelope, env_size = read_vx(data)
 
812
                        my_dict['SIZE'] = [x, y, z]
 
813
                        sub2chunklen -= (12+env_size)
 
814
                elif sub2chunkname == "ROTA":
 
815
                        ###if DEBUG: print "------------ ROTA"
 
816
                        x, y, z = struct.unpack(">fff", data.read(12))
 
817
                        envelope, env_size = read_vx(data)
 
818
                        my_dict['ROTA'] = [x, y, z]
 
819
                        sub2chunklen -= (12+env_size)
 
820
                elif sub2chunkname == "CSYS":
 
821
                        ###if DEBUG: print "------------ CSYS"
 
822
                        ena, = struct.unpack(">h", data.read(2))
 
823
                        my_dict['CSYS'] = ena
 
824
                        sub2chunklen -= 2
 
825
                else:                                                       # Misc Chunks
 
826
                        ###if DEBUG: print "------------ SURF: BLOK: TMAP: %s: skipping" % sub2chunkname
 
827
                        pass
 
828
                if  sub2chunklen > 0:
 
829
                        discard = data.read(sub2chunklen)
 
830
        #end loop on blok attributes subchunks
 
831
        ##############################################################
 
832
        # ok, now other attributes without sub_chunks
 
833
        ##############################################################
 
834
        while(accumulate_i < lenght): # ---------------------------------- loop on header parameters: lenght has already stripped the 6 bypes header
 
835
                subchunkname, = struct.unpack("4s", data.read(4))
 
836
                subchunklen, = struct.unpack(">H", data.read(2))
 
837
                accumulate_i = accumulate_i + 6 + subchunklen
 
838
                if subchunkname == "PROJ":
 
839
                        ###if DEBUG: print "---------- PROJ"
 
840
                        p, = struct.unpack(">h", data.read(2))
 
841
                        my_dict['PROJ'] = p
 
842
                        subchunklen -= 2
 
843
                elif subchunkname == "AXIS":
 
844
                        ###if DEBUG: print "---------- AXIS"
 
845
                        a, = struct.unpack(">h", data.read(2))
 
846
                        my_dict['MAJAXIS'] = a
 
847
                        subchunklen -= 2
 
848
                elif subchunkname == "IMAG":
 
849
                        ###if DEBUG: print "---------- IMAG"
 
850
                        i, i_size = read_vx(data)
 
851
                        my_dict['IMAG'] = i
 
852
                        subchunklen -= i_size
 
853
                elif subchunkname == "WRAP":
 
854
                        ###if DEBUG: print "---------- WRAP"
 
855
                        ww, wh = struct.unpack(">hh", data.read(4))
 
856
                        #reduce width and height to just 1 parameter for both
 
857
                        my_dict['WRAP'] = max([ww,wh])
 
858
                        #my_dict['WRAPWIDTH'] = ww
 
859
                        #my_dict['WRAPHEIGHT'] = wh
 
860
                        subchunklen -= 4
 
861
                elif subchunkname == "WRPW":
 
862
                        ###if DEBUG: print "---------- WRPW"
 
863
                        w, = struct.unpack(">f", data.read(4))
 
864
                        my_dict['WRPW'] = w
 
865
                        envelope, env_size = read_vx(data)
 
866
                        subchunklen -= (env_size+4)
 
867
                elif subchunkname == "WRPH":
 
868
                        ###if DEBUG: print "---------- WRPH"
 
869
                        w, = struct.unpack(">f", data.read(4))
 
870
                        my_dict['WRPH'] = w
 
871
                        envelope, env_size = read_vx(data)
 
872
                        subchunklen -= (env_size+4)
 
873
                elif subchunkname == "VMAP":
 
874
                        ###if DEBUG: print "---------- VMAP"
 
875
                        vmp, i = read_name(data)
 
876
                        my_dict['VMAP'] = vmp
 
877
                        my_uvname = vmp
 
878
                        subchunklen -= i
 
879
                else:                                                    # Misc Chunks
 
880
                        ###if DEBUG: print "---------- SURF: BLOK: %s: skipping" % subchunkname
 
881
                        pass
 
882
                if  subchunklen > 0:
 
883
                        discard = data.read(subchunklen)
 
884
        #end loop on blok subchunks
 
885
        return my_dict, my_uvname
 
886
 
 
887
 
 
888
# =====================
 
889
# === Read Surfaces ===
 
890
# =====================
 
891
def read_surfs(lwochunk, surf_list, tag_list):
 
892
        my_dict = {}
 
893
        data = cStringIO.StringIO(lwochunk.read())
 
894
        surf_name, i = read_name(data)
 
895
        parent_name, j = read_name(data)
 
896
        i += j
 
897
        if (surf_name == "") or not(surf_name in tag_list):
 
898
                ###if DEBUG: print "Reading SURF: Actually empty surf name not allowed. Skipping"
 
899
                return {}
 
900
        if (parent_name != ""):
 
901
                parent_index = [x['NAME'] for x in surf_list].count(parent_name)
 
902
                if parent_index >0:
 
903
                        my_dict = surf_list[parent_index-1]
 
904
        my_dict['NAME'] = surf_name
 
905
        ###if DEBUG: print "Surface data for TAG %s" % surf_name
 
906
        while(i < lwochunk.chunksize):
 
907
                subchunkname, = struct.unpack("4s", data.read(4))
 
908
                subchunklen, = struct.unpack(">H", data.read(2))
 
909
                i = i + 6 + subchunklen #6 bytes subchunk header
 
910
                if subchunkname == "COLR":                             #color: mapped on color
 
911
                        ###if DEBUG: print "-------- COLR"
 
912
                        r, g, b = struct.unpack(">fff", data.read(12))
 
913
                        envelope, env_size = read_vx(data)
 
914
                        my_dict['COLR'] = [r, g, b]
 
915
                        subchunklen -= (12+env_size)
 
916
                elif subchunkname == "DIFF":                           #diffusion: mapped on reflection (diffuse shader)
 
917
                        ###if DEBUG: print "-------- DIFF"
 
918
                        s, = struct.unpack(">f", data.read(4))
 
919
                        envelope, env_size = read_vx(data)
 
920
                        my_dict['DIFF'] = s
 
921
                        subchunklen -= (4+env_size)
 
922
                elif subchunkname == "SPEC":                           #specularity: mapped to specularity (spec shader)
 
923
                        ###if DEBUG: print "-------- SPEC"
 
924
                        s, = struct.unpack(">f", data.read(4))
 
925
                        envelope, env_size = read_vx(data)
 
926
                        my_dict['SPEC'] = s
 
927
                        subchunklen -= (4+env_size)
 
928
                elif subchunkname == "REFL":                           #reflection: mapped on raymirror
 
929
                        ###if DEBUG: print "-------- REFL"
 
930
                        s, = struct.unpack(">f", data.read(4))
 
931
                        envelope, env_size = read_vx(data)
 
932
                        my_dict['REFL'] = s
 
933
                        subchunklen -= (4+env_size)
 
934
                elif subchunkname == "TRNL":                           #translucency: mapped on same param
 
935
                        ###if DEBUG: print "-------- TRNL"
 
936
                        s, = struct.unpack(">f", data.read(4))
 
937
                        envelope, env_size = read_vx(data)
 
938
                        my_dict['TRNL'] = s
 
939
                        subchunklen -= (4+env_size)
 
940
                elif subchunkname == "GLOS":                           #glossiness: mapped on specularity hardness (spec shader)
 
941
                        ###if DEBUG: print "-------- GLOS"
 
942
                        s, = struct.unpack(">f", data.read(4))
 
943
                        envelope, env_size = read_vx(data)
 
944
                        my_dict['GLOS'] = s
 
945
                        subchunklen -= (4+env_size)
 
946
                elif subchunkname == "TRAN":                           #transparency: inverted and mapped on alpha channel
 
947
                        ###if DEBUG: print "-------- TRAN"
 
948
                        s, = struct.unpack(">f", data.read(4))
 
949
                        envelope, env_size = read_vx(data)
 
950
                        my_dict['TRAN'] = s
 
951
                        subchunklen -= (4+env_size)
 
952
                elif subchunkname == "LUMI":                           #luminosity: mapped on emit channel
 
953
                        ###if DEBUG: print "-------- LUMI"
 
954
                        s, = struct.unpack(">f", data.read(4))
 
955
                        envelope, env_size = read_vx(data)
 
956
                        my_dict['LUMI'] = s
 
957
                        subchunklen -= (4+env_size)
 
958
                elif subchunkname == "GVAL":                           #glow: mapped on add channel
 
959
                        ###if DEBUG: print "-------- GVAL"
 
960
                        s, = struct.unpack(">f", data.read(4))
 
961
                        envelope, env_size = read_vx(data)
 
962
                        my_dict['GVAL'] = s
 
963
                        subchunklen -= (4+env_size)
 
964
                elif subchunkname == "SMAN":                           #smoothing angle
 
965
                        ###if DEBUG: print "-------- SMAN"
 
966
                        s, = struct.unpack(">f", data.read(4))
 
967
                        my_dict['SMAN'] = s
 
968
                        subchunklen -= 4
 
969
                elif subchunkname == "SIDE":                           #double sided?
 
970
                        ###if DEBUG: print "-------- SIDE"                             #if 1 side do not define key
 
971
                        s, = struct.unpack(">H", data.read(2))
 
972
                        if s == 3:
 
973
                                my_dict['SIDE'] = s
 
974
                        subchunklen -= 2
 
975
                elif subchunkname == "RIND":                           #Refraction: mapped on IOR
 
976
                        ###if DEBUG: print "-------- RIND"
 
977
                        s, = struct.unpack(">f", data.read(4))
 
978
                        envelope, env_size = read_vx(data)
 
979
                        my_dict['RIND'] = s
 
980
                        subchunklen -= (4+env_size)
 
981
                elif subchunkname == "BLOK":                           #blocks
 
982
                        ###if DEBUG: print "-------- BLOK"
 
983
                        rr, uvname = read_surfblok(data.read(subchunklen))
 
984
                        #paranoia setting: preventing adding an empty dict
 
985
                        if rr: # != {}
 
986
                                try:
 
987
                                        my_dict['BLOK'].append(rr)
 
988
                                except:
 
989
                                        my_dict['BLOK'] = [rr]
 
990
                                        
 
991
                        if uvname: # != "":
 
992
                                my_dict['UVNAME'] = uvname                            #theoretically there could be a number of them: only one used per surf
 
993
                        # all are dictionaries - so testing keys 
 
994
                        if not('g_IMAG' in my_dict) and ('CHAN' in rr) and ('OPAC' in rr) and ('IMAG' in rr):
 
995
                                if (rr['CHAN'] == 'COLR') and (rr['OPAC'] == 0):
 
996
                                        my_dict['g_IMAG'] = rr['IMAG']                 #do not set anything, just save image object for later assignment
 
997
                        subchunklen = 0 #force ending
 
998
                else:                                                       # Misc Chunks
 
999
                        pass
 
1000
                        ###if DEBUG: print "-------- SURF:%s: skipping" % subchunkname
 
1001
                if  subchunklen > 0:
 
1002
                        discard = data.read(subchunklen)
 
1003
        #end loop on surf chunks
 
1004
        try:#if my_dict.has_key('BLOK'):
 
1005
           my_dict['BLOK'].reverse() #texture applied in reverse order with respect to reading from lwo
 
1006
        except:
 
1007
                pass
 
1008
        
 
1009
        #uncomment this if material pre-allocated by read_surf
 
1010
        my_dict['g_MAT'] = bpy.data.materials.new(my_dict['NAME'])
 
1011
        ###if DEBUG: print "-> Material pre-allocated."
 
1012
        return my_dict
 
1013
 
 
1014
# =========================
 
1015
# === Recalculate Faces ===
 
1016
# =========================
 
1017
 
 
1018
def get_uvface(complete_list, facenum):
 
1019
        # extract from the complete list only vertexes of the desired polygon
 
1020
        '''
 
1021
        my_facelist = []
 
1022
        for elem in complete_list:
 
1023
                if elem[0] == facenum:
 
1024
                        my_facelist.append(elem)
 
1025
        return my_facelist
 
1026
        '''
 
1027
        return [elem for elem in complete_list if elem[0] == facenum]
 
1028
 
 
1029
def get_newindex(polygon_list, vertnum):
 
1030
        # extract from the polygon list the new index associated to a vertex
 
1031
        if not polygon_list: # == []
 
1032
                return -1
 
1033
        for elem in polygon_list:
 
1034
                if elem[1] == vertnum:
 
1035
                        return elem[2]
 
1036
        # ###if DEBUG: print "WARNING: expected vertex %s for polygon %s. Polygon_list dump follows" % (vertnum, polygon_list[0][0])
 
1037
        # ###if DEBUG: print polygon_list
 
1038
        return -1
 
1039
 
 
1040
def get_surf(surf_list, cur_tag):
 
1041
        for elem in surf_list: # elem can be None
 
1042
                if elem and elem['NAME'] == cur_tag:
 
1043
                        return elem
 
1044
        return {}
 
1045
 
 
1046
 
 
1047
 
 
1048
# ====================================
 
1049
# === Modified Create Blender Mesh ===
 
1050
# ====================================
 
1051
def my_create_mesh(clip_list, surf, objspec_list, current_facelist, objname, not_used_faces):
 
1052
        #take the needed faces and update the not-used face list
 
1053
        complete_vertlist = objspec_list[2]
 
1054
        complete_facelist = objspec_list[3]
 
1055
        uvcoords_dict = objspec_list[7]
 
1056
        facesuv_dict = objspec_list[8]
 
1057
        vertex_map = {} #implementation as dict
 
1058
        cur_ptag_faces = []
 
1059
        cur_ptag_faces_indexes = []
 
1060
        maxface = len(complete_facelist)
 
1061
        for ff in current_facelist:
 
1062
                if ff >= maxface:
 
1063
                        ###if DEBUG: print "Non existent face addressed: Giving up with this object"
 
1064
                        return None, not_used_faces              #return the created object
 
1065
                cur_face = complete_facelist[ff]
 
1066
                cur_ptag_faces_indexes.append(ff)
 
1067
                if not_used_faces: # != []
 
1068
                        not_used_faces[ff] = -1
 
1069
                for vv in cur_face: vertex_map[vv] = 1
 
1070
        #end loop on faces
 
1071
        store_edge = 0
 
1072
        
 
1073
        scn= bpy.data.scenes.active
 
1074
        msh = bpy.data.meshes.new()
 
1075
        obj = scn.objects.new(msh)
 
1076
        
 
1077
        mat = None
 
1078
        try:
 
1079
                msh.materials = [surf['g_MAT']]
 
1080
        except:
 
1081
                pass
 
1082
        
 
1083
        msh.mode |= Blender.Mesh.Modes.AUTOSMOOTH #smooth it anyway
 
1084
        if 'SMAN' in surf: # has_key
 
1085
                #not allowed mixed mode mesh (all the mesh is smoothed and all with the same angle)
 
1086
                #only one smoothing angle will be active! => take the max one
 
1087
                msh.degr = min(80, int(surf['SMAN']/3.1415926535897932384626433832795*180.0))     #lwo in radians - blender in degrees
 
1088
        
 
1089
        try:
 
1090
                img= lookup_imag(clip_list, surf['g_IMAG'])['g_IMG']
 
1091
        except:
 
1092
                img= None
 
1093
        
 
1094
        #uv_flag = ((surf.has_key('UVNAME')) and (uvcoords_dict.has_key(surf['UVNAME'])) and (img != None))
 
1095
        uv_flag = (('UVNAME' in surf) and (surf['UVNAME'] in uvcoords_dict))
 
1096
 
 
1097
        ###if DEBUG: print "\n#===================================================================#"
 
1098
        ###if DEBUG: print "Processing Object: %s" % objname
 
1099
        ###if DEBUG: print "#===================================================================#"
 
1100
        
 
1101
        if uv_flag:
 
1102
                msh.verts.extend([(0.0,0.0,0.0),])
 
1103
                j = 1
 
1104
        else:
 
1105
                j = 0
 
1106
        
 
1107
        def tmp_get_vert(k, i):
 
1108
                vertex_map[k] = i+j # j is the dummy vert
 
1109
                # ###if DEBUG: print complete_vertlist[i]
 
1110
                return complete_vertlist[k]
 
1111
        
 
1112
        
 
1113
        
 
1114
        msh.verts.extend([tmp_get_vert(k, i) for i, k in enumerate(vertex_map.iterkeys())])
 
1115
        msh.transform(TXMTX)                                    # faster then applying while reading.
 
1116
        #end sweep over vertexes
 
1117
 
 
1118
        #append faces
 
1119
        FACE_TEX= Blender.Mesh.FaceModes.TEX
 
1120
        FACE_ALPHA= Blender.Mesh.FaceTranspModes.ALPHA
 
1121
        EDGE_DRAW_FLAG= Blender.Mesh.EdgeFlags.EDGEDRAW | Blender.Mesh.EdgeFlags.EDGERENDER
 
1122
        
 
1123
        
 
1124
        edges = []
 
1125
        face_data = [] # [(indicies, material, uvs, image), ]
 
1126
        face_uvs = []
 
1127
        edges_fgon = []
 
1128
        
 
1129
        if uv_flag:
 
1130
                uvcoords_dict_context = uvcoords_dict[surf['UVNAME']]
 
1131
                try:    current_uvdict = facesuv_dict[surf['UVNAME']]
 
1132
                except: current_uvdict = None
 
1133
                
 
1134
        default_uv = Blender.Mathutils.Vector(0,0)
 
1135
        def tmp_get_face_uvs(cur_face, i):
 
1136
                uvs = []
 
1137
                if current_uvdict:
 
1138
                        uvface = get_uvface(current_uvdict,i)
 
1139
                        for vi in cur_face:
 
1140
                                ni = get_newindex(uvface, vi)
 
1141
                                if ni == -1: ni = vi
 
1142
                                
 
1143
                                try:
 
1144
                                        uvs.append(uvcoords_dict_context[ ni ])
 
1145
                                except:
 
1146
                                        ###if DEBUG: print '\tWarning, Corrupt UVs'
 
1147
                                        uvs.append(default_uv)
 
1148
                else:
 
1149
                        for vi in cur_face:
 
1150
                                try:
 
1151
                                        uvs.append(uvcoords_dict_context[ vi ])
 
1152
                                except:
 
1153
                                        ###if DEBUG: print '\tWarning, Corrupt UVs'
 
1154
                                        uvs.append(default_uv)
 
1155
                
 
1156
                return uvs
 
1157
        cur_face
 
1158
        for i in cur_ptag_faces_indexes:
 
1159
                cur_face = complete_facelist[i]
 
1160
                numfaceverts = len(cur_face)
 
1161
                
 
1162
                if numfaceverts == 2:           edges.append((vertex_map[cur_face[0]], vertex_map[cur_face[1]]))
 
1163
                elif numfaceverts == 3 or numfaceverts == 4:    
 
1164
                        rev_face = [__i for __i in reversed(cur_face)]
 
1165
                        face_data.append( [vertex_map[j] for j in rev_face] )
 
1166
                        if uv_flag: face_uvs.append(tmp_get_face_uvs(rev_face, i))
 
1167
                elif numfaceverts > 4:
 
1168
                        meta_faces= BPyMesh.ngon(complete_vertlist, cur_face, PREF_FIX_LOOPS= True)
 
1169
                        edge_face_count = {}
 
1170
                        for mf in meta_faces:
 
1171
                                # These will always be tri's since they are scanfill faces
 
1172
                                mf = cur_face[mf[2]], cur_face[mf[1]], cur_face[mf[0]]
 
1173
                                face_data.append( [vertex_map[j] for j in mf] )
 
1174
                                
 
1175
                                if uv_flag: face_uvs.append(tmp_get_face_uvs(mf, i))
 
1176
                                
 
1177
                                #if USE_FGON:
 
1178
                                if len(meta_faces) > 1:
 
1179
                                        mf = face_data[-1] # reuse mf
 
1180
                                        for j in xrange(3):
 
1181
                                                v1= mf[j]
 
1182
                                                v2= mf[j-1]
 
1183
                                                if v1!=v2:
 
1184
                                                        if v1>v2:
 
1185
                                                                v2,v1= v1,v2
 
1186
                                                        try:
 
1187
                                                                edge_face_count[v1,v2]+= 1
 
1188
                                                        except:
 
1189
                                                                edge_face_count[v1,v2]= 0
 
1190
                                
 
1191
 
 
1192
                        
 
1193
                        if edge_face_count:
 
1194
                                edges_fgon.extend( [vert_key for vert_key, count in edge_face_count.iteritems() if count] )
 
1195
        
 
1196
        if edges:
 
1197
                msh.edges.extend(edges)
 
1198
        
 
1199
        face_mapping_removed = msh.faces.extend(face_data, indexList=True)
 
1200
        if 'TRAN' in surf or (mat and mat.alpha<1.0): # incase mat is null
 
1201
                transp_flag = True
 
1202
        else:
 
1203
                transp_flag = False
 
1204
        
 
1205
        if uv_flag:
 
1206
                msh.faceUV = True
 
1207
                msh_faces= msh.faces
 
1208
                for i, uvs in enumerate(face_uvs):
 
1209
                        i_mapped = face_mapping_removed[i]
 
1210
                        if i_mapped != None:
 
1211
                                f = msh_faces[i_mapped]
 
1212
                                f.uv = uvs
 
1213
                                if img:
 
1214
                                        f.image = img
 
1215
                                
 
1216
                                if transp_flag: f.transp |= FACE_ALPHA
 
1217
        
 
1218
        if edges_fgon:
 
1219
                msh_edges = msh.edges
 
1220
                FGON= Blender.Mesh.EdgeFlags.FGON
 
1221
                edges_fgon = msh.findEdges( edges_fgon )
 
1222
                if type(edges_fgon) != list: edges_fgon = [edges_fgon]
 
1223
                for ed in edges_fgon:
 
1224
                        if ed!=None:
 
1225
                                msh_edges[ed].flag |= FGON
 
1226
        
 
1227
        if not(uv_flag):        #clear eventual UV data
 
1228
                msh.faceUV = False
 
1229
        
 
1230
        if uv_flag:
 
1231
                msh.verts.delete([0,])
 
1232
        
 
1233
        return obj, not_used_faces              #return the created object
 
1234
 
 
1235
 
 
1236
# ============================================
 
1237
# === Set Subsurf attributes on given mesh ===
 
1238
# ============================================
 
1239
def set_subsurf(obj):
 
1240
        mods = obj.modifiers                      # get the object's modifiers
 
1241
        mod = mods.append(Blender.Modifier.Type.SUBSURF)  # add a new subsurf modifier
 
1242
        mod[Blender.Modifier.Settings.LEVELS] = 2         # set subsurf subdivision levels to 2
 
1243
        mod[Blender.Modifier.Settings.RENDLEVELS] = 2     # set subsurf rendertime subdivision levels to 2
 
1244
        obj.makeDisplayList()
 
1245
 
 
1246
 
 
1247
# =================================
 
1248
# === object size and dimension ===
 
1249
# =================================
 
1250
def obj_size_pos(obj):
 
1251
        bbox = obj.getBoundBox()
 
1252
        bbox_min = map(lambda *row: min(row), *bbox) #transpose & get min
 
1253
        bbox_max = map(lambda *row: max(row), *bbox) #transpose & get max
 
1254
        obj_size = (bbox_max[0]-bbox_min[0], bbox_max[1]-bbox_min[1], bbox_max[2]-bbox_min[2])
 
1255
        obj_pos = ( (bbox_max[0]+bbox_min[0]) / 2, (bbox_max[1]+bbox_min[1]) / 2, (bbox_max[2]+bbox_min[2]) / 2)
 
1256
        return (obj_size, obj_pos)
 
1257
 
 
1258
 
 
1259
# =========================
 
1260
# === Create the object ===
 
1261
# =========================
 
1262
def create_objects(clip_list, objspec_list, surf_list):
 
1263
        nf = len(objspec_list[3])
 
1264
        not_used_faces = range(nf)
 
1265
        ptag_dict = objspec_list[5]
 
1266
        obj_dict = {}  #links tag names to object, used for material assignments
 
1267
        obj_dim_dict = {}
 
1268
        obj_list = []  #have it handy for parent association
 
1269
        middlechar = "+"
 
1270
        endchar = ""
 
1271
        if (objspec_list[6] == 1):
 
1272
                middlechar = endchar = "#"
 
1273
        for cur_tag, ptag_dict_val in ptag_dict.iteritems():
 
1274
                if ptag_dict_val != []:
 
1275
                        cur_surf = get_surf(surf_list, cur_tag)
 
1276
                        cur_obj, not_used_faces=  my_create_mesh(clip_list, cur_surf, objspec_list, ptag_dict_val, objspec_list[0][:9]+middlechar+cur_tag[:9], not_used_faces)
 
1277
                        # Works now with new modifiers
 
1278
                        if objspec_list[6] == 1:
 
1279
                                set_subsurf(cur_obj)
 
1280
                        if cur_obj: # != None
 
1281
                                obj_dict[cur_tag] = cur_obj
 
1282
                                obj_dim_dict[cur_tag] = obj_size_pos(cur_obj)
 
1283
                                obj_list.append(cur_obj)
 
1284
        #end loop on current group
 
1285
        #and what if some faces not used in any named PTAG? get rid of unused faces
 
1286
        orphans = []
 
1287
        for tt in not_used_faces:
 
1288
                if tt > -1: orphans.append(tt)
 
1289
        #end sweep on unused face list
 
1290
        not_used_faces = None
 
1291
        if orphans: # != []
 
1292
                cur_surf = get_surf(surf_list, "_Orphans")
 
1293
                cur_obj, not_used_faces = my_create_mesh(clip_list, cur_surf, objspec_list, orphans, objspec_list[0][:9]+middlechar+"Orphans", [])
 
1294
                if cur_obj: # != None
 
1295
                        if objspec_list[6] == 1:
 
1296
                                set_subsurf(cur_obj)
 
1297
                        obj_dict["_Orphans"] = cur_obj
 
1298
                        obj_dim_dict["_Orphans"] = obj_size_pos(cur_obj)
 
1299
                        obj_list.append(cur_obj)
 
1300
        objspec_list[1]= obj_dict
 
1301
        objspec_list[4]= obj_dim_dict
 
1302
        
 
1303
        return
 
1304
 
 
1305
 
 
1306
 
 
1307
# ===========================================
 
1308
# === Lookup for image index in clip_list ===
 
1309
# ===========================================
 
1310
def lookup_imag(clip_list, ima_id):
 
1311
        for ii in clip_list:
 
1312
                if ii and ii['ID'] == ima_id:
 
1313
                        if 'XREF' in ii: # has_key
 
1314
                                #cross reference - recursively look for images
 
1315
                                return lookup_imag(clip_list, ii['XREF'])
 
1316
                        else:
 
1317
                                return ii
 
1318
        return None
 
1319
 
 
1320
 
 
1321
# ===================================================
 
1322
# === Create and assign image mapping to material ===
 
1323
# ===================================================
 
1324
def create_blok(surf, mat, clip_list, obj_size, obj_pos):
 
1325
 
 
1326
        def output_size_ofs(size, pos, blok):
 
1327
                #just automate repetitive task
 
1328
                # 0 == X, 1 == Y, 2 == Z
 
1329
                size_default = [1.0] * 3
 
1330
                size2 = [1.0] * 3
 
1331
                ofs_default = [0.0] * 3
 
1332
                offset = [1.0] * 3
 
1333
                axis_default = [Blender.Texture.Proj.X, Blender.Texture.Proj.Y, Blender.Texture.Proj.Z]
 
1334
                axis = [1.0] * 3
 
1335
                c_map_txt = ["    X--", "    -Y-", "    --Z"]
 
1336
                c_map = [0,1,2]             # standard, good for Z axis projection
 
1337
                if blok['MAJAXIS'] == 0:
 
1338
                        c_map = [1,2,0]         # X axis projection
 
1339
                if blok['MAJAXIS'] == 2:
 
1340
                        c_map = [0,2,1]         # Y axis projection
 
1341
 
 
1342
                ###if DEBUG: print "!!!axis mapping:"
 
1343
                #this is the smart way
 
1344
                ###if DEBUG: for mp in c_map: print c_map_txt[mp]
 
1345
 
 
1346
                if blok['SIZE'][0] != 0.0:          #paranoia controls
 
1347
                        size_default[0] = (size[0]/blok['SIZE'][0])
 
1348
                        ofs_default[0] = ((blok['CNTR'][0]-pos[0])/blok['SIZE'][0])
 
1349
                if blok['SIZE'][1] != 0.0:
 
1350
                        size_default[2] = (size[2]/blok['SIZE'][1])
 
1351
                        ofs_default[2] = ((blok['CNTR'][1]-pos[2])/blok['SIZE'][1])
 
1352
                if blok['SIZE'][2] != 0.0:
 
1353
                        size_default[1] = (size[1]/blok['SIZE'][2])
 
1354
                        ofs_default[1] = ((blok['CNTR'][2]-pos[1])/blok['SIZE'][2])
 
1355
 
 
1356
                for mp in xrange(3):
 
1357
                        axis[mp] = axis_default[c_map[mp]]
 
1358
                        size2[mp] = size_default[c_map[mp]]
 
1359
                        offset[mp] = ofs_default[c_map[mp]]
 
1360
                        if offset[mp]>10.0: offset[mp]-10.0
 
1361
                        if offset[mp]<-10.0: offset[mp]+10.0
 
1362
#        size = [size_default[mp] for mp in c_map]
 
1363
 
 
1364
                ###if DEBUG: print "!!!texture size and offsets:"
 
1365
                ###if DEBUG: print "    sizeX = %.5f; sizeY = %.5f; sizeZ = %.5f" % (size[0],size[1],size[2])
 
1366
                ###if DEBUG: print "    ofsX = %.5f; ofsY = %.5f; ofsZ = %.5f" % (offset[0],offset[1],offset[2])
 
1367
                return axis, size2, offset
 
1368
 
 
1369
        ti = 0
 
1370
        alphaflag = 0 #switched to 1 if some tex in this block is using alpha
 
1371
        lastimag = 0 #experimental ....
 
1372
        for blok in surf['BLOK']:
 
1373
                ###if DEBUG: print "#...................................................................#"
 
1374
                ###if DEBUG: print "# Processing texture block no.%s for surf %s" % (ti,surf['NAME'])
 
1375
                ###if DEBUG: print "#...................................................................#"
 
1376
                # tobj.pdict (blok)
 
1377
                if ti > 9: break                                    #only 8 channels 0..7 allowed for texture mapping
 
1378
                #if not blok['ENAB']:
 
1379
                #    ###if DEBUG: print "***Image is not ENABled! Quitting this block"
 
1380
                #    break
 
1381
                if not('IMAG' in blok): # has_key
 
1382
                        ###if DEBUG: print "***No IMAGE for this block? Quitting"
 
1383
                        break                 #extract out the image index within the clip_list
 
1384
                if blok['IMAG'] == 0: blok['IMAG'] = lastimag #experimental ....
 
1385
                ###if DEBUG: print "looking for image number %d" % blok['IMAG']
 
1386
                ima = lookup_imag(clip_list, blok['IMAG'])
 
1387
                if ima == None:
 
1388
                        ###if DEBUG: print "***Block index image not within CLIP list? Quitting Block"
 
1389
                        break                              #safety check (paranoia setting)
 
1390
                img = ima['g_IMG']
 
1391
                lastimag = blok['IMAG']  #experimental ....
 
1392
                if img == None:
 
1393
                        ###if DEBUG: print "***Failed to pre-allocate image %s found: giving up" % ima['BASENAME']
 
1394
                        break
 
1395
                tname = str(ima['ID'])
 
1396
                if blok['ENAB']:
 
1397
                        tname += "+"
 
1398
                else:
 
1399
                        tname += "x" #let's signal when should not be enabled
 
1400
                if 'CHAN' in blok: # has_key
 
1401
                        tname += blok['CHAN']
 
1402
                newtex = bpy.data.textures.new(tname)
 
1403
                newtex.setType('Image')                 # make it anu image texture
 
1404
                newtex.image = img
 
1405
                #how does it extends beyond borders
 
1406
                if 'WRAP' in blok: # has_key
 
1407
                        if (blok['WRAP'] == 3) or (blok['WRAP'] == 2):
 
1408
                                newtex.setExtend('Extend')
 
1409
                        elif (blok['WRAP'] == 1):
 
1410
                                newtex.setExtend('Repeat')
 
1411
                        elif (blok['WRAP'] == 0):
 
1412
                                newtex.setExtend('Clip')
 
1413
                ###if DEBUG: print "generated texture %s" % tname
 
1414
 
 
1415
                #MapTo is determined by CHAN parameter
 
1416
                #assign some defaults
 
1417
                colfac = 1.0
 
1418
                dvar = 1.0
 
1419
                norfac = 0.5
 
1420
                nega = False
 
1421
                mapflag = Blender.Texture.MapTo.COL  #default to color
 
1422
                maptype = Blender.Texture.Mappings.FLAT
 
1423
                if 'CHAN' in blok: # has_key
 
1424
                        if blok['CHAN'] == 'COLR' and 'OPACVAL' in blok: # has_key
 
1425
                                colfac = blok['OPACVAL']
 
1426
                                # Blender needs this to be clamped
 
1427
                                colfac = max(0.0, min(1.0, colfac))
 
1428
                                ###if DEBUG: print "!!!Set Texture -> MapTo -> Col = %.3f" % colfac
 
1429
                        if blok['CHAN'] == 'BUMP':
 
1430
                                mapflag = Blender.Texture.MapTo.NOR
 
1431
                                if 'OPACVAL' in blok: norfac = blok['OPACVAL'] # has_key
 
1432
                                ###if DEBUG: print "!!!Set Texture -> MapTo -> Nor = %.3f" % norfac
 
1433
                        if blok['CHAN'] == 'LUMI':
 
1434
                                mapflag = Blender.Texture.MapTo.EMIT
 
1435
                                if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key
 
1436
                                ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar
 
1437
                        if blok['CHAN'] == 'DIFF':
 
1438
                                mapflag = Blender.Texture.MapTo.REF
 
1439
                                if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key
 
1440
                                ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar
 
1441
                        if blok['CHAN'] == 'SPEC':
 
1442
                                mapflag = Blender.Texture.MapTo.SPEC
 
1443
                                if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key
 
1444
                                ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar
 
1445
                        if blok['CHAN'] == 'TRAN':
 
1446
                                mapflag = Blender.Texture.MapTo.ALPHA
 
1447
                                if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key
 
1448
                                ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar
 
1449
                                alphaflag = 1
 
1450
                                nega = True
 
1451
                if 'NEGA' in blok: # has_key
 
1452
                        ###if DEBUG: print "!!!Watch-out: effect of this texture channel must be INVERTED!"
 
1453
                        nega = not nega
 
1454
 
 
1455
                blendmode_list = ['Mix',
 
1456
                                                 'Subtractive',
 
1457
                                                 'Difference',
 
1458
                                                 'Multiply',
 
1459
                                                 'Divide',
 
1460
                                                 'Mix with calculated alpha layer and stencil flag',
 
1461
                                                 'Texture Displacement',
 
1462
                                                 'Additive']
 
1463
                set_blendmode = 7 #default additive
 
1464
                if 'OPAC' in blok: # has_key
 
1465
                        set_blendmode = blok['OPAC']
 
1466
                if set_blendmode == 5: #transparency
 
1467
                        newtex.imageFlags |= Blender.Texture.ImageFlags.CALCALPHA
 
1468
                        if nega: newtex.flags |= Blender.Texture.Flags.NEGALPHA
 
1469
                ###if DEBUG: print "!!!Set Texture -> MapTo -> Blending Mode = %s" % blendmode_list[set_blendmode]
 
1470
 
 
1471
                #the TexCo flag is determined by PROJ parameter
 
1472
                axis = [Blender.Texture.Proj.X, Blender.Texture.Proj.Y, Blender.Texture.Proj.Z]
 
1473
                size = [1.0] * 3
 
1474
                ofs = [0.0] * 3
 
1475
                if 'PROJ' in blok: # has_key
 
1476
                        if blok['PROJ'] == 0: #0 - Planar
 
1477
                                ###if DEBUG: print "!!!Flat projection"
 
1478
                                coordflag = Blender.Texture.TexCo.ORCO
 
1479
                                maptype = Blender.Texture.Mappings.FLAT
 
1480
                        elif blok['PROJ'] == 1: #1 - Cylindrical
 
1481
                                ###if DEBUG: print "!!!Cylindrical projection"
 
1482
                                coordflag = Blender.Texture.TexCo.ORCO
 
1483
                                maptype = Blender.Texture.Mappings.TUBE
 
1484
                        elif blok['PROJ'] == 2: #2 - Spherical
 
1485
                                ###if DEBUG: print "!!!Spherical projection"
 
1486
                                coordflag = Blender.Texture.TexCo.ORCO
 
1487
                                maptype = Blender.Texture.Mappings.SPHERE
 
1488
                        elif blok['PROJ'] == 3: #3 - Cubic
 
1489
                                ###if DEBUG: print "!!!Cubic projection"
 
1490
                                coordflag = Blender.Texture.TexCo.ORCO
 
1491
                                maptype = Blender.Texture.Mappings.CUBE
 
1492
                        elif blok['PROJ'] == 4: #4 - Front Projection
 
1493
                                ###if DEBUG: print "!!!Front projection"
 
1494
                                coordflag = Blender.Texture.TexCo.ORCO
 
1495
                                maptype = Blender.Texture.Mappings.FLAT # ??? could it be a FLAT with some other TexCo type?
 
1496
                        elif blok['PROJ'] == 5: #5 - UV
 
1497
                                ###if DEBUG: print "UVMapped"
 
1498
                                coordflag = Blender.Texture.TexCo.UV
 
1499
                                maptype = Blender.Texture.Mappings.FLAT  #in case of UV default to FLAT mapping => effectively not used
 
1500
                        if blok['PROJ'] != 5: #This holds for any projection map except UV
 
1501
                                axis, size, ofs = output_size_ofs(obj_size, obj_pos, blok)
 
1502
                                
 
1503
                                # Clamp ofs and size else blender will raise an error
 
1504
                                for ii in xrange(3):
 
1505
                                        ofs[ii]= min(10.0, max(-10, ofs[ii]))
 
1506
                                        size[ii]= min(100, max(-100, size[ii]))
 
1507
 
 
1508
                mat.setTexture(ti, newtex, coordflag, mapflag)
 
1509
                current_mtex = mat.getTextures()[ti]
 
1510
                current_mtex.mapping = maptype
 
1511
                current_mtex.colfac = colfac
 
1512
                current_mtex.dvar = dvar
 
1513
                current_mtex.norfac = norfac
 
1514
                current_mtex.neg = nega
 
1515
                current_mtex.xproj = axis[0]
 
1516
                current_mtex.yproj = axis[1]
 
1517
                current_mtex.zproj = axis[2]
 
1518
                current_mtex.size = tuple(size)
 
1519
                current_mtex.ofs = tuple(ofs)
 
1520
                if (set_blendmode == 5): #transparency
 
1521
                        current_mtex.stencil = not (nega)
 
1522
 
 
1523
                ti += 1
 
1524
        #end loop over bloks
 
1525
        return alphaflag
 
1526
 
 
1527
 
 
1528
# ========================================
 
1529
# === Create and assign a new material ===
 
1530
# ========================================
 
1531
#def update_material(surf_list, ptag_dict, obj, clip_list, uv_dict, dir_part):
 
1532
def update_material(clip_list, objspec, surf_list):
 
1533
        if (surf_list == []) or (objspec[5] == {}) or (objspec[1] == {}):
 
1534
                ###if DEBUG: print "something getting wrong in update_material: dump follows  ..."
 
1535
                ###if DEBUG: print surf_list
 
1536
                ###if DEBUG: print objspec[5]
 
1537
                ###if DEBUG: print objspec[1]
 
1538
                return
 
1539
        obj_dict = objspec[1]
 
1540
        all_faces = objspec[3]
 
1541
        obj_dim_dict = objspec[4]
 
1542
        ptag_dict = objspec[5]
 
1543
        uvcoords_dict = objspec[7]
 
1544
        facesuv_dict = objspec[8]
 
1545
        for surf in surf_list:
 
1546
                if surf and surf['NAME'] in ptag_dict: # in ptag_dict.keys()
 
1547
                        ###if DEBUG: print "#-------------------------------------------------------------------#"
 
1548
                        ###if DEBUG: print "Processing surface (material): %s" % surf['NAME']
 
1549
                        ###if DEBUG: print "#-------------------------------------------------------------------#"
 
1550
                        #material set up
 
1551
                        facelist = ptag_dict[surf['NAME']]
 
1552
                        #bounding box and position
 
1553
                        cur_obj = obj_dict[surf['NAME']]
 
1554
                        obj_size = obj_dim_dict[surf['NAME']][0]
 
1555
                        obj_pos = obj_dim_dict[surf['NAME']][1]
 
1556
                        ###if DEBUG: print surf
 
1557
                        #uncomment this if material pre-allocated by read_surf
 
1558
                        mat = surf['g_MAT']
 
1559
                        if mat == None:
 
1560
                                ###if DEBUG: print "Sorry, no pre-allocated material to update. Giving up for %s." % surf['NAME']
 
1561
                                break
 
1562
                        #mat = Blender.Material.New(surf['NAME'])
 
1563
                        #surf['g_MAT'] = mat
 
1564
                        if 'COLR' in surf: # has_key
 
1565
                                mat.rgbCol = surf['COLR']
 
1566
                        if 'LUMI' in surf:
 
1567
                                mat.setEmit(surf['LUMI'])
 
1568
                        if 'GVAL' in surf: # has_key
 
1569
                                mat.setAdd(surf['GVAL'])
 
1570
                        if 'SPEC' in surf: # has_key
 
1571
                                mat.setSpec(surf['SPEC'])                                                       #it should be * 2 but seems to be a bit higher lwo [0.0, 1.0] - blender [0.0, 2.0]
 
1572
                        if 'DIFF' in surf: # has_key
 
1573
                                mat.setRef(surf['DIFF'])                                                        #lwo [0.0, 1.0] - blender [0.0, 1.0]
 
1574
                        if 'GLOS' in surf: # has_key                                                    #lwo [0.0, 1.0] - blender [0, 255]
 
1575
                                glo = int(371.67 * surf['GLOS'] - 42.334)                       #linear mapping - seems to work better than exp mapping
 
1576
                                if glo <32:  glo = 32                                                           #clamped to 32-255
 
1577
                                if glo >255: glo = 255
 
1578
                                mat.setHardness(glo)
 
1579
                        if 'TRNL' in surf: # has_key
 
1580
                                mat.setTranslucency(surf['TRNL'])                #NOT SURE ABOUT THIS lwo [0.0, 1.0] - blender [0.0, 1.0]
 
1581
 
 
1582
                        mm = mat.mode
 
1583
                        mm |= Blender.Material.Modes.TRANSPSHADOW
 
1584
                        if 'REFL' in surf: # has_key
 
1585
                                mat.setRayMirr(surf['REFL'])                     #lwo [0.0, 1.0] - blender [0.0, 1.0]
 
1586
                                mm |= Blender.Material.Modes.RAYMIRROR
 
1587
                        if 'TRAN' in surf: # has_key
 
1588
                                mat.setAlpha(1.0-surf['TRAN'])                                        #lwo [0.0, 1.0] - blender [1.0, 0.0]
 
1589
                                mm |= Blender.Material.Modes.RAYTRANSP
 
1590
                        if 'RIND' in surf: # has_key
 
1591
                                s = surf['RIND']
 
1592
                                if s < 1.0: s = 1.0
 
1593
                                if s > 3.0: s = 3.0
 
1594
                                mat.setIOR(s)                                                         #clipped to blender [1.0, 3.0]
 
1595
                                mm |= Blender.Material.Modes.RAYTRANSP
 
1596
                        if 'BLOK' in surf and surf['BLOK'] != []:
 
1597
                                #update the material according to texture.
 
1598
                                alphaflag = create_blok(surf, mat, clip_list, obj_size, obj_pos)
 
1599
                                if alphaflag:
 
1600
                                        mm |= Blender.Material.Modes.RAYTRANSP
 
1601
                        mat.mode = mm
 
1602
                        #finished setting up the material
 
1603
                #end if exist SURF
 
1604
        #end loop on materials (SURFs)
 
1605
        return
 
1606
 
 
1607
 
 
1608
# ======================
 
1609
# === Read Faces 6.0 ===
 
1610
# ======================
 
1611
def read_faces_6(lwochunk):
 
1612
        data = cStringIO.StringIO(lwochunk.read())
 
1613
        faces = []
 
1614
        polygon_type = data.read(4)
 
1615
        subsurf = 0
 
1616
        if polygon_type != "FACE" and polygon_type != "PTCH":
 
1617
                ###if DEBUG: print "No FACE/PATCH Were Found. Polygon Type: %s" % polygon_type
 
1618
                return "", 2
 
1619
        if polygon_type == 'PTCH': subsurf = 1
 
1620
        i = 0
 
1621
        while(i < lwochunk.chunksize-4):
 
1622
                #if not i%1000 and my_meshtools.show_progress:
 
1623
                #       Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces")
 
1624
                facev = []
 
1625
                numfaceverts, = struct.unpack(">H", data.read(2))
 
1626
                i += 2
 
1627
 
 
1628
                for j in xrange(numfaceverts):
 
1629
                        index, index_size = read_vx(data)
 
1630
                        i += index_size
 
1631
                        facev.append(index)
 
1632
                faces.append(facev)
 
1633
        ###if DEBUG: print "read %s faces; type of block %d (0=FACE; 1=PATCH)" % (len(faces), subsurf)
 
1634
        return faces, subsurf
 
1635
 
 
1636
def main():
 
1637
        if not struct:
 
1638
                Blender.Draw.PupMenu('This importer requires a full python install')
 
1639
                return
 
1640
        
 
1641
        Blender.Window.FileSelector(read, "Import LWO", '*.lwo')
 
1642
 
 
1643
if __name__=='__main__':
 
1644
        main()
 
1645
 
 
1646
 
 
1647
# Cams debugging lwo loader
 
1648
"""
 
1649
TIME= Blender.sys.time()
 
1650
import os
 
1651
print 'Searching for files'
 
1652
os.system('find /fe/lwo/Objects/ -follow -iname "*.lwo" > /tmp/templwo_list')
 
1653
# os.system('find /storage/ -iname "*.lwo" > /tmp/templwo_list')
 
1654
print '...Done'
 
1655
file= open('/tmp/templwo_list', 'r')
 
1656
lines= file.readlines()
 
1657
 
 
1658
# sort by filesize for faster testing
 
1659
lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines]
 
1660
lines_size.sort()
 
1661
lines = [f[1] for f in lines_size]
 
1662
 
 
1663
file.close()
 
1664
 
 
1665
def between(v,a,b):
 
1666
        if v <= max(a,b) and v >= min(a,b):
 
1667
                return True
 
1668
                
 
1669
        return False
 
1670
size= 0.0
 
1671
for i, _lwo in enumerate(lines):
 
1672
        #if i==425:      # SCANFILL
 
1673
        #if 1:
 
1674
        #if i==520:      # SCANFILL CRASH
 
1675
        #if i==47:       # SCANFILL CRASH
 
1676
        #if between(i, 525, 550):
 
1677
        #if i > 1635:
 
1678
        #if i != 1519: # 730
 
1679
        if i>141:
 
1680
                #if 1:
 
1681
                # _lwo= _lwo[:-1]
 
1682
                print 'Importing', _lwo, '\nNUMBER', i, 'of', len(lines)
 
1683
                _lwo_file= _lwo.split('/')[-1].split('\\')[-1]
 
1684
                newScn= bpy.data.scenes.new(_lwo_file)
 
1685
                bpy.data.scenes.active = newScn
 
1686
                size += ((os.path.getsize(_lwo)/1024.0))/ 1024.0
 
1687
                read(_lwo)
 
1688
                # Remove objects to save memory?
 
1689
                '''
 
1690
                for ob in newScn.objects:
 
1691
                        if ob.type=='Mesh':
 
1692
                                me= ob.getData(mesh=1)
 
1693
                                me.verts= None
 
1694
                        newScn.unlink(ob)
 
1695
                '''
 
1696
                print 'mb size so far', size
 
1697
 
 
1698
print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME)
 
1699
"""
 
 
b'\\ No newline at end of file'