# -*- coding: utf-8 -*-
"""
title=Shapekey sample
issue=Fabius Astelix @ 2009-10-07 from code developed by clcheung
revisers=
summary=will be tested some relative shapekeys defined in blender - they will be applied to an animated actor
the sample will expect to change the actor expression to look like the expression name describe.

"""
# Panda imports
import direct.directbase.DirectStart

from pandac.PandaModules import NodePath, WindowProperties
from pandac.PandaModules import TextNode, FadeLODNode
from pandac.PandaModules import Vec3,Vec4,Point3
from direct.actor.Actor import Actor
from pandac.PandaModules import AmbientLight,PointLight
from pandac.PandaModules import LightAttrib,TextNode
from pandac.PandaModules import CardMaker
from pandac.PandaModules import OrthographicLens
from pandac.PandaModules import AntialiasAttrib
from direct.gui.OnscreenText import OnscreenText
from direct.showbase.DirectObject import DirectObject
from direct.task.Task import Task
#
import math, sys
#================================================================
#  GLOBALS
#================================================================
TXT_TITLE="Shape Keys Sample"
TXT_INSTRUCTIONS="""Click to change shape key:
"""
#the amount of displacement will be applied to the actor's mesh - 1.0 is suggested to match the setup in blender but this value could be exaggerated or mitigated here if necessary
MORPHSIZE=1.0
#================================================================
#  CLASSES
#================================================================
#
class World(DirectObject):
  """
  """
  def __init__(self):
    DirectObject.__init__(self)
    # default scene an user interface setup
    self.setup_scene(camsetup=(0,-7.5, 3, 0,0,0), mousecontrol=True)
    self.setup_ui(TXT_TITLE, TXT_INSTRUCTIONS)

    # let's start of the show
    self.start_sample()
  #------------------------------------------------------
  #
  def start_sample(self):
    global TXT_INSTRUCTIONS

    # these names match the shape keys creted in blender for the actor.
    morphnames=["Basic", "amaze", "frown", "mad", "rage", "wink",]

    self.actor = Actor("shapekey")
    self.actor.setPos(0, 0, 0)
    self.actor.reparentTo(base.render)

    # here will be created the morph targets to displace the mesh acoording to the shape data exported with chicken. as you see the main tool do achieve this is the controlJoint - afterwards in the setMorph class method will be displaced with setX to apply the deformation.
    self.morphTargets = []
    self.prevmorph=None
    i=0
    for name in morphnames:
      morph = self.actor.controlJoint(None, 'modelRoot', name)
      self.morphTargets.append(morph)
      TXT_INSTRUCTIONS+="\n%d=%s"%(i, name)
      self.accept('%d'%i, self.setMorph, [i])
      i+=1

    self.actor.loadAnims(
      {'idle':'shapekey-anim1'},
      partName='modelRoot'
    )
    self.actor.loop('idle')

    self.instructions.setText(TXT_INSTRUCTIONS)
  #------------------------------------------------------
  #
  def setMorph(self, index):
    """here will be applied the deformation to the controlJoint object that define the vertices involved -setX wil displace 'em accordingly
    """
    if self.prevmorph != None: self.morphTargets[self.prevmorph].setX(0.0)
    self.morphTargets[index].setX(MORPHSIZE)
    self.prevmorph=index
  #------------------------------------------------------
  #
  def setup_scene(self,
    camtype='', camlens=None, camsetup=(0, 0, 25, 0, 0, 0),
    ambient=(.3, .3, .3, 1),
    lightcolor=(.9, .9, .9, 1),
    bgcolor=(0.4, 0.4, 0.4, 1.0),
    lightPos=(0.0, -20.0, 10.0),
    mousecontrol=False
  ):
    '''default scene setup
    '''
    # scene background
    ## color
    base.setBackgroundColor(bgcolor)
    ## overall light
    ambientLight = AmbientLight( "lgt_sce_ambient00" )
    ambientLightNP=render.attachNewNode(ambientLight)
    ambientLight.setColor(ambient)

    ## light lamps
    light = PointLight('plight')
    lightNP = base.render.attachNewNode(light)
    lightNP.setPos((0,-20,10))
    base.render.setLight(lightNP)

    light2 = PointLight('plight2')
    light2NP = base.render.attachNewNode(light2)
    light2NP.setPos((0,20,10))
    base.render.setLight(light2NP)

    # camera
    ## lens
    if camtype.lower() == 'ortho':
      baselens=OrthographicLens()
      #default lens
      if not camlens: camlens=(4,3)
      baselens.setFilmSize(*camlens)
    else:
      baselens=base.cam.node().getLens()
      if not camlens: camlens=38
      baselens.setFov(camlens)
    base.cam.node().setLens(baselens)

    baselens.setNearFar(0.01, 2000)

    ## place the camera
    if not mousecontrol:
      base.disableMouse()
      base.camera.setPosHpr(*camsetup)
    else:
      base.mouseInterfaceNode.setPos(
        -camsetup[0],-camsetup[1],-camsetup[2]
      )
      base.mouseInterfaceNode.setHpr(
        -camsetup[3],camsetup[4],camsetup[5]
      )
  #------------------------------------------------------
  #
  def setup_ui(self, title='', instructions=''):
    '''default ui setup
    '''
    if title:
      self.title = OnscreenText(text=TXT_TITLE,
        style=1, fg=(1,1,0,1),
        pos = (0, -.1), scale = .09,
        parent=base.a2dTopCenter,
      )
    if instructions:
      self.instructions = OnscreenText(text=TXT_INSTRUCTIONS,
        pos = (-1.3, .90), fg=(1,1,1,1),
        align = TextNode.ALeft, scale = .05
      )

world=World()
if __name__ == "__main__":
  run()
