applied patch from Boris van Schooten, [#8148] Animation bugfix for md2_export script
[blender-staging.git] / release / scripts / md2_export.py
1 #!BPY
2
3 """
4 Name: 'MD2 (.md2)'
5 Blender: 243
6 Group: 'Export'
7 Tooltip: 'Export to Quake file format (.md2).'
8 """
9
10 __author__ = 'Bob Holcomb'
11 __version__ = '0.18.1 patch 1'
12 __url__ = ["Bob's site, http://bane.servebeer.com",
13      "Support forum, http://bane.servebeer.com", "blender", "elysiun"]
14 __email__ = ["Bob Holcomb, bob_holcomb:hotmail*com", "scripts"]
15 __bpydoc__ = """\
16 This script Exports a Quake 2 file (MD2).
17
18  Additional help from: Shadwolf, Skandal, Rojo, Cambo<br>
19  Thanks Guys!
20 """
21
22 # This is a PATCHED VERSION, fixing the bug due to which animations would
23 # (almost) never work.  It is now also possible to output a MD2 model without
24 # texture.
25 # On: 23 january 2008
26 # By: Boris van Schooten (schooten@cs.utwente.nl)
27
28 # ***** BEGIN GPL LICENSE BLOCK *****
29 #
30 # Script copyright (C): Bob Holcomb
31 #
32 # This program is free software; you can redistribute it and/or
33 # modify it under the terms of the GNU General Public License
34 # as published by the Free Software Foundation; either version 2
35 # of the License, or (at your option) any later version.
36 #
37 # This program is distributed in the hope that it will be useful,
38 # but WITHOUT ANY WARRANTY; without even the implied warranty of
39 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
40 # GNU General Public License for more details.
41 #
42 # You should have received a copy of the GNU General Public License
43 # along with this program; if not, write to the Free Software Foundation,
44 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
45 #
46 # ***** END GPL LICENCE BLOCK *****
47 # --------------------------------------------------------------------------
48
49
50 import Blender
51 from Blender import *
52 from Blender.Draw import *
53 from Blender.BGL import *
54 from Blender.Window import *
55
56 import struct, string
57 from types import *
58
59
60
61 ######################################################
62 # GUI Loader
63 ######################################################
64
65 # Export globals
66 g_filename=Create("tris.md2")
67 g_frame_filename=Create("default")
68
69 g_filename_search=Create("")
70 g_frame_search=Create("default")
71
72 g_texture_path=Create("")
73
74 user_frame_list=[]
75
76 #Globals
77 g_scale=Create(1.0)
78
79 # Events
80 EVENT_NOEVENT=1
81 EVENT_SAVE_MD2=2
82 EVENT_CHOOSE_FILENAME=3
83 EVENT_CHOOSE_FRAME=4
84 EVENT_EXIT=100
85
86 ######################################################
87 # Callbacks for Window functions
88 ######################################################
89 def filename_callback(input_filename):
90         global g_filename
91         g_filename.val=input_filename
92
93 def frame_callback(input_frame):
94         global g_frame_filename
95         g_frame_filename.val=input_frame
96
97 def draw_gui():
98         global g_scale
99         global g_filename
100         global g_frame_filename
101         global EVENT_NOEVENT,EVENT_SAVE_MD2,EVENT_CHOOSE_FILENAME,EVENT_CHOOSE_FRAME,EVENT_EXIT
102         global g_texture_path
103
104         ########## Titles
105         glClear(GL_COLOR_BUFFER_BIT)
106         glRasterPos2d(10, 120)
107         Text("MD2 Export")
108
109         ######### Parameters GUI Buttons
110         ######### MD2 Filename text entry
111         g_filename = String("MD2 file to save: ", EVENT_NOEVENT, 10, 75, 210, 18,
112                             g_filename.val, 255, "MD2 file to save")
113         ########## MD2 File Search Button
114         Button("Browse",EVENT_CHOOSE_FILENAME,220,75,80,18)
115
116         ##########  MD2 Frame List Text entry
117         g_frame_filename = String("Frame List file to load: ", EVENT_NOEVENT, 10, 55, 210, 18,
118                                 g_frame_filename.val, 255, "Frame List to load-overrides MD2 defaults")
119         ########## Frame List Search Button
120         Button("Browse",EVENT_CHOOSE_FRAME,220,55,80,18)
121         
122         ##########  Texture path to append
123         g_texture_path=String("Texture Path: ", EVENT_NOEVENT, 10,35,210,18,
124                                                                                                                 g_texture_path.val,255, "Texture path to prepend")
125
126
127         ########## Scale slider-default is 1/8 which is a good scale for md2->blender
128         g_scale= Slider("Scale Factor: ", EVENT_NOEVENT, 10, 95, 210, 18,
129                     1.0, 0.001, 10.0, 1, "Scale factor for object Model");
130
131         ######### Draw and Exit Buttons
132         Button("Export",EVENT_SAVE_MD2 , 10, 10, 80, 18)
133         Button("Exit",EVENT_EXIT , 170, 10, 80, 18)
134
135 def event(evt, val):    
136         if (evt == QKEY and not val):
137                 Exit()
138
139 def bevent(evt):
140         global g_filename
141         global g_frame_filename
142         global EVENT_NOEVENT,EVENT_SAVE_MD2,EVENT_EXIT
143
144         ######### Manages GUI events
145         if (evt==EVENT_EXIT):
146                 Blender.Draw.Exit()
147         elif (evt==EVENT_CHOOSE_FILENAME):
148                 FileSelector(filename_callback, "MD2 File Selection")
149         elif (evt==EVENT_CHOOSE_FRAME):
150                 FileSelector(frame_callback, "Frame Selection")
151         elif (evt==EVENT_SAVE_MD2):
152                 save_md2(g_filename.val)
153                 Blender.Draw.Exit()
154                 return
155
156 Register(draw_gui, event, bevent)
157
158 ######################################################
159 # MD2 Model Constants
160 ######################################################
161 MD2_MAX_TRIANGLES=4096
162 MD2_MAX_VERTICES=2048
163 MD2_MAX_TEXCOORDS=2048
164 MD2_MAX_FRAMES=512
165 MD2_MAX_SKINS=32
166 MD2_MAX_FRAMESIZE=(MD2_MAX_VERTICES * 4 + 128)
167
168 MD2_FRAME_NAME_LIST=(("stand",1,40),
169                                         ("run",41,46),
170                                         ("attack",47,54),
171                                         ("pain1",55,58),
172                                         ("pain2",59,62),
173                                         ("pain3",63,66),
174                                         ("jump",67,72),
175                                         ("flip",73,84),
176                                         ("salute", 85,95),
177                                         ("taunt",96,112),
178                                         ("wave",113,123),
179                                         ("point",124,135),
180                                         ("crstnd",136,154),
181                                         ("crwalk",155,160),
182                                         ("crattack",161,169),
183                                         ("crpain",170,173),
184                                         ("crdeath",174,178),
185                                         ("death1",179,184),
186                                         ("death2",185,190),
187                                         ("death3",191,198))
188                                         #198 frames
189                                         
190 MD2_NORMALS=((-0.525731, 0.000000, 0.850651), 
191                         (-0.442863, 0.238856, 0.864188), 
192                         (-0.295242, 0.000000, 0.955423), 
193                         (-0.309017, 0.500000, 0.809017), 
194                         (-0.162460, 0.262866, 0.951056), 
195                         (0.000000, 0.000000, 1.000000), 
196                         (0.000000, 0.850651, 0.525731), 
197                         (-0.147621, 0.716567, 0.681718), 
198                         (0.147621, 0.716567, 0.681718), 
199                         (0.000000, 0.525731, 0.850651), 
200                         (0.309017, 0.500000, 0.809017), 
201                         (0.525731, 0.000000, 0.850651), 
202                         (0.295242, 0.000000, 0.955423), 
203                         (0.442863, 0.238856, 0.864188), 
204                         (0.162460, 0.262866, 0.951056), 
205                         (-0.681718, 0.147621, 0.716567), 
206                         (-0.809017, 0.309017, 0.500000), 
207                         (-0.587785, 0.425325, 0.688191), 
208                         (-0.850651, 0.525731, 0.000000), 
209                         (-0.864188, 0.442863, 0.238856), 
210                         (-0.716567, 0.681718, 0.147621), 
211                         (-0.688191, 0.587785, 0.425325), 
212                         (-0.500000, 0.809017, 0.309017), 
213                         (-0.238856, 0.864188, 0.442863), 
214                         (-0.425325, 0.688191, 0.587785), 
215                         (-0.716567, 0.681718, -0.147621), 
216                         (-0.500000, 0.809017, -0.309017), 
217                         (-0.525731, 0.850651, 0.000000), 
218                         (0.000000, 0.850651, -0.525731), 
219                         (-0.238856, 0.864188, -0.442863), 
220                         (0.000000, 0.955423, -0.295242), 
221                         (-0.262866, 0.951056, -0.162460), 
222                         (0.000000, 1.000000, 0.000000), 
223                         (0.000000, 0.955423, 0.295242), 
224                         (-0.262866, 0.951056, 0.162460), 
225                         (0.238856, 0.864188, 0.442863), 
226                         (0.262866, 0.951056, 0.162460), 
227                         (0.500000, 0.809017, 0.309017), 
228                         (0.238856, 0.864188, -0.442863), 
229                         (0.262866, 0.951056, -0.162460), 
230                         (0.500000, 0.809017, -0.309017), 
231                         (0.850651, 0.525731, 0.000000), 
232                         (0.716567, 0.681718, 0.147621), 
233                         (0.716567, 0.681718, -0.147621), 
234                         (0.525731, 0.850651, 0.000000), 
235                         (0.425325, 0.688191, 0.587785), 
236                         (0.864188, 0.442863, 0.238856), 
237                         (0.688191, 0.587785, 0.425325), 
238                         (0.809017, 0.309017, 0.500000), 
239                         (0.681718, 0.147621, 0.716567), 
240                         (0.587785, 0.425325, 0.688191), 
241                         (0.955423, 0.295242, 0.000000), 
242                         (1.000000, 0.000000, 0.000000), 
243                         (0.951056, 0.162460, 0.262866), 
244                         (0.850651, -0.525731, 0.000000), 
245                         (0.955423, -0.295242, 0.000000), 
246                         (0.864188, -0.442863, 0.238856), 
247                         (0.951056, -0.162460, 0.262866), 
248                         (0.809017, -0.309017, 0.500000), 
249                         (0.681718, -0.147621, 0.716567), 
250                         (0.850651, 0.000000, 0.525731), 
251                         (0.864188, 0.442863, -0.238856), 
252                         (0.809017, 0.309017, -0.500000), 
253                         (0.951056, 0.162460, -0.262866), 
254                         (0.525731, 0.000000, -0.850651), 
255                         (0.681718, 0.147621, -0.716567), 
256                         (0.681718, -0.147621, -0.716567), 
257                         (0.850651, 0.000000, -0.525731), 
258                         (0.809017, -0.309017, -0.500000), 
259                         (0.864188, -0.442863, -0.238856), 
260                         (0.951056, -0.162460, -0.262866), 
261                         (0.147621, 0.716567, -0.681718), 
262                         (0.309017, 0.500000, -0.809017), 
263                         (0.425325, 0.688191, -0.587785), 
264                         (0.442863, 0.238856, -0.864188), 
265                         (0.587785, 0.425325, -0.688191), 
266                         (0.688191, 0.587785, -0.425325), 
267                         (-0.147621, 0.716567, -0.681718), 
268                         (-0.309017, 0.500000, -0.809017), 
269                         (0.000000, 0.525731, -0.850651), 
270                         (-0.525731, 0.000000, -0.850651), 
271                         (-0.442863, 0.238856, -0.864188), 
272                         (-0.295242, 0.000000, -0.955423), 
273                         (-0.162460, 0.262866, -0.951056), 
274                         (0.000000, 0.000000, -1.000000), 
275                         (0.295242, 0.000000, -0.955423), 
276                         (0.162460, 0.262866, -0.951056), 
277                         (-0.442863, -0.238856, -0.864188), 
278                         (-0.309017, -0.500000, -0.809017), 
279                         (-0.162460, -0.262866, -0.951056), 
280                         (0.000000, -0.850651, -0.525731), 
281                         (-0.147621, -0.716567, -0.681718), 
282                         (0.147621, -0.716567, -0.681718), 
283                         (0.000000, -0.525731, -0.850651), 
284                         (0.309017, -0.500000, -0.809017), 
285                         (0.442863, -0.238856, -0.864188), 
286                         (0.162460, -0.262866, -0.951056), 
287                         (0.238856, -0.864188, -0.442863), 
288                         (0.500000, -0.809017, -0.309017), 
289                         (0.425325, -0.688191, -0.587785), 
290                         (0.716567, -0.681718, -0.147621), 
291                         (0.688191, -0.587785, -0.425325), 
292                         (0.587785, -0.425325, -0.688191), 
293                         (0.000000, -0.955423, -0.295242), 
294                         (0.000000, -1.000000, 0.000000), 
295                         (0.262866, -0.951056, -0.162460), 
296                         (0.000000, -0.850651, 0.525731), 
297                         (0.000000, -0.955423, 0.295242), 
298                         (0.238856, -0.864188, 0.442863), 
299                         (0.262866, -0.951056, 0.162460), 
300                         (0.500000, -0.809017, 0.309017), 
301                         (0.716567, -0.681718, 0.147621), 
302                         (0.525731, -0.850651, 0.000000), 
303                         (-0.238856, -0.864188, -0.442863), 
304                         (-0.500000, -0.809017, -0.309017), 
305                         (-0.262866, -0.951056, -0.162460), 
306                         (-0.850651, -0.525731, 0.000000), 
307                         (-0.716567, -0.681718, -0.147621), 
308                         (-0.716567, -0.681718, 0.147621), 
309                         (-0.525731, -0.850651, 0.000000), 
310                         (-0.500000, -0.809017, 0.309017), 
311                         (-0.238856, -0.864188, 0.442863), 
312                         (-0.262866, -0.951056, 0.162460), 
313                         (-0.864188, -0.442863, 0.238856), 
314                         (-0.809017, -0.309017, 0.500000), 
315                         (-0.688191, -0.587785, 0.425325), 
316                         (-0.681718, -0.147621, 0.716567), 
317                         (-0.442863, -0.238856, 0.864188), 
318                         (-0.587785, -0.425325, 0.688191), 
319                         (-0.309017, -0.500000, 0.809017), 
320                         (-0.147621, -0.716567, 0.681718), 
321                         (-0.425325, -0.688191, 0.587785), 
322                         (-0.162460, -0.262866, 0.951056), 
323                         (0.442863, -0.238856, 0.864188), 
324                         (0.162460, -0.262866, 0.951056), 
325                         (0.309017, -0.500000, 0.809017), 
326                         (0.147621, -0.716567, 0.681718), 
327                         (0.000000, -0.525731, 0.850651), 
328                         (0.425325, -0.688191, 0.587785), 
329                         (0.587785, -0.425325, 0.688191), 
330                         (0.688191, -0.587785, 0.425325), 
331                         (-0.955423, 0.295242, 0.000000), 
332                         (-0.951056, 0.162460, 0.262866), 
333                         (-1.000000, 0.000000, 0.000000), 
334                         (-0.850651, 0.000000, 0.525731), 
335                         (-0.955423, -0.295242, 0.000000), 
336                         (-0.951056, -0.162460, 0.262866), 
337                         (-0.864188, 0.442863, -0.238856), 
338                         (-0.951056, 0.162460, -0.262866), 
339                         (-0.809017, 0.309017, -0.500000), 
340                         (-0.864188, -0.442863, -0.238856), 
341                         (-0.951056, -0.162460, -0.262866), 
342                         (-0.809017, -0.309017, -0.500000), 
343                         (-0.681718, 0.147621, -0.716567), 
344                         (-0.681718, -0.147621, -0.716567), 
345                         (-0.850651, 0.000000, -0.525731), 
346                         (-0.688191, 0.587785, -0.425325), 
347                         (-0.587785, 0.425325, -0.688191), 
348                         (-0.425325, 0.688191, -0.587785), 
349                         (-0.425325, -0.688191, -0.587785), 
350                         (-0.587785, -0.425325, -0.688191), 
351                         (-0.688191, -0.587785, -0.425325))
352
353
354 ######################################################
355 # MD2 data structures
356 ######################################################
357 class md2_point:
358         vertices=[]
359         lightnormalindex=0
360         binary_format="<3BB"
361         def __init__(self):
362                 self.vertices=[0]*3
363                 self.lightnormalindex=0
364         def save(self, file):
365                 temp_data=[0]*4
366                 temp_data[0]=self.vertices[0]
367                 temp_data[1]=self.vertices[1]
368                 temp_data[2]=self.vertices[2]
369                 temp_data[3]=self.lightnormalindex
370                 data=struct.pack(self.binary_format, temp_data[0], temp_data[1], temp_data[2], temp_data[3])
371                 file.write(data)
372         def dump(self):
373                 print "MD2 Point Structure"
374                 print "vertex X: ", self.vertices[0]
375                 print "vertex Y: ", self.vertices[1]
376                 print "vertex Z: ", self.vertices[2]
377                 print "lightnormalindex: ",self.lightnormalindex
378                 print ""
379                 
380 class md2_face:
381         vertex_index=[]
382         texture_index=[]
383         binary_format="<3h3h"
384         def __init__(self):
385                 self.vertex_index = [ 0, 0, 0 ]
386                 self.texture_index = [ 0, 0, 0]
387         def save(self, file):
388                 temp_data=[0]*6
389                 #swap vertices around so they draw right
390                 temp_data[0]=self.vertex_index[0]
391                 temp_data[1]=self.vertex_index[2]
392                 temp_data[2]=self.vertex_index[1]
393                 #swap texture vertices around so they draw right
394                 temp_data[3]=self.texture_index[0]
395                 temp_data[4]=self.texture_index[2]
396                 temp_data[5]=self.texture_index[1]
397                 data=struct.pack(self.binary_format,temp_data[0],temp_data[1],temp_data[2],temp_data[3],temp_data[4],temp_data[5])
398                 file.write(data)
399         def dump (self):
400                 print "MD2 Face Structure"
401                 print "vertex 1 index: ", self.vertex_index[0]
402                 print "vertex 2 index: ", self.vertex_index[1]
403                 print "vertex 3 index: ", self.vertex_index[2]
404                 print "texture 1 index: ", self.texture_index[0]
405                 print "texture 2 index: ", self.texture_index[1]
406                 print "texture 3 index: ", self.texture_index[2]
407                 print ""
408                 
409 class md2_tex_coord:
410         u=0
411         v=0
412         binary_format="<2h"
413         def __init__(self):
414                 self.u=0
415                 self.v=0
416         def save(self, file):
417                 temp_data=[0]*2
418                 temp_data[0]=self.u
419                 temp_data[1]=self.v
420                 data=struct.pack(self.binary_format, temp_data[0], temp_data[1])
421                 file.write(data)
422         def dump (self):
423                 print "MD2 Texture Coordinate Structure"
424                 print "texture coordinate u: ",self.u
425                 print "texture coordinate v: ",self.v
426                 print ""
427                 
428 class md2_GL_command:
429         s=0.0
430         t=0.0
431         vert_index=0
432         binary_format="<2fi"
433         
434         def __init__(self):
435                 self.s=0.0
436                 self.t=0.0
437                 vert_index=0
438         def save(self,file):
439                 temp_data=[0]*3
440                 temp_data[0]=float(self.s)
441                 temp_data[1]=float(self.t)
442                 temp_data[2]=self.vert_index
443                 data=struct.pack(self.binary_format, temp_data[0],temp_data[1],temp_data[2])
444                 file.write(data)
445         def dump (self):
446                 print "MD2 OpenGL Command"
447                 print "s: ", self.s
448                 print "t: ", self.t
449                 print "Vertex Index: ", self.vert_index
450                 print ""
451
452 class md2_GL_cmd_list:
453         num=0
454         cmd_list=[]
455         binary_format="<i"
456         
457         def __init__(self):
458                 self.num=0
459                 self.cmd_list=[]
460         
461         def save(self,file):
462                 data=struct.pack(self.binary_format, self.num)
463                 file.write(data)
464                 for cmd in self.cmd_list:
465                         cmd.save(file)
466         def dump(self):
467                 print "MD2 OpenGL Command List"
468                 print "number: ", self.num
469                 for cmd in self.cmd_list:
470                         cmd.dump()
471                 print ""
472
473 class md2_skin:
474         name=""
475         binary_format="<64s"
476         def __init__(self):
477                 self.name=""
478         def save(self, file):
479                 temp_data=self.name
480                 data=struct.pack(self.binary_format, temp_data)
481                 file.write(data)
482         def dump (self):
483                 print "MD2 Skin"
484                 print "skin name: ",self.name
485                 print ""
486                 
487 class md2_frame:
488         scale=[]
489         translate=[]
490         name=[]
491         vertices=[]
492         binary_format="<3f3f16s"
493
494         def __init__(self):
495                 self.scale=[0.0]*3
496                 self.translate=[0.0]*3
497                 self.name=""
498                 self.vertices=[]
499         def save(self, file):
500                 temp_data=[0]*7
501                 temp_data[0]=float(self.scale[0])
502                 temp_data[1]=float(self.scale[1])
503                 temp_data[2]=float(self.scale[2])
504                 temp_data[3]=float(self.translate[0])
505                 temp_data[4]=float(self.translate[1])
506                 temp_data[5]=float(self.translate[2])
507                 temp_data[6]=self.name
508                 data=struct.pack(self.binary_format, temp_data[0],temp_data[1],temp_data[2],temp_data[3],temp_data[4],temp_data[5],temp_data[6])
509                 file.write(data)
510         def dump (self):
511                 print "MD2 Frame"
512                 print "scale x: ",self.scale[0]
513                 print "scale y: ",self.scale[1]
514                 print "scale z: ",self.scale[2]
515                 print "translate x: ",self.translate[0]
516                 print "translate y: ",self.translate[1]
517                 print "translate z: ",self.translate[2]
518                 print "name: ",self.name
519                 print ""
520                 
521 class md2_obj:
522         #Header Structure
523         ident=0                         #int 0  This is used to identify the file
524         version=0                       #int 1  The version number of the file (Must be 8)
525         skin_width=0            #int 2  The skin width in pixels
526         skin_height=0           #int 3  The skin height in pixels
527         frame_size=0            #int 4  The size in bytes the frames are
528         num_skins=0                     #int 5  The number of skins associated with the model
529         num_vertices=0          #int 6  The number of vertices (constant for each frame)
530         num_tex_coords=0        #int 7  The number of texture coordinates
531         num_faces=0                     #int 8  The number of faces (polygons)
532         num_GL_commands=0       #int 9  The number of gl commands
533         num_frames=0            #int 10 The number of animation frames
534         offset_skins=0          #int 11 The offset in the file for the skin data
535         offset_tex_coords=0     #int 12 The offset in the file for the texture data
536         offset_faces=0          #int 13 The offset in the file for the face data
537         offset_frames=0         #int 14 The offset in the file for the frames data
538         offset_GL_commands=0#int 15     The offset in the file for the gl commands data
539         offset_end=0            #int 16 The end of the file offset
540         binary_format="<17i"  #little-endian (<), 17 integers (17i)
541         #md2 data objects
542         tex_coords=[]
543         faces=[]
544         frames=[]
545         skins=[]
546         GL_commands=[]
547         
548         def __init__ (self):
549                 self.tex_coords=[]
550                 self.faces=[]
551                 self.frames=[]
552                 self.skins=[]
553         def save(self, file):
554                 temp_data=[0]*17
555                 temp_data[0]=self.ident
556                 temp_data[1]=self.version
557                 temp_data[2]=self.skin_width
558                 temp_data[3]=self.skin_height
559                 temp_data[4]=self.frame_size
560                 temp_data[5]=self.num_skins
561                 temp_data[6]=self.num_vertices
562                 temp_data[7]=self.num_tex_coords
563                 temp_data[8]=self.num_faces
564                 temp_data[9]=self.num_GL_commands
565                 temp_data[10]=self.num_frames
566                 temp_data[11]=self.offset_skins
567                 temp_data[12]=self.offset_tex_coords
568                 temp_data[13]=self.offset_faces
569                 temp_data[14]=self.offset_frames
570                 temp_data[15]=self.offset_GL_commands
571                 temp_data[16]=self.offset_end
572                 data=struct.pack(self.binary_format, temp_data[0],temp_data[1],temp_data[2],temp_data[3],temp_data[4],temp_data[5],temp_data[6],temp_data[7],temp_data[8],temp_data[9],temp_data[10],temp_data[11],temp_data[12],temp_data[13],temp_data[14],temp_data[15],temp_data[16])
573                 file.write(data)
574                 #write the skin data
575                 for skin in self.skins:
576                         skin.save(file)
577                 #save the texture coordinates
578                 for tex_coord in self.tex_coords:
579                         tex_coord.save(file)
580                 #save the face info
581                 for face in self.faces:
582                         face.save(file)
583                 #save the frames
584                 for frame in self.frames:
585                         frame.save(file)
586                         for vert in frame.vertices:
587                                 vert.save(file)
588                 #save the GL command List
589                 for cmd in self.GL_commands:
590                         cmd.save(file)
591         def dump (self):
592                 print "Header Information"
593                 print "ident: ", self.ident
594                 print "version: ", self.version
595                 print "skin width: ", self.skin_width
596                 print "skin height: ", self.skin_height
597                 print "frame size: ", self.frame_size
598                 print "number of skins: ", self.num_skins
599                 print "number of texture coordinates: ", self.num_tex_coords
600                 print "number of faces: ", self.num_faces
601                 print "number of frames: ", self.num_frames
602                 print "number of vertices: ", self.num_vertices
603                 print "number of GL commands: ",self.num_GL_commands
604                 print "offset skins: ", self.offset_skins
605                 print "offset texture coordinates: ", self.offset_tex_coords
606                 print "offset faces: ", self.offset_faces
607                 print "offset frames: ",self.offset_frames
608                 print "offset GL Commands: ",self.offset_GL_commands
609                 print "offset end: ",self.offset_end
610                 print ""
611
612 ######################################################
613 # Validation
614 ######################################################
615 def validation(object):
616         global user_frame_list
617
618         #move the object to the origin if it's not already there
619         if object.getLocation('worldspace')!=(0.0, 0.0, 0.0):
620                 print "Model not centered at origin"
621                 result=Blender.Draw.PupMenu("Model not centered at origin%t|Center (will not work with animations!)|Do not center")
622                 if result==1:
623                         object.setLocation(0.0,0.0,0.0)
624
625         #resize the object in case it is not the right size
626         if object.getSize('worldspace')!=(1.0,1.0,1.0):
627                 print "Object is scaled-You should scale the mesh verts, not the object"
628                 result=Blender.Draw.PupMenu("Object is scaled-You should scale the mesh verts, not the object%t|Fix scale (will not work with animations!)|Do not scale")
629                 if result==1:
630                         object.setSize(1.0,1.0,1.0)
631                 
632         if object.getEuler('worldspace')!=Blender.Mathutils.Euler(0.0,0.0,0.0):
633                 print "object.rot: ", object.getEuler('worldspace')
634                 print "Object is rotated-You should rotate the mesh verts, not the object"
635                 result=Blender.Draw.PupMenu("Object is rotated-You should rotate the mesh verts, not the object%t|Fix rotation (will not work with animations!)|Do not rotate")
636                 if result==1:
637                         object.setEuler([0.0,0.0,0.0])
638         
639         #get access to the mesh data
640         mesh=object.getData(False, True) #get the object (not just name) and the Mesh, not NMesh
641
642         #check it's composed of only tri's      
643         result=0
644         for face in mesh.faces:
645                 if len(face.verts)!=3:
646                         #select the face for future triangulation
647                         face.sel=1
648                         if result==0:  #first time we have this problem, don't pop-up a window every time it finds a quad
649                           print "Model not made entirely of triangles"
650                           result=Blender.Draw.PupMenu("Model not made entirely out of Triangles-Convert?%t|YES|Quit")
651         
652         #triangulate or quit
653         if result==1:
654                 #selecting face mode
655                 Blender.Mesh.Mode(3)
656                 editmode = Window.EditMode()    # are we in edit mode?  If so ...
657                 if editmode: Window.EditMode(0) # leave edit mode before getting the mesh
658                 mesh.quadToTriangle(0) #use closest verticies in breaking a quad
659         elif result==2:
660                 return False #user will fix (I guess)
661
662         #check it has UV coordinates
663         if mesh.vertexUV==True:
664                 print "Vertex UV not supported"
665                 result=Blender.Draw.PupMenu("Vertex UV not suppored-Use Sticky UV%t|Quit")
666                 return False
667                         
668         elif mesh.faceUV==True:
669                 for face in mesh.faces:
670                         if(len(face.uv)==3):
671                                 pass
672                         else:
673                                 print "Model's vertices do not all have UV"
674                                 result=Blender.Draw.PupMenu("Model's vertices do not all have UV%t|Quit")
675                                 return False
676         
677         else:
678                 print "Model does not have UV (face or vertex)"
679                 result=Blender.Draw.PupMenu("Model does not have UV (face or vertex)%t|Output (0,0) as UV coordinates and do not generate GL commands|Quit")
680                 if result==2:
681                         return False
682
683         #check it has an associated texture map
684         last_face=""
685         if mesh.faceUV:
686                 last_face=mesh.faces[0].image
687                 #check if each face uses the same texture map (only one allowed)
688                 for face in mesh.faces:
689                         mesh_image=face.image
690                         if not mesh_image:
691                                 print "Model has a face without a texture Map"
692                                 result=Blender.Draw.PupMenu("Model has a face without a texture Map%t|This should never happen!")
693                                 #return False
694                         if mesh_image!=last_face:
695                                 print "Model has more than 1 texture map assigned"
696                                 result=Blender.Draw.PupMenu("Model has more than 1 texture map assigned%t|Quit")
697                                 #return False
698                 if mesh_image:
699                         size=mesh_image.getSize()
700                         #is this really what the user wants
701                         if (size[0]!=256 or size[1]!=256):
702                                 print "Texture map size is non-standard (not 256x256), it is: ",size[0],"x",size[1]
703                                 result=Blender.Draw.PupMenu("Texture map size is non-standard (not 256x256), it is: "+str(size[0])+"x"+str(size[1])+": Continue?%t|YES|NO")
704                                 if(result==2):
705                                         return False
706
707
708         #verify frame list data
709         user_frame_list=get_frame_list()        
710         temp=user_frame_list[len(user_frame_list)-1]
711         temp_num_frames=temp[2]
712         
713         #verify tri/vert/frame counts are within MD2 standard
714         face_count=len(mesh.faces)
715         vert_count=len(mesh.verts)      
716         frame_count=temp_num_frames
717         
718         if face_count>MD2_MAX_TRIANGLES:
719                 print "Number of triangles exceeds MD2 standard: ", face_count,">",MD2_MAX_TRIANGLES
720                 result=Blender.Draw.PupMenu("Number of triangles exceeds MD2 standard: Continue?%t|YES|NO")
721                 if(result==2):
722                         return False
723         if vert_count>MD2_MAX_VERTICES:
724                 print "Number of verticies exceeds MD2 standard",vert_count,">",MD2_MAX_VERTICES
725                 result=Blender.Draw.PupMenu("Number of verticies exceeds MD2 standard: Continue?%t|YES|NO")
726                 if(result==2):
727                         return False
728         if frame_count>MD2_MAX_FRAMES:
729                 print "Number of frames exceeds MD2 standard of",frame_count,">",MD2_MAX_FRAMES
730                 result=Blender.Draw.PupMenu("Number of frames exceeds MD2 standard: Continue?%t|YES|NO")
731                 if(result==2):
732                         return False
733         #model is OK
734         return True
735
736 ######################################################
737 # Fill MD2 data structure
738 ######################################################
739 def fill_md2(md2, object):
740         #global defines
741         global user_frame_list
742         global g_texture_path
743         
744         Blender.Window.DrawProgressBar(0.25,"Filling MD2 Data")
745         
746         #get a Mesh, not NMesh
747         mesh=object.getData(False, True)        
748         #don't forget to copy the data! -- Boris van Schooten
749         mesh=mesh.__copy__();
750         #load up some intermediate data structures
751         tex_list={}
752         tex_count=0
753         #create the vertex list from the first frame
754         Blender.Set("curframe", 1)
755         
756         #header information
757         md2.ident=844121161
758         md2.version=8   
759         md2.num_vertices=len(mesh.verts)
760         md2.num_faces=len(mesh.faces)
761
762         #get the skin information
763         #use the first faces' image for the texture information
764         if mesh.faceUV:
765                 mesh_image=mesh.faces[0].image
766                 size=mesh_image.getSize()
767                 md2.skin_width=size[0]
768                 md2.skin_height=size[1]
769                 md2.num_skins=1
770                 #add a skin node to the md2 data structure
771                 md2.skins.append(md2_skin())
772                 md2.skins[0].name=g_texture_path.val+Blender.sys.basename(mesh_image.getFilename())
773                 if len(md2.skins[0].name)>64:
774                         print "Texture Path and name is more than 64 characters"
775                         result=Blender.Draw.PupMenu("Texture path and name is more than 64 characters-Quitting")
776                         return False
777
778         #put texture information in the md2 structure
779         #build UV coord dictionary (prevents double entries-saves space)
780         for face in mesh.faces:
781                 for i in xrange(0,3):
782                         if mesh.faceUV:
783                                 t=(face.uv[i])
784                         else:
785                                 t=(0,0)
786                         tex_key=(t[0],t[1])
787                         if not tex_list.has_key(tex_key):
788                                 tex_list[tex_key]=tex_count
789                                 tex_count+=1
790         md2.num_tex_coords=tex_count #each vert has its own UV coord
791
792         for this_tex in xrange (0, md2.num_tex_coords):
793                 md2.tex_coords.append(md2_tex_coord())
794         for coord, index in tex_list.iteritems():
795                 #md2.tex_coords.append(md2_tex_coord())
796                 md2.tex_coords[index].u=int(coord[0]*md2.skin_width)
797                 md2.tex_coords[index].v=int((1-coord[1])*md2.skin_height)
798
799         #put faces in the md2 structure
800         #for each face in the model
801         for this_face in xrange(0, md2.num_faces):
802                 md2.faces.append(md2_face())
803                 for i in xrange(0,3):
804                         #blender uses indexed vertexes so this works very well
805                         md2.faces[this_face].vertex_index[i]=mesh.faces[this_face].verts[i].index
806                         #lookup texture index in dictionary
807                         if mesh.faceUV:
808                                 uv_coord=(mesh.faces[this_face].uv[i])
809                         else:
810                                 uv_coord=(0,0)
811                         tex_key=(uv_coord[0],uv_coord[1])
812                         tex_index=tex_list[tex_key]
813                         md2.faces[this_face].texture_index[i]=tex_index
814         
815         Blender.Window.DrawProgressBar(0.5, "Computing GL Commands")
816
817         #compute GL commands
818         md2.num_GL_commands=build_GL_commands(md2, mesh)
819
820         #get the frame data
821         #calculate 1 frame size  + (1 vert size*num_verts)
822         md2.frame_size=40+(md2.num_vertices*4) #in bytes
823         
824         #get the frame list
825         user_frame_list=get_frame_list()
826         if user_frame_list=="default":
827                 md2.num_frames=198
828         else:
829                 temp=user_frame_list[len(user_frame_list)-1]  #last item
830                 md2.num_frames=temp[2] #last frame number
831         
832
833         progress=0.5
834         progressIncrement=0.25/md2.num_frames
835
836         #fill in each frame with frame info and all the vertex data for that frame
837         for frame_counter in xrange(0,md2.num_frames):
838                 
839                 progress+=progressIncrement
840                 Blender.Window.DrawProgressBar(progress, "Calculating Frame: "+str(frame_counter))
841                         
842                 #add a frame
843                 md2.frames.append(md2_frame())
844                 #update the mesh objects vertex positions for the animation
845                 Blender.Set("curframe", frame_counter)  #set blender to the correct frame
846                 mesh.getFromObject(object.name)  #update the mesh to make verts current
847                 
848 #each frame has a scale and transform value that gets the vertex value between 0-255
849 #since the scale and transform are the same for the all the verts in the frame, we only need
850 #to figure this out once per frame
851                 
852                 #we need to start with the bounding box
853                 #bounding_box=object.getBoundBox() #uses the object, not the mesh data
854                 #initialize with the first vertex for both min and max.  X and Y are swapped for MD2 format
855         
856                 #initialize 
857                 frame_min_x=100000.0
858                 frame_max_x=-100000.0
859                 frame_min_y=100000.0
860                 frame_max_y=-100000.0
861                 frame_min_z=100000.0
862                 frame_max_z=-100000.0
863         
864                 for face in mesh.faces:
865                         for vert in face.verts:                                 
866                                 if frame_min_x>vert.co[1]: frame_min_x=vert.co[1]
867                                 if frame_max_x<vert.co[1]: frame_max_x=vert.co[1]
868                                 if frame_min_y>vert.co[0]: frame_min_y=vert.co[0]
869                                 if frame_max_y<vert.co[0]: frame_max_y=vert.co[0]
870                                 if frame_min_z>vert.co[2]: frame_min_z=vert.co[2]
871                                 if frame_max_z<vert.co[2]: frame_max_z=vert.co[2]
872                 
873                 #the scale is the difference between the min and max (on that axis) / 255
874                 frame_scale_x=(frame_max_x-frame_min_x)/255
875                 frame_scale_y=(frame_max_y-frame_min_y)/255
876                 frame_scale_z=(frame_max_z-frame_min_z)/255
877                 
878                 if frame_scale_x == 0: frame_scale_x = 1.0
879                 if frame_scale_y == 0: frame_scale_y = 1.0
880                 if frame_scale_z == 0: frame_scale_z = 1.0
881                 
882                 #translate value of the mesh to center it on the origin
883                 frame_trans_x=frame_min_x
884                 frame_trans_y=frame_min_y
885                 frame_trans_z=frame_min_z
886                 
887                 #fill in the data
888                 md2.frames[frame_counter].scale=(-frame_scale_x, frame_scale_y, frame_scale_z)
889                 md2.frames[frame_counter].translate=(-frame_trans_x, frame_trans_y, frame_trans_z)
890                 
891                 #now for the vertices
892                 for vert_counter in xrange(0, md2.num_vertices):
893                         #add a vertex to the md2 structure
894                         md2.frames[frame_counter].vertices.append(md2_point())
895                         #figure out the new coords based on scale and transform
896                         #then translates the point so it's not less than 0
897                         #then scale it so it's between 0..255
898                         #print "frame scale : ", frame_scale_x, " ", frame_scale_y, " ", frame_scale_z
899                         new_x=int((mesh.verts[vert_counter].co[1]-frame_trans_x)/frame_scale_x)
900                         new_y=int((mesh.verts[vert_counter].co[0]-frame_trans_y)/frame_scale_y)
901                         new_z=int((mesh.verts[vert_counter].co[2]-frame_trans_z)/frame_scale_z)
902                         #put them in the structure
903                         md2.frames[frame_counter].vertices[vert_counter].vertices=(new_x, new_y, new_z)
904
905                         #need to add the lookup table check here
906                         maxdot = -999999.0;
907                         maxdotindex = -1;
908
909                         
910                         #swap y and x for difference in axis orientation 
911                         x1=-mesh.verts[vert_counter].no[1]
912                         y1=mesh.verts[vert_counter].no[0]
913                         z1=mesh.verts[vert_counter].no[2]
914                         for j in xrange(0,162):
915                                 #dot = (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
916                                 dot = (x1*MD2_NORMALS[j][0]+
917                                        y1*MD2_NORMALS[j][1]+
918                                                          z1*MD2_NORMALS[j][2]);
919                                 if (dot > maxdot):
920                                         maxdot = dot;
921                                         maxdotindex = j;
922                         
923                         md2.frames[frame_counter].vertices[vert_counter].lightnormalindex=maxdotindex+2
924                         
925                         del maxdot, maxdotindex
926                         del new_x, new_y, new_z
927                 del frame_max_x, frame_max_y, frame_max_z, frame_min_x, frame_min_y, frame_min_z
928                 del frame_scale_x, frame_scale_y, frame_scale_z, frame_trans_x, frame_trans_y, frame_trans_z                    
929                         
930                         
931         #output all the frame names-user_frame_list is loaded during the validation
932         for frame_set in user_frame_list:
933                 for counter in xrange(frame_set[1]-1, frame_set[2]):
934                         md2.frames[counter].name=frame_set[0]+"_"+str(counter-frame_set[1]+2)
935
936         #compute these after everthing is loaded into a md2 structure
937         header_size=17*4 #17 integers, and each integer is 4 bytes
938         skin_size=64*md2.num_skins #64 char per skin * number of skins
939         tex_coord_size=4*md2.num_tex_coords #2 short * number of texture coords
940         face_size=12*md2.num_faces #3 shorts for vertex index, 3 shorts for tex index
941         frames_size=(((12+12+16)+(4*md2.num_vertices)) * md2.num_frames) #frame info+verts per frame*num frames
942         GL_command_size=md2.num_GL_commands*4 #each is an int or float, so 4 bytes per
943         
944         #fill in the info about offsets
945         md2.offset_skins=0+header_size
946         md2.offset_tex_coords=md2.offset_skins+skin_size
947         md2.offset_faces=md2.offset_tex_coords+tex_coord_size
948         md2.offset_frames=md2.offset_faces+face_size
949         md2.offset_GL_commands=md2.offset_frames+frames_size
950         md2.offset_end=md2.offset_GL_commands+GL_command_size
951
952 ######################################################
953 # Get Frame List
954 ######################################################
955 def get_frame_list():
956         global g_frame_filename
957         frame_list=[]
958
959         if g_frame_filename.val=="default":
960                 return MD2_FRAME_NAME_LIST
961
962         else:
963         #check for file
964                 if (Blender.sys.exists(g_frame_filename.val)==1):
965                         #open file and read it in
966                         file=open(g_frame_filename.val,"r")
967                         lines=file.readlines()
968                         file.close()
969
970                         #check header (first line)
971                         if lines[0].strip() != "# MD2 Frame Name List":
972                                 print "its not a valid file"
973                                 result=Blender.Draw.PupMenu("This is not a valid frame definition file-using default%t|OK")
974                                 return MD2_FRAME_NAME_LIST
975                         else:
976                                 #read in the data
977                                 num_frames=0
978                                 for counter in xrange(1, len(lines)):
979                                         current_line=lines[counter].strip()
980                                         if current_line[0]=="#":
981                                                 #found a comment
982                                                 pass
983                                         else:
984                                                 data=current_line.split()
985                                                 frame_list.append([data[0],num_frames+1, num_frames+int(data[1])])
986                                                 num_frames+=int(data[1])
987                                 return frame_list
988                 else:
989                         print "Cannot find file"
990                         result=Blender.Draw.PupMenu("Cannot find frame definion file-using default%t|OK")
991                         return MD2_FRAME_NAME_LIST
992
993 ######################################################
994 # Globals for GL command list calculations
995 ######################################################
996 used_tris=[]
997 edge_dict={}
998 strip_verts=[]
999 strip_st=[]
1000 strip_tris=[]
1001 strip_first_run=True
1002 odd=False
1003
1004 ######################################################
1005 # Find Strip length function
1006 ######################################################
1007 def find_strip_length(mesh, start_tri, edge_key):
1008         #print "Finding strip length"
1009         
1010         global used_tris
1011         global edge_dict
1012         global strip_tris
1013         global strip_st
1014         global strip_verts
1015         global strip_first_run
1016         global odd
1017         
1018         used_tris[start_tri]=2
1019         
1020         strip_tris.append(start_tri) #add this tri to the potential list of tri-strip                                           
1021         
1022         #print "I am face: ", start_tri
1023         #print "Using edge Key: ", edge_key
1024         
1025         faces=edge_dict[edge_key] #get list of face indexes that share this edge
1026         if (len(faces)==0):
1027                 #print "Cant find edge with key: ", edge_key
1028                 pass
1029                 
1030         #print "Faces sharing this edge: ", faces
1031         for face_index in faces:
1032                 face=mesh.faces[face_index]
1033                 if face_index==start_tri: #don't want to check myself
1034                         #print "I found myself, continuing"
1035                         pass
1036                 else:
1037                         if used_tris[face_index]!=0: #found a used tri-move along
1038                                 #print "Found a used tri: ", face_index
1039                                 pass
1040                         else:
1041                                 #find non-shared vert
1042                                 for vert_counter in xrange(0,3):
1043                                         if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]):
1044                                                 next_vert=vert_counter
1045                                                 
1046                                                 if(odd==False):
1047                                                         #print "Found a suitable even connecting tri: ", face_index                     
1048                                                         used_tris[face_index]=2 #mark as dirty for this rum
1049                                                         odd=True
1050                                                                                 
1051                                                         #find the new edge
1052                                                         if(face.verts[next_vert].index < face.verts[(next_vert+2)%3].index):
1053                                                                 temp_key=(face.verts[next_vert].index,face.verts[(next_vert+2)%3].index)
1054                                                         else:
1055                                                                 temp_key=(face.verts[(next_vert+2)%3].index, face.verts[next_vert].index)
1056                                                         
1057                                                         #print "temp key: ", temp_key
1058                                                         temp_faces=edge_dict[temp_key]
1059                                                         
1060                                                         if(len(temp_faces)==0):
1061                                                                 print "Can't find any other faces with key: ", temp_key
1062                                                         else:
1063                                                                 #search the new edge    
1064                                                                 #print "found other faces, searching them"      
1065                                                                 find_strip_length(mesh, face_index, temp_key) #recursive greedy-takes first tri it finds as best 
1066                                                                 break;
1067                                                 else:
1068                                                         #print "Found a suitable odd connecting tri: ", face_index                      
1069                                                         used_tris[face_index]=2 #mark as dirty for this rum
1070                                                         odd=False
1071                                                                 
1072                                                         #find the new edge
1073                                                         if(face.verts[next_vert].index < face.verts[(next_vert+1)%3].index):
1074                                                                 temp_key=(face.verts[next_vert].index,face.verts[(next_vert+1)%3].index)
1075                                                         else:
1076                                                                 temp_key=(face.verts[(next_vert+1)%3].index, face.verts[next_vert].index)
1077                                                         #print "temp key: ", temp_key
1078                                                         temp_faces=edge_dict[temp_key]
1079                                                         if(len(temp_faces)==0):
1080                                                                 print "Can't find any other faces with key: ", temp_key
1081                                                         else:
1082                                                                 #search the new edge    
1083                                                                 #print "found other faces, searching them"      
1084                                                                 find_strip_length(mesh, face_index, temp_key) #recursive greedy-takes first tri it finds as best 
1085                                                                 break;
1086
1087         return len(strip_tris)
1088
1089
1090 ######################################################
1091 # Tri-Stripify function
1092 ######################################################
1093 def stripify_tri_list(mesh, edge_key):
1094         global edge_dict
1095         global strip_tris
1096         global strip_st
1097         global strip_verts
1098         
1099         shared_edge=[]
1100         key=[]
1101         
1102         #print "*****Stripify the triangle list*******"
1103         #print "strip tris: ", strip_tris
1104         #print "strip_tri length: ", len(strip_tris)
1105                 
1106         for tri_counter in xrange(0, len(strip_tris)):
1107                 face=mesh.faces[strip_tris[tri_counter]]
1108                 if (tri_counter==0): #first one only 
1109                         #find non-edge vert
1110                         for vert_counter in xrange(0,3):
1111                                 if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]):
1112                                         start_vert=vert_counter
1113                         strip_verts.append(face.verts[start_vert].index)
1114                         strip_st.append(face.uv[start_vert])
1115                         
1116                         strip_verts.append(face.verts[(start_vert+2)%3].index)
1117                         strip_st.append(face.uv[(start_vert+2)%3])
1118
1119                         strip_verts.append(face.verts[(start_vert+1)%3].index)
1120                         strip_st.append(face.uv[(start_vert+1)%3])
1121                 else:
1122                         for vert_counter in xrange(0,3):
1123                                 if(face.verts[vert_counter].index!=strip_verts[-1] and face.verts[vert_counter].index!=strip_verts[-2]):
1124                                         strip_verts.append(face.verts[vert_counter].index)
1125                                         strip_st.append(face.uv[vert_counter])
1126                                         break
1127                 
1128         
1129
1130 ######################################################
1131 # Build GL command List
1132 ######################################################
1133 def build_GL_commands(md2, mesh):
1134         # we can't output gl command structure without uv
1135         if not mesh.faceUV:
1136                 print "No UV: not building GL Commands"
1137                 return 0
1138
1139         print "Building GL Commands"
1140
1141         global used_tris
1142         global edge_dict
1143         global strip_verts
1144         global strip_tris
1145         global strip_st
1146         
1147         #globals initialization
1148         used_tris=[0]*len(mesh.faces)
1149         #print "Used: ", used_tris
1150         num_commands=0
1151         
1152         #edge dictionary generation
1153         edge_dict=dict([(ed.key,[]) for ed in mesh.edges])
1154         for face in (mesh.faces):
1155                 for key in face.edge_keys:
1156                         edge_dict[key].append(face.index)
1157         
1158         #print "edge Dict: ", edge_dict
1159
1160         for tri_counter in xrange(0,len(mesh.faces)):
1161                 if used_tris[tri_counter]!=0: 
1162                         #print "Found a used triangle: ", tri_counter
1163                         pass
1164                 else:
1165                         #print "Found an unused triangle: ", tri_counter
1166
1167                         #intialization
1168                         strip_tris=[0]*0
1169                         strip_verts=[0]*0
1170                         strip_st=[0]*0
1171                         strip_first_run=True
1172                         odd=True
1173                         
1174                         #find the strip length
1175                         strip_length=find_strip_length(mesh, tri_counter, mesh.faces[tri_counter].edge_keys[0])
1176
1177                         #mark tris as used
1178                         for used_counter in xrange(0,strip_length):
1179                                 used_tris[strip_tris[used_counter]]=1
1180                                 
1181                         stripify_tri_list(mesh, mesh.faces[tri_counter].edge_keys[0])
1182
1183                         #create command list
1184                         cmd_list=md2_GL_cmd_list()
1185                         #number of commands in this list                        
1186                         print "strip length: ", strip_length
1187                         cmd_list.num=(len(strip_tris)+2) #positive for strips, fans would be negative, but not supported yet
1188                         num_commands+=1
1189                         
1190                         #add s,t,vert for this command list
1191                         for command_counter in xrange(0, len(strip_tris)+2):
1192                                 cmd=md2_GL_command()
1193                                 cmd.s=strip_st[command_counter][0]
1194                                 cmd.t=1.0-strip_st[command_counter][1] #flip upside down
1195                                 cmd.vert_index=strip_verts[command_counter]
1196                                 num_commands+=3
1197                                 cmd_list.cmd_list.append(cmd)
1198                         print "Cmd List length: ", len(cmd_list.cmd_list)
1199                         print "Cmd list num: ", cmd_list.num
1200                         print "Cmd List: ", cmd_list.dump()
1201                         md2.GL_commands.append(cmd_list)                
1202
1203         #add the null command at the end
1204         temp_cmdlist=md2_GL_cmd_list()  
1205         temp_cmdlist.num=0
1206         md2.GL_commands.append(temp_cmdlist)  
1207         num_commands+=1         
1208
1209         #cleanup and return
1210         used=strip_vert=strip_st=strip_tris=0
1211         return num_commands
1212                 
1213
1214
1215
1216 ######################################################
1217 # Save MD2 Format
1218 ######################################################
1219 def save_md2(filename):
1220         print ""
1221         print "***********************************"
1222         print "MD2 Export"
1223         print "***********************************"
1224         print ""
1225         
1226         Blender.Window.DrawProgressBar(0.0,"Begining MD2 Export")
1227         
1228         md2=md2_obj()  #blank md2 object to save
1229
1230         #get the object
1231         mesh_objs = Blender.Object.GetSelected()
1232
1233         #check there is a blender object selected
1234         if len(mesh_objs)==0:
1235                 print "Fatal Error: Must select a mesh to output as MD2"
1236                 print "Found nothing"
1237                 result=Blender.Draw.PupMenu("Must select an object to export%t|OK")
1238                 return
1239
1240         mesh_obj=mesh_objs[0] #this gets the first object (should be only one)
1241
1242         #check if it's a mesh object
1243         if mesh_obj.getType()!="Mesh":
1244                 print "Fatal Error: Must select a mesh to output as MD2"
1245                 print "Found: ", mesh_obj.getType()
1246                 result=Blender.Draw.PupMenu("Selected Object must be a mesh to output as MD2%t|OK")
1247                 return
1248
1249         ok=validation(mesh_obj)
1250         if ok==False:
1251                 return
1252         
1253         fill_md2(md2, mesh_obj)
1254         md2.dump()
1255         
1256         Blender.Window.DrawProgressBar(1.0, "Writing to Disk")
1257         
1258         #actually write it to disk
1259         file=open(filename,"wb")
1260         md2.save(file)
1261         file.close()
1262         
1263         #cleanup
1264         md2=0
1265         
1266         print "Closed the file"
1267