~ubuntu-branches/ubuntu/trusty/blender/trusty

« back to all changes in this revision

Viewing changes to release/scripts/addons_contrib/io_export_md3.py

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2012-05-12 20:02:22 UTC
  • mfrom: (14.2.16 sid)
  • Revision ID: package-import@ubuntu.com-20120512200222-lznjs2cxzaq96wua
Tags: 2.63a-1
* New upstream bugfix release
  + debian/patches/: re-worked since source code changed

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# ##### BEGIN GPL LICENSE BLOCK #####
2
 
#
3
 
#  This program is free software; you can redistribute it and/or
4
 
#  modify it under the terms of the GNU General Public License
5
 
#  as published by the Free Software Foundation; either version 2
6
 
#  of the License, or (at your option) any later version.
7
 
#
8
 
#  This program is distributed in the hope that it will be useful,
9
 
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
#  GNU General Public License for more details.
12
 
#
13
 
#  You should have received a copy of the GNU General Public License
14
 
#  along with this program; if not, write to the Free Software Foundation,
15
 
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
 
#
17
 
# ##### END GPL LICENSE BLOCK #####
18
 
 
19
 
bl_info = {
20
 
    'name': 'Quake Model 3 (.md3)',
21
 
    'author': 'Xembie',
22
 
    'version': (0, 7),
23
 
    'blender': (2, 5, 3),
24
 
    'location': 'File > Export',
25
 
    'description': 'Save a Quake Model 3 File)',
26
 
    'warning': '', # used for warning icon and text in addons panel
27
 
    'wiki_url': 'http://wiki.blender.org/index.php/Extensions:2.5/Py/'\
28
 
        'Scripts/',
29
 
    'tracker_url': 'http://projects.blender.org/tracker/index.php?'\
30
 
        'func=detail&aid=23160',
31
 
    'category': 'Import-Export'}
32
 
 
33
 
 
34
 
import bpy,struct,math,os
35
 
 
36
 
MAX_QPATH = 64
37
 
 
38
 
MD3_IDENT = "IDP3"
39
 
MD3_VERSION = 15
40
 
MD3_MAX_TAGS = 16
41
 
MD3_MAX_SURFACES = 32
42
 
MD3_MAX_FRAMES = 1024
43
 
MD3_MAX_SHADERS = 256
44
 
MD3_MAX_VERTICES = 4096
45
 
MD3_MAX_TRIANGLES = 8192
46
 
MD3_XYZ_SCALE = 64.0
47
 
 
48
 
class md3Vert:
49
 
    xyz = []
50
 
    normal = 0
51
 
    binaryFormat = "<3hH"
52
 
    
53
 
    def __init__(self):
54
 
        self.xyz = [0.0, 0.0, 0.0]
55
 
        self.normal = 0
56
 
        
57
 
    def GetSize(self):
58
 
        return struct.calcsize(self.binaryFormat)
59
 
    
60
 
    # copied from PhaethonH <phaethon@linux.ucla.edu> md3.py
61
 
    def Decode(self, latlng):
62
 
        lat = (latlng >> 8) & 0xFF;
63
 
        lng = (latlng) & 0xFF;
64
 
        lat *= math.pi / 128;
65
 
        lng *= math.pi / 128;
66
 
        x = math.cos(lat) * math.sin(lng)
67
 
        y = math.sin(lat) * math.sin(lng)
68
 
        z =                 math.cos(lng)
69
 
        retval = [ x, y, z ]
70
 
        return retval
71
 
    
72
 
    # copied from PhaethonH <phaethon@linux.ucla.edu> md3.py
73
 
    def Encode(self, normal):
74
 
        x = normal[0]
75
 
        y = normal[1]
76
 
        z = normal[2]
77
 
        # normalize
78
 
        l = math.sqrt((x*x) + (y*y) + (z*z))
79
 
        if l == 0:
80
 
            return 0
81
 
        x = x/l
82
 
        y = y/l
83
 
        z = z/l
84
 
        
85
 
        if (x == 0.0) & (y == 0.0) :
86
 
            if z > 0.0:
87
 
                return 0
88
 
            else:
89
 
                return (128 << 8)
90
 
        
91
 
        lng = math.acos(z) * 255 / (2 * math.pi)
