applied patch from Boris van Schooten, [#8148] Animation bugfix for md2_export script
authorCampbell Barton <ideasman42@gmail.com>
Fri, 18 Apr 2008 23:04:54 +0000 (23:04 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 18 Apr 2008 23:04:54 +0000 (23:04 +0000)
made some other small fixes while testing. (divide by zero errors)

release/scripts/md2_export.py
release/scripts/md2_import.py
source/blender/src/buttons_shading.c

index 71e056a5f539bf98c020fd7331d8a9170e787be5..6fc7c1adfa216f0e3ea98d694271c18147aee81b 100644 (file)
@@ -8,7 +8,7 @@ Tooltip: 'Export to Quake file format (.md2).'
 """
 
 __author__ = 'Bob Holcomb'
-__version__ = '0.18.1'
+__version__ = '0.18.1 patch 1'
 __url__ = ["Bob's site, http://bane.servebeer.com",
      "Support forum, http://bane.servebeer.com", "blender", "elysiun"]
 __email__ = ["Bob Holcomb, bob_holcomb:hotmail*com", "scripts"]
@@ -19,6 +19,12 @@ This script Exports a Quake 2 file (MD2).
  Thanks Guys!
 """
 
+# This is a PATCHED VERSION, fixing the bug due to which animations would
+# (almost) never work.  It is now also possible to output a MD2 model without
+# texture.
+# On: 23 january 2008
+# By: Boris van Schooten (schooten@cs.utwente.nl)
+
 # ***** BEGIN GPL LICENSE BLOCK *****
 #
 # Script copyright (C): Bob Holcomb
@@ -105,13 +111,13 @@ def draw_gui():
        g_filename = String("MD2 file to save: ", EVENT_NOEVENT, 10, 75, 210, 18,
                             g_filename.val, 255, "MD2 file to save")
        ########## MD2 File Search Button
-       Button("Search",EVENT_CHOOSE_FILENAME,220,75,80,18)
+       Button("Browse",EVENT_CHOOSE_FILENAME,220,75,80,18)
 
        ##########  MD2 Frame List Text entry
        g_frame_filename = String("Frame List file to load: ", EVENT_NOEVENT, 10, 55, 210, 18,
                                 g_frame_filename.val, 255, "Frame List to load-overrides MD2 defaults")
        ########## Frame List Search Button
-       Button("Search",EVENT_CHOOSE_FRAME,220,55,80,18)
+       Button("Browse",EVENT_CHOOSE_FRAME,220,55,80,18)
        
        ##########  Texture path to append
        g_texture_path=String("Texture Path: ", EVENT_NOEVENT, 10,35,210,18,
@@ -143,14 +149,9 @@ def bevent(evt):
        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
+               save_md2(g_filename.val)
+               Blender.Draw.Exit()
+               return
 
 Register(draw_gui, event, bevent)
 
@@ -616,21 +617,24 @@ def validation(object):
 
        #move the object to the origin if it's not already there
        if object.getLocation('worldspace')!=(0.0, 0.0, 0.0):
-               object.setLocation(0.0,0.0,0.0)
-               print "Model not centered at origin-Centering"
-               result=Blender.Draw.PupMenu("Model not centered at origin-Centering for you")
+               print "Model not centered at origin"
+               result=Blender.Draw.PupMenu("Model not centered at origin%t|Center (will not work with animations!)|Do not center")
+               if result==1:
+                       object.setLocation(0.0,0.0,0.0)
 
        #resize the object in case it is not the right size
        if object.getSize('worldspace')!=(1.0,1.0,1.0):
-               object.setSize(1.0,1.0,1.0)
                print "Object is scaled-You should scale the mesh verts, not the object"
-               result=Blender.Draw.PupMenu("Object is scaled-You should scale the mesh verts, not the object-fixing for you")
+               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")
+               if result==1:
+                       object.setSize(1.0,1.0,1.0)
                
        if object.getEuler('worldspace')!=Blender.Mathutils.Euler(0.0,0.0,0.0):
                print "object.rot: ", object.getEuler('worldspace')
-               object.setEuler([0.0,0.0,0.0])
                print "Object is rotated-You should rotate the mesh verts, not the object"
-               result=Blender.Draw.PupMenu("Object is rotated-You should rotate the mesh verts, not the object-fixing for you")
+               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")
+               if result==1:
+                       object.setEuler([0.0,0.0,0.0])
        
        #get access to the mesh data
        mesh=object.getData(False, True) #get the object (not just name) and the Mesh, not NMesh
@@ -643,7 +647,7 @@ def validation(object):
                        face.sel=1
                        if result==0:  #first time we have this problem, don't pop-up a window every time it finds a quad
                          print "Model not made entirely of triangles"
-                         result=Blender.Draw.PupMenu("Model not made entirely out of Triangles-Convert?%t|YES|NO")
+                         result=Blender.Draw.PupMenu("Model not made entirely out of Triangles-Convert?%t|YES|Quit")
        
        #triangulate or quit
        if result==1:
@@ -672,36 +676,34 @@ def validation(object):
        
        else:
                print "Model does not have UV (face or vertex)"
-               result=Blender.Draw.PupMenu("Model does not have UV (face or vertex)%t|Quit")
-               return False
+               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")
+               if result==2:
+                       return False
 
        #check it has an associated texture map
        last_face=""
-       last_face=mesh.faces[0].image
-       if last_face=="":
-               print "Model does not have a texture Map"
-               result=Blender.Draw.PupMenu("Model does not have a texture Map%t|Quit")
-               return False
+       if mesh.faceUV:
+               last_face=mesh.faces[0].image
+               #check if each face uses the same texture map (only one allowed)
+               for face in mesh.faces:
+                       mesh_image=face.image
+                       if not mesh_image:
+                               print "Model has a face without a texture Map"
+                               result=Blender.Draw.PupMenu("Model has a face without a texture Map%t|This should never happen!")
+                               #return False
+                       if mesh_image!=last_face:
+                               print "Model has more than 1 texture map assigned"
+                               result=Blender.Draw.PupMenu("Model has more than 1 texture map assigned%t|Quit")
+                               #return False
+               if mesh_image:
+                       size=mesh_image.getSize()
+                       #is this really what the user wants
+                       if (size[0]!=256 or size[1]!=256):
+                               print "Texture map size is non-standard (not 256x256), it is: ",size[0],"x",size[1]
+                               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")
+                               if(result==2):
+                                       return False
 
-       #check if each face uses the same texture map (only one allowed)
-       for face in mesh.faces:
-               mesh_image=face.image
-               if not mesh_image:
-                       print "Model has a face without a texture Map"
-                       result=Blender.Draw.PupMenu("Model has a face without a texture Map%t|Quit")
-                       return False
-               if mesh_image!=last_face:
-                       print "Model has more than 1 texture map assigned"
-                       result=Blender.Draw.PupMenu("Model has more than 1 texture map assigned%t|Quit")
-                       return False
-               
-       size=mesh_image.getSize()
-       #is this really what the user wants
-       if (size[0]!=256 or size[1]!=256):
-               print "Texture map size is non-standard (not 256x256), it is: ",size[0],"x",size[1]
-               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")
-               if(result==2):
-                       return False
 
        #verify frame list data
        user_frame_list=get_frame_list()        
@@ -743,7 +745,8 @@ def fill_md2(md2, object):
        
        #get a Mesh, not NMesh
        mesh=object.getData(False, True)        
-       
+       #don't forget to copy the data! -- Boris van Schooten
+       mesh=mesh.__copy__();
        #load up some intermediate data structures
        tex_list={}
        tex_count=0
@@ -758,31 +761,35 @@ def fill_md2(md2, object):
 
        #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=g_texture_path.val+Blender.sys.basename(mesh_image.getFilename())
-       if len(md2.skins[0].name)>64:
-               print "Texture Path and name is more than 64 characters"
-               result=Blender.Draw.PupMenu("Texture path and name is more than 64 characters-Quitting")
-               return False
+       if mesh.faceUV:
+               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=g_texture_path.val+Blender.sys.basename(mesh_image.getFilename())
+               if len(md2.skins[0].name)>64:
+                       print "Texture Path and name is more than 64 characters"
+                       result=Blender.Draw.PupMenu("Texture path and name is more than 64 characters-Quitting")
+                       return False
 
        #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])
+               for i in xrange(0,3):
+                       if mesh.faceUV:
+                               t=(face.uv[i])
+                       else:
+                               t=(0,0)
                        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):
+       for this_tex in xrange (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())
@@ -791,13 +798,16 @@ def fill_md2(md2, object):
 
        #put faces in the md2 structure
        #for each face in the model
-       for this_face in range(0, md2.num_faces):
+       for this_face in xrange(0, md2.num_faces):
                md2.faces.append(md2_face())
-               for i in range(0,3):
+               for i in xrange(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])
+                       if mesh.faceUV:
+                               uv_coord=(mesh.faces[this_face].uv[i])
+                       else:
+                               uv_coord=(0,0)
                        tex_key=(uv_coord[0],uv_coord[1])
                        tex_index=tex_list[tex_key]
                        md2.faces[this_face].texture_index[i]=tex_index
@@ -824,7 +834,7 @@ def fill_md2(md2, object):
        progressIncrement=0.25/md2.num_frames
 
        #fill in each frame with frame info and all the vertex data for that frame
-       for frame_counter in range(0,md2.num_frames):
+       for frame_counter in xrange(0,md2.num_frames):
                
                progress+=progressIncrement
                Blender.Window.DrawProgressBar(progress, "Calculating Frame: "+str(frame_counter))
@@ -865,6 +875,10 @@ def fill_md2(md2, object):
                frame_scale_y=(frame_max_y-frame_min_y)/255
                frame_scale_z=(frame_max_z-frame_min_z)/255
                
+               if frame_scale_x == 0: frame_scale_x = 1.0
+               if frame_scale_y == 0: frame_scale_y = 1.0
+               if frame_scale_z == 0: frame_scale_z = 1.0
+               
                #translate value of the mesh to center it on the origin
                frame_trans_x=frame_min_x
                frame_trans_y=frame_min_y
@@ -875,7 +889,7 @@ def fill_md2(md2, object):
                md2.frames[frame_counter].translate=(-frame_trans_x, frame_trans_y, frame_trans_z)
                
                #now for the vertices
-               for vert_counter in range(0, md2.num_vertices):
+               for vert_counter in xrange(0, md2.num_vertices):
                        #add a vertex to the md2 structure
                        md2.frames[frame_counter].vertices.append(md2_point())
                        #figure out the new coords based on scale and transform
@@ -893,12 +907,12 @@ def fill_md2(md2, object):
                        maxdotindex = -1;
 
                        
-                       for j in range(0,162):
+                       #swap y and x for difference in axis orientation 
+                       x1=-mesh.verts[vert_counter].no[1]
+                       y1=mesh.verts[vert_counter].no[0]
+                       z1=mesh.verts[vert_counter].no[2]
+                       for j in xrange(0,162):
                                #dot = (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
-                               #swap y and x for difference in axis orientation 
-                               x1=-mesh.verts[vert_counter].no[1]
-                               y1=mesh.verts[vert_counter].no[0]
-                               z1=mesh.verts[vert_counter].no[2]
                                dot = (x1*MD2_NORMALS[j][0]+
                                       y1*MD2_NORMALS[j][1]+
                                                         z1*MD2_NORMALS[j][2]);
@@ -916,7 +930,7 @@ def fill_md2(md2, object):
                        
        #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]):
+               for counter in xrange(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
@@ -954,14 +968,14 @@ def get_frame_list():
                        file.close()
 
                        #check header (first line)
-                       if lines[0].stip()<>"# MD2 Frame Name List":
+                       if lines[0].strip() != "# MD2 Frame Name List":
                                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)):
