#!BPY """ Name: 'MD2 (.md2)' Blender: 241 Group: 'Export' Tooltip: 'Export to Quake file format (.md2).' """ __author__ = 'Bob Holcomb' __version__ = '0.17.1' __url__ = ["Bob's site, http://bane.servebeer.com", "Support forum, http://scourage.servebeer.com/phpbb/", "blender", "elysiun"] __email__ = ["Bob Holcomb, bob_holcomb:hotmail*com", "scripts"] __bpydoc__ = """\ This script Exports a Quake 2 file (MD2). Additional help from: Shadwolf, Skandal, Rojo, Cambo
Thanks Guys! """ # ***** BEGIN GPL LICENSE BLOCK ***** # # Script copyright (C): Bob Holcomb # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ***** END GPL LICENCE BLOCK ***** # -------------------------------------------------------------------------- import Blender from Blender import * from Blender.Draw import * from Blender.BGL import * from Blender.Window import * import struct, string from types import * ###################################################### # GUI Loader ###################################################### # Export globals g_filename=Create("/home/bob/work/blender_scripts/md2/test-export.md2") g_frame_filename=Create("default") g_filename_search=Create("model") g_frame_search=Create("default") user_frame_list=[] #Globals g_scale=Create(1.0) # Events EVENT_NOEVENT=1 EVENT_SAVE_MD2=2 EVENT_CHOOSE_FILENAME=3 EVENT_CHOOSE_FRAME=4 EVENT_EXIT=100 ###################################################### # Callbacks for Window functions ###################################################### def filename_callback(input_filename): global g_filename g_filename.val=input_filename def frame_callback(input_frame): global g_frame_filename g_frame_filename.val=input_frame def draw_gui(): global g_scale global g_filename global g_frame_filename global EVENT_NOEVENT,EVENT_SAVE_MD2,EVENT_CHOOSE_FILENAME,EVENT_CHOOSE_FRAME,EVENT_EXIT ########## Titles glClear(GL_COLOR_BUFFER_BIT) glRasterPos2d(8, 103) Text("MD2 Export") ######### Parameters GUI Buttons g_filename = String("MD2 file to save: ", EVENT_NOEVENT, 10, 55, 210, 18, g_filename.val, 255, "MD2 file to save") ########## MD2 File Search Button Button("Search",EVENT_CHOOSE_FILENAME,220,55,80,18) g_frame_filename = String("Frame List file to load: ", EVENT_NOEVENT, 10, 35, 210, 18, g_frame_filename.val, 255, "Frame List to load-overrides MD2 defaults") ########## Texture Search Button Button("Search",EVENT_CHOOSE_FRAME,220,35,80,18) ########## Scale slider-default is 1/8 which is a good scale for md2->blender g_scale= Slider("Scale Factor: ", EVENT_NOEVENT, 10, 75, 210, 18, 1.0, 0.001, 10.0, 1, "Scale factor for obj Model"); ######### Draw and Exit Buttons Button("Export",EVENT_SAVE_MD2 , 10, 10, 80, 18) Button("Exit",EVENT_EXIT , 170, 10, 80, 18) def event(evt, val): if (evt == QKEY and not val): Exit() def bevent(evt): global g_filename global g_frame_filename global EVENT_NOEVENT,EVENT_SAVE_MD2,EVENT_EXIT ######### Manages GUI events if (evt==EVENT_EXIT): Blender.Draw.Exit() elif (evt==EVENT_CHOOSE_FILENAME): FileSelector(filename_callback, "MD2 File Selection") elif (evt==EVENT_CHOOSE_FRAME): FileSelector(frame_callback, "Frame Selection") elif (evt==EVENT_SAVE_MD2): if (g_filename.val == "model"): save_md2("blender.md2") Blender.Draw.Exit() return else: save_md2(g_filename.val) Blender.Draw.Exit() return Register(draw_gui, event, bevent) ###################################################### # MD2 Model Constants ###################################################### MD2_MAX_TRIANGLES=4096 MD2_MAX_VERTICES=2048 MD2_MAX_TEXCOORDS=2048 MD2_MAX_FRAMES=512 MD2_MAX_SKINS=32 MD2_MAX_FRAMESIZE=(MD2_MAX_VERTICES * 4 + 128) MD2_FRAME_NAME_LIST=(("stand",1,40), ("run",41,46), ("attack",47,54), ("pain1",55,58), ("pain2",59,62), ("pain3",63,66), ("jump",67,72), ("flip",73,84), ("salute", 85,95), ("taunt",96,112), ("wave",113,123), ("point",124,135), ("crstnd",136,154), ("crwalk",155,160), ("crattack",161,169), ("crpain",170,173), ("crdeath",174,178), ("death1",179,184), ("death2",185,190), ("death3",191,198)) #198 frames MD2_NORMALS=((-0.525731, 0.000000, 0.850651), (-0.442863, 0.238856, 0.864188), (-0.295242, 0.000000, 0.955423), (-0.309017, 0.500000, 0.809017), (-0.162460, 0.262866, 0.951056), (0.000000, 0.000000, 1.000000), (0.000000, 0.850651, 0.525731), (-0.147621, 0.716567, 0.681718), (0.147621, 0.716567, 0.681718), (0.000000, 0.525731, 0.850651), (0.309017, 0.500000, 0.809017), (0.525731, 0.000000, 0.850651), (0.295242, 0.000000, 0.955423), (0.442863, 0.238856, 0.864188), (0.162460, 0.262866, 0.951056), (-0.681718, 0.147621, 0.716567), (-0.809017, 0.309017, 0.500000), (-0.587785, 0.425325, 0.688191), (-0.850651, 0.525731, 0.000000), (-0.864188, 0.442863, 0.238856), (-0.716567, 0.681718, 0.147621), (-0.688191, 0.587785, 0.425325), (-0.500000, 0.809017, 0.309017), (-0.238856, 0.864188, 0.442863), (-0.425325, 0.688191, 0.587785), (-0.716567, 0.681718, -0.147621), (-0.500000, 0.809017, -0.309017), (-0.525731, 0.850651, 0.000000), (0.000000, 0.850651, -0.525731), (-0.238856, 0.864188, -0.442863), (0.000000, 0.955423, -0.295242), (-0.262866, 0.951056, -0.162460), (0.000000, 1.000000, 0.000000), (0.000000, 0.955423, 0.295242), (-0.262866, 0.951056, 0.162460), (0.238856, 0.864188, 0.442863), (0.262866, 0.951056, 0.162460), (0.500000, 0.809017, 0.309017), (0.238856, 0.864188, -0.442863), (0.262866, 0.951056, -0.162460), (0.500000, 0.809017, -0.309017), (0.850651, 0.525731, 0.000000), (0.716567, 0.681718, 0.147621), (0.716567, 0.681718, -0.147621), (0.525731, 0.850651, 0.000000), (0.425325, 0.688191, 0.587785), (0.864188, 0.442863, 0.238856), (0.688191, 0.587785, 0.425325), (0.809017, 0.309017, 0.500000), (0.681718, 0.147621, 0.716567), (0.587785, 0.425325, 0.688191), (0.955423, 0.295242, 0.000000), (1.000000, 0.000000, 0.000000), (0.951056, 0.162460, 0.262866), (0.850651, -0.525731, 0.000000), (0.955423, -0.295242, 0.000000), (0.864188, -0.442863, 0.238856), (0.951056, -0.162460, 0.262866), (0.809017, -0.309017, 0.500000), (0.681718, -0.147621, 0.716567), (0.850651, 0.000000, 0.525731), (0.864188, 0.442863, -0.238856), (0.809017, 0.309017, -0.500000), (0.951056, 0.162460, -0.262866), (0.525731, 0.000000, -0.850651), (0.681718, 0.147621, -0.716567), (0.681718, -0.147621, -0.716567), (0.850651, 0.000000, -0.525731), (0.809017, -0.309017, -0.500000), (0.864188, -0.442863, -0.238856), (0.951056, -0.162460, -0.262866), (0.147621, 0.716567, -0.681718), (0.309017, 0.500000, -0.809017), (0.425325, 0.688191, -0.587785), (0.442863, 0.238856, -0.864188), (0.587785, 0.425325, -0.688191), (0.688191, 0.587785, -0.425325), (-0.147621, 0.716567, -0.681718), (-0.309017, 0.500000, -0.809017), (0.000000, 0.525731, -0.850651), (-0.525731, 0.000000, -0.850651), (-0.442863, 0.238856, -0.864188), (-0.295242, 0.000000, -0.955423), (-0.162460, 0.262866, -0.951056), (0.000000, 0.000000, -1.000000), (0.295242, 0.000000, -0.955423), (0.162460, 0.262866, -0.951056), (-0.442863, -0.238856, -0.864188), (-0.309017, -0.500000, -0.809017), (-0.162460, -0.262866, -0.951056), (0.000000, -0.850651, -0.525731), (-0.147621, -0.716567, -0.681718), (0.147621, -0.716567, -0.681718), (0.000000, -0.525731, -0.850651), (0.309017, -0.500000, -0.809017), (0.442863, -0.238856, -0.864188), (0.162460, -0.262866, -0.951056), (0.238856, -0.864188, -0.442863), (0.500000, -0.809017, -0.309017), (0.425325, -0.688191, -0.587785), (0.716567, -0.681718, -0.147621), (0.688191, -0.587785, -0.425325), (0.587785, -0.425325, -0.688191), (0.000000, -0.955423, -0.295242), (0.000000, -1.000000, 0.000000), (0.262866, -0.951056, -0.162460), (0.000000, -0.850651, 0.525731), (0.000000, -0.955423, 0.295242), (0.238856, -0.864188, 0.442863), (0.262866, -0.951056, 0.162460), (0.500000, -0.809017, 0.309017), (0.716567, -0.681718, 0.147621), (0.525731, -0.850651, 0.000000), (-0.238856, -0.864188, -0.442863), (-0.500000, -0.809017, -0.309017), (-0.262866, -0.951056, -0.162460), (-0.850651, -0.525731, 0.000000), (-0.716567, -0.681718, -0.147621), (-0.716567, -0.681718, 0.147621), (-0.525731, -0.850651, 0.000000), (-0.500000, -0.809017, 0.309017), (-0.238856, -0.864188, 0.442863), (-0.262866, -0.951056, 0.162460), (-0.864188, -0.442863, 0.238856), (-0.809017, -0.309017, 0.500000), (-0.688191, -0.587785, 0.425325), (-0.681718, -0.147621, 0.716567), (-0.442863, -0.238856, 0.864188), (-0.587785, -0.425325, 0.688191), (-0.309017, -0.500000, 0.809017), (-0.147621, -0.716567, 0.681718), (-0.425325, -0.688191, 0.587785), (-0.162460, -0.262866, 0.951056), (0.442863, -0.238856, 0.864188), (0.162460, -0.262866, 0.951056), (0.309017, -0.500000, 0.809017), (0.147621, -0.716567, 0.681718), (0.000000, -0.525731, 0.850651), (0.425325, -0.688191, 0.587785), (0.587785, -0.425325, 0.688191), (0.688191, -0.587785, 0.425325), (-0.955423, 0.295242, 0.000000), (-0.951056, 0.162460, 0.262866), (-1.000000, 0.000000, 0.000000), (-0.850651, 0.000000, 0.525731), (-0.955423, -0.295242, 0.000000), (-0.951056, -0.162460, 0.262866), (-0.864188, 0.442863, -0.238856), (-0.951056, 0.162460, -0.262866), (-0.809017, 0.309017, -0.500000), (-0.864188, -0.442863, -0.238856), (-0.951056, -0.162460, -0.262866), (-0.809017, -0.309017, -0.500000), (-0.681718, 0.147621, -0.716567), (-0.681718, -0.147621, -0.716567), (-0.850651, 0.000000, -0.525731), (-0.688191, 0.587785, -0.425325), (-0.587785, 0.425325, -0.688191), (-0.425325, 0.688191, -0.587785), (-0.425325, -0.688191, -0.587785), (-0.587785, -0.425325, -0.688191), (-0.688191, -0.587785, -0.425325)) ###################################################### # MD2 data structures ###################################################### class md2_point: vertices=[] lightnormalindex=0 binary_format="<3BB" def __init__(self): self.vertices=[0]*3 self.lightnormalindex=0 def save(self, file): temp_data=[0]*4 temp_data[0]=self.vertices[0] temp_data[1]=self.vertices[1] temp_data[2]=self.vertices[2] temp_data[3]=self.lightnormalindex data=struct.pack(self.binary_format, temp_data[0], temp_data[1], temp_data[2], temp_data[3]) file.write(data) def dump(self): print "MD2 Point Structure" print "vertex X: ", self.vertices[0] print "vertex Y: ", self.vertices[1] print "vertex Z: ", self.vertices[2] print "lightnormalindex: ",self.lightnormalindex print "" class md2_face: vertex_index=[] texture_index=[] binary_format="<3h3h" def __init__(self): self.vertex_index = [ 0, 0, 0 ] self.texture_index = [ 0, 0, 0] def save(self, file): temp_data=[0]*6 #swap vertices around so they draw right temp_data[0]=self.vertex_index[0] temp_data[1]=self.vertex_index[2] temp_data[2]=self.vertex_index[1] #swap texture vertices around so they draw right temp_data[3]=self.texture_index[0] temp_data[4]=self.texture_index[2] temp_data[5]=self.texture_index[1] data=struct.pack(self.binary_format,temp_data[0],temp_data[1],temp_data[2],temp_data[3],temp_data[4],temp_data[5]) file.write(data) def dump (self): print "MD2 Face Structure" print "vertex 1 index: ", self.vertex_index[0] print "vertex 2 index: ", self.vertex_index[1] print "vertex 3 index: ", self.vertex_index[2] print "texture 1 index: ", self.texture_index[0] print "texture 2 index: ", self.texture_index[1] print "texture 3 index: ", self.texture_index[2] print "" class md2_tex_coord: u=0 v=0 binary_format="<2h" def __init__(self): self.u=0 self.v=0 def save(self, file): temp_data=[0]*2 temp_data[0]=self.u temp_data[1]=self.v data=struct.pack(self.binary_format, temp_data[0], temp_data[1]) file.write(data) def dump (self): print "MD2 Texture Coordinate Structure" print "texture coordinate u: ",self.u print "texture coordinate v: ",self.v print "" class md2_GL_command: s=0.0 t=0.0 vert_index=0 binary_format="<2fi" def __init__(self): self.s=0.0 self.t=0.0 vert_index=0 def save(self,file): temp_data=[0]*3 temp_data[0]=float(self.s) temp_data[1]=float(self.t) temp_data[2]=self.vert_index data=struct.pack(self.binary_format, temp_data[0],temp_data[1],temp_data[2]) file.write(data) def dump (self): print "MD2 OpenGL Command" print "s: ", self.s print "t: ", self.t print "Vertex Index: ", self.vert_index print "" class md2_GL_cmd_list: num=0 cmd_list=[] binary_format="MD2_MAX_TRIANGLES: print "Number of triangles exceeds MD2 standard: ", face_count,">",MD2_MAX_TRIANGLES result=Blender.Draw.PupMenu("Number of triangles exceeds MD2 standard: Continue?%t|YES|NO") if(result==2): return False if vert_count>MD2_MAX_VERTICES: print "Number of verticies exceeds MD2 standard",vert_count,">",MD2_MAX_VERTICES result=Blender.Draw.PupMenu("Number of verticies exceeds MD2 standard: Continue?%t|YES|NO") if(result==2): return False if frame_count>MD2_MAX_FRAMES: print "Number of frames exceeds MD2 standard of",frame_count,">",MD2_MAX_FRAMES result=Blender.Draw.PupMenu("Number of frames exceeds MD2 standard: Continue?%t|YES|NO") if(result==2): return False #model is OK return True ###################################################### # Fill MD2 data structure ###################################################### def fill_md2(md2, object): global user_frame_list #get a Mesh, not NMesh mesh=object.getData(False, True) #load up some intermediate data structures tex_list={} tex_count=0 #create the vertex list from the first frame Blender.Set("curframe", 1) #header information md2.ident=844121161 md2.version=8 md2.num_vertices=len(mesh.verts) md2.num_faces=len(mesh.faces) #get the skin information #use the first faces' image for the texture information mesh_image=mesh.faces[0].image size=mesh_image.getSize() md2.skin_width=size[0] md2.skin_height=size[1] md2.num_skins=1 #add a skin node to the md2 data structure md2.skins.append(md2_skin()) md2.skins[0].name=Blender.sys.basename(mesh_image.getFilename()) #put texture information in the md2 structure #build UV coord dictionary (prevents double entries-saves space) for face in mesh.faces: for i in range(0,3): t=(face.uv[i]) tex_key=(t[0],t[1]) if not tex_list.has_key(tex_key): tex_list[tex_key]=tex_count tex_count+=1 md2.num_tex_coords=tex_count #each vert has its own UV coord for this_tex in range (0, md2.num_tex_coords): md2.tex_coords.append(md2_tex_coord()) for coord, index in tex_list.iteritems(): #md2.tex_coords.append(md2_tex_coord()) md2.tex_coords[index].u=int(coord[0]*md2.skin_width) md2.tex_coords[index].v=int((1-coord[1])*md2.skin_height) #put faces in the md2 structure #for each face in the model for this_face in range(0, md2.num_faces): md2.faces.append(md2_face()) for i in range(0,3): #blender uses indexed vertexes so this works very well md2.faces[this_face].vertex_index[i]=mesh.faces[this_face].verts[i].index #lookup texture index in dictionary uv_coord=(mesh.faces[this_face].uv[i]) tex_key=(uv_coord[0],uv_coord[1]) tex_index=tex_list[tex_key] md2.faces[this_face].texture_index[i]=tex_index #compute GL commands md2.num_GL_commands=build_GL_commands(md2) #get the frame data #calculate 1 frame size + (1 vert size*num_verts) md2.frame_size=40+(md2.num_vertices*4) #in bytes #get the frame list user_frame_list=get_frame_list() if user_frame_list=="default": md2.num_frames=198 else: temp=user_frame_list[len(user_frame_list)-1] #last item md2.num_frames=temp[2] #last frame number #fill in each frame with frame info and all the vertex data for that frame for frame_counter in range(0,md2.num_frames): #add a frame md2.frames.append(md2_frame()) #update the mesh objects vertex positions for the animation Blender.Set("curframe", frame_counter) #set blender to the correct frame mesh.getFromObject(object.name) #update the mesh to make verts current #each frame has a scale and transform value that gets the vertex value between 0-255 #since the scale and transform are the same for the all the verts in the frame, we only need #to figure this out once per frame #we need to start with the bounding box bounding_box=object.getBoundBox() #uses the object, not the mesh data #initialize with the first vertex for both min and max. X and Y are swapped for MD2 format point=bounding_box[0] frame_min_x=point[1] frame_max_x=point[1] frame_min_y=point[0] frame_max_y=point[0] frame_min_z=point[2] frame_max_z=point[2] #find min/max values for point in bounding_box: if frame_min_x>point[1]: frame_min_x=point[1] if frame_max_xpoint[0]: frame_min_y=point[0] if frame_max_ypoint[2]: frame_min_z=point[2] if frame_max_z maxdot): maxdot = dot; maxdotindex = j; md2.frames[frame_counter].vertices[vert_counter].lightnormalindex=maxdotindex #output all the frame names-user_frame_list is loaded during the validation for frame_set in user_frame_list: for counter in range(frame_set[1]-1, frame_set[2]): md2.frames[counter].name=frame_set[0]+"_"+str(counter-frame_set[1]+2) #compute these after everthing is loaded into a md2 structure header_size=17*4 #17 integers, and each integer is 4 bytes skin_size=64*md2.num_skins #64 char per skin * number of skins tex_coord_size=4*md2.num_tex_coords #2 short * number of texture coords face_size=12*md2.num_faces #3 shorts for vertex index, 3 shorts for tex index frames_size=(((12+12+16)+(4*md2.num_vertices)) * md2.num_frames) #frame info+verts per frame*num frames GL_command_size=md2.num_GL_commands*4 #each is an int or float, so 4 bytes per #fill in the info about offsets md2.offset_skins=0+header_size md2.offset_tex_coords=md2.offset_skins+skin_size md2.offset_faces=md2.offset_tex_coords+tex_coord_size md2.offset_frames=md2.offset_faces+face_size md2.offset_GL_commands=md2.offset_frames+frames_size md2.offset_end=md2.offset_GL_commands+GL_command_size ###################################################### # Get Frame List ###################################################### def get_frame_list(): global g_frame_filename frame_list=[] if g_frame_filename.val=="default": return MD2_FRAME_NAME_LIST else: #check for file if (Blender.sys.exists(g_frame_filename.val)==1): #open file and read it in file=open(g_frame_filename.val,"r") lines=file.readlines() file.close() #check header (first line) if lines[0]<>"# MD2 Frame Name List\n": print "its not a valid file" result=Blender.Draw.PupMenu("This is not a valid frame definition file-using default%t|OK") return MD2_FRAME_NAME_LIST else: #read in the data num_frames=0 for counter in range(1, len(lines)): current_line=lines[counter] if current_line[0]=="#": #found a comment pass else: data=current_line.split() frame_list.append([data[0],num_frames+1, num_frames+int(data[1])]) num_frames+=int(data[1]) return frame_list else: print "Cannot find file" result=Blender.Draw.PupMenu("Cannot find frame definion file-using default%t|OK") return MD2_FRAME_NAME_LIST ###################################################### # Tri-Strip/Tri-Fan functions ###################################################### def find_strip_length(md2, start_tri, start_vert): #variables shared between fan and strip functions global used global strip_vert global strip_st global strip_tris global strip_count m1=m2=0 st1=st2=0 used[start_tri]=2 last=start_tri strip_vert[0]=md2.faces[last].vertex_index[start_vert%3] strip_vert[1]=md2.faces[last].vertex_index[(start_vert+1)%3] strip_vert[2]=md2.faces[last].vertex_index[(start_vert+2)%3] strip_st[0]=md2.faces[last].texture_index[start_vert%3] strip_st[1]=md2.faces[last].texture_index[(start_vert+1)%3] strip_st[2]=md2.faces[last].texture_index[(start_vert+2)%3] strip_tris[0]=start_tri strip_count=1 m1=md2.faces[last].vertex_index[(start_vert+2)%3] st1=md2.faces[last].texture_index[(start_vert+2)%3] m2=md2.faces[last].vertex_index[(start_vert+1)%3] st2=md2.faces[last].texture_index[(start_vert+1)%3] #look for matching triangle check=start_tri+1 for tri_counter in range(start_tri+1, md2.num_faces): for k in range(0,3): if md2.faces[check].vertex_index[k]!=m1: continue if md2.faces[check].texture_index[k]!=st1: continue if md2.faces[check].vertex_index[(k+1)%3]!=m2: continue if md2.faces[check].texture_index[(k+1)%3]!=st2: continue #if we can't use this triangle, this tri_strip is done if (used[tri_counter]!=0): for clear_counter in range(start_tri+1, md2.num_faces): if used[clear_counter]==2: used[clear_counter]=0 return strip_count #new edge if (strip_count & 1): m2=md2.faces[check].vertex_index[(k+2)%3] st2=md2.faces[check].texture_index[(k+2)%3] else: m1=md2.faces[check].vertex_index[(k+2)%3] st1=md2.faces[check].texture_index[(k+2)%3] strip_vert[strip_count+2]=md2.faces[tri_counter].vertex_index[(k+2)%3] strip_st[strip_count+2]=md2.faces[tri_counter].texture_index[(k+2)%3] strip_tris[strip_count]=tri_counter strip_count+=1 used[tri_counter]=2 check+=1 return strip_count def find_fan_length(md2, start_tri, start_vert): #variables shared between fan and strip functions global used global strip_vert global strip_st global strip_tris global strip_count m1=m2=0 st1=st2=0 used[start_tri]=2 last=start_tri strip_vert[0]=md2.faces[last].vertex_index[start_vert%3] strip_vert[1]=md2.faces[last].vertex_index[(start_vert+1)%3] strip_vert[2]=md2.faces[last].vertex_index[(start_vert+2)%3] strip_st[0]=md2.faces[last].texture_index[start_vert%3] strip_st[1]=md2.faces[last].texture_index[(start_vert+1)%3] strip_st[2]=md2.faces[last].texture_index[(start_vert+2)%3] strip_tris[0]=start_tri strip_count=1 m1=md2.faces[last].vertex_index[(start_vert+0)%3] st1=md2.faces[last].texture_index[(start_vert+0)%3] m2=md2.faces[last].vertex_index[(start_vert+2)%3] st2=md2.faces[last].texture_index[(start_vert+2)%3] #look for matching triangle check=start_tri+1 for tri_counter in range(start_tri+1, md2.num_faces): for k in range(0,3): if md2.faces[check].vertex_index[k]!=m1: continue if md2.faces[check].texture_index[k]!=st1: continue if md2.faces[check].vertex_index[(k+1)%3]!=m2: continue if md2.faces[check].texture_index[(k+1)%3]!=st2: continue #if we can't use this triangle, this tri_strip is done if (used[tri_counter]!=0): for clear_counter in range(start_tri+1, md2.num_faces): if used[clear_counter]==2: used[clear_counter]=0 return strip_count #new edge m2=md2.faces[check].vertex_index[(k+2)%3] st2=md2.faces[check].texture_index[(k+2)%3] strip_vert[strip_count+2]=m2 strip_st[strip_count+2]=st2 strip_tris[strip_count]=tri_counter strip_count+=1 used[tri_counter]=2 check+=1 return strip_count ###################################################### # Globals for GL command list calculations ###################################################### used=[] strip_vert=0 strip_st=0 strip_tris=0 strip_count=0 ###################################################### # Build GL command List ###################################################### def build_GL_commands(md2): #variables shared between fan and strip functions global used used=[0]*md2.num_faces global strip_vert strip_vert=[0]*128 global strip_st strip_st=[0]*128 global strip_tris strip_tris=[0]*128 global strip_count strip_count=0 #variables num_commands=0 start_vert=0 fan_length=strip_length=0 length=best_length=0 best_type=0 best_vert=[0]*1024 best_st=[0]*1024 best_tris=[0]*1024 s=0.0 t=0.0 for face_counter in range(0,md2.num_faces): if used[face_counter]!=0: #don't evaluate a tri that's been used #print "found a used triangle: ", face_counter pass else: best_length=0 #restart the counter #for each vertex index in this face for start_vert in range(0,3): fan_length=find_fan_length(md2, face_counter, start_vert) if (fan_length>best_length): best_type=1 best_length=fan_length for index in range (0, best_length+2): best_st[index]=strip_st[index] best_vert[index]=strip_vert[index] for index in range(0, best_length): best_tris[index]=strip_tris[index] strip_length=find_strip_length(md2, face_counter, start_vert) if (strip_length>best_length): best_type=0 best_length=strip_length for index in range (0, best_length+2): best_st[index]=strip_st[index] best_vert[index]=strip_vert[index] for index in range(0, best_length): best_tris[index]=strip_tris[index] #mark the tris on the best strip/fan as used for used_counter in range (0, best_length): used[best_tris[used_counter]]=1 temp_cmdlist=md2_GL_cmd_list() #push the number of commands into the command stream if best_type==1: temp_cmdlist.num=best_length+2 num_commands+=1 else: temp_cmdlist.num=(-(best_length+2)) num_commands+=1 for command_counter in range (0, best_length+2): #emit a vertex into the reorder buffer cmd=md2_GL_command() index=best_st[command_counter] #calc and put S/T coords in the structure s=md2.tex_coords[index].u t=md2.tex_coords[index].v s=(s+0.5)/md2.skin_width t=(t+0.5)/md2.skin_height cmd.s=s cmd.t=t cmd.vert_index=best_vert[command_counter] temp_cmdlist.cmd_list.append(cmd) num_commands+=3 md2.GL_commands.append(temp_cmdlist) #end of list temp_cmdlist=md2_GL_cmd_list() temp_cmdlist.num=0 md2.GL_commands.append(temp_cmdlist) num_commands+=1 #cleanup and return used=best_vert=best_st=best_tris=strip_vert=strip_st=strip_tris=0 return num_commands ###################################################### # Save MD2 Format ###################################################### def save_md2(filename): md2=md2_obj() #blank md2 object to save #get the object mesh_objs = Blender.Object.GetSelected() #check there is a blender object selected if len(mesh_objs)==0: print "Fatal Error: Must select a mesh to output as MD2" print "Found nothing" result=Blender.Draw.PupMenu("Must select an object to export%t|OK") return mesh_obj=mesh_objs[0] #this gets the first object (should be only one) #check if it's a mesh object if mesh_obj.getType()!="Mesh": print "Fatal Error: Must select a mesh to output as MD2" print "Found: ", mesh_obj.getType() result=Blender.Draw.PupMenu("Selected Object must be a mesh to output as MD2%t|OK") return ok=validation(mesh_obj) if ok==False: return fill_md2(md2, mesh_obj) md2.dump() #actually write it to disk file=open(filename,"wb") md2.save(file) file.close() #cleanup md2=0 print "Closed the file"