92
 
        lat = math.atan2(y, x) * 255 / (2 * math.pi)
93
 
        retval = ((int(lat) & 0xFF) << 8) | (int(lng) & 0xFF)
94
 
        return retval
95
 
        
96
 
    def Save(self, file):
97
 
        tmpData = [0] * 4
98
 
        tmpData[0] = int(self.xyz[0] * MD3_XYZ_SCALE)
99
 
        tmpData[1] = int(self.xyz[1] * MD3_XYZ_SCALE)
100
 
        tmpData[2] = int(self.xyz[2] * MD3_XYZ_SCALE)
101
 
        tmpData[3] = self.normal
102
 
        data = struct.pack(self.binaryFormat, tmpData[0], tmpData[1], tmpData[2], tmpData[3])
103
 
        file.write(data)
104
 
        
105
 
class md3TexCoord:
106
 
    u = 0.0
107
 
    v = 0.0
108
 
 
109
 
    binaryFormat = "<2f"
110
 
 
111
 
    def __init__(self):
112
 
        self.u = 0.0
113
 
        self.v = 0.0
114
 
        
115
 
    def GetSize(self):
116
 
        return struct.calcsize(self.binaryFormat)
117
 
 
118
 
    def Save(self, file):
119
 
        tmpData = [0] * 2
120
 
        tmpData[0] = self.u
121
 
        tmpData[1] = 1.0 - self.v
122
 
        data = struct.pack(self.binaryFormat, tmpData[0], tmpData[1])
123
 
        file.write(data)
124
 
 
125
 
class md3Triangle:
126
 
    indexes = []
127
 
 
128
 
    binaryFormat = "<3i"
129
 
 
130
 
    def __init__(self):
131
 
        self.indexes = [ 0, 0, 0 ]
132
 
        
133
 
    def GetSize(self):
134
 
        return struct.calcsize(self.binaryFormat)
135
 
 
136
 
    def Save(self, file):
137
 
        tmpData = [0] * 3
138
 
        tmpData[0] = self.indexes[0]
139
 
        tmpData[1] = self.indexes[2] # reverse
140
 
        tmpData[2] = self.indexes[1] # reverse
141
 
        data = struct.pack(self.binaryFormat,tmpData[0], tmpData[1], tmpData[2])
142
 
        file.write(data)
143
 
 
144
 
class md3Shader:
145
 
    name = ""
146
 
    index = 0
147
 
    
148
 
    binaryFormat = "<%dsi" % MAX_QPATH
149
 
 
150
 
    def __init__(self):
151
 
        self.name = ""
152
 
        self.index = 0
153
 
        
154
 
    def GetSize(self):
155
 
        return struct.calcsize(self.binaryFormat)
156
 
 
157
 
    def Save(self, file):
158
 
        tmpData = [0] * 2
159
 
        tmpData[0] = self.name
160
 
        tmpData[1] = self.index
161
 
        data = struct.pack(self.binaryFormat, tmpData[0], tmpData[1])
162
 
        file.write(data)
163
 
 
164
 
class md3Surface:
165
 
    ident = ""
166
 
    name = ""
167
 
    flags = 0
168
 
    numFrames = 0
169
 
    numShaders = 0
170
 
    numVerts = 0
171
 
    numTriangles = 0
172
 
    ofsTriangles = 0
173
 
    ofsShaders = 0
174
 
    ofsUV = 0
175
 
    ofsVerts = 0
176
 
    ofsEnd = 0
177
 
    shaders = []
178
 
    triangles = []
179
 
    uv = []
180
 
    verts = []
181
 
    
182
 
    binaryFormat = "<4s%ds10i" % MAX_QPATH  # 1 int, name, then 10 ints
183
 
    
184
 
    def __init__(self):
185
 
        self.ident = ""
186
 
        self.name = ""
187
 
        self.flags = 0
188
 
        self.numFrames = 0
189
 
        self.numShaders = 0
190
 
        self.numVerts = 0
191
 
        self.numTriangles = 0
192
 
        self.ofsTriangles = 0
193
 
        self.ofsShaders = 0
194
 
        self.ofsUV = 0
195
 
        self.ofsVerts = 0
196
 
        self.ofsEnd
197
 
        self.shaders = []
198
 
        self.triangles = []
199
 
        self.uv = []