+                               for counter in xrange(1, len(lines)):
                                        current_line=lines[counter].strip()
                                        if current_line[0]=="#":
                                                #found a comment
@@ -1025,7 +1039,7 @@ def find_strip_length(mesh, start_tri, edge_key):
                                pass
                        else:
                                #find non-shared vert
-                               for vert_counter in range(0,3):
+                               for vert_counter in xrange(0,3):
                                        if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]):
                                                next_vert=vert_counter
                                                
@@ -1089,11 +1103,11 @@ def stripify_tri_list(mesh, edge_key):
        #print "strip tris: ", strip_tris
        #print "strip_tri length: ", len(strip_tris)
                
-       for tri_counter in range(0, len(strip_tris)):
+       for tri_counter in xrange(0, len(strip_tris)):
                face=mesh.faces[strip_tris[tri_counter]]
                if (tri_counter==0): #first one only 
                        #find non-edge vert
-                       for vert_counter in range(0,3):
+                       for vert_counter in xrange(0,3):
                                if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]):
                                        start_vert=vert_counter
                        strip_verts.append(face.verts[start_vert].index)
@@ -1105,7 +1119,7 @@ def stripify_tri_list(mesh, edge_key):
                        strip_verts.append(face.verts[(start_vert+1)%3].index)
                        strip_st.append(face.uv[(start_vert+1)%3])
                else:
