Scripts:
- added import and export scripts for 3ds and md2 (Quake 2) models contributed by author Bob Holcomb. Thanks! - updated ac3d importer to be more forgiving and exporter to get rid of deprecated call. More additions and possibly fixes to come. Note: we're forming a group to take care of importers and exporters and improve the situation as a whole in Blender. Discussions should happen at the bf-scripts-dev mailing list: http://projects.blender.org/mailman/listinfo/bf-scripts-dev Thanks Tom Musgrove (LetterRip) for helping a lot with scripts.
This commit is contained in:
673
release/scripts/3ds_export.py
Normal file
673
release/scripts/3ds_export.py
Normal file
@@ -0,0 +1,673 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: '3D Studio (.3ds)...'
|
||||
Blender: 237
|
||||
Group: 'Export'
|
||||
Tooltip: 'Export to 3DS file format (.3ds).'
|
||||
"""
|
||||
|
||||
__author__ = ["Campbell Barton", "Bob Holcomb", "Richard L<>rk<72>ng", "Damien McGinnes"]
|
||||
__url__ = ("blender", "elysiun", "http://www.gametutorials.com")
|
||||
__version__ = "0.82"
|
||||
__bpydoc__ = """\
|
||||
|
||||
3ds Exporter
|
||||
|
||||
This script Exports a 3ds file and the materials into blender for editing.
|
||||
|
||||
Exporting is based on 3ds loader from www.gametutorials.com(Thanks DigiBen).
|
||||
"""
|
||||
|
||||
# ***** 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
|
||||
######################################################
|
||||
# Importing modules
|
||||
######################################################
|
||||
|
||||
import Blender
|
||||
from Blender import NMesh, Scene, Object, Material
|
||||
import struct
|
||||
|
||||
|
||||
######################################################
|
||||
# Data Structures
|
||||
######################################################
|
||||
|
||||
#Some of the chunks that we will export
|
||||
#----- Primary Chunk, at the beginning of each file
|
||||
PRIMARY= long("0x4D4D",16)
|
||||
|
||||
#------ Main Chunks
|
||||
OBJECTINFO = long("0x3D3D",16); #This gives the version of the mesh and is found right before the material and object information
|
||||
VERSION = long("0x0002",16); #This gives the version of the .3ds file
|
||||
EDITKEYFRAME= long("0xB000",16); #This is the header for all of the key frame info
|
||||
|
||||
#------ sub defines of OBJECTINFO
|
||||
MATERIAL=45055 #0xAFFF // This stored the texture info
|
||||
OBJECT=16384 #0x4000 // This stores the faces, vertices, etc...
|
||||
|
||||
#>------ sub defines of MATERIAL
|
||||
MATNAME = long("0xA000",16); # This holds the material name
|
||||
MATAMBIENT = long("0xA010",16); # Ambient color of the object/material
|
||||
MATDIFFUSE = long("0xA020",16); # This holds the color of the object/material
|
||||
MATSPECULAR = long("0xA030",16); # SPecular color of the object/material
|
||||
MATSHINESS = long("0xA040",16); # ??
|
||||
MATMAP = long("0xA200",16); # This is a header for a new material
|
||||
MATMAPFILE = long("0xA300",16); # This holds the file name of the texture
|
||||
|
||||
RGB1= long("0x0011",16)
|
||||
RGB2= long("0x0012",16)
|
||||
|
||||
#>------ sub defines of OBJECT
|
||||
OBJECT_MESH = long("0x4100",16); # This lets us know that we are reading a new object
|
||||
OBJECT_LIGHT = long("0x4600",16); # This lets un know we are reading a light object
|
||||
OBJECT_CAMERA= long("0x4700",16); # This lets un know we are reading a camera object
|
||||
|
||||
#>------ sub defines of CAMERA
|
||||
OBJECT_CAM_RANGES= long("0x4720",16); # The camera range values
|
||||
|
||||
#>------ sub defines of OBJECT_MESH
|
||||
OBJECT_VERTICES = long("0x4110",16); # The objects vertices
|
||||
OBJECT_FACES = long("0x4120",16); # The objects faces
|
||||
OBJECT_MATERIAL = long("0x4130",16); # This is found if the object has a material, either texture map or color
|
||||
OBJECT_UV = long("0x4140",16); # The UV texture coordinates
|
||||
OBJECT_TRANS_MATRIX = long("0x4160",16); # The Object Matrix
|
||||
|
||||
#==============================================#
|
||||
# Strips the slashes from the back of a string #
|
||||
#==============================================#
|
||||
def stripPath(path):
|
||||
return path.split('/')[-1].split('\\')[-1]
|
||||
|
||||
#==================================================#
|
||||
# New name based on old with a different extension #
|
||||
#==================================================#
|
||||
def newFName(ext):
|
||||
return Blender.Get('filename')[: -len(Blender.Get('filename').split('.', -1)[-1]) ] + ext
|
||||
|
||||
|
||||
#the chunk class
|
||||
class chunk:
|
||||
ID=0
|
||||
size=0
|
||||
|
||||
def __init__(self):
|
||||
self.ID=0
|
||||
self.size=0
|
||||
|
||||
def get_size(self):
|
||||
self.size=6
|
||||
|
||||
def write(self, file):
|
||||
#write header
|
||||
data=struct.pack(\
|
||||
"<HI",\
|
||||
self.ID,\
|
||||
self.size)
|
||||
file.write(data)
|
||||
|
||||
def dump(self):
|
||||
print "ID: ", self.ID
|
||||
print "ID in hex: ", hex(self.ID)
|
||||
print "size: ", self.size
|
||||
|
||||
|
||||
|
||||
#may want to add light, camera, keyframe chunks.
|
||||
class vert_chunk(chunk):
|
||||
verts=[]
|
||||
|
||||
def __init__(self):
|
||||
self.verts=[]
|
||||
self.ID=OBJECT_VERTICES
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=2 #for the number of verts short
|
||||
temp_size += 12 * len(self.verts) #3 floats x 4 bytes each
|
||||
self.size+=temp_size
|
||||
#~ print "vert_chunk size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write header
|
||||
data=struct.pack("<H", len(self.verts))
|
||||
file.write(data)
|
||||
#write verts
|
||||
for vert in self.verts:
|
||||
data=struct.pack("<3f",vert[0],vert[1], vert[2])
|
||||
file.write(data)
|
||||
|
||||
class obj_material_chunk(chunk):
|
||||
name=""
|
||||
faces=[]
|
||||
|
||||
def __init__(self):
|
||||
self.name=""
|
||||
self.faces=[]
|
||||
self.ID=OBJECT_MATERIAL
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=(len(self.name)+1)
|
||||
temp_size+=2
|
||||
for face in self.faces:
|
||||
temp_size+=2
|
||||
self.size+=temp_size
|
||||
#~ print "obj material chunk size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write name
|
||||
name_length=len(self.name)+1
|
||||
binary_format="<"+str(name_length)+"s"
|
||||
data=struct.pack(binary_format, self.name)
|
||||
file.write(data)
|
||||
binary_format="<H"
|
||||
#~ print "Nr of faces: ", len(self.faces)
|
||||
data=struct.pack(binary_format, len(self.faces))
|
||||
file.write(data)
|
||||
for face in self.faces:
|
||||
data=struct.pack(binary_format, face)
|
||||
file.write(data)
|
||||
|
||||
class face_chunk(chunk):
|
||||
faces=[]
|
||||
num_faces=0
|
||||
m_chunks=[]
|
||||
|
||||
def __init__(self):
|
||||
self.faces=[]
|
||||
self.ID=OBJECT_FACES
|
||||
self.num_faces=0
|
||||
self.m_chunks=[]
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size = 2 #num faces info
|
||||
temp_size += 8 * len(self.faces) #4 short ints x 2 bytes each
|
||||
for m in self.m_chunks:
|
||||
temp_size+=m.get_size()
|
||||
self.size += temp_size
|
||||
#~ print "face_chunk size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
data=struct.pack("<H", len(self.faces))
|
||||
file.write(data)
|
||||
#write faces
|
||||
for face in self.faces:
|
||||
data=struct.pack("<4H", face[0],face[1], face[2], 0) # The last zero is only used by 3d studio
|
||||
file.write(data)
|
||||
#write materials
|
||||
for m in self.m_chunks:
|
||||
m.write(file)
|
||||
|
||||
class uv_chunk(chunk):
|
||||
uv=[]
|
||||
num_uv=0
|
||||
|
||||
def __init__(self):
|
||||
self.uv=[]
|
||||
self.ID=OBJECT_UV
|
||||
self.num_uv=0
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=2 #for num UV
|
||||
for this_uv in self.uv:
|
||||
temp_size+=8 #2 floats at 4 bytes each
|
||||
self.size+=temp_size
|
||||
#~ print "uv chunk size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
|
||||
#write header
|
||||
data=struct.pack("<H", len(self.uv))
|
||||
file.write(data)
|
||||
|
||||
#write verts
|
||||
for this_uv in self.uv:
|
||||
data=struct.pack("<2f", this_uv[0], this_uv[1])
|
||||
file.write(data)
|
||||
|
||||
class mesh_chunk(chunk):
|
||||
v_chunk=vert_chunk()
|
||||
f_chunk=face_chunk()
|
||||
uv_chunk=uv_chunk()
|
||||
|
||||
def __init__(self):
|
||||
self.v_chunk=vert_chunk()
|
||||
self.f_chunk=face_chunk()
|
||||
self.uv_chunk=uv_chunk()
|
||||
self.ID=OBJECT_MESH
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=self.v_chunk.get_size()
|
||||
temp_size+=self.f_chunk.get_size()
|
||||
temp_size+=self.uv_chunk.get_size()
|
||||
self.size+=temp_size
|
||||
#~ print "object mesh chunk size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write stuff
|
||||
self.v_chunk.write(file)
|
||||
self.f_chunk.write(file)
|
||||
self.uv_chunk.write(file)
|
||||
|
||||
class object_chunk(chunk):
|
||||
name=""
|
||||
mesh_chunks=[]
|
||||
|
||||
def __init__(self):
|
||||
self.name=""
|
||||
self.mesh_chunks=[]
|
||||
self.ID=OBJECT
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=len(self.name)+1 #+1 for null character
|
||||
for mesh in self.mesh_chunks:
|
||||
temp_size+=mesh.get_size()
|
||||
self.size+=temp_size
|
||||
#~ print "object chunk size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write name
|
||||
|
||||
binary_format = "<%ds" % (len(self.name)+1)
|
||||
data=struct.pack(binary_format, self.name)
|
||||
file.write(data)
|
||||
#write stuff
|
||||
for mesh in self.mesh_chunks:
|
||||
mesh.write(file)
|
||||
|
||||
class object_info_chunk(chunk):
|
||||
obj_chunks=[]
|
||||
mat_chunks=[]
|
||||
|
||||
def __init__(self):
|
||||
self.obj_chunks=[]
|
||||
self.mat_chunks=[]
|
||||
self.ID=OBJECTINFO
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=0
|
||||
for mat in self.mat_chunks:
|
||||
temp_size+=mat.get_size()
|
||||
for obj in self.obj_chunks:
|
||||
temp_size+=obj.get_size()
|
||||
self.size+=temp_size
|
||||
#~ print "object info size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write all the materials
|
||||
for mat in self.mat_chunks:
|
||||
mat.write(file)
|
||||
#write all the objects
|
||||
for obj in self.obj_chunks:
|
||||
obj.write(file)
|
||||
|
||||
|
||||
|
||||
class version_chunk(chunk):
|
||||
version=3
|
||||
|
||||
def __init__(self):
|
||||
self.ID=VERSION
|
||||
self.version=3 #that the document that I'm using
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
self.size += 4 #bytes for the version info
|
||||
#~ print "version chunk size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write header and version
|
||||
data=struct.pack("<I", self.version)
|
||||
file.write(data)
|
||||
|
||||
class rgb_chunk(chunk):
|
||||
col=[]
|
||||
|
||||
def __init__(self):
|
||||
self.col=[]
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
self.size+=3 #color size
|
||||
#~ print "rgb chunk size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write colors
|
||||
for c in self.col:
|
||||
file.write( struct.pack("<c", chr(int(255*c))) )
|
||||
|
||||
|
||||
class rgb1_chunk(rgb_chunk):
|
||||
|
||||
def __init__(self):
|
||||
self.ID=RGB1
|
||||
|
||||
class rgb2_chunk(rgb_chunk):
|
||||
|
||||
def __init__(self):
|
||||
self.ID=RGB2
|
||||
|
||||
class material_ambient_chunk(chunk):
|
||||
col1=None
|
||||
col2=None
|
||||
|
||||
def __init__(self):
|
||||
self.ID=MATAMBIENT
|
||||
self.col1=rgb1_chunk()
|
||||
self.col2=rgb2_chunk()
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=self.col1.get_size()
|
||||
temp_size+=self.col2.get_size()
|
||||
self.size+=temp_size
|
||||
#~ print "material ambient size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write colors
|
||||
self.col1.write(file)
|
||||
self.col2.write(file)
|
||||
|
||||
class material_diffuse_chunk(chunk):
|
||||
col1=None
|
||||
col2=None
|
||||
|
||||
def __init__(self):
|
||||
self.ID=MATDIFFUSE
|
||||
self.col1=rgb1_chunk()
|
||||
self.col2=rgb2_chunk()
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=self.col1.get_size()
|
||||
temp_size+=self.col2.get_size()
|
||||
self.size+=temp_size
|
||||
#~ print "material diffuse size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write colors
|
||||
self.col1.write(file)
|
||||
self.col2.write(file)
|
||||
|
||||
class material_specular_chunk(chunk):
|
||||
col1=None
|
||||
col2=None
|
||||
|
||||
def __init__(self):
|
||||
self.ID=MATSPECULAR
|
||||
self.col1=rgb1_chunk()
|
||||
self.col2=rgb2_chunk()
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=self.col1.get_size()
|
||||
temp_size+=self.col2.get_size()
|
||||
self.size+=temp_size
|
||||
#~ print "material specular size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write colors
|
||||
self.col1.write(file)
|
||||
self.col2.write(file)
|
||||
|
||||
class material_name_chunk(chunk):
|
||||
name=""
|
||||
|
||||
def __init__(self):
|
||||
self.ID=MATNAME
|
||||
self.name=""
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=(len(self.name)+1)
|
||||
self.size+=temp_size
|
||||
#~ print "material name size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write name
|
||||
name_length=len(self.name)+1
|
||||
binary_format="<"+str(name_length)+"s"
|
||||
data=struct.pack(binary_format, self.name)
|
||||
file.write(data)
|
||||
|
||||
class material_chunk(chunk):
|
||||
matname_chunk=None
|
||||
matambient_chunk=None
|
||||
matdiffuse_chunk=None
|
||||
matspecular_chunk=None
|
||||
|
||||
def __init__(self):
|
||||
self.ID=MATERIAL
|
||||
self.matname_chunk=material_name_chunk()
|
||||
self.matambient_chunk=material_ambient_chunk()
|
||||
self.matdiffuse_chunk=material_diffuse_chunk()
|
||||
self.matspecular_chunk=material_specular_chunk()
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=self.matname_chunk.get_size()
|
||||
temp_size+=self.matambient_chunk.get_size()
|
||||
temp_size+=self.matdiffuse_chunk.get_size()
|
||||
temp_size+=self.matspecular_chunk.get_size()
|
||||
self.size+=temp_size
|
||||
#~ print "material chunk size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write name chunk
|
||||
self.matname_chunk.write(file)
|
||||
#write material colors
|
||||
self.matambient_chunk.write(file)
|
||||
self.matdiffuse_chunk.write(file)
|
||||
self.matspecular_chunk.write(file)
|
||||
|
||||
class primary_chunk(chunk):
|
||||
version=None
|
||||
obj_info=None
|
||||
|
||||
def __init__(self):
|
||||
self.version=version_chunk()
|
||||
self.obj_info=object_info_chunk()
|
||||
self.ID=PRIMARY
|
||||
|
||||
def get_size(self):
|
||||
chunk.get_size(self)
|
||||
temp_size=self.version.get_size()
|
||||
temp_size+=self.obj_info.get_size()
|
||||
self.size+=temp_size
|
||||
#~ print "primary chunk size: ", self.size
|
||||
return self.size
|
||||
|
||||
def write(self, file):
|
||||
chunk.write(self, file)
|
||||
#write version chunk
|
||||
self.version.write(file)
|
||||
#write object_info chunk
|
||||
self.obj_info.write(file)
|
||||
|
||||
def read_chunk(file, chunk):
|
||||
chunk.ID, chunk.size = \
|
||||
struct.unpack(\
|
||||
chunk.binary_format, \
|
||||
file.read(struct.calcsize(chunk.binary_format)) )
|
||||
|
||||
def read_string(file):
|
||||
s=""
|
||||
index=0
|
||||
|
||||
#read in the characters till we get a null character
|
||||
data=struct.unpack("c", file.read(struct.calcsize("c")))
|
||||
s=s+(data[0])
|
||||
#print "string: ",s
|
||||
while(ord(s[index])!=0):
|
||||
index+=1
|
||||
data=struct.unpack("c", file.read(struct.calcsize("c")))
|
||||
s=s+(data[0])
|
||||
#print "string: ",s
|
||||
return str(s)
|
||||
|
||||
######################################################
|
||||
# EXPORT
|
||||
######################################################
|
||||
def save_3ds(filename):
|
||||
# Time the export
|
||||
time1 = Blender.sys.time()
|
||||
|
||||
exported_materials = {}
|
||||
|
||||
#fill the chunks full of data
|
||||
primary=primary_chunk()
|
||||
#get all the objects in this scene
|
||||
object_list = [ ob for ob in Blender.Object.GetSelected() if ob.getType() == 'Mesh' ]
|
||||
#fill up the data structures with objects
|
||||
for obj in object_list:
|
||||
#create a new object chunk
|
||||
primary.obj_info.obj_chunks.append(object_chunk())
|
||||
#get the mesh data
|
||||
blender_mesh = obj.getData()
|
||||
blender_mesh.transform(obj.getMatrix())
|
||||
#set the object name
|
||||
primary.obj_info.obj_chunks[len(primary.obj_info.obj_chunks)-1].name=obj.getName()
|
||||
|
||||
matrix = obj.getMatrix()
|
||||
|
||||
#make a new mesh chunk object
|
||||
mesh=mesh_chunk()
|
||||
|
||||
mesh.v_chunk.verts = blender_mesh.verts
|
||||
|
||||
dummy = None # just incase...
|
||||
|
||||
for m in blender_mesh.materials:
|
||||
mesh.f_chunk.m_chunks.append(obj_material_chunk())
|
||||
mesh.f_chunk.m_chunks[len(mesh.f_chunk.m_chunks)-1].name = m.name
|
||||
|
||||
# materials should only be exported once
|
||||
try:
|
||||
dummy = exported_materials[m.name]
|
||||
|
||||
|
||||
except KeyError:
|
||||
material = material_chunk()
|
||||
material.matname_chunk.name=m.name
|
||||
material.matambient_chunk.col1.col = m.mirCol
|
||||
material.matambient_chunk.col2.col = m.mirCol
|
||||
material.matdiffuse_chunk.col1.col = m.rgbCol
|
||||
material.matdiffuse_chunk.col2.col = m.rgbCol
|
||||
material.matspecular_chunk.col1.col = m.specCol
|
||||
material.matspecular_chunk.col2.col = m.specCol
|
||||
|
||||
primary.obj_info.mat_chunks.append(material)
|
||||
|
||||
exported_materials[m.name] = None
|
||||
|
||||
del dummy # unpolute the namespace
|
||||
|
||||
valid_faces = [f for f in blender_mesh.faces if len(f) > 2]
|
||||
facenr=0
|
||||
#fill in faces
|
||||
for face in valid_faces:
|
||||
|
||||
#is this a tri or a quad
|
||||
num_fv=len(face.v)
|
||||
|
||||
|
||||
#it's a tri
|
||||
if num_fv==3:
|
||||
mesh.f_chunk.faces.append((face[0].index, face[1].index, face[2].index))
|
||||
if (face.materialIndex < len(mesh.f_chunk.m_chunks)):
|
||||
mesh.f_chunk.m_chunks[face.materialIndex].faces.append(facenr)
|
||||
facenr+=1
|
||||
|
||||
else: #it's a quad
|
||||
mesh.f_chunk.faces.append((face[0].index, face[1].index, face[2].index)) # 0,1,2
|
||||
mesh.f_chunk.faces.append((face[2].index, face[3].index, face[0].index)) # 2,3,0
|
||||
#first tri
|
||||
if (face.materialIndex < len(mesh.f_chunk.m_chunks)):
|
||||
mesh.f_chunk.m_chunks[face.materialIndex].faces.append(facenr)
|
||||
facenr+=1
|
||||
#other tri
|
||||
if (face.materialIndex < len(mesh.f_chunk.m_chunks)):
|
||||
mesh.f_chunk.m_chunks[face.materialIndex].faces.append(facenr)
|
||||
facenr+=1
|
||||
|
||||
|
||||
#fill in the UV info
|
||||
if blender_mesh.hasVertexUV():
|
||||
for vert in blender_mesh.verts:
|
||||
mesh.uv_chunk.uv.append((vert.uvco[0], vert.uvco[1]))
|
||||
|
||||
elif blender_mesh.hasFaceUV():
|
||||
for face in valid_faces:
|
||||
# Tri or quad.
|
||||
for uv_coord in face.uv:
|
||||
mesh.uv_chunk.uv.append((uv_coord[0], uv_coord[1]))
|
||||
|
||||
#filled in our mesh, lets add it to the file
|
||||
primary.obj_info.obj_chunks[len(primary.obj_info.obj_chunks)-1].mesh_chunks.append(mesh)
|
||||
|
||||
#check the size
|
||||
primary.get_size()
|
||||
#open the files up for writing
|
||||
file = open( filename, "wb" )
|
||||
#recursively write the stuff to file
|
||||
primary.write(file)
|
||||
file.close()
|
||||
print "3ds export time: %.2f" % (Blender.sys.time() - time1)
|
||||
|
||||
|
||||
Blender.Window.FileSelector(save_3ds, "Export 3DS", newFName('3ds'))
|
||||
548
release/scripts/3ds_import.py
Normal file
548
release/scripts/3ds_import.py
Normal file
@@ -0,0 +1,548 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: '3D Studio (.3ds)...'
|
||||
Blender: 237
|
||||
Group: 'Import'
|
||||
Tooltip: 'Import from 3DS file format (.3ds).'
|
||||
"""
|
||||
|
||||
__author__ = ["Bob Holcomb", "Richard L<>rk<72>ng", "Damien McGinnes", "Campbell Barton"]
|
||||
__url__ = ("blender", "elysiun", "http://www.gametutorials.com")
|
||||
__version__ = "0.82"
|
||||
__bpydoc__ = """\
|
||||
|
||||
3ds Importer
|
||||
|
||||
This script imports a 3ds file and the materials into blender for editing.
|
||||
|
||||
Loader is based on 3ds loader from www.gametutorials.com(Thanks DigiBen).
|
||||
|
||||
Changes:<br>
|
||||
0.81a (fork- not 0.9) Campbell Barton 2005-06-08<br>
|
||||
- Simplified import code<br>
|
||||
- Never overwrite data<br>
|
||||
- Faster list handling<br>
|
||||
- Leaves import selected<br>
|
||||
|
||||
0.81 Damien McGinnes 2005-01-09<br>
|
||||
- handle missing images better<br>
|
||||
|
||||
0.8 Damien McGinnes 2005-01-08<br>
|
||||
- copies sticky UV coords to face ones<br>
|
||||
- handles images better<br>
|
||||
- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script
|
||||
|
||||
"""
|
||||
|
||||
# ***** 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 *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# Importing modules
|
||||
|
||||
import Blender
|
||||
from Blender import NMesh, Scene, Object, Material, Image
|
||||
|
||||
import sys, struct, string
|
||||
|
||||
import os
|
||||
|
||||
#this script imports uvcoords as sticky vertex coords
|
||||
#this parameter enables copying these to face uv coords
|
||||
#which shold be more useful.
|
||||
|
||||
|
||||
#===========================================================================#
|
||||
# Returns unique name of object/mesh (stops overwriting existing meshes) #
|
||||
#===========================================================================#
|
||||
def getUniqueName(name):
|
||||
newName = name
|
||||
uniqueInt = 0
|
||||
while 1:
|
||||
try:
|
||||
ob = Object.Get(newName)
|
||||
# Okay, this is working, so lets make a new name
|
||||
newName = '%s.%d' % (name, uniqueInt)
|
||||
uniqueInt +=1
|
||||
except AttributeError:
|
||||
if newName not in NMesh.GetNames():
|
||||
return newName
|
||||
else:
|
||||
newName = '%s.%d' % (name, uniqueInt)
|
||||
uniqueInt +=1
|
||||
|
||||
|
||||
######################################################
|
||||
# Data Structures
|
||||
######################################################
|
||||
|
||||
#Some of the chunks that we will see
|
||||
#----- Primary Chunk, at the beginning of each file
|
||||
PRIMARY= long("0x4D4D",16)
|
||||
|
||||
#------ Main Chunks
|
||||
OBJECTINFO = long("0x3D3D",16); #This gives the version of the mesh and is found right before the material and object information
|
||||
VERSION = long("0x0002",16); #This gives the version of the .3ds file
|
||||
EDITKEYFRAME= long("0xB000",16); #This is the header for all of the key frame info
|
||||
|
||||
#------ sub defines of OBJECTINFO
|
||||
MATERIAL=45055 #0xAFFF // This stored the texture info
|
||||
OBJECT=16384 #0x4000 // This stores the faces, vertices, etc...
|
||||
|
||||
#>------ sub defines of MATERIAL
|
||||
MATNAME = long("0xA000",16); # This holds the material name
|
||||
MATAMBIENT = long("0xA010",16); # Ambient color of the object/material
|
||||
MATDIFFUSE = long("0xA020",16); # This holds the color of the object/material
|
||||
MATSPECULAR = long("0xA030",16); # SPecular color of the object/material
|
||||
MATSHINESS = long("0xA040",16); # ??
|
||||
MATMAP = long("0xA200",16); # This is a header for a new material
|
||||
MATMAPFILE = long("0xA300",16); # This holds the file name of the texture
|
||||
|
||||
#>------ sub defines of OBJECT
|
||||
OBJECT_MESH = long("0x4100",16); # This lets us know that we are reading a new object
|
||||
OBJECT_LIGHT = long("0x4600",16); # This lets un know we are reading a light object
|
||||
OBJECT_CAMERA= long("0x4700",16); # This lets un know we are reading a camera object
|
||||
|
||||
#>------ sub defines of CAMERA
|
||||
OBJECT_CAM_RANGES= long("0x4720",16); # The camera range values
|
||||
|
||||
#>------ sub defines of OBJECT_MESH
|
||||
OBJECT_VERTICES = long("0x4110",16); # The objects vertices
|
||||
OBJECT_FACES = long("0x4120",16); # The objects faces
|
||||
OBJECT_MATERIAL = long("0x4130",16); # This is found if the object has a material, either texture map or color
|
||||
OBJECT_UV = long("0x4140",16); # The UV texture coordinates
|
||||
OBJECT_TRANS_MATRIX = long("0x4160",16); # The Object Matrix
|
||||
|
||||
#the chunk class
|
||||
class chunk:
|
||||
ID=0
|
||||
length=0
|
||||
bytes_read=0
|
||||
|
||||
#we don't read in the bytes_read, we compute that
|
||||
binary_format="<HI"
|
||||
|
||||
def __init__(self):
|
||||
self.ID=0
|
||||
self.length=0
|
||||
self.bytes_read=0
|
||||
|
||||
def dump(self):
|
||||
print "ID: ", self.ID
|
||||
print "ID in hex: ", hex(self.ID)
|
||||
print "length: ", self.length
|
||||
print "bytes_read: ", self.bytes_read
|
||||
|
||||
|
||||
def read_chunk(file, chunk):
|
||||
temp_data=file.read(struct.calcsize(chunk.binary_format))
|
||||
data=struct.unpack(chunk.binary_format, temp_data)
|
||||
chunk.ID=data[0]
|
||||
chunk.length=data[1]
|
||||
#update the bytes read function
|
||||
chunk.bytes_read=6
|
||||
|
||||
#if debugging
|
||||
#chunk.dump()
|
||||
|
||||
def read_string(file):
|
||||
s=""
|
||||
index=0
|
||||
#print "reading a string"
|
||||
#read in the characters till we get a null character
|
||||
temp_data=file.read(1)
|
||||
data=struct.unpack("c", temp_data)
|
||||
s=s+(data[0])
|
||||
#print "string: ",s
|
||||
while(ord(s[index])!=0):
|
||||
index+=1
|
||||
temp_data=file.read(1)
|
||||
data=struct.unpack("c", temp_data)
|
||||
s=s+(data[0])
|
||||
#print "string: ",s
|
||||
|
||||
#remove the null character from the string
|
||||
the_string=s[:-1]
|
||||
return str(the_string)
|
||||
|
||||
######################################################
|
||||
# IMPORT
|
||||
######################################################
|
||||
def process_next_object_chunk(file, previous_chunk):
|
||||
new_chunk=chunk()
|
||||
temp_chunk=chunk()
|
||||
|
||||
while (previous_chunk.bytes_read<previous_chunk.length):
|
||||
#read the next chunk
|
||||
read_chunk(file, new_chunk)
|
||||
|
||||
|
||||
def process_next_chunk(file, previous_chunk, new_object_list):
|
||||
contextObName = None
|
||||
#contextLamp = None
|
||||
contextMaterial = None
|
||||
contextMatrix = Blender.Mathutils.Matrix(); contextMatrix.identity()
|
||||
contextMesh = None
|
||||
|
||||
TEXDICT={}
|
||||
MATDICT={}
|
||||
|
||||
objectList = [] # Keep a list of imported objects.
|
||||
|
||||
# Localspace variable names, faster.
|
||||
STRUCT_SIZE_1CHAR = struct.calcsize("c")
|
||||
STRUCT_SIZE_2FLOAT = struct.calcsize("2f")
|
||||
STRUCT_SIZE_3FLOAT = struct.calcsize("3f")
|
||||
STRUCT_SIZE_UNSIGNED_SHORT = struct.calcsize("H")
|
||||
STRUCT_SIZE_4UNSIGNED_SHORT = struct.calcsize("4H")
|
||||
STRUCT_SIZE_4x3MAT = struct.calcsize("ffffffffffff")
|
||||
|
||||
|
||||
def putContextMesh(myContextMesh):
|
||||
INV_MAT = Blender.Mathutils.CopyMat(contextMatrix)
|
||||
INV_MAT.invert()
|
||||
contextMesh.transform(INV_MAT)
|
||||
objectList.append(NMesh.PutRaw(contextMesh))
|
||||
objectList[-1].name = contextObName
|
||||
objectList[-1].setMatrix(contextMatrix)
|
||||
|
||||
|
||||
#a spare chunk
|
||||
new_chunk=chunk()
|
||||
temp_chunk=chunk()
|
||||
|
||||
#loop through all the data for this chunk (previous chunk) and see what it is
|
||||
while (previous_chunk.bytes_read<previous_chunk.length):
|
||||
#read the next chunk
|
||||
#print "reading a chunk"
|
||||
read_chunk(file, new_chunk)
|
||||
|
||||
#is it a Version chunk?
|
||||
if (new_chunk.ID==VERSION):
|
||||
#print "found a VERSION chunk"
|
||||
#read in the version of the file
|
||||
#it's an unsigned short (H)
|
||||
temp_data=file.read(struct.calcsize("I"))
|
||||
data=struct.unpack("I", temp_data)
|
||||
version=data[0]
|
||||
new_chunk.bytes_read+=4 #read the 4 bytes for the version number
|
||||
#this loader works with version 3 and below, but may not with 4 and above
|
||||
if (version>3):
|
||||
print "\tNon-Fatal Error: Version greater than 3, may not load correctly: ", version
|
||||
|
||||
#is it an object info chunk?
|
||||
elif (new_chunk.ID==OBJECTINFO):
|
||||
# print "found an OBJECTINFO chunk"
|
||||
process_next_chunk(file, new_chunk, new_object_list)
|
||||
|
||||
#keep track of how much we read in the main chunk
|
||||
new_chunk.bytes_read+=temp_chunk.bytes_read
|
||||
|
||||
#is it an object chunk?
|
||||
elif (new_chunk.ID==OBJECT):
|
||||
# print "found an OBJECT chunk"
|
||||
tempName = str(read_string(file))
|
||||
contextObName = getUniqueName( tempName )
|
||||
new_chunk.bytes_read += (len(tempName)+1)
|
||||
|
||||
#is it a material chunk?
|
||||
elif (new_chunk.ID==MATERIAL):
|
||||
# print "found a MATERIAL chunk"
|
||||
contextMaterial = Material.New()
|
||||
|
||||
elif (new_chunk.ID==MATNAME):
|
||||
# print "Found a MATNAME chunk"
|
||||
material_name=""
|
||||
material_name=str(read_string(file))
|
||||
|
||||
#plus one for the null character that ended the string
|
||||
new_chunk.bytes_read+=(len(material_name)+1)
|
||||
|
||||
contextMaterial.setName(material_name)
|
||||
MATDICT[material_name] = contextMaterial.name
|
||||
|
||||
elif (new_chunk.ID==MATAMBIENT):
|
||||
# print "Found a MATAMBIENT chunk"
|
||||
|
||||
read_chunk(file, temp_chunk)
|
||||
temp_data=file.read(struct.calcsize("3B"))
|
||||
data=struct.unpack("3B", temp_data)
|
||||
temp_chunk.bytes_read+=3
|
||||
contextMaterial.mirCol = [float(col)/255 for col in data] # data [0,1,2] == rgb
|
||||
new_chunk.bytes_read+=temp_chunk.bytes_read
|
||||
|
||||
elif (new_chunk.ID==MATDIFFUSE):
|
||||
# print "Found a MATDIFFUSE chunk"
|
||||
|
||||
read_chunk(file, temp_chunk)
|
||||
temp_data=file.read(struct.calcsize("3B"))
|
||||
data=struct.unpack("3B", temp_data)
|
||||
temp_chunk.bytes_read+=3
|
||||
contextMaterial.rgbCol = [float(col)/255 for col in data] # data [0,1,2] == rgb
|
||||
new_chunk.bytes_read+=temp_chunk.bytes_read
|
||||
|
||||
elif (new_chunk.ID==MATSPECULAR):
|
||||
# print "Found a MATSPECULAR chunk"
|
||||
|
||||
read_chunk(file, temp_chunk)
|
||||
temp_data=file.read(struct.calcsize("3B"))
|
||||
data=struct.unpack("3B", temp_data)
|
||||
temp_chunk.bytes_read+=3
|
||||
|
||||
contextMaterial.specCol = [float(col)/255 for col in data] # data [0,1,2] == rgb
|
||||
new_chunk.bytes_read+=temp_chunk.bytes_read
|
||||
|
||||
elif (new_chunk.ID==MATMAP):
|
||||
# print "Found a MATMAP chunk"
|
||||
pass # This chunk has no data
|
||||
|
||||
elif (new_chunk.ID==MATMAPFILE):
|
||||
# print "Found a MATMAPFILE chunk"
|
||||
texture_name=""
|
||||
texture_name=str(read_string(file))
|
||||
try:
|
||||
img = Image.Load(texture_name)
|
||||
TEXDICT[contextMaterial.name]=img
|
||||
except IOError:
|
||||
fname = os.path.join( os.path.dirname(FILENAME), texture_name)
|
||||
try:
|
||||
img = Image.Load(fname)
|
||||
TEXDICT[contextMaterial.name]=img
|
||||
except IOError:
|
||||
print "\tERROR: failed to load image ",texture_name
|
||||
TEXDICT[contextMaterial.name] = None # Dummy
|
||||
|
||||
#plus one for the null character that gets removed
|
||||
new_chunk.bytes_read += (len(texture_name)+1)
|
||||
|
||||
|
||||
elif (new_chunk.ID==OBJECT_MESH):
|
||||
# print "Found an OBJECT_MESH chunk"
|
||||
if contextMesh != None: # Write context mesh if we have one.
|
||||
putContextMesh(contextMesh)
|
||||
|
||||
contextMesh = NMesh.New()
|
||||
|
||||
# Reset matrix
|
||||
contextMatrix = Blender.Mathutils.Matrix(); contextMatrix.identity()
|
||||
|
||||
elif (new_chunk.ID==OBJECT_VERTICES):
|
||||
# print "Found an OBJECT_VERTICES chunk"
|
||||
#print "object_verts: length: ", new_chunk.length
|
||||
temp_data=file.read(STRUCT_SIZE_UNSIGNED_SHORT)
|
||||
data=struct.unpack("H", temp_data)
|
||||
new_chunk.bytes_read+=2
|
||||
num_verts=data[0]
|
||||
# print "number of verts: ", num_verts
|
||||
for counter in range (num_verts):
|
||||
temp_data=file.read(STRUCT_SIZE_3FLOAT)
|
||||
new_chunk.bytes_read += STRUCT_SIZE_3FLOAT #12: 3 floats x 4 bytes each
|
||||
data=struct.unpack("3f", temp_data)
|
||||
v=NMesh.Vert(data[0],data[1],data[2])
|
||||
contextMesh.verts.append(v)
|
||||
#print "object verts: bytes read: ", new_chunk.bytes_read
|
||||
|
||||
elif (new_chunk.ID==OBJECT_FACES):
|
||||
# print "Found an OBJECT_FACES chunk"
|
||||
#print "object faces: length: ", new_chunk.length
|
||||
temp_data=file.read(STRUCT_SIZE_UNSIGNED_SHORT)
|
||||
data=struct.unpack("H", temp_data)
|
||||
new_chunk.bytes_read+=2
|
||||
num_faces=data[0]
|
||||
#print "number of faces: ", num_faces
|
||||
|
||||
for counter in range(num_faces):
|
||||
temp_data=file.read(STRUCT_SIZE_4UNSIGNED_SHORT)
|
||||
new_chunk.bytes_read += STRUCT_SIZE_4UNSIGNED_SHORT #4 short ints x 2 bytes each
|
||||
data=struct.unpack("4H", temp_data)
|
||||
|
||||
#insert the mesh info into the faces, don't worry about data[3] it is a 3D studio thing
|
||||
f = NMesh.Face( [contextMesh.verts[data[i]] for i in xrange(3) ] )
|
||||
f.uv = [ tuple(contextMesh.verts[data[i]].uvco[:2]) for i in xrange(3) ]
|
||||
contextMesh.faces.append(f)
|
||||
#print "object faces: bytes read: ", new_chunk.bytes_read
|
||||
|
||||
elif (new_chunk.ID==OBJECT_MATERIAL):
|
||||
# print "Found an OBJECT_MATERIAL chunk"
|
||||
material_name=""
|
||||
material_name=str(read_string(file))
|
||||
new_chunk.bytes_read += len(material_name)+1 # remove 1 null character.
|
||||
|
||||
#look up the material in all the materials
|
||||
material_found=0
|
||||
for mat in Material.Get():
|
||||
|
||||
#found it, add it to the mesh
|
||||
if(mat.name==material_name):
|
||||
if len(contextMesh.materials) >= 15:
|
||||
print "\tCant assign more than 16 materials per mesh, keep going..."
|
||||
break
|
||||
else:
|
||||
meshHasMat = 0
|
||||
for myMat in contextMesh.materials:
|
||||
if myMat.name == mat.name:
|
||||
meshHasMat = 1
|
||||
|
||||
if meshHasMat == 0:
|
||||
contextMesh.addMaterial(mat)
|
||||
material_found=1
|
||||
|
||||
#figure out what material index this is for the mesh
|
||||
for mat_counter in range(len(contextMesh.materials)):
|
||||
if contextMesh.materials[mat_counter].name == material_name:
|
||||
mat_index=mat_counter
|
||||
#print "material index: ",mat_index
|
||||
|
||||
|
||||
break # get out of this for loop so we don't accidentally set material_found back to 0
|
||||
else:
|
||||
material_found=0
|
||||
# print "Not matching: ", mat.name, " and ", material_name
|
||||
|
||||
if material_found == 1:
|
||||
contextMaterial = mat
|
||||
#read the number of faces using this material
|
||||
temp_data=file.read(STRUCT_SIZE_UNSIGNED_SHORT)
|
||||
data=struct.unpack("H", temp_data)
|
||||
new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
|
||||
num_faces_using_mat=data[0]
|
||||
|
||||
#list of faces using mat
|
||||
for face_counter in range(num_faces_using_mat):
|
||||
temp_data=file.read(STRUCT_SIZE_UNSIGNED_SHORT)
|
||||
new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
|
||||
data=struct.unpack("H", temp_data)
|
||||
contextMesh.faces[data[0]].materialIndex = mat_index
|
||||
|
||||
try:
|
||||
mname = MATDICT[contextMaterial.name]
|
||||
contextMesh.faces[data[0]].image = TEXDICT[mname]
|
||||
except:
|
||||
continue
|
||||
else:
|
||||
#read past the information about the material you couldn't find
|
||||
#print "Couldn't find material. Reading past face material info"
|
||||
buffer_size=new_chunk.length-new_chunk.bytes_read
|
||||
binary_format=str(buffer_size)+"c"
|
||||
temp_data=file.read(struct.calcsize(binary_format))
|
||||
new_chunk.bytes_read+=buffer_size
|
||||
|
||||
#print "object mat: bytes read: ", new_chunk.bytes_read
|
||||
|
||||
elif (new_chunk.ID == OBJECT_UV):
|
||||
# print "Found an OBJECT_UV chunk"
|
||||
temp_data=file.read(STRUCT_SIZE_UNSIGNED_SHORT)
|
||||
data=struct.unpack("H", temp_data)
|
||||
new_chunk.bytes_read+=2
|
||||
num_uv=data[0]
|
||||
|
||||
for counter in range(num_uv):
|
||||
temp_data=file.read(STRUCT_SIZE_2FLOAT)
|
||||
new_chunk.bytes_read += STRUCT_SIZE_2FLOAT #2 float x 4 bytes each
|
||||
data=struct.unpack("2f", temp_data)
|
||||
|
||||
#insert the insert the UV coords in the vertex data
|
||||
contextMesh.verts[counter].uvco = data
|
||||
|
||||
elif (new_chunk.ID == OBJECT_TRANS_MATRIX):
|
||||
# print "Found an OBJECT_TRANS_MATRIX chunk"
|
||||
|
||||
temp_data=file.read(STRUCT_SIZE_4x3MAT)
|
||||
data = list( struct.unpack("ffffffffffff", temp_data) )
|
||||
new_chunk.bytes_read += STRUCT_SIZE_4x3MAT
|
||||
|
||||
contextMatrix = Blender.Mathutils.Matrix(\
|
||||
data[:3] + [0],\
|
||||
data[3:6] + [0],\
|
||||
data[6:9] + [0],\
|
||||
data[9:] + [1])
|
||||
|
||||
|
||||
|
||||
else: #(new_chunk.ID!=VERSION or new_chunk.ID!=OBJECTINFO or new_chunk.ID!=OBJECT or new_chunk.ID!=MATERIAL):
|
||||
# print "skipping to end of this chunk"
|
||||
buffer_size=new_chunk.length-new_chunk.bytes_read
|
||||
binary_format=str(buffer_size)+"c"
|
||||
temp_data=file.read(struct.calcsize(binary_format))
|
||||
new_chunk.bytes_read+=buffer_size
|
||||
|
||||
|
||||
#update the previous chunk bytes read
|
||||
previous_chunk.bytes_read += new_chunk.bytes_read
|
||||
#print "Bytes left in this chunk: ", previous_chunk.length-previous_chunk.bytes_read
|
||||
|
||||
# FINISHED LOOP
|
||||
# There will be a number of objects still not added
|
||||
if contextMesh != None:
|
||||
putContextMesh(contextMesh)
|
||||
|
||||
for ob in objectList:
|
||||
ob.sel = 1
|
||||
|
||||
def load_3ds (filename):
|
||||
print 'Importing "%s"' % filename
|
||||
|
||||
time1 = Blender.sys.time()
|
||||
|
||||
global FILENAME
|
||||
FILENAME=filename
|
||||
current_chunk=chunk()
|
||||
|
||||
file=open(filename,"rb")
|
||||
|
||||
#here we go!
|
||||
# print "reading the first chunk"
|
||||
new_object_list = []
|
||||
read_chunk(file, current_chunk)
|
||||
if (current_chunk.ID!=PRIMARY):
|
||||
print "\tFatal Error: Not a valid 3ds file: ", filename
|
||||
file.close()
|
||||
return
|
||||
|
||||
process_next_chunk(file, current_chunk, new_object_list)
|
||||
|
||||
# Select all new objects.
|
||||
for ob in new_object_list: ob.sel = 1
|
||||
|
||||
print 'finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1))
|
||||
file.close()
|
||||
|
||||
#***********************************************
|
||||
# MAIN
|
||||
#***********************************************
|
||||
def my_callback(filename):
|
||||
load_3ds(filename)
|
||||
|
||||
Blender.Window.FileSelector(my_callback, "Import 3DS", '*.3ds')
|
||||
|
||||
# For testing compatibility
|
||||
'''
|
||||
TIME = Blender.sys.time()
|
||||
import os
|
||||
for _3ds in os.listdir('/3ds/'):
|
||||
if _3ds.lower().endswith('3ds'):
|
||||
print _3ds
|
||||
newScn = Scene.New(_3ds)
|
||||
newScn.makeCurrent()
|
||||
my_callback('/3ds/' + _3ds)
|
||||
|
||||
print "TOTAL TIME: ", Blender.sys.time() - TIME
|
||||
'''
|
||||
@@ -202,7 +202,8 @@ def transform_verts(verts, m):
|
||||
vecs = []
|
||||
for v in verts:
|
||||
vec = Mathutils.Vector([v[0],v[1],v[2], 1])
|
||||
vecs.append(Mathutils.VecMultMat(vec, m))
|
||||
#vecs.append(Mathutils.VecMultMat(vec, m))
|
||||
vecs.append(vec*m)
|
||||
return vecs
|
||||
|
||||
# ---
|
||||
|
||||
@@ -10,7 +10,7 @@ Tip: 'Import an AC3D (.ac) file.'
|
||||
__author__ = "Willian P. Germano"
|
||||
__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org",
|
||||
"PLib 3d gaming lib, http://plib.sf.net")
|
||||
__version__ = "2.36 2005-04-14"
|
||||
__version__ = "2.36a 2005-12-04"
|
||||
|
||||
__bpydoc__ = """\
|
||||
This script imports AC3D models into Blender.
|
||||
@@ -43,9 +43,9 @@ users can configure (see config options above).
|
||||
# $Id$
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# AC3DImport version 2.36 Apr 14, 2005
|
||||
# AC3DImport version 2.36a Dec 04, 2005
|
||||
# Program versions: Blender 2.36+ and AC3Db files (means version 0xb)
|
||||
# changed: updated to use the Scripts Config Editor facilities
|
||||
# changed: fixed a bug: error on 1 vertex "closed" polylines
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
@@ -366,7 +366,7 @@ class AC3DImport:
|
||||
faces.append(cut)
|
||||
face = face[1:]
|
||||
|
||||
if flaglow == 1:
|
||||
if flaglow == 1 and faces:
|
||||
face = [faces[-1][-1], faces[0][0]]
|
||||
faces.append(face)
|
||||
|
||||
@@ -498,7 +498,9 @@ class AC3DImport:
|
||||
for vi in range(len(f)):
|
||||
bface.v.append(mesh.verts[f[vi][0]])
|
||||
bface.uv.append((f[vi][1][0], f[vi][1][1]))
|
||||
mesh.faces.append(bface)
|
||||
#mesh.faces.append(bface)
|
||||
# quick hack, will switch from NMesh to Mesh later:
|
||||
if len(bface.v) > 1: mesh.addFace(bface)
|
||||
|
||||
mesh.mode = 0
|
||||
object = Blender.NMesh.PutRaw(mesh)
|
||||
|
||||
1016
release/scripts/md2_export.py
Normal file
1016
release/scripts/md2_export.py
Normal file
File diff suppressed because it is too large
Load Diff
571
release/scripts/md2_import.py
Normal file
571
release/scripts/md2_import.py
Normal file
@@ -0,0 +1,571 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'MD2 (.md2)'
|
||||
Blender: 239
|
||||
Group: 'Import'
|
||||
Tooltip: 'Import from Quake file format (.md2).'
|
||||
"""
|
||||
|
||||
__author__ = 'Bob Holcomb'
|
||||
__version__ = '0.15'
|
||||
__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 imports a Quake 2 file (MD2), textures,
|
||||
and animations into blender for editing. Loader is based on MD2 loader from www.gametutorials.com-Thanks DigiBen! and the md3 blender loader by PhaethonH <phaethon@linux.ucla.edu><br>
|
||||
|
||||
Additional help from: Shadwolf, Skandal, Rojo, Cambo<br>
|
||||
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 NMesh, Object, sys
|
||||
from Blender.BGL import *
|
||||
from Blender.Draw import *
|
||||
from Blender.Window import *
|
||||
from Blender.Image import *
|
||||
|
||||
import struct, string
|
||||
from types import *
|
||||
|
||||
|
||||
|
||||
|
||||
######################################################
|
||||
# Main Body
|
||||
######################################################
|
||||
|
||||
#returns the string from a null terminated string
|
||||
def asciiz (s):
|
||||
n = 0
|
||||
while (ord(s[n]) != 0):
|
||||
n = n + 1
|
||||
return s[0:n]
|
||||
|
||||
|
||||
######################################################
|
||||
# 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 data structures
|
||||
######################################################
|
||||
class md2_alias_triangle:
|
||||
vertices=[]
|
||||
lightnormalindex=0
|
||||
|
||||
binary_format="<3BB" #little-endian (<), 3 Unsigned char
|
||||
|
||||
def __init__(self):
|
||||
self.vertices=[0]*3
|
||||
self.lightnormalindex=0
|
||||
|
||||
def load(self, file):
|
||||
temp_data = file.read(struct.calcsize(self.binary_format))
|
||||
data = struct.unpack(self.binary_format, temp_data)
|
||||
self.vertices[0]=data[0]
|
||||
self.vertices[1]=data[1]
|
||||
self.vertices[2]=data[2]
|
||||
self.lightnormalindex=data[3]
|
||||
return self
|
||||
|
||||
def dump(self):
|
||||
print "MD2 Alias_Triangle Structure"
|
||||
print "vertex: ", self.vertices[0]
|
||||
print "vertex: ", self.vertices[1]
|
||||
print "vertex: ", self.vertices[2]
|
||||
print "lightnormalindex: ",self.lightnormalindex
|
||||
print ""
|
||||
|
||||
class md2_face:
|
||||
vertex_index=[]
|
||||
texture_index=[]
|
||||
|
||||
binary_format="<3h3h" #little-endian (<), 3 short, 3 short
|
||||
|
||||
def __init__(self):
|
||||
self.vertex_index = [ 0, 0, 0 ]
|
||||
self.texture_index = [ 0, 0, 0]
|
||||
|
||||
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]=data[0]
|
||||
self.vertex_index[1]=data[1]
|
||||
self.vertex_index[2]=data[2]
|
||||
self.texture_index[0]=data[3]
|
||||
self.texture_index[1]=data[4]
|
||||
self.texture_index[2]=data[5]
|
||||
return self
|
||||
|
||||
def dump (self):
|
||||
print "MD2 Face Structure"
|
||||
print "vertex index: ", self.vertex_index[0]
|
||||
print "vertex index: ", self.vertex_index[1]
|
||||
print "vertex index: ", self.vertex_index[2]
|
||||
print "texture index: ", self.texture_index[0]
|
||||
print "texture index: ", self.texture_index[1]
|
||||
print "texture index: ", self.texture_index[2]
|
||||
print ""
|
||||
|
||||
class md2_tex_coord:
|
||||
u=0
|
||||
v=0
|
||||
|
||||
binary_format="<2h" #little-endian (<), 2 unsigned short
|
||||
|
||||
def __init__(self):
|
||||
self.u=0
|
||||
self.v=0
|
||||
|
||||
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 dump (self):
|
||||
print "MD2 Texture Coordinate Structure"
|
||||
print "texture coordinate u: ",self.u
|
||||
print "texture coordinate v: ",self.v
|
||||
print ""
|
||||
|
||||
|
||||
class md2_skin:
|
||||
name=""
|
||||
|
||||
binary_format="<64s" #little-endian (<), char[64]
|
||||
|
||||
def __init__(self):
|
||||
self.name=""
|
||||
|
||||
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])
|
||||
return self
|
||||
|
||||
def dump (self):
|
||||
print "MD2 Skin"
|
||||
print "skin name: ",self.name
|
||||
print ""
|
||||
|
||||
class md2_alias_frame:
|
||||
scale=[]
|
||||
translate=[]
|
||||
name=[]
|
||||
vertices=[]
|
||||
|
||||
binary_format="<3f3f16s" #little-endian (<), 3 float, 3 float char[16]
|
||||
#did not add the "3bb" to the end of the binary format
|
||||
#because the alias_vertices will be read in through
|
||||
#thier own loader
|
||||
|
||||
def __init__(self):
|
||||
self.scale=[0.0]*3
|
||||
self.translate=[0.0]*3
|
||||
self.name=""
|
||||
self.vertices=[]
|
||||
|
||||
|
||||
def load (self, file):
|
||||
temp_data=file.read(struct.calcsize(self.binary_format))
|
||||
data=struct.unpack(self.binary_format, temp_data)
|
||||
self.scale[0]=data[0]
|
||||
self.scale[1]=data[1]
|
||||
self.scale[2]=data[2]
|
||||
self.translate[0]=data[3]
|
||||
self.translate[1]=data[4]
|
||||
self.translate[2]=data[5]
|
||||
self.name=asciiz(data[6])
|
||||
return self
|
||||
|
||||
def dump (self):
|
||||
print "MD2 Alias Frame"
|
||||
print "scale x: ",self.scale[0]
|
||||
print "scale y: ",self.scale[1]
|
||||
print "scale z: ",self.scale[2]
|
||||
print "translate x: ",self.translate[0]
|
||||
print "translate y: ",self.translate[1]
|
||||
print "translate z: ",self.translate[2]
|
||||
print "name: ",self.name
|
||||
print ""
|
||||
|
||||
class md2_obj:
|
||||
#Header Structure
|
||||
ident=0 #int 0 This is used to identify the file
|
||||
version=0 #int 1 The version number of the file (Must be 8)
|
||||
skin_width=0 #int 2 The skin width in pixels
|
||||
skin_height=0 #int 3 The skin height in pixels
|
||||
frame_size=0 #int 4 The size in bytes the frames are
|
||||
num_skins=0 #int 5 The number of skins associated with the model
|
||||
num_vertices=0 #int 6 The number of vertices (constant for each frame)
|
||||
num_tex_coords=0 #int 7 The number of texture coordinates
|
||||
num_faces=0 #int 8 The number of faces (polygons)
|
||||
num_GL_commands=0 #int 9 The number of gl commands
|
||||
num_frames=0 #int 10 The number of animation frames
|
||||
offset_skins=0 #int 11 The offset in the file for the skin data
|
||||
offset_tex_coords=0 #int 12 The offset in the file for the texture data
|
||||
offset_faces=0 #int 13 The offset in the file for the face data
|
||||
offset_frames=0 #int 14 The offset in the file for the frames data
|
||||
offset_GL_commands=0#int 15 The offset in the file for the gl commands data
|
||||
offset_end=0 #int 16 The end of the file offset
|
||||
|
||||
binary_format="<17i" #little-endian (<), 17 integers (17i)
|
||||
|
||||
#md2 data objects
|
||||
tex_coords=[]
|
||||
faces=[]
|
||||
frames=[]
|
||||
skins=[]
|
||||
|
||||
def __init__ (self):
|
||||
self.tex_coords=[]
|
||||
self.faces=[]
|
||||
self.frames=[]
|
||||
self.skins=[]
|
||||
|
||||
|
||||
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!=844121161 or self.version!=8):
|
||||
print "Not a valid MD2 file"
|
||||
Exit()
|
||||
|
||||
self.skin_width=data[2]
|
||||
self.skin_height=data[3]
|
||||
self.frame_size=data[4]
|
||||
|
||||
#make the # of skin objects for model
|
||||
self.num_skins=data[5]
|
||||
for i in xrange(0,self.num_skins):
|
||||
self.skins.append(md2_skin())
|
||||
|
||||
self.num_vertices=data[6]
|
||||
|
||||
#make the # of texture coordinates for model
|
||||
self.num_tex_coords=data[7]
|
||||
for i in xrange(0,self.num_tex_coords):
|
||||
self.tex_coords.append(md2_tex_coord())
|
||||
|
||||
#make the # of triangle faces for model
|
||||
self.num_faces=data[8]
|
||||
for i in xrange(0,self.num_faces):
|
||||
self.faces.append(md2_face())
|
||||
|
||||
self.num_GL_commands=data[9]
|
||||
|
||||
#make the # of frames for the model
|
||||
self.num_frames=data[10]
|
||||
for i in xrange(0,self.num_frames):
|
||||
self.frames.append(md2_alias_frame())
|
||||
#make the # of vertices for each frame
|
||||
for j in xrange(0,self.num_vertices):
|
||||
self.frames[i].vertices.append(md2_alias_triangle())
|
||||
|
||||
self.offset_skins=data[11]
|
||||
self.offset_tex_coords=data[12]
|
||||
self.offset_faces=data[13]
|
||||
self.offset_frames=data[14]
|
||||
self.offset_GL_commands=data[15]
|
||||
|
||||
#load the skin info
|
||||
file.seek(self.offset_skins,0)
|
||||
for i in xrange(0, self.num_skins):
|
||||
self.skins[i].load(file)
|
||||
#self.skins[i].dump()
|
||||
|
||||
#load the texture coordinates
|
||||
file.seek(self.offset_tex_coords,0)
|
||||
for i in xrange(0, self.num_tex_coords):
|
||||
self.tex_coords[i].load(file)
|
||||
#self.tex_coords[i].dump()
|
||||
|
||||
#load the face info
|
||||
file.seek(self.offset_faces,0)
|
||||
for i in xrange(0, self.num_faces):
|
||||
self.faces[i].load(file)
|
||||
#self.faces[i].dump()
|
||||
|
||||
#load the frames
|
||||
file.seek(self.offset_frames,0)
|
||||
for i in xrange(0, self.num_frames):
|
||||
self.frames[i].load(file)
|
||||
#self.frames[i].dump()
|
||||
for j in xrange(0,self.num_vertices):
|
||||
self.frames[i].vertices[j].load(file)
|
||||
#self.frames[i].vertices[j].dump()
|
||||
return self
|
||||
|
||||
def dump (self):
|
||||
print "Header Information"
|
||||
print "ident: ", self.ident
|
||||
print "version: ", self.version
|
||||
print "skin width: ", self.skin_width
|
||||
print "skin height: ", self.skin_height
|
||||
print "frame size: ", self.frame_size
|
||||
print "number of skins: ", self.num_skins
|
||||
print "number of texture coordinates: ", self.num_tex_coords
|
||||
print "number of faces: ", self.num_faces
|
||||
print "number of frames: ", self.num_frames
|
||||
print "number of vertices: ", self.num_vertices
|
||||
print "offset skins: ", self.offset_skins
|
||||
print "offset texture coordinates: ", self.offset_tex_coords
|
||||
print "offset faces: ", self.offset_faces
|
||||
print "offset frames: ",self.offset_frames
|
||||
print ""
|
||||
|
||||
######################################################
|
||||
# Import functions
|
||||
######################################################
|
||||
def load_textures(md2, texture_filename):
|
||||
#did the user specify a texture they wanted to use?
|
||||
if (texture_filename!="texture"):
|
||||
if (Blender.sys.exists(texture_filename)):
|
||||
mesh_image=Blender.Image.Load(texture_filename)
|
||||
return mesh_image
|
||||
else:
|
||||
result=Blender.Draw.PupMenu("Cannot find texture: "+texture_filename+"-Continue?%t|OK")
|
||||
if(result==1):
|
||||
return -1
|
||||
#does the model have textures specified with it?
|
||||
if int(md2.num_skins) > 0:
|
||||
for i in xrange(0,md2.num_skins):
|
||||
#md2.skins[i].dump()
|
||||
if (Blender.sys.exists(md2.skins[i].name)):
|
||||
mesh_image=Blender.Image.Load(md2.skins[i].name)
|
||||
else:
|
||||
result=Blender.Draw.PupMenu("Cannot find texture: "+md2.skins[i].name+"-Continue?%t|OK")
|
||||
if(result==1):
|
||||
return -1
|
||||
return mesh_image
|
||||
else:
|
||||
result=Blender.Draw.PupMenu("There will be no Texutre"+"-Continue?%t|OK")
|
||||
if(result==1):
|
||||
return -1
|
||||
|
||||
|
||||
def animate_md2(md2, mesh_obj):
|
||||
######### Animate the verts through keyframe animation
|
||||
mesh=mesh_obj.getData()
|
||||
for i in xrange(1, md2.num_frames):
|
||||
#update the vertices
|
||||
for j in xrange(0,md2.num_vertices):
|
||||
x=(md2.frames[i].scale[0]*md2.frames[i].vertices[j].vertices[0]+md2.frames[i].translate[0])*g_scale.val
|
||||
y=(md2.frames[i].scale[1]*md2.frames[i].vertices[j].vertices[1]+md2.frames[i].translate[1])*g_scale.val
|
||||
z=(md2.frames[i].scale[2]*md2.frames[i].vertices[j].vertices[2]+md2.frames[i].translate[2])*g_scale.val
|
||||
|
||||
#put the vertex in the right spot
|
||||
mesh.verts[j].co[0]=y
|
||||
mesh.verts[j].co[1]=-x
|
||||
mesh.verts[j].co[2]=z
|
||||
|
||||
mesh.update()
|
||||
NMesh.PutRaw(mesh, mesh_obj.name)
|
||||
#absolute keys, need to figure out how to get them working around the 100 frame limitation
|
||||
mesh.insertKey(i,"absolute")
|
||||
|
||||
#not really necissary, but I like playing with the frame counter
|
||||
Blender.Set("curframe", i)
|
||||
|
||||
|
||||
def load_md2 (md2_filename, texture_filename):
|
||||
#read the file in
|
||||
file=open(md2_filename,"rb")
|
||||
md2=md2_obj()
|
||||
md2.load(file)
|
||||
#md2.dump()
|
||||
file.close()
|
||||
|
||||
######### Creates a new mesh
|
||||
mesh = NMesh.New()
|
||||
|
||||
uv_coord=[]
|
||||
uv_list=[]
|
||||
|
||||
#load the textures to use later
|
||||
#-1 if there is no texture to load
|
||||
mesh_image=load_textures(md2, texture_filename)
|
||||
|
||||
######### Make the verts
|
||||
DrawProgressBar(0.25,"Loading Vertex Data")
|
||||
for i in xrange(0,md2.num_vertices):
|
||||
#use the first frame for the mesh vertices
|
||||
x=(md2.frames[0].scale[0]*md2.frames[0].vertices[i].vertices[0]+md2.frames[0].translate[0])*g_scale.val
|
||||
y=(md2.frames[0].scale[1]*md2.frames[0].vertices[i].vertices[1]+md2.frames[0].translate[1])*g_scale.val
|
||||
z=(md2.frames[0].scale[2]*md2.frames[0].vertices[i].vertices[2]+md2.frames[0].translate[2])*g_scale.val
|
||||
vertex=NMesh.Vert(y,-x,z)
|
||||
mesh.verts.append(vertex)
|
||||
|
||||
######## Make the UV list
|
||||
DrawProgressBar(0.50,"Loading UV Data")
|
||||
mesh.hasFaceUV(1) #turn on face UV coordinates for this mesh
|
||||
for i in xrange(0, md2.num_tex_coords):
|
||||
u=(float(md2.tex_coords[i].u)/float(md2.skin_width))
|
||||
v=(float(md2.tex_coords[i].v)/float(md2.skin_height))
|
||||
#for some reason quake2 texture maps are upside down, flip that
|
||||
uv_coord=(u,1-v)
|
||||
uv_list.append(uv_coord)
|
||||
|
||||
######### Make the faces
|
||||
DrawProgressBar(0.75,"Loading Face Data")
|
||||
for i in xrange(0,md2.num_faces):
|
||||
face = NMesh.Face()
|
||||
#draw the triangles in reverse order so they show up
|
||||
face.v.append(mesh.verts[md2.faces[i].vertex_index[0]])
|
||||
face.v.append(mesh.verts[md2.faces[i].vertex_index[2]])
|
||||
face.v.append(mesh.verts[md2.faces[i].vertex_index[1]])
|
||||
#append the list of UV
|
||||
#ditto in reverse order with the texture verts
|
||||
face.uv.append(uv_list[md2.faces[i].texture_index[0]])
|
||||
face.uv.append(uv_list[md2.faces[i].texture_index[2]])
|
||||
face.uv.append(uv_list[md2.faces[i].texture_index[1]])
|
||||
|
||||
#set the texture that this face uses if it has one
|
||||
if (mesh_image!=-1):
|
||||
face.image=mesh_image
|
||||
|
||||
#add the face
|
||||
mesh.faces.append(face)
|
||||
|
||||
mesh_obj=NMesh.PutRaw(mesh)
|
||||
animate_md2(md2, mesh_obj)
|
||||
DrawProgressBar(0.999,"Loading Animation Data")
|
||||
|
||||
#locate the Object containing the mesh at the cursor location
|
||||
cursor_pos=Blender.Window.GetCursorPos()
|
||||
mesh_obj.setLocation(float(cursor_pos[0]),float(cursor_pos[1]),float(cursor_pos[2]))
|
||||
DrawProgressBar (1.0, "Finished")
|
||||
|
||||
#***********************************************
|
||||
# MAIN
|
||||
#***********************************************
|
||||
|
||||
# Import globals
|
||||
g_md2_filename=Create("model")
|
||||
g_texture_filename=Create("texture")
|
||||
|
||||
g_filename_search=Create("model")
|
||||
g_texture_search=Create("texture")
|
||||
|
||||
#Globals
|
||||
g_scale=Create(1.0)
|
||||
|
||||
# Events
|
||||
EVENT_NOEVENT=1
|
||||
EVENT_LOAD_MD2=2
|
||||
EVENT_CHOOSE_FILENAME=3
|
||||
EVENT_CHOOSE_TEXTURE=4
|
||||
EVENT_SAVE_MD2=5
|
||||
EVENT_EXIT=100
|
||||
|
||||
######################################################
|
||||
# Callbacks for Window functions
|
||||
######################################################
|
||||
def filename_callback(input_filename):
|
||||
global g_md2_filename
|
||||
g_md2_filename.val=input_filename
|
||||
|
||||
def texture_callback(input_texture):
|
||||
global g_texture_filename
|
||||
g_texture_filename.val=input_texture
|
||||
|
||||
######################################################
|
||||
# GUI Loader
|
||||
######################################################
|
||||
|
||||
|
||||
def draw_gui():
|
||||
global g_scale
|
||||
global g_md2_filename
|
||||
global g_texture_filename
|
||||
global EVENT_NOEVENT,EVENT_LOAD_MD2,EVENT_CHOOSE_FILENAME,EVENT_CHOOSE_TEXTURE,EVENT_EXIT
|
||||
|
||||
########## Titles
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
glRasterPos2d(8, 125)
|
||||
Text("MD2 loader")
|
||||
|
||||
######### Parameters GUI Buttons
|
||||
g_md2_filename = String("MD2 file to load: ", EVENT_NOEVENT, 10, 55, 210, 18,
|
||||
g_md2_filename.val, 255, "MD2 file to load")
|
||||
########## MD2 File Search Button
|
||||
Button("Search",EVENT_CHOOSE_FILENAME,220,55,80,18)
|
||||
|
||||
g_texture_filename = String("Texture file to load: ", EVENT_NOEVENT, 10, 35, 210, 18,
|
||||
g_texture_filename.val, 255, "Texture file to load-overrides MD2 file")
|
||||
########## Texture Search Button
|
||||
Button("Search",EVENT_CHOOSE_TEXTURE,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("Load",EVENT_LOAD_MD2 , 10, 10, 80, 18)
|
||||
Button("Exit",EVENT_EXIT , 170, 10, 80, 18)
|
||||
|
||||
def event(evt, val):
|
||||
if (evt == QKEY and not val):
|
||||
Blender.Draw.Exit()
|
||||
|
||||
def bevent(evt):
|
||||
global g_md2_filename
|
||||
global g_texture_filename
|
||||
global EVENT_NOEVENT,EVENT_LOAD_MD2,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_TEXTURE):
|
||||
FileSelector(texture_callback, "Texture Selection")
|
||||
elif (evt==EVENT_LOAD_MD2):
|
||||
if (g_md2_filename.val == "model"):
|
||||
Blender.Draw.Exit()
|
||||
return
|
||||
else:
|
||||
load_md2(g_md2_filename.val, g_texture_filename.val)
|
||||
Blender.Redraw()
|
||||
Blender.Draw.Exit()
|
||||
return
|
||||
|
||||
|
||||
Register(draw_gui, event, bevent)
|
||||
Reference in New Issue
Block a user