2.5: Top Menu
[blender.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", "blenderartists.org"]
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
616 def validation(object):
617         global user_frame_list
618         
619         #get access to the mesh data
620         mesh=object.getData(False, True) #get the object (not just name) and the Mesh, not NMesh
621
622         #check it's composed of only tri's      
623         result=0
624         for face in mesh.faces:
625                 if len(face.verts)!=3:
626                         #select the face for future triangulation
627                         face.sel=1
628                         if result==0:  #first time we have this problem, don't pop-up a window every time it finds a quad
629                           print "Model not made entirely of triangles"
630                           result=Blender.Draw.PupMenu("Model not made entirely out of Triangles-Convert?%t|YES|Quit")
631         
632         #triangulate or quit
633         if result==1:
634                 #selecting face mode
635                 Blender.Mesh.Mode(3)
636                 editmode = Window.EditMode()    # are we in edit mode?  If so ...
637                 if editmode: Window.EditMode(0) # leave edit mode before getting the mesh
638                 mesh.quadToTriangle(0) #use closest verticies in breaking a quad
639         elif result==2:
640                 return False #user will fix (I guess)
641
642         #check it has UV coordinates
643         if mesh.vertexUV==True:
644                 print "Vertex UV not supported"
645                 result=Blender.Draw.PupMenu("Vertex UV not suppored-Use Sticky UV%t|Quit")
646                 return False
647                         
648         elif mesh.faceUV==True:
649                 for face in mesh.faces:
650                         if(len(face.uv)==3):
651                                 pass
652                         else:
653                                 print "Model's vertices do not all have UV"
654                                 result=Blender.Draw.PupMenu("Model's vertices do not all have UV%t|Quit")
655                                 return False
656         
657         else:
658                 print "Model does not have UV (face or vertex)"
659                 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")
660                 if result==2:
661                         return False
662
663         #check it has an associated texture map
664         last_face=""
665         if mesh.faceUV:
666                 last_face=mesh.faces[0].image
667                 #check if each face uses the same texture map (only one allowed)
668                 for face in mesh.faces:
669                         mesh_image=face.image
670                         if not mesh_image:
671                                 print "Model has a face without a texture Map"
672                                 result=Blender.Draw.PupMenu("Model has a face without a texture Map%t|This should never happen!")
673                                 #return False
674                         if mesh_image!=last_face:
675                                 print "Model has more than 1 texture map assigned"
676                                 result=Blender.Draw.PupMenu("Model has more than 1 texture map assigned%t|Quit")
677                                 #return False
678                 if mesh_image:
679                         try:            size=mesh_image.getSize()
680                         except: size= 256,256 # No image data
681                         #is this really what the user wants
682                         if (size[0]!=256 or size[1]!=256):
683                                 print "Texture map size is non-standard (not 256x256), it is: ",size[0],"x",size[1]
684                                 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")
685                                 if(result==2):
686                                         return False
687
688
689         #verify frame list data
690         user_frame_list=get_frame_list()        
691         temp=user_frame_list[len(user_frame_list)-1]
692         temp_num_frames=temp[2]
693         
694         #verify tri/vert/frame counts are within MD2 standard
695         face_count=len(mesh.faces)
696         vert_count=len(mesh.verts)      
697         frame_count=temp_num_frames
698         
699         if face_count>MD2_MAX_TRIANGLES:
700                 print "Number of triangles exceeds MD2 standard: ", face_count,">",MD2_MAX_TRIANGLES
701                 result=Blender.Draw.PupMenu("Number of triangles exceeds MD2 standard: Continue?%t|YES|NO")
702                 if(result==2):
703                         return False
704         if vert_count>MD2_MAX_VERTICES:
705                 print "Number of verticies exceeds MD2 standard",vert_count,">",MD2_MAX_VERTICES
706                 result=Blender.Draw.PupMenu("Number of verticies exceeds MD2 standard: Continue?%t|YES|NO")
707                 if(result==2):
708                         return False
709         if frame_count>MD2_MAX_FRAMES:
710                 print "Number of frames exceeds MD2 standard of",frame_count,">",MD2_MAX_FRAMES
711                 result=Blender.Draw.PupMenu("Number of frames exceeds MD2 standard: Continue?%t|YES|NO")
712                 if(result==2):
713                         return False
714         #model is OK
715         return True
716
717 ######################################################
718 # Fill MD2 data structure
719 ######################################################
720 def fill_md2(md2, object):
721         #global defines
722         global user_frame_list
723         global g_texture_path
724         
725         Blender.Window.DrawProgressBar(0.25,"Filling MD2 Data")
726         
727         #get a Mesh, not NMesh
728         mesh=object.getData(False, True)        
729         #don't forget to copy the data! -- Boris van Schooten
730         mesh=mesh.__copy__();
731         #load up some intermediate data structures
732         tex_list={}
733         tex_count=0
734         #create the vertex list from the first frame
735         Blender.Set("curframe", 1)
736         
737         has_uvs = mesh.faceUV
738         
739         #header information
740         md2.ident=844121161
741         md2.version=8   
742         md2.num_vertices=len(mesh.verts)
743         md2.num_faces=len(mesh.faces)
744
745         #get the skin information
746         #use the first faces' image for the texture information
747         if has_uvs:
748                 mesh_image=mesh.faces[0].image
749                 try:            size=mesh_image.getSize()
750                 except: size= 256,256
751                 
752                 md2.skin_width=size[0]
753                 md2.skin_height=size[1]
754                 md2.num_skins=1
755                 #add a skin node to the md2 data structure
756                 md2.skins.append(md2_skin())
757                 md2.skins[0].name=g_texture_path.val+Blender.sys.basename(mesh_image.getFilename())
758                 if len(md2.skins[0].name)>64:
759                         print "Texture Path and name is more than 64 characters"
760                         result=Blender.Draw.PupMenu("Texture path and name is more than 64 characters-Quitting")
761                         return False
762
763         #put texture information in the md2 structure
764         #build UV coord dictionary (prevents double entries-saves space)
765         if not has_uvs:
766                 t=(0,0)
767         
768         for face in mesh.faces:
769                 for i in xrange(0,3):
770                         if has_uvs:
771                                 t=(face.uv[i])
772                                 
773                         tex_key=(t[0],t[1])
774                         if not tex_list.has_key(tex_key):
775                                 tex_list[tex_key]=tex_count
776                                 tex_count+=1
777         md2.num_tex_coords=tex_count #each vert has its own UV coord
778
779         for this_tex in xrange (0, md2.num_tex_coords):
780                 md2.tex_coords.append(md2_tex_coord())
781         for coord, index in tex_list.iteritems():
782                 #md2.tex_coords.append(md2_tex_coord())
783                 md2.tex_coords[index].u=int(coord[0]*md2.skin_width)
784                 md2.tex_coords[index].v=int((1-coord[1])*md2.skin_height)
785
786         #put faces in the md2 structure
787         #for each face in the model
788         
789         if not has_uvs:
790                 uv_coords=[(0,0)]*3
791         
792         for this_face in xrange(0, md2.num_faces):
793                 md2.faces.append(md2_face())
794                 mf = mesh.faces[this_face]
795                 mf_v = mf.v
796                 if has_uvs:
797                         uv_coords = mf.uv
798                 
799                 for i in xrange(0,3):
800                         #blender uses indexed vertexes so this works very well
801                         md2.faces[this_face].vertex_index[i] = mf_v[i].index
802                         #lookup texture index in dictionary
803                         if has_uvs:
804                                 uv_coord = uv_coords[i]
805                         # otherwise we set it before
806                                 
807                         tex_key=(uv_coord[0],uv_coord[1])
808                         tex_index=tex_list[tex_key]
809                         md2.faces[this_face].texture_index[i]=tex_index
810         
811         Blender.Window.DrawProgressBar(0.5, "Computing GL Commands")
812
813         #compute GL commands
814         md2.num_GL_commands=build_GL_commands(md2, mesh)
815
816         #get the frame data
817         #calculate 1 frame size  + (1 vert size*num_verts)
818         md2.frame_size=40+(md2.num_vertices*4) #in bytes
819         
820         #get the frame list
821         user_frame_list=get_frame_list()
822         if user_frame_list=="default":
823                 md2.num_frames=198
824         else:
825                 temp=user_frame_list[len(user_frame_list)-1]  #last item
826                 md2.num_frames=temp[2] #last frame number
827         
828
829         progress=0.5
830         progressIncrement=0.25/md2.num_frames
831
832         #fill in each frame with frame info and all the vertex data for that frame
833         for frame_counter in xrange(0,md2.num_frames):
834                 
835                 progress+=progressIncrement
836                 Blender.Window.DrawProgressBar(progress, "Calculating Frame: %d of %d" % (frame_counter, md2.num_frames))
837                         
838                 #add a frame
839                 md2.frames.append(md2_frame())
840                 #update the mesh objects vertex positions for the animation
841                 Blender.Set("curframe", frame_counter)  #set blender to the correct frame
842                 
843                 
844                 
845                 
846                 mesh.getFromObject(object)  #update the mesh to make verts current
847                 mesh.transform(object.matrixWorld)
848                 
849 #each frame has a scale and transform value that gets the vertex value between 0-255
850 #since the scale and transform are the same for the all the verts in the frame, we only need
851 #to figure this out once per frame
852                 
853                 #we need to start with the bounding box
854                 #bounding_box=object.getBoundBox() #uses the object, not the mesh data
855                 #initialize with the first vertex for both min and max.  X and Y are swapped for MD2 format
856         
857                 #initialize 
858                 frame_min_x=100000.0
859                 frame_max_x=-100000.0
860                 frame_min_y=100000.0
861                 frame_max_y=-100000.0
862                 frame_min_z=100000.0
863                 frame_max_z=-100000.0
864         
865                 for face in mesh.faces:
866                         for vert in face:
867                                 co = vert.co
868                                 if frame_min_x>co[1]: frame_min_x=co[1]
869                                 if frame_max_x<co[1]: frame_max_x=co[1]
870                                 if frame_min_y>co[0]: frame_min_y=co[0]
871                                 if frame_max_y<co[0]: frame_max_y=co[0]
872                                 if frame_min_z>co[2]: frame_min_z=co[2]
873                                 if frame_max_z<co[2]: frame_max_z=co[2]
874                 
875                 #the scale is the difference between the min and max (on that axis) / 255
876                 frame_scale_x=(frame_max_x-frame_min_x)/255
877                 frame_scale_y=(frame_max_y-frame_min_y)/255
878                 frame_scale_z=(frame_max_z-frame_min_z)/255
879                 
880                 if frame_scale_x == 0: frame_scale_x = 1.0
881                 if frame_scale_y == 0: frame_scale_y = 1.0
882                 if frame_scale_z == 0: frame_scale_z = 1.0
883                 
884                 #translate value of the mesh to center it on the origin
885                 frame_trans_x=frame_min_x
886                 frame_trans_y=frame_min_y
887                 frame_trans_z=frame_min_z
888                 
889                 #fill in the data
890                 md2.frames[frame_counter].scale=(-frame_scale_x, frame_scale_y, frame_scale_z)
891                 md2.frames[frame_counter].translate=(-frame_trans_x, frame_trans_y, frame_trans_z)
892                 
893                 #now for the vertices
894                 for vert_counter in xrange(0, md2.num_vertices):
895                         #add a vertex to the md2 structure
896                         md2.frames[frame_counter].vertices.append(md2_point())
897                         #figure out the new coords based on scale and transform
898                         #then translates the point so it's not less than 0
899                         #then scale it so it's between 0..255
900                         #print "frame scale : ", frame_scale_x, " ", frame_scale_y, " ", frame_scale_z
901                         co = mesh.verts[vert_counter].co
902                         new_x=int((co[1]-frame_trans_x)/frame_scale_x)
903                         new_y=int((co[0]-frame_trans_y)/frame_scale_y)
904                         new_z=int((co[2]-frame_trans_z)/frame_scale_z)
905                         #put them in the structure
906                         md2.frames[frame_counter].vertices[vert_counter].vertices=(new_x, new_y, new_z)
907
908                         #need to add the lookup table check here
909                         maxdot = -999999.0;
910                         maxdotindex = -1;
911
912                         
913                         #swap y and x for difference in axis orientation 
914                         no = mesh.verts[vert_counter].no
915                         x1=     -no[1]
916                         y1=      no[0]
917                         z1=      no[2]
918                         
919                         for j in xrange(0,162):
920                                 #dot = (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
921                                 dot = (x1*MD2_NORMALS[j][0] + y1*MD2_NORMALS[j][1]+ z1*MD2_NORMALS[j][2]);
922                                 if (dot > maxdot):
923                                         maxdot = dot;
924                                         maxdotindex = j;
925                         
926                         md2.frames[frame_counter].vertices[vert_counter].lightnormalindex=maxdotindex+2
927                         
928                         del maxdot, maxdotindex
929                         del new_x, new_y, new_z
930                 del frame_max_x, frame_max_y, frame_max_z, frame_min_x, frame_min_y, frame_min_z
931                 del frame_scale_x, frame_scale_y, frame_scale_z, frame_trans_x, frame_trans_y, frame_trans_z                    
932                         
933                         
934         #output all the frame names-user_frame_list is loaded during the validation
935         for frame_set in user_frame_list:
936                 for counter in xrange(frame_set[1]-1, frame_set[2]):
937                         md2.frames[counter].name=frame_set[0]+"_"+str(counter-frame_set[1]+2)
938
939         #compute these after everthing is loaded into a md2 structure
940         header_size=17*4 #17 integers, and each integer is 4 bytes
941         skin_size=64*md2.num_skins #64 char per skin * number of skins
942         tex_coord_size=4*md2.num_tex_coords #2 short * number of texture coords
943         face_size=12*md2.num_faces #3 shorts for vertex index, 3 shorts for tex index
944         frames_size=(((12+12+16)+(4*md2.num_vertices)) * md2.num_frames) #frame info+verts per frame*num frames
945         GL_command_size=md2.num_GL_commands*4 #each is an int or float, so 4 bytes per
946         
947         #fill in the info about offsets
948         md2.offset_skins=0+header_size
949         md2.offset_tex_coords=md2.offset_skins+skin_size
950         md2.offset_faces=md2.offset_tex_coords+tex_coord_size
951         md2.offset_frames=md2.offset_faces+face_size
952         md2.offset_GL_commands=md2.offset_frames+frames_size
953         md2.offset_end=md2.offset_GL_commands+GL_command_size
954
955 ######################################################
956 # Get Frame List
957 ######################################################
958 def get_frame_list():
959         global g_frame_filename
960         frame_list=[]
961
962         if g_frame_filename.val=="default":
963                 return MD2_FRAME_NAME_LIST
964
965         else:
966         #check for file
967                 if (Blender.sys.exists(g_frame_filename.val)==1):
968                         #open file and read it in
969                         file=open(g_frame_filename.val,"r")
970                         lines=file.readlines()
971                         file.close()
972
973                         #check header (first line)
974                         if lines[0].strip() != "# MD2 Frame Name List":
975                                 print "its not a valid file"
976                                 result=Blender.Draw.PupMenu("This is not a valid frame definition file-using default%t|OK")
977                                 return MD2_FRAME_NAME_LIST
978                         else:
979                                 #read in the data
980                                 num_frames=0
981                                 for counter in xrange(1, len(lines)):
982                                         current_line=lines[counter].strip()
983                                         if current_line[0]=="#":
984                                                 #found a comment
985                                                 pass
986                                         else:
987                                                 data=current_line.split()
988                                                 frame_list.append([data[0],num_frames+1, num_frames+int(data[1])])
989                                                 num_frames+=int(data[1])
990                                 return frame_list
991                 else:
992                         print "Cannot find file"
993                         result=Blender.Draw.PupMenu("Cannot find frame definion file-using default%t|OK")
994                         return MD2_FRAME_NAME_LIST
995
996 ######################################################
997 # Globals for GL command list calculations
998 ######################################################
999 used_tris=[]
1000 edge_dict={}
1001 strip_verts=[]
1002 strip_st=[]
1003 strip_tris=[]
1004 strip_first_run=True
1005 odd=False
1006
1007 ######################################################
1008 # Find Strip length function
1009 ######################################################
1010 def find_strip_length(mesh, start_tri, edge_key):
1011         #print "Finding strip length"
1012         
1013         global used_tris
1014         global edge_dict
1015         global strip_tris
1016         global strip_st
1017         global strip_verts
1018         global strip_first_run
1019         global odd
1020         
1021         used_tris[start_tri]=2
1022         
1023         strip_tris.append(start_tri) #add this tri to the potential list of tri-strip                                           
1024         
1025         #print "I am face: ", start_tri
1026         #print "Using edge Key: ", edge_key
1027         
1028         faces=edge_dict[edge_key] #get list of face indexes that share this edge
1029         if (len(faces)==0):
1030                 #print "Cant find edge with key: ", edge_key
1031                 pass
1032                 
1033         #print "Faces sharing this edge: ", faces
1034         for face_index in faces:
1035                 face=mesh.faces[face_index]
1036                 if face_index==start_tri: #don't want to check myself
1037                         #print "I found myself, continuing"
1038                         pass
1039                 else:
1040                         if used_tris[face_index]!=0: #found a used tri-move along
1041                                 #print "Found a used tri: ", face_index
1042                                 pass
1043                         else:
1044                                 #find non-shared vert
1045                                 for vert_counter in xrange(0,3):
1046                                         if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]):
1047                                                 next_vert=vert_counter
1048                                                 
1049                                                 if(odd==False):
1050                                                         #print "Found a suitable even connecting tri: ", face_index                     
1051                                                         used_tris[face_index]=2 #mark as dirty for this rum
1052                                                         odd=True
1053                                                                                 
1054                                                         #find the new edge
1055                                                         if(face.verts[next_vert].index < face.verts[(next_vert+2)%3].index):
1056                                                                 temp_key=(face.verts[next_vert].index,face.verts[(next_vert+2)%3].index)
1057                                                         else:
1058                                                                 temp_key=(face.verts[(next_vert+2)%3].index, face.verts[next_vert].index)
1059                                                         
1060                                                         #print "temp key: ", temp_key
1061                                                         temp_faces=edge_dict[temp_key]
1062                                                         
1063                                                         if(len(temp_faces)==0):
1064                                                                 print "Can't find any other faces with key: ", temp_key
1065                                                         else:
1066                                                                 #search the new edge    
1067                                                                 #print "found other faces, searching them"      
1068                                                                 find_strip_length(mesh, face_index, temp_key) #recursive greedy-takes first tri it finds as best 
1069                                                                 break;
1070                                                 else:
1071                                                         #print "Found a suitable odd connecting tri: ", face_index                      
1072                                                         used_tris[face_index]=2 #mark as dirty for this rum
1073                                                         odd=False
1074                                                                 
1075                                                         #find the new edge
1076                                                         if(face.verts[next_vert].index < face.verts[(next_vert+1)%3].index):
1077                                                                 temp_key=(face.verts[next_vert].index,face.verts[(next_vert+1)%3].index)
1078                                                         else:
1079                                                                 temp_key=(face.verts[(next_vert+1)%3].index, face.verts[next_vert].index)
1080                                                         #print "temp key: ", temp_key
1081                                                         temp_faces=edge_dict[temp_key]
1082                                                         if(len(temp_faces)==0):
1083                                                                 print "Can't find any other faces with key: ", temp_key
1084                                                         else:
1085                                                                 #search the new edge    
1086                                                                 #print "found other faces, searching them"      
1087                                                                 find_strip_length(mesh, face_index, temp_key) #recursive greedy-takes first tri it finds as best 
1088                                                                 break;
1089
1090         return len(strip_tris)
1091
1092
1093 ######################################################
1094 # Tri-Stripify function
1095 ######################################################
1096 def stripify_tri_list(mesh, edge_key):
1097         global edge_dict
1098         global strip_tris
1099         global strip_st
1100         global strip_verts
1101         
1102         shared_edge=[]
1103         key=[]
1104         
1105         #print "*****Stripify the triangle list*******"
1106         #print "strip tris: ", strip_tris
1107         #print "strip_tri length: ", len(strip_tris)
1108                 
1109         for tri_counter in xrange(0, len(strip_tris)):
1110                 face=mesh.faces[strip_tris[tri_counter]]
1111                 if (tri_counter==0): #first one only 
1112                         #find non-edge vert
1113                         for vert_counter in xrange(0,3):
1114                                 if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]):
1115                                         start_vert=vert_counter
1116                         strip_verts.append(face.verts[start_vert].index)
1117                         strip_st.append(face.uv[start_vert])
1118                         
1119                         strip_verts.append(face.verts[(start_vert+2)%3].index)
1120                         strip_st.append(face.uv[(start_vert+2)%3])
1121
1122                         strip_verts.append(face.verts[(start_vert+1)%3].index)
1123                         strip_st.append(face.uv[(start_vert+1)%3])
1124                 else:
1125                         for vert_counter in xrange(0,3):
1126                                 if(face.verts[vert_counter].index!=strip_verts[-1] and face.verts[vert_counter].index!=strip_verts[-2]):
1127                                         strip_verts.append(face.verts[vert_counter].index)
1128                                         strip_st.append(face.uv[vert_counter])
1129                                         break
1130                 
1131         
1132
1133 ######################################################
1134 # Build GL command List
1135 ######################################################
1136 def build_GL_commands(md2, mesh):
1137         # we can't output gl command structure without uv
1138         if not mesh.faceUV:
1139                 print "No UV: not building GL Commands"
1140                 return 0
1141
1142         print "Building GL Commands"
1143
1144         global used_tris
1145         global edge_dict
1146         global strip_verts
1147         global strip_tris
1148         global strip_st
1149         
1150         #globals initialization
1151         used_tris=[0]*len(mesh.faces)
1152         #print "Used: ", used_tris
1153         num_commands=0
1154         
1155         #edge dictionary generation
1156         edge_dict=dict([(ed.key,[]) for ed in mesh.edges])
1157         for face in (mesh.faces):
1158                 for key in face.edge_keys:
1159                         edge_dict[key].append(face.index)
1160         
1161         #print "edge Dict: ", edge_dict
1162
1163         for tri_counter in xrange(0,len(mesh.faces)):
1164                 if used_tris[tri_counter]!=0: 
1165                         #print "Found a used triangle: ", tri_counter
1166                         pass
1167                 else:
1168                         #print "Found an unused triangle: ", tri_counter
1169
1170                         #intialization
1171                         strip_tris=[0]*0
1172                         strip_verts=[0]*0
1173                         strip_st=[0]*0
1174                         strip_first_run=True
1175                         odd=True
1176                         
1177                         #find the strip length
1178                         strip_length=find_strip_length(mesh, tri_counter, mesh.faces[tri_counter].edge_keys[0])
1179
1180                         #mark tris as used
1181                         for used_counter in xrange(0,strip_length):
1182                                 used_tris[strip_tris[used_counter]]=1
1183                                 
1184                         stripify_tri_list(mesh, mesh.faces[tri_counter].edge_keys[0])
1185
1186                         #create command list
1187                         cmd_list=md2_GL_cmd_list()
1188                         #number of commands in this list                        
1189                         print "strip length: ", strip_length
1190                         cmd_list.num=(len(strip_tris)+2) #positive for strips, fans would be negative, but not supported yet
1191                         num_commands+=1
1192                         
1193                         #add s,t,vert for this command list
1194                         for command_counter in xrange(0, len(strip_tris)+2):
1195                                 cmd=md2_GL_command()
1196                                 cmd.s=strip_st[command_counter][0]
1197                                 cmd.t=1.0-strip_st[command_counter][1] #flip upside down
1198                                 cmd.vert_index=strip_verts[command_counter]
1199                                 num_commands+=3
1200                                 cmd_list.cmd_list.append(cmd)
1201                         print "Cmd List length: ", len(cmd_list.cmd_list)
1202                         print "Cmd list num: ", cmd_list.num
1203                         print "Cmd List: ", cmd_list.dump()
1204                         md2.GL_commands.append(cmd_list)                
1205
1206         #add the null command at the end
1207         temp_cmdlist=md2_GL_cmd_list()  
1208         temp_cmdlist.num=0
1209         md2.GL_commands.append(temp_cmdlist)  
1210         num_commands+=1         
1211
1212         #cleanup and return
1213         used=strip_vert=strip_st=strip_tris=0
1214         return num_commands
1215                 
1216
1217
1218
1219 ######################################################
1220 # Save MD2 Format
1221 ######################################################
1222 def save_md2(filename):
1223         print ""
1224         print "***********************************"
1225         print "MD2 Export"
1226         print "***********************************"
1227         print ""
1228         
1229         Blender.Window.DrawProgressBar(0.0,"Begining MD2 Export")
1230         
1231         md2=md2_obj()  #blank md2 object to save
1232
1233         #get the object
1234         mesh_objs = Blender.Object.GetSelected()
1235
1236         #check there is a blender object selected
1237         if len(mesh_objs)==0:
1238                 print "Fatal Error: Must select a mesh to output as MD2"
1239                 print "Found nothing"
1240                 result=Blender.Draw.PupMenu("Must select an object to export%t|OK")
1241                 return
1242
1243         mesh_obj=mesh_objs[0] #this gets the first object (should be only one)
1244
1245         #check if it's a mesh object
1246         if mesh_obj.getType()!="Mesh":
1247                 print "Fatal Error: Must select a mesh to output as MD2"
1248                 print "Found: ", mesh_obj.getType()
1249                 result=Blender.Draw.PupMenu("Selected Object must be a mesh to output as MD2%t|OK")
1250                 return
1251
1252         ok=validation(mesh_obj)
1253         if ok==False:
1254                 return
1255         
1256         fill_md2(md2, mesh_obj)
1257         md2.dump()
1258         
1259         Blender.Window.DrawProgressBar(1.0, "Writing to Disk")
1260         
1261         #actually write it to disk
1262         file=open(filename,"wb")
1263         md2.save(file)
1264         file.close()
1265         
1266         #cleanup
1267         md2=0
1268         
1269         print "Closed the file"
1270