200
 
        self.verts = []
201
 
        
202
 
    def GetSize(self):
203
 
        sz = struct.calcsize(self.binaryFormat)
204
 
        self.ofsTriangles = sz
205
 
        for t in self.triangles:
206
 
            sz += t.GetSize()
207
 
        self.ofsShaders = sz
208
 
        for s in self.shaders:
209
 
            sz += s.GetSize()
210
 
        self.ofsUV = sz
211
 
        for u in self.uv:
212
 
            sz += u.GetSize()
213
 
        self.ofsVerts = sz
214
 
        for v in self.verts:
215
 
            sz += v.GetSize()
216
 
        self.ofsEnd = sz
217
 
        return self.ofsEnd
218
 
    
219
 
    def Save(self, file):
220
 
        self.GetSize()
221
 
        tmpData = [0] * 12
222
 
        tmpData[0] = self.ident
223
 
        tmpData[1] = self.name
224
 
        tmpData[2] = self.flags
225
 
        tmpData[3] = self.numFrames
226
 
        tmpData[4] = self.numShaders
227
 
        tmpData[5] = self.numVerts
228
 
        tmpData[6] = self.numTriangles
229
 
        tmpData[7] = self.ofsTriangles
230
 
        tmpData[8] = self.ofsShaders
231
 
        tmpData[9] = self.ofsUV
232
 
        tmpData[10] = self.ofsVerts
233
 
        tmpData[11] = self.ofsEnd
234
 
        data = struct.pack(self.binaryFormat, tmpData[0],tmpData[1],tmpData[2],tmpData[3],tmpData[4],tmpData[5],tmpData[6],tmpData[7],tmpData[8],tmpData[9],tmpData[10],tmpData[11])
235
 
        file.write(data)
236
 
 
237
 
        # write the tri data
238
 
        for t in self.triangles:
239
 
            t.Save(file)
240
 
 
241
 
        # save the shader coordinates
242
 
        for s in self.shaders:
243
 
            s.Save(file)
244
 
 
245
 
        # save the uv info
246
 
        for u in self.uv:
247
 
            u.Save(file)
248
 
 
249
 
        # save the verts
250
 
        for v in self.verts:
251
 
            v.Save(file)
252
 
 
253
 
class md3Tag:
254
 
    name = ""
255
 
    origin = []
256
 
    axis = []
257
 
    
258
 
    binaryFormat="<%ds3f9f" % MAX_QPATH
259
 
    
260
 
    def __init__(self):
261
 
        self.name = ""
262
 
        self.origin = [0, 0, 0]
263
 
        self.axis = [0, 0, 0, 0, 0, 0, 0, 0, 0]
264
 
        
265
 
    def GetSize(self):
266
 
        return struct.calcsize(self.binaryFormat)
267
 
        
268
 
    def Save(self, file):
269
 
        tmpData = [0] * 13
270
 
        tmpData[0] = self.name
271
 
        tmpData[1] = float(self.origin[0])
272
 
        tmpData[2] = float(self.origin[1])
273
 
        tmpData[3] = float(self.origin[2])
274
 
        tmpData[4] = float(self.axis[0])
275
 
        tmpData[5] = float(self.axis[1])
276
 
        tmpData[6] = float(self.axis[2])
277
 
        tmpData[7] = float(self.axis[3])
278
 
        tmpData[8] = float(self.axis[4])
279
 
        tmpData[9] = float(self.axis[5])
280
 
        tmpData[10] = float(self.axis[6])
281
 
        tmpData[11] = float(self.axis[7])
282
 
        tmpData[12] = float(self.axis[8])
283
 
        data = struct.pack(self.binaryFormat, tmpData[0],tmpData[1],tmpData[2],tmpData[3],tmpData[4],tmpData[5],tmpData[6], tmpData[7], tmpData[8], tmpData[9], tmpData[10], tmpData[11], tmpData[12])
284
 
        file.write(data)
285
 
    
286
 
class md3Frame:
287
 
    mins = 0
288
 
    maxs = 0
289
 
    localOrigin = 0
290
 
    radius = 0.0
291
 
    name = ""
292
 
    
293
 
    binaryFormat="<3f3f3ff16s"
294
 
    
295
 
    def __init__(self):
296
 
        self.mins = [0, 0, 0]
