|
|
Category: SoFII Mapping Posted: Tuesday, Aug. 1, 2006 05:40 pm |
 |
You dont need milkshape to produce custom models. :D
I use Blender ( www.blender3d.com), using this python script:
#!BPY
"""
Name: 'MD3 (+shaders)'
Blender: 234
Group: 'Export'
Tip: 'Export to Quake 3 file format. (.md3)'
"""
######################################################
# MD3 Exporter
# Original By: Bob Holcomb
# Modified By: Damien McGinnes
# Date: 23 Oct 04
# Ver: 0.2
######################################################
# This script exports a Quake 3 file (MD3), textures,
# and animations from blender for playing.
# Loader is based on MD3 loader
# from www.gametutorials.com-Thanks DigiBen! and the
# md3 blender loader by PhaethonH
######################################################
######################################################
# This exporter has been extended to write textured
# materials info as MD3 shaders.
#
# The first encountered texture in a mesh object is
# used as the shader for the whole object.
#
# Modified by: Arsenij Vodjanov
# Date: 2 Feb 2005
######################################################
import Blender
from Blender import NMesh, Object, Draw, BGL
from Blender import *
#from Blender.BGL import *
#from Blender.Draw import *
from Blender.Image import *
import sys, struct, string, math
from types import *
import os
from os import path
######################################################
# Main Body
######################################################
def asciiz (s):
n = 0
while (ord(s[n]) != 0):
n = n + 1
return s[0:n]
def apply_transform(vert, matrix):
vertCopy = Mathutils.CopyVec(vert)
vertCopy.resize4D()
return Mathutils.VecMultMat(vertCopy, matrix)
######################################################
# MD3 Model Constants
######################################################
MD3_IDENT = "IDP3"
MD3_VERSION = 15
MD3_MAX_QPATH=64
MD3_MAX_TAGS=16
MD3_MAX_SURFACES=32
MD3_MAX_FRAMES=1024
MD3_MAX_SHADERS=256
MD3_MAX_VERTICES=4096
MD3_MAX_TRIANGLES=8192
MD3_XYZ_SCALE=(1.0/64.0)
FLIP_TEX_V_ON_EXPORT=1
NUM_FRAMES = 1
EXPORT_ALL = 0 #export only selected objs, or all?
######################################################
# MD3 data structures
######################################################
class vert:
co=[]
def __init__(self):
self.co=[0]*3
self.co[0]=0.0
self.co[1]=0.0
self.co[2]=0.0
class md3_vert:
co=[]
normal=0
binary_format="<3hh"
def __init__(self):
self.co=[0]*3
self.normal=0
def getsize(self):
return struct.calcsize(self.binary_format)
#copied from PhaethonH md3.py
def decode (self, latlng):
#Decode 16-bit latitude-longitude value into a normal vector.
#Code ripped from q3toosl/q3map/misc_model.c:
# // decode the lat/lng normal to a 3 float normal
# lat = ( xyz->normal >> 8 ) & 0xff;
# lng = ( xyz->normal & 0xff );
# lat *= Q_PI/128;
# lng *= Q_PI/128;
#
# temp[0] = cos(lat) * sin(lng);
# temp[1] = sin(lat) * sin(lng);
# temp[2] = cos(lng);
lat = (latlng >> 8) & 0xFF;
lng = (latlng) & 0xFF;
lat *= math.pi/128;
lng *= math.pi/128;
x = math.cos(lat) * math.sin(lng)
y = math.sin(lat) * math.sin(lng)
z = math.cos(lng)
retval = [ x, y, z ]
return retval
#copied from PhaethonH md3.py
#modified so hopefully it will work ;)
def encode (self, normal):
#Encode a normal vector into a 16-bit latitude-longitude value.
x, y, z = normal
#normalise
l = math.sqrt((x*x) + (y*y) + (z*z))
if l == 0:
return 0
x = x/l
y = y/l
z = z/l
if (x == 0.0) & (y == 0.0) :
if z > 0.0:
return 0
else:
return (128 << 8)
lng = math.acos(z) * 255 / (2 * math.pi)
lat = math.atan2(y, x) * 255 / (2 * math.pi)
retval = ((int(lat) & 0xFF) << 8) | (int(lng) & 0xFF)
return retval
def load(self,file):
temp_data=file.read(struct.calcsize(self.binary_format))
data=struct.unpack(self.binary_format, temp_data)
self.co[0:3]=data[0:3]
self.normal=data[3]
return self
def save(self, file):
temp_data=[0]*4
temp_data[0]=self.co[0]/MD3_XYZ_SCALE
temp_data[1]=self.co[1]/MD3_XYZ_SCALE
temp_data[2]=self.co[2]/MD3_XYZ_SCALE
temp_data[3]=self.normal
data=struct.pack(self.binary_format, temp_data[0], temp_data[1], temp_data[2], temp_data[3])
file.write(data)
#print "Wrote MD3 Vertex: "
#self.dump()
def dump(self):
print "MD3 Vertex Structure"
print "X: ", self.co[0]/MD3_XYZ_SCALE
print "Y: ", self.co[1]/MD3_XYZ_SCALE
print "Z: ", self.co[2]/MD3_XYZ_SCALE
print "Normal: ", self.normal
print ""
class md3_tex_coord:
u=0.0
v=0.0
binary_format="<2f"
def __init__(self):
self.u=0.0
self.v=0.0
def getsize(self):
return struct.calcsize(self.binary_format)
def load (self, file):
temp_data=file.read(struct.calcsize(self.binary_format))
data=struct.unpack(self.binary_format, temp_data)
self.u=data[0]
self.v=data[1]
return self
def save(self, file):
temp_data=[0]*2
temp_data[0]=self.u
if FLIP_TEX_V_ON_EXPORT:
temp_data[1]=1.0 - self.v
else:
temp_data[1]=self.v
data=struct.pack(self.binary_format, temp_data[0], temp_data[1])
file.write(data)
#print "wrote MD3 texture coordinate structure: "
#self.dump()
def dump (self):
print "MD3 Texture Coordinate Structure"
print "texture coordinate u: ",self.u
print "texture coordinate v: ",self.v
print ""
class md3_triangle:
vertex_index=[]
binary_format="<3i"
def __init__(self):
self.vertex_index = [ 0, 0, 0 ]
def getsize(self):
return struct.calcsize(self.binary_format)
def load (self, file):
temp_data=file.read(struct.calcsize(self.binary_format))
data=struct.unpack(self.binary_format, temp_data)
self.vertex_index[0:3]=data[0:3]
return self
def save(self, file):
temp_data=[0]*3
temp_data[0]=self.vertex_index[0]
temp_data[1]=self.vertex_index[2] #reverse
temp_data[2]=self.vertex_index[1] #reverse
data=struct.pack(self.binary_format,temp_data[0],temp_data[1],temp_data[2])
file.write(data)
#print "wrote MD3 tri structure: "
#self.dump()
def dump (self):
print "MD3 Triangle Structure"
print "vertex index: ", self.vertex_index[0]
print "vertex index: ", self.vertex_index[2] #reverse
print "vertex index: ", self.vertex_index[1] #reverse
print ""
class md3_shader:
name=""
index=0
binary_format="<%dsi" % MD3_MAX_QPATH
def __init__(self):
self.name=""
self.index=0
def getsize(self):
return struct.calcsize(self.binary_format)
def load (self, file):
temp_data=file.read(struct.calcsize(self.binary_format))
data=struct.unpack(self.binary_format, temp_data)
self.name=asciiz(data[0])
self.index=data[1]
return self
def save(self, file):
temp_data=[0]*2
temp_data[0]=self.name
temp_data[1]=self.index
data=struct.pack(self.binary_format, temp_data[0], temp_data[1])
file.write(data)
#print "wrote MD3 shader structure: "
#self.dump()
def dump (self):
print "MD3 Shader"
print "shader name: ",self.name
print "shader index: ",self.index
print ""
class md3_surface:
ident=""
name=""
flags=0
num_frames=0
num_shaders=0
num_verts=0
num_tris=0
offset_tris=0
offset_shaders=0
offset_uv=0
offset_verts=0
offset_end=0
shaders=[]
tris=[]
uv=[]
verts=[]
binary_format="<4s%ds10i" % MD3_MAX_QPATH #1 int, name, then 10 ints
def __init__(self):
self.ident=""
self.name=""
self.flags=0
self.num_frames=0
self.num_shaders=0
self.num_verts=0
self.num_tris=0
self.offset_tris=0
self.offset_shaders=0
self.offset_uv=0
self.offset_verts=0
self.offset_end
self.shaders=[]
self.tris=[]
self.uv=[]
self.verts=[]
def getsize(self):
sz =struct.calcsize(self.binary_format)
self.offset_tris = sz
for t in self.tris:
sz += t.getsize()
self.offset_shaders = sz
for s in self.shaders:
sz += s.getsize()
self.offset_uv = sz
for u in self.uv:
sz += u.getsize()
self.offset_verts = sz
for v in self.verts:
sz += v.getsize()
self.offset_end = sz
return self.offset_end
def load (self, file):
#where are we in the file (for calculating real offsets)
offset_begin=file.tell()
temp_data=file.read(struct.calcsize(self.binary_format))
data=struct.unpack(self.binary_format, temp_data)
self.ident=data[0]
self.name=asciiz(data[1])
self.flags=data[2]
self.num_frames=data[3]
self.num_shaders=data[4]
self.num_verts=data[5]
self.num_tris=data[6]
self.offset_tris=data[7]
self.offset_shaders=data[8]
self.offset_uv=data[9]
self.offset_verts=data[10]
self.offset_end=data[11]
#load the tri info
file.seek(offset_begin+self.offset_tris,0)
for i in range(0, self.num_tris):
self.tris.append(md3_triangle())
self.tris.load(file)
#self.tris.dump()
#load the shader info
file.seek(offset_begin+self.offset_shaders,0)
for i in range(0, self.num_shaders):
self.shaders.append(md3_shader())
self.shaders.load(file)
#self.shaders.dump()
#load the uv info
file.seek(offset_begin+self.offset_uv,0)
for i in range(0, self.num_tris*3):
self.uv.append(md3_tex_coord())
self.uv.load(file)
#self.uv.dump()
#load the verts info
file.seek(offset_begin+self.offset_verts,0)
for i in range(0, self.num_verts):
self.verts.append(md3_vert())
self.verts.load(file)
#self.verts.dump()
#go to the end of this structure
file.seek(offset_begin+self.offset_end, 0)
return self
def save(self, file):
self.getsize()
temp_data=[0]*12
temp_data[0]=self.ident
temp_data[1]=self.name
temp_data[2]=self.flags
temp_data[3]=self.num_frames
temp_data[4]=self.num_shaders
temp_data[5]=self.num_verts
temp_data[6]=self.num_tris
temp_data[7]=self.offset_tris
temp_data[8]=self.offset_shaders
temp_data[9]=self.offset_uv
temp_data[10]=self.offset_verts
temp_data[11]=self.offset_end
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])
file.write(data)
dat = struct.unpack(self.binary_format, data)
#write the tri data
for t in self.tris:
t.save(file)
#save the shader coordinates
for s in self.shaders:
s.save(file)
#save the uv info
for u in self.uv:
u.save(file)
#save the verts
for v in self.verts:
v.save(file)
#print "finished writing md3 surf"
#self.dump()
def dump (self):
#for s in self.shaders:
# s.dump()
print "MD3 Surface"
print "Ident: ", self.ident
print "Name: ", self.name
print "Flags: ", self.flags
print "Number of Frames: ", self.num_frames
print "Number of Shaders: ", self.num_shaders, "len shaders", len(self.shaders)
print "Number of Verts: ", self.num_verts, "len uvs:", len(self.uv), "len verts:", len(self.verts)
print "Number of Triangles: ", self.num_tris, "len tris:", len(self.tris)
print "Offset to Triangles: ",self.offset_tris
print "Offset to Shaders: ",self.offset_shaders
print "Offset to UV: ", self.offset_uv
print "Offset to Verts: ", self.offset_verts
print "Offset to end: ", self.offset_end
print ""
class md3_tag:
name=""
origin=[]
axis=[]
binary_format="<%ds3f9f" % MD3_MAX_QPATH
def __init__(self):
self.name=""
self.origin=vert()
self.axis=[vert()]*3
def getsize(self):
return struct.calcsize(self.binary_format)
def load(self, file):
temp_data=file.read(struct.calcsize(self.binary_format))
data=struct.unpack(self.binary_format, temp_data)
self.name=asciiz(data[0])
self.origin.co[0:3]=data[1:4]
self.axis[0].co[0:3]=data[4:7]
self.axis[1].co[0:3]=data[7:10]
self.axis[2].co[0:3]=data[10:13]
return self
def save(self, file):
temp_data=[0]*13
temp_data[0]=self.name
temp_data[1:4]=float(self.origin.co[0:3])
temp_data[4:7]=float(self.axis[0].co[0:3])
temp_data[7:10]=float(self.axis[1].co[0:3])
temp_data[10:13]=float(self.axis[2].co[0:3])
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])
file.write(data)
#print "wrote MD3 Tag structure: "
#self.dump()
def dump(self):
print "MD3 Tag"
print "Name: ", self.name
print "Origin: ",self.origin.co
print "Axis: ",self.axis[0].co, self.axis[1].co, self.axis[2].co
print ""
class md3_frame:
min_bounds=0
max_bounds=0
local_origin=0
radius=0.0
name=""
binary_format="<3f3f3ff16s"
def __init__(self):
self.min_bounds=vert()
self.max_bounds=vert()
self.local_origin=vert()
self.radius=0.0
self.name=""
def getsize(self):
return struct.calcsize(self.binary_format)
def load (self, file):
temp_data=file.read(struct.calcsize(self.binary_format))
data=struct.unpack(self.binary_format, temp_data)
self.min_bounds.co[0:3]=data[0:3]
self.max_bounds.co[0:3]=data[3:6]
self.local_origin.co[0:3]=data[6:9]
self.radius=data[9]
self.name=asciiz(data[10])
return self
def save(self, file):
temp_data=[0]*11
temp_data[0:3]=self.min_bounds.co[0:3]
temp_data[3:6]=self.max_bounds.co[0:3]
temp_data[6:9]=self.local_origin.co[0:3]
temp_data[9]=self.radius
temp_data[10]=self.name
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])
file.write(data)
#print "wrote MD3 frame structure: "
#self.dump()
def dump (self):
print "MD3 Frame"
print "Min Bounds: ",self.min_bounds.co
print "Max Bounds: ",self.max_bounds.co
print "Local Origin: ",self.local_origin.co
print "Radius: ",self.radius
print "Name: ",self.name
print ""
class md3_obj:
#Header Structure
ident="" #This is used to identify the file (must be IDP3)
version=0 #The version number of the file (Must be 15)
name=""
flags=0
num_frames=0
num_tags=0
num_surfaces=0
num_skins=0 #don't think this is used, but here anyways
offset_frames=0
offset_tags=0
offset_surfaces=0
offset_end=0
frames=[]
tags=[]
surfaces=[]
binary_format="<4si%ds9i" % MD3_MAX_QPATH #little-endian (<), 17 integers (17i)
def __init__ (self):
self.ident=""
self.version=0
self.name=""
self.flags=0
self.num_frames=0
self.num_tags=0
self.num_surfaces=0
self.num_skins=0
self.offset_frames=0
self.offset_tags=0
self.offset_surfaces=0
self.offset_end=0
self.frames=[]
self.tags=[]
self.surfaces=[]
def getsize(self):
self.offset_frames = struct.calcsize(self.binary_format)
self.offset_tags = self.offset_frames
for f in self.frames:
self.offset_tags += f.getsize()
self.offset_surfaces += self.offset_tags
for t in self.tags:
self.offset_surfaces += t.getsize()
self.offset_end = self.offset_surfaces
for s in self.surfaces:
self.offset_end += s.getsize()
return self.offset_end
def load (self, file):
temp_data = file.read(struct.calcsize(self.binary_format))
data = struct.unpack(self.binary_format, temp_data)
self.ident=data[0]
self.version=data[1]
if (self.ident!="IDP3" or self.version!=15):
print "Not a valid MD3 file"
print "Ident=", self.ident
print "Version=",self.version
Exit()
self.name=asciiz(data[2])
self.flags=data[3]
self.num_frames=data[4]
self.num_tags=data[5]
self.num_surfaces=data[6]
self.num_skins=data[7]
self.offset_frames=data[8]
self.offset_tags=data[9]
self.offset_surfaces=data[10]
self.offset_end=data[11]
#load the frame info
file.seek(self.offset_frames,0)
for i in range(0, self.num_frames):
self.frames.append(md3_frame())
self.frames.load(file)
#self.frames.dump()
#load the tags info
file.seek(self.offset_tags,0)
for i in range(0, self.num_tags):
self.tags.append(md3_tag())
self.tags.load(file)
#self.tags.dump()
#load the surface info
file.seek(self.offset_surfaces,0)
for i in range(0, self.num_surfaces):
self.surfaces.append(md3_surface())
self.surfaces.load(file)
self.surfaces.dump()
return self
def save(self, file):
self.getsize()
temp_data=[0]*12
temp_data[0]=self.ident
temp_data[1]=self.version
temp_data[2]=self.name
temp_data[3]=self.flags
temp_data[4]=self.num_frames
temp_data[5]=self.num_tags
temp_data[6]=self.num_surfaces
temp_data[7]=self.num_skins
temp_data[8]=self.offset_frames
temp_data[9]=self.offset_tags
temp_data[10]=self.offset_surfaces
temp_data[11]=self.offset_end
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])
file.write(data)
for f in self.frames:
f.save(file)
for t in self.tags:
t.save(file)
for s in self.surfaces:
s.save(file)
def dump (self):
#for s in self.surfaces:
# s.dump()
print "Header Information"
print "ident: ", self.ident
print "version: ", self.version
print "Name: ", self.name
print "Flags: ", self.flags
print "Number of Frames: ",self.num_frames, "len frames", len(self.frames)
print "Number of Tags: ", self.num_tags, "len tags:", len(self.tags)
print "Number of Surfaces: ", self.num_surfaces, "len surfaces:", len(self.surfaces)
print "Number of Skins: ", self.num_skins
print "Offset Frames: ", self.offset_frames
print "Offset Tags: ", self.offset_tags
print "Offset Surfaces: ", self.offset_surfaces
print "Offset end: ", self.offset_end
print ""
######################################################
# Export functions
######################################################
def updateFrameData(v, f):
min_bounds=0
max_bounds=0
local_origin=0
radius=0.0
name=""
for i in range(0,3):
f.min_bounds.co = min(v, f.min_bounds.co)
for i in range(0,3):
f.max_bounds.co = max(v, f.min_bounds.co)
def process_surface(mesh_obj, md3):
#because md3 doesnt suppoort faceUVs like blender, we need to duplicate
#any vertex that has multiple uv coords
global md3_uinfo, md3_strip_ext, md3_set_tga
vert_dict={}
index_dict={} #maps a vertex index to the revised index after duplicating to account for uv
vert_list=[] #list of vertices ordered by revised index
vert_count=0
tex_list=[] #list of tex coords ordered by revised index
face_list=[] #list of faces (they index into vert_list)
face_count=0
Blender.Set("curframe", 1)
#get access to the mesh data (as at frame #1)
mesh=NMesh.GetRawFromObject(mesh_obj.name)
matrix = mesh_obj.getMatrix('worldspace')
surf = md3_surface()
surf.num_frames = md3.num_frames
surf.name = mesh_obj.getName()
surf.ident = MD3_IDENT
# Find the index of the first referenced texture-mode material
texmat_index = -1
texmat_found = 0
m_index = 0
for material in mesh.materials:
print "---Found material \'%s\'for surface " % material.getName(), surf.name
if (material.getMode() & Material.Modes.TEXFACE) and (texmat_index == -1):
print "---The material has texture image, will use it"
texmat_index = m_index
texmat_found = 1
m_index += 1
# create default shader for surface
surf.shaders.append(md3_shader())
surf.num_shaders =+ 1
surf.shaders[0].index = 0
if m_index==0: # no materials
surf.shaders[0].name = md3_uinfo[2] + "_".join(surf.name.split("."))
else:
surf.shaders[0].name = md3_uinfo[2] + mesh.materials[texmat_index].name
#process each face in the mesh
for face in mesh.faces:
# see if this face uses the texture-mode material
if (face.materialIndex == texmat_index) and (texmat_found==1):
print "Found face using texmat w/ index ", texmat_index
texmat_found = 0 # prevent creation of more shaders
if (face.image):
surf.shaders[0].name = face.image.getFilename()
splitlist = []
if (surf.shaders[0].name.find("\\")!=-1):
splitlist = surf.shaders[0].name.split("\\")
if (surf.shaders[0].name.find("/")!=-1):
splitlist = surf.shaders[0].name.split("/")
splitlist = splitlist[len(splitlist)-1].split(".")
ext = ""
if len(splitlist)>1 and md3_strip_ext==0:
if md3_set_tga==1: ext = "tga"
else: ext = splitlist[len(splitlist)-1]
del splitlist[len(splitlist)-1]
surf.shaders[0].name = md3_uinfo[2] + ".".join(splitlist) + "." + ext
# done with shaders
tris_in_this_face=[] #to handle quads and up...
#this makes a list of indices for each tri in this face. a quad will be [[0,1,1],[0,2,3]]
for vi in range(1, len(face.v)-1):
tris_in_this_face.append([0, vi, vi+1])
#loop across each tri in the face, then each vertex in the tri
for this_tri in tris_in_this_face:
face_count += 1
tri = md3_triangle()
tri_ind = 0
for i in this_tri:
#get the vertex index, coords and uv coords
index = face.v.index
v = face.v.co
if mesh.hasFaceUV():
uv = face.uv
elif mesh.hasVertexUV():
uv = (face.v.uvco[0], face.v.uvco[1])
else:
uv = (0.0, 0.0) #handle case with no tex coords
if vert_dict.has_key((index, uv)):
# if we've seen this exact vertex before, simply add it
# to the tris list of vertex indices
tri.vertex_index[tri_ind] = vert_dict[(index, uv)]
else:
# havent seen this tri before
# (or its uv coord is different, so we need to duplicate it)
vert_dict[(index, uv)]=vert_count
# put the uv coord into the list
# (uv coord are directly related to each vertex)
tex = md3_tex_coord()
tex.u = uv[0]
tex.v = uv[1]
tex_list.append(tex)
tri.vertex_index[tri_ind] = vert_count
# now because we have created a new index,
# we need a way to link it to the index that
# blender returns for NMVert.index
if index_dict.has_key(index):
# already there - each of the entries against
# this key represents the same vertex with a
# different uv value
ilist = index_dict[index]
ilist.append(vert_count)
index_dict[index] = ilist
else:
#this is a new one
index_dict[index] = [vert_count]
vert_count += 1
tri_ind +=1
face_list.append(tri)
# we're done with faces and uv coords
for t in tex_list:
surf.uv.append(t)
for f in face_list:
surf.tris.append(f)
surf.num_tris = len(face_list)
surf.num_verts = vert_count
# now vertices are stored as frames -
# all vertices for frame 1, all vertices for frame 2...., all vertices for frame n
# so we need to iterate across blender's frames, and copy out each vertex
for frnum in range(1, md3.num_frames+1):
Blender.Set("curframe", frnum)
m=NMesh.GetRawFromObject(mesh_obj.name)
vlist = [0]*vert_count
for vertex in m.verts:
try:
vindices = index_dict[vertex.index]
except:
print "warning found a vertex in %s that is not part of a face" % mesh_obj.name
continue
vTx = apply_transform(vertex.co, matrix)
nTx = apply_transform(vertex.no, matrix)
updateFrameData(vTx, md3.frames[frnum-1])
vert = md3_vert()
vert.co = vTx[0:3]
vert.normal = vert.encode(nTx[0:3])
for ind in vindices: #apply the position to all the duplicated vertices
vlist[ind] = vert
for vl in vlist:
surf.verts.append(vl)
surf.dump()
md3.surfaces.append(surf)
md3.num_surfaces+=1
def save_md3 (md3_filename):
md3 = md3_obj()
md3.ident=MD3_IDENT
md3.version=MD3_VERSION
md3.name = md3_uinfo[0] + md3_uinfo[1]
tag_list=[]
Blender.Set("curframe", 1)
#create a bunch of blank frames, they'll be filled in by 'process_surface'
md3.num_frames=NUM_FRAMES
for i in range(1, NUM_FRAMES+1):
fr = md3_frame()
fr.name = "FRAME"+str(i)
md3.frames.append(fr)
#do we export all objects or just the selected ones?
if EXPORT_ALL:
objlist = Blender.Object.Get()
else:
objlist = Blender.Object.GetSelected()
#process each object for the export
for obj in objlist:
#check if it's a mesh object
if obj.getType()=="Mesh":
print "processing surface", obj.name
if len(md3.surfaces) == MD3_MAX_SURFACES:
print "hit md3 limit (%i) for number of surfaces, skipping" % MD3_MAX_SURFACES , obj.getName()
else:
process_surface(obj,md3)
elif obj.getType()=="Empty": #for tags, we just put em in a list so we can process them all together
if obj.name[0:4] == "tag_":
print "processing tag", obj.name
tag_list.append(obj)
md3.num_tags+=1
else:
print "Skipping non mesh object", obj.name
#work out the transforms for the tags for each frame of the export
for fr in range(1, NUM_FRAMES+1):
Blender.Set("curframe", fr)
for tag in tag_list:
t = md3_tag()
matrix = tag.getMatrix('worldspace')
for i in range(0,3):
t.axis[0].co = matrix[0]
t.axis[1].co = matrix[1]
t.axis[2].co = matrix[2]
t.origin.co = matrix[3]
t.name = obj.name[4:]
md3.tags.append(t)
#export!
file=open(md3_filename,"wb")
md3.save(file)
file.close()
md3.dump()
#***********************************************
# MAIN
#***********************************************
#
def my_callback(filename):
if(filename.find('.md3', -4) <= 0):
filename += '.md3'
print "Exporting MD3 format to ", filename
save_md3(filename)
#***********************************************
# MD3 info that must be provided by the user
#***********************************************
# individual shader path storage -- not implemented
#md3_shader_dict = {} # image name -> index
#md3_shader_paths = {} # index -> path string
# input fields
md3_uinfo = [0]*3
md3_uinfo[0] = "models/mapobjects/mymodel/" # md3 model path
md3_uinfo[1] = "mymodel.md3" # md3 model name
md3_uinfo[2] = "models/mapobjects/mymodel/" # md3 shader path (for selected shader)
md3_set_tga = 0 # replace texture extensions with '.tga'
md3_strip_ext = 0 # strip all texture extensions
#
gui_samepath = 1 # use same path for shaders and model
#***********************************************
# GUI
#***********************************************
#
gui_num_components = 3 # number of components that can have keyboard focus
#
gui_infocus = 0 # Index of the input component that has keyboard focus. -1 = none
#
# gui_menu_active = 0 # Draw the shader selection menu? -- not implemented
#
# gui_active_shader = -1 # Index of the currently selected shader. -1 = none -- not implemented
#
def gui_done():
global md3_uinfo
if len(md3_uinfo[0])>0 and md3_uinfo[0][len(md3_uinfo[0])-1]!='/':
md3_uinfo[0] += '/'
if len(md3_uinfo[2])>0 and md3_uinfo[2][len(md3_uinfo[2])-1]!='/':
md3_uinfo[2] += '/'
if md3_uinfo[1].find('.md3', -4) <= 0:
md3_uinfo[1] += '.md3'
print "MD3 options:"
print "Set TGA ext: ", md3_set_tga
print "Strip ext: ", md3_strip_ext
print "MD3 model: ", md3_uinfo[0] + md3_uinfo[1]
print "Shader path: ", md3_uinfo[2]
Blender.Window.FileSelector(my_callback, "Export MD3", md3_uinfo[1])
#
#
def event(evt, val): # the function to handle input events
global md3_uinfo, gui_infocus, gui_samepath, gui_num_components #, gui_active_shader
if not val: # val = 0: it's a key/mbutton release
if evt in [Draw.LEFTMOUSE, Draw.MIDDLEMOUSE, Draw.RIGHTMOUSE]:
Draw.Redraw(1)
return
if evt == Draw.ESCKEY:
Draw.Exit() # exit when user presses ESC
return
elif evt == Draw.TABKEY:
gui_infocus += 1
if gui_infocus>=gui_num_components: gui_infocus = 0
Draw.Redraw(1)
# if gui_infocus==2 and gui_active_shader==-1: gui_infocus = 0
#Draw.Register(gui, event, button_event)
return
if Draw.AKEY <= evt <= Draw.ZKEY: md3_uinfo[gui_infocus] += chr(evt)
elif Draw.ZEROKEY <= evt <= Draw.NINEKEY: md3_uinfo[gui_infocus] += chr(evt)
elif evt == Draw.MINUSKEY: md3_uinfo[gui_infocus] += '-'
elif evt == Draw.SPACEKEY: md3_uinfo[gui_infocus] += '_'
elif evt == Draw.PERIODKEY and gui_infocus==1: md3_uinfo[gui_infocus] += ".md3"
elif (evt == Draw.SLASHKEY or evt == Draw.BACKSLASHKEY) and gui_infocus!=1:
if len(md3_uinfo[gui_infocus]) and md3_uinfo[gui_infocus][len(md3_uinfo[gui_infocus])-1] != '/': md3_uinfo[gui_infocus] += '/'
elif evt == Draw.BACKSPACEKEY and len(md3_uinfo[gui_infocus]): md3_uinfo[gui_infocus] = md3_uinfo[gui_infocus][:-1]
else: return # this is important: only re-register if an event was caught
if len(md3_uinfo[gui_infocus])>55:
md3_uinfo[gui_infocus] = md3_uinfo[gui_infocus][:-1]
if (gui_infocus==0 or gui_infocus==2) and gui_samepath==1:
md3_uinfo[2-gui_infocus] = md3_uinfo[gui_infocus]
Draw.Redraw(1)
# Draw.Register(gui, event, button_event) # re-register to stay in the loop
#
def button_event(evt): # the function to handle Draw Button events
global md3_uinfo, md3_set_tga, md3_strip_ext, gui_infocus, gui_samepath, gui_num_components # , gui_active_shader
if evt == 1: # accept
Draw.Exit()
gui_done()
return
elif evt == 2: # cancel
Draw.Exit()
return
#
elif evt == 10: # set focus to input 0
gui_infocus = 0
elif evt == 11:
gui_infocus = 1
elif evt == 12: # and gui_active_shader!=-1:
gui_infocus = 2
#
elif evt == 20: # All-tga toggle
md3_set_tga = 1 - md3_set_tga
if md3_set_tga==1: md3_strip_ext = 0
elif evt == 21: # Strip-extension toggle
md3_strip_ext = 1 - md3_strip_ext
if md3_strip_ext==1: md3_set_tga = 0
#
elif evt == 30: # Same-path toggle
gui_samepath = 1 - gui_samepath
else:
return
Draw.Redraw(1)
# Draw.Register(gui, event, button_event)
#
def gui(): # the function to draw the screen
global md3_uinfo, md3_set_tga, md3_strip_ext, gui_samepath, gui_infocus, gui_num_components #, gui_active_shader
BGL.glClearColor(0.1,0.1,0.1,1)
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
BGL.glColor4f(0.4,0.4,0.4, 0.25)
BGL.glBegin(BGL.GL_POLYGON)
BGL.glVertex2i(5, 5)
BGL.glVertex2i(795, 5)
BGL.glVertex2i(795, 450)
BGL.glVertex2i(5, 450)
BGL.glEnd()
BGL.glColor3f(0,0,0)
BGL.glRasterPos2i(186, 410)
Draw.Text("MD3 EXPORTER")
BGL.glColor3f(1,1,1)
BGL.glRasterPos2i(185, 411)
Draw.Text("MD3 EXPORTER")
BGL.glColor4f(0.35,0.35,0.35, 0.25)
BGL.glBegin(BGL.GL_POLYGON)
BGL.glVertex2i(460, 380)
BGL.glVertex2i(760, 380)
BGL.glVertex2i(760, 90)
BGL.glVertex2i(460, 90)
BGL.glEnd()
BGL.glColor3f(0.4,0.7,0.5)
BGL.glRasterPos2i(470, 360)
Draw.Text("* Use TAB to move cursor between input fields.")
BGL.glRasterPos2i(470, 340)
Draw.Text("* Spaces are converted to underscores.")
BGL.glRasterPos2i(470, 320)
Draw.Text("* Paths should be relative to the game's base")
BGL.glRasterPos2i(470, 300)
Draw.Text("directory, e.g.: \'models/mapobjects/my_model\'")
BGL.glRasterPos2i(470, 280)
Draw.Text("* Combined path and filename must be less than")
BGL.glRasterPos2i(470, 260)
Draw.Text("64 characters in length.")
BGL.glRasterPos2i(470, 240)
Draw.Text("* It is usually a good idea to have the same path")
BGL.glRasterPos2i(470, 220)
Draw.Text("for model and shaders. Use different paths if")
BGL.glRasterPos2i(470, 200)
Draw.Text("the textures do not reside in the same directory")
BGL.glRasterPos2i(470, 180)
Draw.Text("as the MD3 itself.")
BGL.glRasterPos2i(470, 160)
Draw.Text("")
BGL.glRasterPos2i(470, 140)
Draw.Text("NOTE: It is currently not possible to set")
BGL.glRasterPos2i(470, 120)
Draw.Text("different paths for individual textures,")
BGL.glRasterPos2i(470, 100)
Draw.Text("although the MD3 file format allows it.")
BGL.glColor3f(0.35,0.35,0.35)
BGL.glBegin(BGL.GL_POLYGON)
BGL.glVertex2i( 5, 380)
BGL.glVertex2i(450, 380)
BGL.glVertex2i(450, 290)
BGL.glVertex2i( 5, 290)
BGL.glEnd()
BGL.glColor3f(1,1,1)
BGL.glRasterPos2i(10, 360)
Draw.Text("Shaders/Textures export options")
BGL.glColor3f(0.25,0.25,0.75)
Draw.Toggle("", 20, 20,326, 15,14, md3_set_tga, "")
BGL.glColor3f(0.8,1,0.8)
BGL.glRasterPos2i(40, 330)
Draw.Text("Replace all texture extensions with \'.tga\' in MD3")
BGL.glColor3f(0.25,0.25,0.75)
Draw.Toggle("", 21, 20,306, 15,14, md3_strip_ext, "")
BGL.glColor3f(0.8,1,0.8)
BGL.glRasterPos2i(40, 310)
Draw.Text("Strip extensions from all texture filenames in MD3")
BGL.glColor3f(0.35,0.35,0.35)
BGL.glBegin(BGL.GL_POLYGON)
BGL.glVertex2i( 5, 270)
BGL.glVertex2i(450, 270)
BGL.glVertex2i(450, 90)
BGL.glVertex2i( 5, 90)
BGL.glEnd()
BGL.glColor3f(1,1,1)
BGL.glRasterPos2i(10, 250)
Draw.Text("Internal directory paths (in MD3 file)")
BGL.glColor3f(0.25,0.25,0.75)
Draw.Toggle("", 30, 20,216, 15,14, gui_samepath, "Toggle on/off")
BGL.glColor3f(0.8,1,0.8)
BGL.glRasterPos2i(40, 220)
Draw.Text("Shaders/textures and the model use the same path")
BGL.glColor3f(1,1,0)
BGL.glRasterPos2i(20, 190)
Draw.Text("MD3 model directory prefix:")
BGL.glColor3f(1,0.9,0.9)
BGL.glRasterPos2i(40, 170)
xlen0 = Draw.Text(md3_uinfo[0])
BGL.glColor3f(1,1,0)
BGL.glRasterPos2i(300, 190)
Draw.Text("Internal model name:")
BGL.glColor3f(1,0.9,0.9)
BGL.glRasterPos2i(320, 170)
xlen1 = Draw.Text(md3_uinfo[1])
BGL.glColor3f(1,1,0)
BGL.glRasterPos2i(20, 140)
Draw.Text("Shaders/textures directory prefix:")
BGL.glColor3f(1,0.9,0.9)
BGL.glRasterPos2i(40, 120)
# if gui_active_shader != -1:
xlen2 = Draw.Text(md3_uinfo[2])
# focus toggle button state
togup0=0
togup1=0
togup2=0
BGL.glColor3f(1,0.1,0.1) # focus cursor color
if gui_infocus==0:
BGL.glRasterPos2i(40+xlen0, 170)
Draw.Text("||")
togup0 = 1
elif gui_infocus==1:
BGL.glRasterPos2i(320+xlen1, 170)
Draw.Text("||")
togup1 = 1
elif gui_infocus==2: # and gui_active_shader!=-1:
BGL.glRasterPos2i(40+xlen2, 120)
Draw.Text("||")
togup2 = 1
BGL.glColor3f(0.25,0.25,0.75)
Draw.Toggle(">", 10, 20, 166, 15,14, togup0, "Set keyboard input focus here")
Draw.Toggle(">", 11, 300,166, 15,14, togup1, "Set keyboard input focus here")
Draw.Toggle(">", 12, 20, 116, 15,14, togup2, "Set keyboard input focus here")
BGL.glColor3f(0.75,1,0.75)
Draw.Button("Accept", 1, 20, 50, 70,30,"Proceed to output filename selection")
BGL.glColor3f(1,0.75,0.75)
Draw.Button("Cancel", 2, 120,50, 70,30,"Cancel exporting operation")
#
print "****"
Draw.Register(gui, event, button_event) # registering the 3 callbacks
The website I got this script from seems to be down atm, just copy the above into a text editor and save it as: "md3-export-0.2-lgt.py".
Hope this helps you. :) |
 |
|
|