[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [4812] trunk/py/scripts/addons/ io_import_scene_mhx.py: MHX importer: Added support for loading and saving mcp files, which is a simplified format for storing poses used by MH.

Thomas Larsson thomas_larsson_01 at hotmail.com
Mon Oct 21 04:47:39 CEST 2013


Revision: 4812
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=4812
Author:   thomasl
Date:     2013-10-21 02:47:39 +0000 (Mon, 21 Oct 2013)
Log Message:
-----------
MHX importer: Added support for loading and saving mcp files, which is a simplified format for storing poses used by MH. 

Modified Paths:
--------------
    trunk/py/scripts/addons/io_import_scene_mhx.py

Modified: trunk/py/scripts/addons/io_import_scene_mhx.py
===================================================================
--- trunk/py/scripts/addons/io_import_scene_mhx.py	2013-10-20 19:25:46 UTC (rev 4811)
+++ trunk/py/scripts/addons/io_import_scene_mhx.py	2013-10-21 02:47:39 UTC (rev 4812)
@@ -38,7 +38,7 @@
 bl_info = {
     'name': 'Import: MakeHuman (.mhx)',
     'author': 'Thomas Larsson',
-    'version': (1, 16, 8),
+    'version': "1.16.9",
     "blender": (2, 68, 0),
     'location': "File > Import > MakeHuman (.mhx)",
     'description': 'Import files in the MakeHuman eXchange format (.mhx)',
@@ -65,7 +65,7 @@
 import time
 import math
 import mathutils
-from mathutils import Vector, Matrix
+from mathutils import Vector, Matrix, Quaternion
 from bpy.props import *
 
 MHX249 = False
@@ -2909,7 +2909,7 @@
 #
 ###################################################################################
 
-from bpy_extras.io_utils import ImportHelper
+from bpy_extras.io_utils import ImportHelper, ExportHelper
 
 MhxBoolProps = [
     ("enforce", "Enforce version", "Only accept MHX files of correct version", T_EnforceVersion),
@@ -2996,6 +2996,247 @@
 
 ###################################################################################
 #
+#    Main panel
+#
+###################################################################################
+
+MhxLayers = [
+    (( 0,    'Root', 'MhxRoot'),
+     ( 8,    'Face', 'MhxFace')),
+    (( 9,    'Tweak', 'MhxTweak'),
+     (10,    'Head', 'MhxHead')),
+    (( 1,    'FK Spine', 'MhxFKSpine'),
+     #(17,    'IK Spine', 'MhxIKSpine')),
+     #((13,    'Inv FK Spine', 'MhxInvFKSpine'),
+     (16,    'Clothes', 'MhxClothes')),
+    ('Left', 'Right'),
+    (( 2,    'IK Arm', 'MhxIKArm'),
+     (18,    'IK Arm', 'MhxIKArm')),
+    (( 3,    'FK Arm', 'MhxFKArm'),
+     (19,    'FK Arm', 'MhxFKArm')),
+    (( 4,    'IK Leg', 'MhxIKLeg'),
+     (20,    'IK Leg', 'MhxIKLeg')),
+    (( 5,    'FK Leg', 'MhxFKLeg'),
+     (21,    'FK Leg', 'MhxFKLeg')),
+    ((12,    'Extra', 'MhxExtra'),
+     (28,    'Extra', 'MhxExtra')),
+    (( 6,    'Fingers', 'MhxFingers'),
+     (22,    'Fingers', 'MhxFingers')),
+    (( 7,    'Links', 'MhxLinks'),
+     (23,    'Links', 'MhxLinks')),
+    ((11,    'Palm', 'MhxPalm'),
+     (27,    'Palm', 'MhxPalm')),
+]
+
+#
+#    class MhxMainPanel(bpy.types.Panel):
+#
+
+class MhxMainPanel(bpy.types.Panel):
+    bl_label = "MHX Main v %s" % bl_info["version"]
+    bl_space_type = "VIEW_3D"
+    bl_region_type = "UI"
+    #bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.object and context.object.MhxRig)
+
+    def draw(self, context):
+        layout = self.layout
+        layout.label("Layers")
+        layout.operator("mhx.pose_enable_all_layers")
+        layout.operator("mhx.pose_disable_all_layers")
+        amt = context.object.data
+        for (left,right) in MhxLayers:
+            row = layout.row()
+            if type(left) == str:
+                row.label(left)
+                row.label(right)
+            else:
+                for (n, name, prop) in [left,right]:
+                    row.prop(amt, "layers", index=n, toggle=True, text=name)
+
+        layout.separator()
+        layout.label("Export/Import MHP")
+        layout.operator("mhx.saveas_mhp")
+        layout.operator("mhx.load_mhp")
+
+
+class VIEW3D_OT_MhxEnableAllLayersButton(bpy.types.Operator):
+    bl_idname = "mhx.pose_enable_all_layers"
+    bl_label = "Enable all layers"
+    bl_options = {'UNDO'}
+
+    def execute(self, context):
+        rig,mesh = getMhxRigMesh(context.object)
+        for (left,right) in MhxLayers:
+            if type(left) != str:
+                for (n, name, prop) in [left,right]:
+                    rig.data.layers[n] = True
+        return{'FINISHED'}
+
+
+class VIEW3D_OT_MhxDisableAllLayersButton(bpy.types.Operator):
+    bl_idname = "mhx.pose_disable_all_layers"
+    bl_label = "Disable all layers"
+    bl_options = {'UNDO'}
+
+    def execute(self, context):
+        rig,mesh = getMhxRigMesh(context.object)
+        layers = 32*[False]
+        pb = context.active_pose_bone
+        if pb:
+            for n in range(32):
+                if pb.bone.layers[n]:
+                    layers[n] = True
+                    break
+        else:
+            layers[0] = True
+        if rig:
+            rig.data.layers = layers
+        return{'FINISHED'}
+
+
+
+def saveMhpFile(rig, scn, filepath):
+    roots = []
+    for pb in rig.pose.bones:
+        if pb.parent is None:
+            roots.append(pb)
+
+    (pname, ext) = os.path.splitext(filepath)
+    mhppath = pname + ".mhp"
+
+    fp = open(mhppath, "w", encoding="utf-8", newline="\n")
+    for root in roots:
+        writeMhpBones(fp, root, None)
+    fp.close()
+    print("Mhp file %s saved" % mhppath)
+
+
+def writeMhpBones(fp, pb, log):
+    if not isMuscleBone(pb):
+        b = pb.bone
+        if pb.parent:
+            string = "quat"
+            mat = b.matrix_local.inverted() * b.parent.matrix_local * pb.parent.matrix.inverted() * pb.matrix
+        else:
+            string = "gquat"
+            mat = pb.matrix.copy()
+            maty = mat[1].copy()
+            matz = mat[2].copy()
+            mat[1] = matz
+            mat[2] = -maty
+
+        t,q,s = mat.decompose()
+        magn = math.sqrt(q.x*q.x + q.y*q.y + q.z*q.z)
+        if magn > 1e-5:
+            fp.write("%s\t%s\t%.5f\t%.5f\t%.5f\t%.5f\n" % (pb.name, string, q.w, q.x, q.y, q.z))
+
+    for child in pb.children:
+        writeMhpBones(fp, child, log)
+
+
+def isMuscleBone(pb):
+    layers = pb.bone.layers
+    if (layers[14] or layers[15] or layers[30] or layers[31]):
+        return True
+    for cns in pb.constraints:
+        if (cns.type == 'STRETCH_TO' or
+            cns.type == 'TRANSFORM' or
+            cns.type == 'TRACK_TO' or
+            cns.type == 'IK' or
+            cns.type[0:5] == 'COPY_'):
+            return True
+    return False
+
+
+def loadMhpFile(rig, scn, filepath):
+    (pname, ext) = os.path.splitext(filepath)
+    mhppath = pname + ".mhp"
+
+    fp = open(mhppath, "rU")
+    for line in fp:
+        words = line.split()
+        if len(words) < 4:
+            continue
+        elif words[1] == "quat":
+            try:
+                pb = rig.pose.bones[words[0]]
+            except KeyError:
+                print("Warning: Did not find bone %s" % words[0])
+                continue
+            if not isMuscleBone(pb):
+                q = Quaternion((float(words[2]), float(words[3]), float(words[4]), float(words[5])))
+                mat = q.to_matrix().to_4x4()
+                pb.matrix_basis = mat
+        elif words[1] == "gquat":
+            try:
+                pb = rig.pose.bones[words[0]]
+            except KeyError:
+                print("Warning: Did not find bone %s" % words[0])
+                continue
+            q = Quaternion((float(words[2]), float(words[3]), float(words[4]), float(words[5])))
+            mat = q.to_matrix().to_4x4()
+            maty = mat[1].copy()
+            matz = mat[2].copy()
+            mat[1] = -matz
+            mat[2] = maty
+            pb.matrix_basis = pb.bone.matrix_local.inverted() * mat
+        elif words[1] == "scale":
+            pass
+        else:
+            print("WARNING: Unknown line in mcp file:\n%s" % line)
+    fp.close()
+    print("Mhp file %s loaded" % mhppath)
+
+
+class VIEW3D_OT_LoadMhpButton(bpy.types.Operator):
+    bl_idname = "mhx.load_mhp"
+    bl_label = "Load MHP File"
+    bl_description = "Load a pose in MHP format"
+    bl_options = {'UNDO'}
+
+    filename_ext = ".mhp"
+    filter_glob = StringProperty(default="*.mhp", options={'HIDDEN'})
+    filepath = bpy.props.StringProperty(
+        name="File Path",
+        description="File path used for mhp file",
+        maxlen= 1024, default= "")
+
+    def execute(self, context):
+        loadMhpFile(context.object, context.scene, self.properties.filepath)
+        return {'FINISHED'}
+
+    def invoke(self, context, event):
+        context.window_manager.fileselect_add(self)
+        return {'RUNNING_MODAL'}
+
+
+class VIEW3D_OT_SaveasMhpFileButton(bpy.types.Operator, ExportHelper):
+    bl_idname = "mhx.saveas_mhp"
+    bl_label = "Save MHP File"
+    bl_description = "Save current pose in MHP format"
+    bl_options = {'UNDO'}
+
+    filename_ext = ".mhp"
+    filter_glob = StringProperty(default="*.mhp", options={'HIDDEN'})
+    filepath = bpy.props.StringProperty(
+        name="File Path",
+        description="File path used for mhp file",
+        maxlen= 1024, default= "")
+
+    def execute(self, context):
+        saveMhpFile(context.object, context.scene, self.properties.filepath)
+        return {'FINISHED'}
+
+    def invoke(self, context, event):
+        context.window_manager.fileselect_add(self)
+        return {'RUNNING_MODAL'}
+
+###################################################################################
+#
 #    Lipsync panel
 #
 ###################################################################################
@@ -4193,7 +4434,6 @@
         updatePose(context)
         return{'FINISHED'}
 
-
 #
 #   MHX FK/IK Switch panel
 #
@@ -4447,102 +4687,6 @@
 
 ###################################################################################
 #
-#    Layers panel
-#
-###################################################################################
-
-MhxLayers = [
-    (( 0,    'Root', 'MhxRoot'),
-     ( 8,    'Face', 'MhxFace')),
-    (( 9,    'Tweak', 'MhxTweak'),
-     (10,    'Head', 'MhxHead')),
-    (( 1,    'FK Spine', 'MhxFKSpine'),
-     #(17,    'IK Spine', 'MhxIKSpine')),
-     #((13,    'Inv FK Spine', 'MhxInvFKSpine'),
-     (16,    'Clothes', 'MhxClothes')),
-    ('Left', 'Right'),
-    (( 2,    'IK Arm', 'MhxIKArm'),
-     (18,    'IK Arm', 'MhxIKArm')),
-    (( 3,    'FK Arm', 'MhxFKArm'),
-     (19,    'FK Arm', 'MhxFKArm')),
-    (( 4,    'IK Leg', 'MhxIKLeg'),
-     (20,    'IK Leg', 'MhxIKLeg')),
-    (( 5,    'FK Leg', 'MhxFKLeg'),
-     (21,    'FK Leg', 'MhxFKLeg')),
-    ((12,    'Extra', 'MhxExtra'),
-     (28,    'Extra', 'MhxExtra')),
-    (( 6,    'Fingers', 'MhxFingers'),
-     (22,    'Fingers', 'MhxFingers')),
-    (( 7,    'Links', 'MhxLinks'),
-     (23,    'Links', 'MhxLinks')),
-    ((11,    'Palm', 'MhxPalm'),
-     (27,    'Palm', 'MhxPalm')),
-]
-
-#
-#    class MhxLayersPanel(bpy.types.Panel):
-#
-
-class MhxLayersPanel(bpy.types.Panel):

@@ Diff output truncated at 10240 characters. @@


More information about the Bf-extensions-cvs mailing list