297
 
        self.maxs = [0, 0, 0]
298
 
        self.localOrigin = [0, 0, 0]
299
 
        self.radius = 0.0
300
 
        self.name = ""
301
 
        
302
 
    def GetSize(self):
303
 
        return struct.calcsize(self.binaryFormat)
304
 
 
305
 
    def Save(self, file):
306
 
        tmpData = [0] * 11
307
 
        tmpData[0] = self.mins[0]
308
 
        tmpData[1] = self.mins[1]
309
 
        tmpData[2] = self.mins[2]
310
 
        tmpData[3] = self.maxs[0]
311
 
        tmpData[4] = self.maxs[1]
312
 
        tmpData[5] = self.maxs[2]
313
 
        tmpData[6] = self.localOrigin[0]
314
 
        tmpData[7] = self.localOrigin[1]
315
 
        tmpData[8] = self.localOrigin[2]
316
 
        tmpData[9] = self.radius
317
 
        tmpData[10] = self.name
318
 
        data = struct.pack(self.binaryFormat, tmpData[0],tmpData[1],tmpData[2],tmpData[3],tmpData[4],tmpData[5],tmpData[6],tmpData[7], tmpData[8], tmpData[9], tmpData[10])
319
 
        file.write(data)
320
 
 
321
 
class md3Object:
322
 
    # header structure
323
 
    ident = ""            # this is used to identify the file (must be IDP3)
324
 
    version = 0            # the version number of the file (Must be 15)
325
 
    name = ""
326
 
    flags = 0
327
 
    numFrames = 0
328
 
    numTags = 0
329
 
    numSurfaces = 0
330
 
    numSkins = 0
331
 
    ofsFrames = 0
332
 
    ofsTags = 0
333
 
    ofsSurfaces = 0
334
 
    ofsEnd = 0
335
 
    frames = []
336
 
    tags = []
337
 
    surfaces = []
338
 
 
339
 
    binaryFormat="<4si%ds9i" % MAX_QPATH  # little-endian (<), 17 integers (17i)
340
 
 
341
 
    def __init__(self):
342
 
        self.ident = 0
343
 
        self.version = 0
344
 
        self.name = ""
345
 
        self.flags = 0
346
 
        self.numFrames = 0
347
 
        self.numTags = 0
348
 
        self.numSurfaces = 0
349
 
        self.numSkins = 0
350
 
        self.ofsFrames = 0
351
 
        self.ofsTags = 0
352
 
        self.ofsSurfaces = 0
353
 
        self.ofsEnd = 0
354
 
        self.frames = []
355
 
        self.tags = []
356
 
        self.surfaces = []
357
 
 
358
 
    def GetSize(self):
359
 
        self.ofsFrames = struct.calcsize(self.binaryFormat)
360
 
        self.ofsTags = self.ofsFrames
361
 
        for f in self.frames:
362
 
            self.ofsTags += f.GetSize()
363
 
        self.ofsSurfaces += self.ofsTags
364
 
        for t in self.tags:
365
 
            self.ofsSurfaces += t.GetSize()
366
 
        self.ofsEnd = self.ofsSurfaces
367
 
        for s in self.surfaces:
368
 
            self.ofsEnd += s.GetSize()
369
 
        return self.ofsEnd
370
 
        
371
 
    def Save(self, file):
372
 
        self.GetSize()
373
 
        tmpData = [0] * 12
374
 
        tmpData[0] = self.ident
375
 
        tmpData[1] = self.version
376
 
        tmpData[2] = self.name
377
 
        tmpData[3] = self.flags
378
 
        tmpData[4] = self.numFrames
379
 
        tmpData[5] = self.numTags
380
 
        tmpData[6] = self.numSurfaces
381
 
        tmpData[7] = self.numSkins
382
 
        tmpData[8] = self.ofsFrames
383
 
        tmpData[9] = self.ofsTags
384
 
        tmpData[10] = self.ofsSurfaces
385
 
        tmpData[11] = self.ofsEnd
386
 
 
387
 
        data = struct.pack(self.binaryFormat, tmpData[0],tmpData[1],tmpData[2],tmpData[3],tmpData[4],tmpData[5],tmpData[6],tmpData[7], tmpData[8], tmpData[9], tmpData[10], tmpData[11])