-                       for vert_counter in range(0,3):
+                       for vert_counter in xrange(0,3):
                                if(face.verts[vert_counter].index!=strip_verts[-1] and face.verts[vert_counter].index!=strip_verts[-2]):
                                        strip_verts.append(face.verts[vert_counter].index)
                                        strip_st.append(face.uv[vert_counter])
@@ -1117,8 +1131,13 @@ def stripify_tri_list(mesh, edge_key):
 # Build GL command List
 ######################################################
 def build_GL_commands(md2, mesh):
+       # we can't output gl command structure without uv
+       if not mesh.faceUV:
+               print "No UV: not building GL Commands"
+               return 0
+
        print "Building GL Commands"
-       
+
        global used_tris
        global edge_dict
        global strip_verts
@@ -1138,7 +1157,7 @@ def build_GL_commands(md2, mesh):
        
        #print "edge Dict: ", edge_dict
 
-       for tri_counter in range(0,len(mesh.faces)):
+       for tri_counter in xrange(0,len(mesh.faces)):
                if used_tris[tri_counter]!=0: 
                        #print "Found a used triangle: ", tri_counter
                        pass
@@ -1156,7 +1175,7 @@ def build_GL_commands(md2, mesh):
                        strip_length=find_strip_length(mesh, tri_counter, mesh.faces[tri_counter].edge_keys[0])
 
                        #mark tris as used
