Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'release/scripts/ms3d_import_ascii.py')
-rw-r--r--release/scripts/ms3d_import_ascii.py479
1 files changed, 479 insertions, 0 deletions
diff --git a/release/scripts/ms3d_import_ascii.py b/release/scripts/ms3d_import_ascii.py
new file mode 100644
index 00000000000..d8c22a1ec99
--- /dev/null
+++ b/release/scripts/ms3d_import_ascii.py
@@ -0,0 +1,479 @@
+#!BPY
+"""
+Name: 'MilkShape3D ASCII (.txt)...'
+Blender: 245
+Group: 'Import'
+Tooltip: 'Import from a MilkShape3D ASCII file format (.txt)'
+"""
+#
+# 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 re
+import math
+from math import *
+import Blender
+from Blender import Mathutils
+from Blender.Mathutils import *
+
+
+
+# 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
+
+
+
+# returns the next non-empty, non-comment line from the file
+def getNextLine(file):
+ ready = False
+ while ready==False:
+ line = file.readline()
+ if len(line)==0:
+ print "Warning: End of file reached."
+ return line
+ ready = True
+ line = line.strip()
+ if len(line)==0 or line.isspace():
+ ready = False
+ if len(line)>=2 and line[0]=='/' and line[1]=='/':
+ ready = False
+ return line
+
+
+
+# imports a MilkShape3D ascii file to the current scene
+def import_ms3d_ascii(path):
+ # limits
+ MAX_NUMMESHES = 1000
+ MAX_NUMVERTS = 100000
+ MAX_NUMNORMALS = 100000
+ MAX_NUMTRIS = 100000
+ MAX_NUMMATS = 16
+ MAX_NUMBONES = 100
+ MAX_NUMPOSKEYS = 1000
+ MAX_NUMROTKEYS = 1000
+
+ # get scene
+ scn = Blender.Scene.GetCurrent()
+ if scn==None:
+ return "No scene to import to!"
+
+ # open the file
+ try:
+ file = open(path, 'r')
+ except IOError:
+ return "Failed to open the file!"
+
+ # Read frame info
+ try:
+ lines = getNextLine(file).split()
+ if len(lines) != 2 or lines[0] != "Frames:":
+ raise ValueError
+ lines = getNextLine(file).split()
+ if len(lines) != 2 or lines[0] != "Frame:":
+ raise ValueError
+ except ValueError:
+ return "Frame information is invalid!"
+
+ # Create the mesh
+ meshOb = Blender.Object.New('Mesh', "MilkShape3D Object")
+ mesh = Blender.Mesh.New("MilkShape3D Mesh")
+ meshOb.link(mesh)
+ scn.objects.link(meshOb)
+
+ # read the number of meshes
+ try:
+ lines = getNextLine(file).split()
+ if len(lines)!=2 or lines[0]!="Meshes:":
+ raise ValueError
+ numMeshes = int(lines[1])
+ if numMeshes < 0 or numMeshes > MAX_NUMMESHES:
+ raise ValueError
+ except ValueError:
+ return "Number of meshes is invalid!"
+
+ # read meshes
+ vertBase = 0
+ faceBase = 0
+ boneIds = []
+ for i in range(numMeshes):
+ # read name, flags and material
+ try:
+ lines = re.findall(r'\".*\"|[^ ]+', getNextLine(file))
+ if len(lines)!=3:
+ raise ValueError
+ material = int(lines[2])
+ except ValueError:
+ return "Name, flags or material in mesh " + str(i+1) + " are invalid!"
+
+ # read the number of vertices
+ try:
+ numVerts = int(getNextLine(file))
+ if numVerts < 0 or numVerts > MAX_NUMVERTS:
+ raise ValueError
+ except ValueError:
+ return "Number of vertices in mesh " + str(i+1) + " is invalid!"
+
+ # read vertices
+ coords = []
+ uvs = []
+ for j in xrange(numVerts):
+ try:
+ lines = getNextLine(file).split()
+ if len(lines)!=7:
+ raise ValueError
+ coords.append([float(lines[1]), float(lines[2]), float(lines[3])])
+ uvs.append([float(lines[4]), 1-float(lines[5])])
+ boneIds.append(int(lines[6]))
+ except ValueError:
+ return "Vertex " + str(j+1) + " in mesh " + str(i+1) + " is invalid!"
+ mesh.verts.extend(coords)
+
+ # read number of normals
+ try:
+ numNormals = int(getNextLine(file))
+ if numNormals < 0 or numNormals > MAX_NUMNORMALS:
+ raise ValueError
+ except ValueError:
+ return "Number of normals in mesh " + str(i+1) + " is invalid!"
+
+ # read normals
+ normals = []
+ for j in xrange(numNormals):
+ try:
+ lines = getNextLine(file).split()
+ if len(lines)!=3:
+ raise ValueError
+ normals.append([float(lines[0]), float(lines[1]), float(lines[2])])
+ except ValueError:
+ return "Normal " + str(j+1) + " in mesh " + str(i+1) + " is invalid!"
+
+ # read the number of triangles
+ try:
+ numTris = int(getNextLine(file))
+ if numTris < 0 or numTris > MAX_NUMTRIS:
+ raise ValueError
+ except ValueError:
+ return "Number of triangles in mesh " + str(i+1) + " is invalid!"
+
+ # read triangles
+ faces = []
+ for j in xrange(numTris):
+ # read the triangle
+ try:
+ lines = getNextLine(file).split()
+ if len(lines)!=8:
+ raise ValueError
+ v1 = int(lines[1])
+ v2 = int(lines[2])
+ v3 = int(lines[3])
+ faces.append([v1+vertBase, v2+vertBase, v3+vertBase])
+ except ValueError:
+ return "Triangle " + str(j+1) + " in mesh " + str(i+1) + " is invalid!"
+ mesh.faces.extend(faces)
+
+ # set texture coordinates and material
+ for j in xrange(faceBase, len(mesh.faces)):
+ face = mesh.faces[j]
+ face.uv = [Vector(uvs[face.verts[0].index-vertBase]), Vector(uvs[face.verts[1].index-vertBase]), Vector(uvs[face.verts[2].index-vertBase])]
+ if material>=0:
+ face.mat = material
+
+ # increase vertex and face base
+ vertBase = len(mesh.verts)
+ faceBase = len(mesh.faces)
+
+ # read the number of materials
+ try:
+ lines = getNextLine(file).split()
+ if len(lines)!=2 or lines[0]!="Materials:":
+ raise ValueError
+ numMats = int(lines[1])
+ if numMats < 0 or numMats > MAX_NUMMATS:
+ raise ValueError
+ except ValueError:
+ return "Number of materials is invalid!"
+
+ # read the materials
+ for i in range(numMats):
+ # read name
+ name = getNextLine(file)[1:-1]
+
+ # create the material
+ mat = Blender.Material.New(name)
+ mesh.materials += [mat]
+
+ # read ambient color
+ try:
+ lines = getNextLine(file).split()
+ if len(lines)!=4:
+ raise ValueError
+ amb = (float(lines[0])+float(lines[1])+float(lines[2]))/3
+ mat.setAmb(amb)
+ except ValueError:
+ return "Ambient color in material " + str(i+1) + " is invalid!"
+
+ # read diffuse color
+ try:
+ lines = getNextLine(file).split()
+ if len(lines)!=4:
+ raise ValueError
+ mat.setRGBCol([float(lines[0]), float(lines[1]), float(lines[2])])
+ except ValueError:
+ return "Diffuse color in material " + str(i+1) + " is invalid!"
+
+ # read specular color
+ try:
+ lines = getNextLine(file).split()
+ if len(lines)!=4:
+ raise ValueError
+ mat.setSpecCol([float(lines[0]), float(lines[1]), float(lines[2])])
+ except ValueError:
+ return "Specular color in material " + str(i+1) + " is invalid!"
+
+ # read emissive color
+ try:
+ lines = getNextLine(file).split()
+ if len(lines)!=4:
+ raise ValueError
+ emit = (float(lines[0])+float(lines[1])+float(lines[2]))/3
+ mat.setEmit(emit)
+ except ValueError:
+ return "Emissive color in material " + str(i+1) + " is invalid!"
+
+ # read shininess
+ try:
+ shi = float(getNextLine(file))
+ #mat.setHardness(int(shi))
+ except ValueError:
+ return "Shininess in material " + str(i+1) + " is invalid!"
+
+ # read transparency
+ try:
+ alpha = float(getNextLine(file))
+ mat.setAlpha(alpha)
+ if alpha < 1:
+ mat.mode |= Blender.Material.Modes.ZTRANSP
+ except ValueError:
+ return "Transparency in material " + str(i+1) + " is invalid!"
+
+ # read texturemap
+ texturemap = getNextLine(file)[1:-1]
+ 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 = getNextLine(file)[1:-1]
+ 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 the number of bones
+ try:
+ lines = getNextLine(file).split()
+ if len(lines)!=2 or lines[0]!="Bones:":
+ raise ValueError
+ numBones = int(lines[1])
+ if numBones < 0 or numBones > MAX_NUMBONES:
+ raise ValueError
+ except:
+ return "Number of bones is invalid!"
+
+ # create the armature
+ armature = None
+ armOb = None
+ if numBones > 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 bones
+ posKeys = {}
+ rotKeys = {}
+ for i in range(numBones):
+ # read name
+ name = getNextLine(file)[1:-1]
+
+ # create the bone
+ bone = Blender.Armature.Editbone()
+ armature.bones[name] = bone
+
+ # read parent
+ parent = getNextLine(file)[1:-1]
+ if len(parent)>0:
+ bone.parent = armature.bones[parent]
+
+ # read position and rotation
+ try:
+ lines = getNextLine(file).split()
+ if len(lines) != 7:
+ raise ValueError
+ pos = [float(lines[1]), float(lines[2]), float(lines[3])]
+ rot = [float(lines[4]), float(lines[5]), float(lines[6])]
+ except ValueError:
+ return "Invalid position or orientation in a bone!"
+
+ # set position and orientation
+ if bone.hasParent():
+ bone.head = Vector(pos) * bone.parent.matrix + bone.parent.head
+ bone.tail = bone.head + Vector([1,0,0])
+ tempM = RM(rot) * bone.parent.matrix
+ tempM.transpose;
+ bone.matrix = tempM
+ else:
+ bone.head = Vector(pos)
+ bone.tail = bone.head + Vector([1,0,0])
+ bone.matrix = RM(rot)
+
+ # 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 position key frames
+ try:
+ numPosKeys = int(getNextLine(file))
+ if numPosKeys < 0 or numPosKeys > MAX_NUMPOSKEYS:
+ raise ValueError
+ except ValueError:
+ return "Invalid number of position key frames!"
+
+ # read position key frames
+ posKeys[name] = []
+ for j in range(numPosKeys):
+ # read time and position
+ try:
+ lines = getNextLine(file).split()
+ if len(lines) != 4:
+ raise ValueError
+ time = float(lines[0])
+ pos = [float(lines[1]), float(lines[2]), float(lines[3])]
+ posKeys[name].append([time, pos])
+ except ValueError:
+ return "Invalid position key frame!"
+
+ # read the number of rotation key frames
+ try:
+ numRotKeys = int(getNextLine(file))
+ if numRotKeys < 0 or numRotKeys > MAX_NUMROTKEYS:
+ raise ValueError
+ except ValueError:
+ return "Invalid number of rotation key frames!"
+
+ # read rotation key frames
+ rotKeys[name] = []
+ for j in range(numRotKeys):
+ # read time and rotation
+ try:
+ lines = getNextLine(file).split()
+ if len(lines) != 4:
+ raise ValueError
+ time = float(lines[0])
+ rot = [float(lines[1]), float(lines[2]), float(lines[3])]
+ rotKeys[name].append([time, rot])
+ except ValueError:
+ return "Invalid rotation key frame!"
+
+ # create action and pose
+ action = None
+ pose = None
+ if armature != None:
+ 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)
+
+ # set the imported object to be the selected one
+ scn.objects.selected = []
+ meshOb.sel= 1
+ Blender.Redraw()
+
+ # The import was a succes!
+ return ""
+
+
+# load the model
+def fileCallback(filename):
+ error = import_ms3d_ascii(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')