388
 
        file.write(data)
389
 
 
390
 
        for f in self.frames:
391
 
            f.Save(file)
392
 
            
393
 
        for t in self.tags:
394
 
            t.Save(file)
395
 
            
396
 
        for s in self.surfaces:
397
 
            s.Save(file)
398
 
 
399
 
 
400
 
def message(log,msg):
401
 
  if log:
402
 
    log.write(msg + "\n")
403
 
  else:
404
 
    print(msg)
405
 
 
406
 
class md3Settings:
407
 
  def __init__(self,
408
 
               savepath,
409
 
               name,
410
 
               logpath,
411
 
               overwrite=True,
412
 
               dumpall=False,
413
 
               ignoreuvs=False,
414
 
               scale=1.0,
415
 
               offsetx=0.0,
416
 
               offsety=0.0,
417
 
               offsetz=0.0):
418
 
    self.savepath = savepath
419
 
    self.name = name
420
 
    self.logpath = logpath
421
 
    self.overwrite = overwrite
422
 
    self.dumpall = dumpall
423
 
    self.ignoreuvs = ignoreuvs
424
 
    self.scale = scale
425
 
    self.offsetx = offsetx
426
 
    self.offsety = offsety
427
 
    self.offsetz = offsetz
428
 
 
429
 
def print_md3(log,md3,dumpall):
430
 
  message(log,"Header Information")
431
 
  message(log,"Ident: " + str(md3.ident))
432
 
  message(log,"Version: " + str(md3.version))
433
 
  message(log,"Name: " + md3.name)
434
 
  message(log,"Flags: " + str(md3.flags))
435
 
  message(log,"Number of Frames: " + str(md3.numFrames))
436
 
  message(log,"Number of Tags: " + str(md3.numTags))
437
 
  message(log,"Number of Surfaces: " + str(md3.numSurfaces))
438
 
  message(log,"Number of Skins: " + str(md3.numSkins))
439
 
  message(log,"Offset Frames: " + str(md3.ofsFrames))
440
 
  message(log,"Offset Tags: " + str(md3.ofsTags))
441
 
  message(log,"Offset Surfaces: " + str(md3.ofsSurfaces))
442
 
  message(log,"Offset end: " + str(md3.ofsEnd))
443
 
  if dumpall:
444
 
    message(log,"Frames:")
445
 
    for f in md3.frames:
446
 
      message(log," Mins: " + str(f.mins[0]) + " " + str(f.mins[1]) + " " + str(f.mins[2]))
447
 
      message(log," Maxs: " + str(f.maxs[0]) + " " + str(f.maxs[1]) + " " + str(f.maxs[2]))
448
 
      message(log," Origin(local): " + str(f.localOrigin[0]) + " " + str(f.localOrigin[1]) + " " + str(f.localOrigin[2]))
449
 
      message(log," Radius: " + str(f.radius))
450
 
      message(log," Name: " + f.name)
451
 
 
452
 
    message(log,"Tags:")
453
 
    for t in md3.tags:
454
 
      message(log," Name: " + t.name)
455
 
      message(log," Origin: " + str(t.origin[0]) + " " + str(t.origin[1]) + " " + str(t.origin[2]))
456
 
      message(log," Axis[0]: " + str(t.axis[0]) + " " + str(t.axis[1]) + " " + str(t.axis[2]))
457
 
      message(log," Axis[1]: " + str(t.axis[3]) + " " + str(t.axis[4]) + " " + str(t.axis[5]))
458
 
      message(log," Axis[2]: " + str(t.axis[6]) + " " + str(t.axis[7]) + " " + str(t.axis[8]))
459
 
 
460
 
    message(log,"Surfaces:")
461
 
    for s in md3.surfaces:
462
 
      message(log," Ident: " + s.ident)
463
 
      message(log," Name: " + s.name)
464
 
      message(log," Flags: " + str(s.flags))
465
 
      message(log," # of Frames: " + str(s.numFrames))
466
 
      message(log," # of Shaders: " + str(s.numShaders))
467
 
      message(log," # of Verts: " + str(s.numVerts))
468
 
      message(log," # of Triangles: " + str(s.numTriangles))
469
 
      message(log," Offset Triangles: " + str(s.ofsTriangles))
470
 
      message(log," Offset UVs: " + str(s.ofsUV))
