diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-11-13 00:16:53 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-11-13 00:16:53 +0300 |
commit | bdfe7d89e2f1292644577972c716931b4ce3c6c3 (patch) | |
tree | d00eb50b749cb001e2b08272c91791e66740b05d /release/scripts/ms3d_import.py | |
parent | 78a1c27c4a6abe0ed31ca93ad21910f3df04da56 (diff) | |
parent | 7e4db234cee71ead34ee81a12e27da4bd548eb4b (diff) |
Merge of trunk into blender 2.5:
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r12987:17416
Issues:
* GHOST/X11 had conflicting changes. Some code was added in 2.5, which was
later added in trunk also, but reverted partially, specifically revision
16683. I have left out this reversion in the 2.5 branch since I think it is
needed there.
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16683
* Scons had various conflicting changes, I decided to go with trunk version
for everything except priorities and some library renaming.
* In creator.c, there were various fixes and fixes for fixes related to the -w
-W and -p options. In 2.5 -w and -W is not coded yet, and -p is done
differently. Since this is changed so much, and I don't think those fixes
would be needed in 2.5, I've left them out.
* Also in creator.c: there was code for a python bugfix where the screen was not
initialized when running with -P. The code that initializes the screen there
I had to disable, that can't work in 2.5 anymore but left it commented as a
reminder.
Further I had to disable some new function calls. using src/ and python/, as
was done already in this branch, disabled function calls:
* bpath.c: error reporting
* BME_conversions.c: editmesh conversion functions.
* SHD_dynamic: disabled almost completely, there is no python/.
* KX_PythonInit.cpp and Ketsji/ build files: Mathutils is not there, disabled.
* text.c: clipboard copy call.
* object.c: OB_SUPPORT_MATERIAL.
* DerivedMesh.c and subsurf_ccg, stipple_quarttone.
Still to be done:
* Go over files and functions that were moved to a different location but could
still use changes that were done in trunk.
Diffstat (limited to 'release/scripts/ms3d_import.py')
-rw-r--r-- | release/scripts/ms3d_import.py | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/release/scripts/ms3d_import.py b/release/scripts/ms3d_import.py new file mode 100644 index 00000000000..c1438cbfc97 --- /dev/null +++ b/release/scripts/ms3d_import.py @@ -0,0 +1,487 @@ +#!BPY +""" +Name: 'MilkShape3D (.ms3d)...' +Blender: 245 +Group: 'Import' +Tooltip: 'Import from MilkShape3D file format (.ms3d)' +""" +# +# Author: Markus Ilmola +# Email: markus.ilmola@pp.inet.fi +# +# 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. +# + +# import needed stuff +import os.path +import math +from math import * +import struct +import Blender +from Blender import Mathutils +from Blender.Mathutils import * + + +# trims a string by removing ending 0 and everything after it +def uku(s): + try: + return s[:s.index('\0')] + except: + return s + + +# Converts ms3d euler angles to a rotation matrix +def RM(a): + sy = sin(a[2]) + cy = cos(a[2]) + sp = sin(a[1]) + cp = cos(a[1]) + sr = sin(a[0]) + cr = cos(a[0]) + return Matrix([cp*cy, cp*sy, -sp], [sr*sp*cy+cr*-sy, sr*sp*sy+cr*cy, sr*cp],[cr*sp*cy+-sr*-sy, cr*sp*sy+-sr*cy, cr*cp]) + + +# Converts ms3d euler angles to a quaternion +def RQ(a): + angle = a[2] * 0.5; + sy = sin(angle); + cy = cos(angle); + angle = a[1] * 0.5; + sp = sin(angle); + cp = cos(angle); + angle = a[0] * 0.5; + sr = sin(angle); + cr = cos(angle); + return Quaternion(cr*cp*cy+sr*sp*sy, sr*cp*cy-cr*sp*sy, cr*sp*cy+sr*cp*sy, cr*cp*sy-sr*sp*cy) + + +# takes a texture filename and tries to load it +def loadImage(path, filename): + image = None + try: + image = Blender.Image.Load(os.path.abspath(filename)) + except IOError: + print "Warning: Failed to load image: " + filename + ". Trying short path instead...\n" + try: + image = Blender.Image.Load(os.path.dirname(path) + "/" + os.path.basename(filename)) + except IOError: + print "Warning: Failed to load image: " + os.path.basename(filename) + "!\n" + return image + + +# imports a ms3d file to the current scene +def import_ms3d(path): + # get scene + scn = Blender.Scene.GetCurrent() + if scn == None: + return "No scene to import to!" + + # open the file + try: + file = open(path, 'rb') + except IOError: + return "Failed to open the file!" + + # get the file size + file.seek(0, os.SEEK_END); + fileSize = file.tell(); + file.seek(0, os.SEEK_SET); + + # read id to check if the file is a MilkShape3D file + id = file.read(10) + if id!="MS3D000000": + return "The file is not a MS3D file!" + + # read version + version = struct.unpack("i", file.read(4))[0] + if version!=4: + return "The file has invalid version!" + + # Create the mesh + scn.objects.selected = [] + mesh = Blender.Mesh.New("MilkShape3D Mesh") + meshOb = scn.objects.new(mesh) + + # read the number of vertices + numVertices = struct.unpack("H", file.read(2))[0] + + # read vertices + coords = [] + boneIds = [] + for i in xrange(numVertices): + # skip flags + file.read(1) + + # read coords + coords.append(struct.unpack("fff", file.read(3*4))) + + # read bone ids + boneIds.append(struct.unpack("b", file.read(1))[0]) + + # skip refcount + file.read(1) + + # add the vertices to the mesh + mesh.verts.extend(coords) + + # read number of triangles + numTriangles = struct.unpack("H", file.read(2))[0] + + # read triangles + faces = [] + uvs = [] + for i in xrange(numTriangles): + # skip flags + file.read(2) + + # read indices (faces) + faces.append(struct.unpack("HHH", file.read(3*2))) + + # read normals + normals = struct.unpack("fffffffff", file.read(3*3*4)) + + # read texture coordinates + s = struct.unpack("fff", file.read(3*4)) + t = struct.unpack("fff", file.read(3*4)) + + # store texture coordinates + uvs.append([[s[0], 1-t[0]], [s[1], 1-t[1]], [s[2], 1-t[2]]]) + + if faces[-1][2] == 0: # Cant have zero at the third index + faces[-1] = faces[-1][1], faces[-1][2], faces[-1][0] + uvs[-1] = uvs[-1][1], uvs[-1][2], uvs[-1][0] + + # skip smooth group + file.read(1) + + # skip group + file.read(1) + + # add the faces to the mesh + mesh.faces.extend(faces) + + # set texture coordinates + for i in xrange(numTriangles): + mesh.faces[i].uv = [Vector(uvs[i][0]), Vector(uvs[i][1]), Vector(uvs[i][2])] + + # read number of groups + numGroups = struct.unpack("H", file.read(2))[0] + + # read groups + for i in xrange(numGroups): + # skip flags + file.read(1) + + # skip name + file.read(32) + + # read the number of triangles in the group + numGroupTriangles = struct.unpack("H", file.read(2))[0] + + # read the group triangles + if numGroupTriangles > 0: + triangleIndices = struct.unpack(str(numGroupTriangles) + "H", file.read(2*numGroupTriangles)); + + # read material + material = struct.unpack("b", file.read(1))[0] + if material>=0: + for j in xrange(numGroupTriangles): + mesh.faces[triangleIndices[j]].mat = material + + # read the number of materials + numMaterials = struct.unpack("H", file.read(2))[0] + + # read materials + for i in xrange(numMaterials): + # read name + name = uku(file.read(32)) + + # create the material + mat = Blender.Material.New(name) + mesh.materials += [mat] + + # read ambient color + ambient = struct.unpack("ffff", file.read(4*4))[0:3] + mat.setAmb((ambient[0]+ambient[1]+ambient[2])/3) + + # read diffuse color + diffuse = struct.unpack("ffff", file.read(4*4))[0:3] + mat.setRGBCol(diffuse) + + # read specular color + specular = struct.unpack("ffff", file.read(4*4))[0:3] + mat.setSpecCol(specular) + + # read emissive color + emissive = struct.unpack("ffff", file.read(4*4))[0:3] + mat.setEmit((emissive[0]+emissive[1]+emissive[2])/3) + + # read shininess + shininess = struct.unpack("f", file.read(4))[0] + + # read transparency + transparency = struct.unpack("f", file.read(4))[0] + mat.setAlpha(transparency) + if transparency < 1: + mat.mode |= Blender.Material.Modes.ZTRANSP + + # read mode + mode = struct.unpack("B", file.read(1))[0] + + # read texturemap + texturemap = uku(file.read(128)) + if len(texturemap)>0: + colorTexture = Blender.Texture.New(name + "_texture") + colorTexture.setType('Image') + colorTexture.setImage(loadImage(path, texturemap)) + mat.setTexture(0, colorTexture, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL) + + # read alphamap + alphamap = uku(file.read(128)) + if len(alphamap)>0: + alphaTexture = Blender.Texture.New(name + "_alpha") + alphaTexture.setType('Image') + alphaTexture.setImage(loadImage(path, alphamap)) + mat.setTexture(1, alphaTexture, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.ALPHA) + + # read animation + fps = struct.unpack("f", file.read(4))[0] + time = struct.unpack("f", file.read(4))[0] + frames = struct.unpack("i", file.read(4))[0] + + # read the number of joints + numJoints = struct.unpack("H", file.read(2))[0] + + # create the armature + armature = 0 + armOb = 0 + if numJoints > 0: + armOb = Blender.Object.New('Armature', "MilkShape3D Skeleton") + armature = Blender.Armature.New("MilkShape3D Skeleton") + armature.drawType = Blender.Armature.STICK + armOb.link(armature) + scn.objects.link(armOb) + armOb.makeParentDeform([meshOb]) + armature.makeEditable() + + # read joints + joints = [] + rotKeys = {} + posKeys = {} + for i in xrange(numJoints): + # skip flags + file.read(1) + + # read name + name = uku(file.read(32)) + joints.append(name) + + # create the bone + bone = Blender.Armature.Editbone() + armature.bones[name] = bone + + # read parent + parent = uku(file.read(32)) + if len(parent)>0: + bone.parent = armature.bones[parent] + + # read orientation + rot = struct.unpack("fff", file.read(3*4)) + + # read position + pos = struct.unpack("fff", file.read(3*4)) + + # set head + if bone.hasParent(): + bone.head = Vector(pos) * bone.parent.matrix + bone.parent.head + tempM = RM(rot) * bone.parent.matrix + tempM.transpose; + bone.matrix = tempM + else: + bone.head = Vector(pos) + bone.matrix = RM(rot) + + # set tail + bvec = bone.tail - bone.head + bvec.normalize() + bone.tail = bone.head + 0.01 * bvec + + # Create vertex group for this bone + mesh.addVertGroup(name) + vgroup = [] + for index, v in enumerate(boneIds): + if v==i: + vgroup.append(index) + mesh.assignVertsToGroup(name, vgroup, 1.0, 1) + + # read the number of rotation keys + numKeyFramesRot = struct.unpack("H", file.read(2))[0] + + # read the number of postions keys + numKeyFramesPos = struct.unpack("H", file.read(2))[0] + + # read rotation keys + rotKeys[name] = [] + for j in xrange(numKeyFramesRot): + # read time + time = fps * struct.unpack("f", file.read(4))[0] + # read data + rotKeys[name].append([time, struct.unpack("fff", file.read(3*4))]) + + # read position keys + posKeys[name] = [] + for j in xrange(numKeyFramesPos): + # read time + time = fps * struct.unpack("f", file.read(4))[0] + # read data + posKeys[name].append([time, struct.unpack("fff", file.read(3*4))]) + + # create action and pose + action = 0 + pose = 0 + if armature!=0: + armature.update() + pose = armOb.getPose() + action = armOb.getAction() + if not action: + action = Blender.Armature.NLA.NewAction() + action.setActive(armOb) + + # create animation key frames + for name, pbone in pose.bones.items(): + # create position keys + for key in posKeys[name]: + pbone.loc = Vector(key[1]) + pbone.insertKey(armOb, int(key[0]+0.5), Blender.Object.Pose.LOC, True) + + # create rotation keys + for key in rotKeys[name]: + pbone.quat = RQ(key[1]) + pbone.insertKey(armOb, int(key[0]+0.5), Blender.Object.Pose.ROT, True) + + # The old format ends here. If there is more data then the file is newer version + + # check to see if there are any comments + if file.tell()<fileSize: + + # read sub version + subVersion = struct.unpack("i", file.read(4))[0] + + # Is the sub version a supported one + if subVersion==1: + + # Group comments + numComments = struct.unpack("i", file.read(4))[0] + for i in range(numComments): + file.read(4) # index + size = struct.unpack("i", file.read(4))[0] # comment size + if size>0: + print "Group comment: " + file.read(size) + + # Material comments + numComments = struct.unpack("i", file.read(4))[0] + for i in range(numComments): + file.read(4) # index + size = struct.unpack("i", file.read(4))[0] # comment size + if size>0: + print "Material comment: " + file.read(size) + + # Joint comments + numComments = struct.unpack("i", file.read(4))[0] + for i in range(numComments): + file.read(4) # index + size = struct.unpack("i", file.read(4))[0] # comment size + if size>0: + print "Joint comment: " + file.read(size) + + # Model comments + numComments = struct.unpack("i", file.read(4))[0] + for i in range(numComments): + file.read(4) # index + size = struct.unpack("i", file.read(4))[0] # comment size + if size>0: + print "Model comment: " + file.read(size) + + # Unknown version give a warning + else: + print "Warning: Unknown version!" + + + # check to see if there is any extra vertex data + if file.tell()<fileSize: + + # read the subversion + subVersion = struct.unpack("i", file.read(4))[0] + + # is the version supported + if subVersion==2: + # read the extra data for each vertex + for i in xrange(numVertices): + # bone ids + ids = struct.unpack("bbb", file.read(3)) + # weights + weights = struct.unpack("BBB", file.read(3)) + # extra + extra = struct.unpack("I", file.read(4)) + # add extra vertices with weights to deform groups + if ids[0]>=0 or ids[1]>=0 or ids[2]>=0: + mesh.assignVertsToGroup(joints[boneIds[i]], [i], 0.01*weights[0], 1) + if ids[0]>=0: + mesh.assignVertsToGroup(joints[ids[0]], [i], 0.01*weights[1], 1) + if ids[1]>=0: + mesh.assignVertsToGroup(joints[ids[1]], [i], 0.01*weights[2], 1) + if ids[2]>=0: + mesh.assignVertsToGroup(joints[ids[2]], [i], 0.01*(100-(weights[0]+weights[1]+weights[2])), 1) + + elif subVersion==1: + # read extra data for each vertex + for i in xrange(numVertices): + # bone ids + ids = struct.unpack("bbb", file.read(3)) + # weights + weights = struct.unpack("BBB", file.read(3)) + # add extra vertices with weights to deform groups + if ids[0]>=0 or ids[1]>=0 or ids[2]>=0: + mesh.assignVertsToGroup(joints[boneIds[i]], [i], 0.01*weights[0], 1) + if ids[0]>=0: + mesh.assignVertsToGroup(joints[ids[0]], [i], 0.01*weights[1], 1) + if ids[1]>=0: + mesh.assignVertsToGroup(joints[ids[1]], [i], 0.01*weights[2], 1) + if ids[2]>=0: + mesh.assignVertsToGroup(joints[ids[2]], [i], 0.01*(100-(weights[0]+weights[1]+weights[2])), 1) + + # non supported subversion give a warning + else: + print "Warning: Unknown subversion!" + + # rest of the extra data in the file is not imported/used + + # refresh the view + Blender.Redraw() + + # close the file + file.close() + + # succes return empty error string + return "" + + +# load the model +def fileCallback(filename): + error = import_ms3d(filename) + if error!="": + Blender.Draw.PupMenu("An error occured during import: " + error + "|Not all data might have been imported succesfully.", 2) + +Blender.Window.FileSelector(fileCallback, 'Import') |