-                       for used_counter in range(0,strip_length):
+                       for used_counter in xrange(0,strip_length):
                                used_tris[strip_tris[used_counter]]=1
                                
                        stripify_tri_list(mesh, mesh.faces[tri_counter].edge_keys[0])
@@ -1169,7 +1188,7 @@ def build_GL_commands(md2, mesh):
                        num_commands+=1
                        
                        #add s,t,vert for this command list
-                       for command_counter in range(0, len(strip_tris)+2):
+                       for command_counter in xrange(0, len(strip_tris)+2):
                                cmd=md2_GL_command()
                                cmd.s=strip_st[command_counter][0]
                                cmd.t=1.0-strip_st[command_counter][1] #flip upside down
@@ -1245,3 +1264,4 @@ def save_md2(filename):
        md2=0
        
        print "Closed the file"
+
index e39b2ca85ec58069d7e70eb22ffae0c95fe408f9..ec778c1e1b8ec88a34e8051f6e4b238040c32a6e 100644 (file)
@@ -448,6 +448,8 @@ def load_md2(md2_filename, texture_filename):
        
        w = float(md2.skin_width)
        h = float(md2.skin_height)
+       if w <= 0.0: w = 1.0
+       if h <= 0.0: h = 1.0
        #for some reason quake2 texture maps are upside down, flip that
        uv_list = [Vector(co.u/w, 1-(co.v/h)) for co in md2.tex_coords]
        del w, h
index 03b73754f46ab07e6942f842c9511a3413366d6d..4500fc4a08cc612d2d94f931d95835fbe6212f29 100644 (file)
@@ -2337,9 +2337,9 @@ static void world_panel_preview(World *wrld)
 
        uiBlockBeginAlign(block);
        uiDefButBitS(block, TOG, WO_SKYBLEND, B_WORLDPRV,"Blend", 220,175,100,25, &wrld->skytype, 0, 0, 0, 0, "Renders background with natural progression from horizon to zenith");
+       uiDefButBitS(block, TOG,WO_SKYPAPER, B_WORLDPRV,"Paper", 220,150,100,25, &wrld->skytype, 0, 0, 0, 0, "Flattens blend or texture coordinates");
        if (wrld->skytype & WO_SKYBLEND) {
-               uiDefButBitS(block, TOG, WO_SKYREAL, B_WORLDPRV,"Real", 220,150,50,25, &wrld->skytype, 0, 0, 0, 0, "Renders background with a real horizon");
-               uiDefButBitS(block, TOG,WO_SKYPAPER, B_WORLDPRV,"Paper",270,150,50,25, &wrld->skytype, 0, 0, 0, 0, "Flattens blend or texture coordinates");
+               uiDefButBitS(block, TOG, WO_SKYREAL, B_WORLDPRV,"Real", 220,125,100,25, &wrld->skytype, 0, 0, 0, 0, "Renders background with a real horizon");
        }
        uiBlockEndAlign(block);