471
 
      message(log," Offset Verts: " + str(s.ofsVerts))
472
 
      message(log," Offset End: " + str(s.ofsEnd))
473
 
      message(log," Shaders:")
474
 
      for shader in s.shaders:
475
 
        message(log,"  Name: " + shader.name)
476
 
        message(log,"  Index: " + str(shader.index))
477
 
      message(log," Triangles:")
478
 
      for tri in s.triangles:
479
 
        message(log,"  Indexes: " + str(tri.indexes[0]) + " " + str(tri.indexes[1]) + " " + str(tri.indexes[2]))
480
 
      message(log," UVs:")
481
 
      for uv in s.uv:
482
 
        message(log,"  U: " + str(uv.u))
483
 
        message(log,"  V: " + str(uv.v)) 
484
 
      message(log," Verts:")
485
 
      for vert in s.verts:
486
 
        message(log,"  XYZ: " + str(vert.xyz[0]) + " " + str(vert.xyz[1]) + " " + str(vert.xyz[2]))
487
 
        message(log,"  Normal: " + str(vert.normal))
488
 
 
489
 
  shader_count = 0
490
 
  vert_count = 0
491
 
  tri_count = 0
492
 
  for surface in md3.surfaces:
493
 
    shader_count += surface.numShaders
494
 
    tri_count += surface.numTriangles
495
 
    vert_count += surface.numVerts
496
 
 
497
 
  if md3.numTags >= MD3_MAX_TAGS:
498
 
    message(log,"!Warning: Tag limit reached! " + str(md3.numTags))
499
 
  if md3.numSurfaces >= MD3_MAX_SURFACES:
500
 
    message(log,"!Warning: Surface limit reached! " + str(md3.numSurfaces))
501
 
  if md3.numFrames >= MD3_MAX_FRAMES:
502
 
    message(log,"!Warning: Frame limit reached! " + str(md3.numFrames))
503
 
  if shader_count >= MD3_MAX_SHADERS:
504
 
    message(log,"!Warning: Shader limit reached! " + str(shader_count))
505
 
  if vert_count >= MD3_MAX_VERTICES:
506
 
    message(log,"!Warning: Vertex limit reached! " + str(vert_count))
507
 
  if tri_count >= MD3_MAX_TRIANGLES:
508
 
    message(log,"!Warning: Triangle limit reached! " + str(tri_count))
509
 
 
510
 
def save_md3(settings):
511
 
  if settings.logpath:
512
 
    if settings.overwrite:
513
 
      log = open(settings.logpath,"w")
514
 
    else:
515
 
      log = open(settings.logpath,"a")
516
 
  else:
517
 
    log = 0
518
 
  message(log,"##########Exporting MD3##########")
519
 
  bpy.ops.object.mode_set(mode='OBJECT')
520
 
  md3 = md3Object()
521
 
  md3.ident = MD3_IDENT
522
 
  md3.version = MD3_VERSION
523
 
  md3.name = settings.name
524
 
  md3.numFrames = (bpy.context.scene.frame_end + 1) - bpy.context.scene.frame_start
525
 
 
526
 
  for obj in bpy.context.selected_objects:
527
 
    if obj.type == 'MESH':
528
 
      nsurface = md3Surface()
529
 
      nsurface.name = obj.name
530
 
      nsurface.ident = MD3_IDENT
531
 
 
532
 
      vertlist = []
533
 
 
534
 
      for f,face in enumerate(obj.data.faces):
535
 
        ntri = md3Triangle()
536
 
        if len(face.verts) != 3:
537
 
          message(log,"Found a nontriangle face in object " + obj.name)
538
 
          continue
539
 
 
540
 
        for v,vert_index in enumerate(face.verts):
541
 
          uv_u = round(obj.data.active_uv_texture.data[f].uv[v][0],5)
542
 
          uv_v = round(obj.data.active_uv_texture.data[f].uv[v][1],5)
543
 
 
544
 
          match = 0
545
 
          match_index = 0
546
 
          for i,vi in enumerate(vertlist):
547
 
            if vi == vert_index:
548
 
              if settings.ignoreuvs:
549
 
                match = 1#there is a uv match for all
550
 
                match_index = i
551
 
              else:
