# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Python Computer Graphics Kit.
#
# The Initial Developer of the Original Code is Matthias Baas.
# Portions created by the Initial Developer are Copyright (C) 2004
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
# $Id: bvhimport.py,v 1.1 2005/02/11 14:32:34 mbaas Exp $

from cgtypes import *
from joint import Joint
from valuetable import ValueTable
import bvh
import pluginmanager
from sl import *

# BVHReader
class BVHReader(bvh.BVHReader):
    """Specialized BVH reader class.

    This class creates a hierarchy of joints and applies the motion to it.
    """
    
    def __init__(self, filename):
        bvh.BVHReader.__init__(self, filename)
      

    def onHierarchy(self, root):
        self.createSkeleton(root)
        self.root = root

    def onMotion(self, frames, dt):
        self.frames = frames
        self.dt = dt
        self.currentframe = 0

    def onFrame(self, values):
        self.applyMotion(self.root, values)
        self.currentframe += 1

    def applyMotion(self, node, values):
        """Apply a motion sample to the skeleton.

        node is the current joint and values the joint angles for the
        entire skeleton.
        The method returns the remaining joint angles.
        """

        t = self.currentframe*self.dt
        
        nc = len(node.channels)
        vals = values[:nc]
        pos = vec3()
        pos_flag = False
        for ch,v in zip(node.channels, vals):
            if ch=="Xrotation":
                node.vtx.add(t, v)
            elif ch=="Yrotation":
                node.vty.add(t, v)
            elif ch=="Zrotation":
                node.vtz.add(t, v)
            elif ch=="Xposition":
                pos.x = v
                pos_flag = True
            elif ch=="Yposition":
                pos.y = v
                pos_flag = True
            elif ch=="Zposition":
                pos.z = v
                pos_flag = True

        if pos_flag:
            node.vtpos.add(t, pos)
            
        values = values[nc:]
        for c in node.children:
            values = self.applyMotion(c, values)
        return values

    # createSkeleton
    def createSkeleton(self, node, parent=None):
        """Create the skeleton hierarchy.

        This method creates the skeleton recursively. Each invocation
        creates one joint.
        """
        order = self.rotationOrder(node.channels)
        # Create a new Joint object
        j = Joint(name = node.name,
                  pos = vec3(node.offset),
                  rotationorder = order,
                  parent = parent)
        # Store the joint in the node so that later the motion can be applied
        node.joint = j
        
        vtx = ValueTable(type="double")
        vty = ValueTable(type="double")
        vtz = ValueTable(type="double")
        vtx.output_slot.connect(j.anglex_slot)
        vty.output_slot.connect(j.angley_slot)
        vtz.output_slot.connect(j.anglez_slot)
        node.vtx = vtx
        node.vty = vty
        node.vtz = vtz
        if node.isRoot():
            vtpos = ValueTable(type="vec3")
            vtpos.output_slot.connect(j.pos_slot)
            node.vtpos = vtpos
            
        for c in node.children:
            self.createSkeleton(c, j)

    # rotationOrder
    def rotationOrder(self, channels):
        """Determine rotation order string from the channel names.
        """
        res = ""
        for c in channels:
            if c[-8:]=="rotation":
                res += c[0]

        # Complete the order string if it doesn't already contain
        # all three axes
        m = { "":"XYZ",
              "X":"XYZ", "Y":"YXZ", "Z":"ZXY",
              "XY":"XYZ", "XZ":"XZY",
              "YX":"YXZ", "YZ":"YZX",
              "ZX":"ZXY", "ZY":"ZYX" }
        if res in m:
            res = m[res]
        return res

######################################################################

# BVHImporter
class BVHImporter:

    _protocols = ["Import"]

    # extension
    def extension():
        """Return the file extensions for this format."""
        return ["bvh"]
    extension = staticmethod(extension)

    # description
    def description(self):
        """Return a short description for the file dialog."""
        return "Biovision Hierarchical"
    description = staticmethod(description)

    # importFile
    def importFile(self, filename):
        """Import a BVH file."""
        
        bvh = BVHReader(filename)
        bvh.read()


######################################################################

# Register the Importer class as a plugin class
pluginmanager.register(BVHImporter)

