void SimpleSkeletalAnimatedObject_cl::SetMode(SampleMode_e newMode)
{
  ClearData();
  m_eSampleMode = newMode;

  switch (newMode)
  {
  case MODE_SINGLEANIM:
    StartSingleAnimation(false); break;
  case MODE_BLENDTWOANIMS:
    BlendTwoAnimations(); break;
  case MODE_LISTENTOEVENTS:
    ListenToEvents(); break;
  case MODE_SETANIMATIONTIME:
    SetAnimationTime(); break;
  case MODE_LAYERTWOANIMATIONS:
    LayerTwoAnimations(); break;
  case MODE_FORWARDKINEMATICS:
    ForwardKinematics(); break;
  case MODE_LOOKAT:
    LookAt(); break;
  }

  // disable motion delta for this sample
  if (GetAnimConfig() != NULL)
    GetAnimConfig()->SetFlags(GetAnimConfig()->GetFlags() & ~APPLY_MOTION_DELTA);
}
void SimpleSkeletalAnimatedObject_cl::ThinkFunction()
{
  // Check whether the object is active.
  if (GetAnimConfig() == NULL)
    return;

  const float dtime = Vision::GetTimer()->GetTimeDifference();

  // highlight the bone after animation event
  if (m_fBoneHighlightDuration > 0.0f && !m_sHighlightedBoneName.IsEmpty())
  {
    int iColorVal = static_cast<int>(m_fBoneHighlightDuration / BONE_HIGHLIGHT_FADEOUTTIME * 255.0f);
    DrawBoneBoundingBox(m_sHighlightedBoneName, VColorRef(iColorVal,iColorVal, 0), 2.f);
    m_fBoneHighlightDuration -= Vision::GetTimer()->GetTimeDifference();
  }

  // update the LookAt
  if (m_eSampleMode == MODE_LOOKAT)
  {
    VASSERT(m_pLookAtTarget);

    // rotate the object around the character
    m_fLookAtRotationPhase = hkvMath::mod(m_fLookAtRotationPhase + dtime*0.7f, hkvMath::pi() * 2.0f);
    hkvVec3 vNewPos(100.f*hkvMath::sinRad(m_fLookAtRotationPhase), 100.0f*hkvMath::cosRad(m_fLookAtRotationPhase), 160.0f);
    vNewPos += GetPosition();
    m_pLookAtTarget->SetPosition(vNewPos);

    // update the LookAt orientation
    UpdateLookatHeadRotation(dtime);
  }
}
void AnimatedWarrior_cl::SetEnabled(bool bEnabled)
{
  if (m_bEnabled == bEnabled)
    return;
  m_bEnabled = bEnabled;

  if (!m_bModelValid)
    return;

#if defined(USE_HAVOK)
  // Turn on/off character controller
  if (m_pCharacterController != NULL)
    m_pCharacterController->SetEnabled(bEnabled ? TRUE : FALSE);
#endif

  VisAnimConfig_cl* pAnimConfig = GetAnimConfig();

  if (bEnabled)
  {
    m_spAnimConfig = GetAnimConfig();
    if (m_spAnimConfig == NULL)
    {
      m_spAnimConfig = VisAnimConfig_cl::CreateSkeletalConfig(GetMesh());
      SetAnimConfig(m_spAnimConfig);
    }
    if (m_spAnimConfig->GetFinalResult() != NULL)
      m_spAnimConfig->GetFinalResult()->SetSkeletalAnimInput(m_spLayerMixer);

    // Resume animation controls
    for (int i = 0; i < UPPERBODY_CONTROLCOUNT; i++)
      m_spUpperBodyControls[i]->Resume();
    for (int i = 0; i < m_FullBodyControlList.Count(); i++)
      m_FullBodyControlList.GetAt(i)->Resume();
  }
  else
  {
    // Pause animation controls
    for (int i = 0; i < UPPERBODY_CONTROLCOUNT; i++)
      m_spUpperBodyControls[i]->Pause();
    for (int i = 0; i < m_FullBodyControlList.Count(); i++)
      m_FullBodyControlList.GetAt(i)->Pause();

    if (m_spAnimConfig != NULL && m_spAnimConfig->GetFinalResult() != NULL)
      m_spAnimConfig->GetFinalResult()->SetSkeletalAnimInput(NULL);
  }
}
bool SimpleSkeletalAnimatedObject_cl::GetHeadRotation(const hkvVec3 &vTargetPos, hkvQuat &targetRot, float fMaxViewAngle)
{
  hkvMat4 objectMatrix;
  hkvMat4 parentObjectMatrix;

  // get the index of the parent bone
  int parentBoneIndex = GetMesh()->GetSkeleton()->GetBone(m_iHeadBoneIndex)->m_iParentIndex;

  // get the 4x4 matrix of the head bone and its parent in object space
  const VisSkeletalAnimResult_cl* pObjectSpaceResult = GetAnimConfig()->GetFinalResult()->GetCurrentObjectSpaceResult();
  pObjectSpaceResult->GetBoneTransformationMatrix(m_iHeadBoneIndex, objectMatrix);
  pObjectSpaceResult->GetBoneTransformationMatrix(parentBoneIndex, parentObjectMatrix);

  // get the current position of the target in object space
  hkvVec3 targetObjectspace = TransformToObjectSpace(vTargetPos);

  // get the current position of the bone in object space
  hkvVec3 boneObjectspace = objectMatrix.getTranslation();

  // calculate the look at direction in object space (just for the angle constraints)
  hkvVec3 vLookAtDir = targetObjectspace - boneObjectspace;

  // check if we are within the angle constraints
  vLookAtDir.normalizeIfNotZero();
  float fCosMax = hkvMath::cosDeg (180.f - fMaxViewAngle);
  bool bInsideFocusArea = vLookAtDir.y < fCosMax;
  if (!bInsideFocusArea)
  {
    // out of focus, so just look straight ahead
    targetRot.setIdentity();
    return false;
  }

  // create a LookAt-3x3 matrix from the bone position and the target position (both are in object space)
  // This orientation is later used to replace(!) the head bone in local space (VIS_REPLACE_BONE|VIS_LOCAL_SPACE flags)
  hkvMat3 lookatMatrix(hkvNoInitialization);
  lookatMatrix.setLookInDirectionMatrix(targetObjectspace - boneObjectspace);

  //  Apply our custom rotation matrix that tells the bone to focus with the eyes and not with the back of the head :-)
  lookatMatrix = lookatMatrix.multiply(m_RelativeHeadOrientation);

  // Invert the parents object matrix rotation to cancel out all parent bone orientations
  hkvMat3 parentObject = parentObjectMatrix.getRotationalPart();
  parentObject.invert();

  // put everything together
  hkvMat3 result = parentObject;
  result = result.multiply (lookatMatrix);

  // ...and make a quaternion from it
  targetRot.setFromMat3 (result);

  return true;
}
void SimpleSkeletalAnimatedObject_cl::UpdateLookatHeadRotation(float fTimeDelta)
{
  hkvQuat targetRotation;

  // evaluate the target rotation
  GetHeadRotation(m_pLookAtTarget->GetPosition(), targetRotation, 75.f);

  hkvVec3 vForwards(0.0f, -1.0f, 0.0f);
  hkvVec3 vFrom = m_CurrentNeckRotation.transform(vForwards);
  hkvVec3 vTo = targetRotation.transform(vForwards);
  float fAngle = vFrom.getAngleBetween (vTo);

  float fAnglePerSecond = 20.0f * fTimeDelta;
  float fFactor = hkvMath::Min(fAnglePerSecond / (fAngle + 0.000001f), 1.0f);
  m_CurrentNeckRotation.setSlerp(m_CurrentNeckRotation, targetRotation, fFactor); 

  // Our new bone orientation defines the rotation absolute.
  // Thus our modify mode must be VIS_REPLACE_BONE and VIS_LOCAL_SPACE
  GetAnimConfig()->GetFinalResult()->SetCustomBoneRotation(m_iHeadBoneIndex, m_CurrentNeckRotation, 
    VIS_REPLACE_BONE|VIS_LOCAL_SPACE);
}
// **************************************************
//              NECK BONE HANDLING
// **************************************************
void AnimatedWarrior_cl::TurnHead(float fDegreesPerSecond, float fTimeDiff, float fMinAngle, float fMaxAngle)
{
  float fAmount = fDegreesPerSecond * fTimeDiff;

  // update joint rotation (with clamp)
  m_fHeadRotationAngles[1] += fAmount;
  if (m_fHeadRotationAngles[1] > fMaxAngle)
    m_fHeadRotationAngles[1] = fMaxAngle;
  else if (m_fHeadRotationAngles[1] < fMinAngle)
    m_fHeadRotationAngles[1] = fMinAngle;

  //// set new rotation
  VASSERT(GetAnimConfig() == m_spAnimConfig);
  VisAnimFinalSkeletalResult_cl *pFinalResult = m_spAnimConfig->GetFinalResult();
  VASSERT(pFinalResult != NULL);

  // update the current localspace result and add custom rotation
  pFinalResult->GetCurrentLocalSpaceResult();
  hkvQuat tempRotation(hkvNoInitialization);
  tempRotation.setFromEulerAngles (m_fHeadRotationAngles[2], m_fHeadRotationAngles[1], m_fHeadRotationAngles[0]);
  pFinalResult->SetCustomBoneRotation(m_iHeadBoneIndex, tempRotation, VIS_MODIFY_BONE|VIS_LOCAL_SPACE);

  m_bHeadInMovement = true;
}