552
 
                if nsurface.uv[i].u == uv_u and nsurface.uv[i].v == uv_v:
553
 
                  match = 1
554
 
                  match_index = i
555
 
 
556
 
          if match == 0:
557
 
            vertlist.append(vert_index)
558
 
            ntri.indexes[v] = nsurface.numVerts
559
 
            ntex = md3TexCoord()
560
 
            ntex.u = uv_u
561
 
            ntex.v = uv_v
562
 
            nsurface.uv.append(ntex)
563
 
            nsurface.numVerts += 1
564
 
          else:
565
 
            ntri.indexes[v] = match_index
566
 
        nsurface.triangles.append(ntri)
567
 
        nsurface.numTriangles += 1
568
 
 
569
 
      if obj.data.active_uv_texture:
570
 
        nshader = md3Shader()
571
 
        nshader.name = obj.data.active_uv_texture.name
572
 
        nshader.index = nsurface.numShaders
573
 
        nsurface.shaders.append(nshader)
574
 
        nsurface.numShaders += 1
575
 
      if nsurface.numShaders < 1: #we should add a blank as a placeholder
576
 
        nshader = md3Shader()
577
 
        nshader.name = "NULL"
578
 
        nsurface.shaders.append(nshader)
579
 
        nsurface.numShaders += 1
580
 
 
581
 
      for frame in range(bpy.context.scene.frame_start,bpy.context.scene.frame_end + 1):
582
 
        bpy.context.scene.set_frame(frame)
583
 
        fobj = obj.create_mesh(bpy.context.scene,True,'PREVIEW')
584
 
        fobj.calc_normals()
585
 
        nframe = md3Frame()
586
 
        nframe.name = str(frame)
587
 
        for vi in vertlist:
588
 
            vert = fobj.verts[vi]
589
 
            nvert = md3Vert()
590
 
            nvert.xyz = vert.co * obj.matrix_world
591
 
            nvert.xyz[0] = (round(nvert.xyz[0] + obj.matrix_world[3][0],5) * settings.scale) + settings.offsetx
592
 
            nvert.xyz[1] = (round(nvert.xyz[1] + obj.matrix_world[3][1],5) * settings.scale) + settings.offsety
593
 
            nvert.xyz[2] = (round(nvert.xyz[2] + obj.matrix_world[3][2],5) * settings.scale) + settings.offsetz
594
 
            nvert.normal = nvert.Encode(vert.normal)
595
 
            for i in range(0,3):
596
 
              nframe.mins[i] = min(nframe.mins[i],nvert.xyz[i])
597
 
              nframe.maxs[i] = max(nframe.maxs[i],nvert.xyz[i])
598
 
            minlength = math.sqrt(math.pow(nframe.mins[0],2) + math.pow(nframe.mins[1],2) + math.pow(nframe.mins[2],2))
599
 
            maxlength = math.sqrt(math.pow(nframe.maxs[0],2) + math.pow(nframe.maxs[1],2) + math.pow(nframe.maxs[2],2))
600
 
            nframe.radius = round(max(minlength,maxlength),5)
601
 
            nsurface.verts.append(nvert) 
602
 
        md3.frames.append(nframe)
603
 
        nsurface.numFrames += 1
604
 
        bpy.data.meshes.remove(fobj)
605
 
      md3.surfaces.append(nsurface)
606
 
      md3.numSurfaces += 1
607
 
 
608
 
    elif obj.type == 'EMPTY':
609
 
      md3.numTags += 1
610
 
      for frame in range(bpy.context.scene.frame_start,bpy.context.scene.frame_end + 1):
611
 
        bpy.context.scene.set_frame(frame)
612
 
        ntag = md3Tag()
613
 
        ntag.origin[0] = (round(obj.matrix_world[3][0] * settings.scale,5)) + settings.offsetx
614
 
        ntag.origin[1] = (round(obj.matrix_world[3][1] * settings.scale,5)) + settings.offsety
615
 
        ntag.origin[2] = (round(obj.matrix_world[3][2] * settings.scale,5)) + settings.offsetz
616
 
        ntag.axis[0] = obj.matrix_world[0][0]
617
 
        ntag.axis[1] = obj.matrix_world[0][1]
618
 
        ntag.axis[2] = obj.matrix_world[0][2]
619
 
        ntag.axis[3] = obj.matrix_world[1][0]
620
 
        ntag.axis[4] = obj.matrix_world[1][1]
621
 
        ntag.axis[5] = obj.matrix_world[1][2]
622
 
        ntag.axis[6] = obj.matrix_world[2][0]
623
 
        ntag.axis[7] = obj.matrix_world[2][1]
624
 
        ntag.axis[8] = obj.matrix_world[2][2]
625
 
        md3.tags.append(ntag)
626
 
  
627
 
  if md3.numSurfaces < 1:
628
 
    message(log,"Select a mesh to export!")
629
 
    if log:
630
 
      log.close()
631
 
    return
632
 
 
633
 
  file = open(settings.savepath, "wb")
634
 
  md3.Save(file)
635
 
  print_md3(log,md3,settings.dumpall)
636
 
  file.close()
637
 
 
638
 
  message(log,"MD3: " + settings.name + " saved to " + settings.savepath)
639
 
  if log:
640
 
    print("Logged to",settings.logpath)
641
 
    log.close()
642
 
 
643
 
from bpy.props import *
644
 
class ExportMD3(bpy.types.Operator):
645
 
  '''Export to Quake Model 3 (.md3)'''
646
 
  bl_idname = "export.md3"
647
 
  bl_label = 'Export MD3'
648
 
 
649
 
  filepath = StringProperty(subtype = 'FILE_PATH',name="File Path", description="Filepath for exporting", maxlen= 1024, default= "")
650
 
  md3name = StringProperty(name="MD3 Name", description="MD3 header name / skin path (64 bytes)",maxlen=64,default="")
651
 
  md3log = StringProperty(name="MD3 Log", description="MD3 log file path",maxlen=1024,default="export_md3.log")
652
 
  md3overwritelog = BoolProperty(name="Overwrite log", description="Overwrite log (off == append)", default=True)
653
 
  md3dumpall = BoolProperty(name="Dump all", description="Dump all data for md3 to log",default=False)
654
 
  md3ignoreuvs = BoolProperty(name="Ignore UVs", description="Ignores uv influence on mesh generation. Use if uv map not made.",default=False)
655
 
  md3scale = FloatProperty(name="Scale", description="Scale all objects from world origin (0,0,0)",default=1.0,precision=5)
656
 
  md3offsetx = FloatProperty(name="Offset X", description="Transition scene along x axis",default=0.0,precision=5)
657
 
  md3offsety = FloatProperty(name="Offset Y", description="Transition scene along y axis",default=0.0,precision=5)
658
 
  md3offsetz = FloatProperty(name="Offset Z", description="Transition scene along z axis",default=0.0,precision=5)
659
 
 
660
 
  def execute(self, context):
661
 
   settings = md3Settings(savepath = self.properties.filepath,
662
 
                          name = self.properties.md3name,
663
 
                          logpath = self.properties.md3log,
664
 
                          overwrite = self.properties.md3overwritelog,
665
 
                          dumpall = self.properties.md3dumpall,
666
 
                          ignoreuvs = self.properties.md3ignoreuvs,
667
 
                          scale = self.properties.md3scale,
668
 
                          offsetx = self.properties.md3offsetx,
669
 
                          offsety = self.properties.md3offsety,
670
 
                          offsetz = self.properties.md3offsetz)
671
 
   save_md3(settings)
672
 
   return {'FINISHED'}
673
 
 
674
 
  def invoke(self, context, event):
675
 
    wm = context.window_manager
676
 
    wm.fileselect_add(self)
677
 
    return {'RUNNING_MODAL'}
678
 
 
679
 
  @classmethod
680
 
  def poll(cls, context):
681
 
    return context.active_object is not None
682
 
 
683
 
def menu_func(self, context):
684
 
  newpath = os.path.splitext(bpy.context.blend_data.filepath)[0] + ".md3"
685
 
  self.layout.operator(ExportMD3.bl_idname, text="Quake Model 3 (.md3)").filepath = newpath 
686
 
 
687
 
def register():
688
 
  bpy.types.INFO_MT_file_export.append(menu_func)
689
 
 
690
 
def unregister():
691
 
  bpy.types.INFO_MT_file_export.remove(menu_func)
692
 
 
693
 
if __name__ == "__main__":
694
 
  register()