void VAnimationEventEffectTrigger::MessageFunction( int iID, INT_PTR iParamA, INT_PTR iParamB )
{  
  IVTransitionEventTrigger::MessageFunction(iID, iParamA, iParamB);

#ifdef WIN32
  if (iID == VIS_MSG_EDITOR_GETSTANDARDVALUES)
  {
    // Get bone names
    const char *szKey = (const char *)iParamA;
    if (!strcmp(szKey,"Bone"))
    {
      // Check for model and skeleton
      VisBaseEntity_cl* pEntity = (VisBaseEntity_cl *)m_pOwner;
      if (pEntity == NULL)
        return;
      VDynamicMesh* pMesh = pEntity->GetMesh();
      if (pMesh == NULL)
        return;
      VisSkeleton_cl *pSkeleton = pMesh->GetSkeleton();
      if (pSkeleton == NULL)
        return;

      // Fill list with bone names (first entry is empty)
      VStrList *pDestList = (VStrList*) iParamB;
      pDestList->AddString(" ");
      for (int i = 0; i < pSkeleton->GetBoneCount(); i++)
        pDestList->AddString(pSkeleton->GetBone(i)->m_sBoneName.AsChar());
    }
  }
#endif
}
void vHavokBehaviorComponent::UpdateAnimationAndBoneIndexList()
{
	// Set up the animation config
	VDynamicMesh* mesh = m_entityOwner->GetMesh();
	if( mesh != HK_NULL && mesh->GetSkeleton() != HK_NULL )
	{
		// create an anim config, if one is not present
		VisAnimConfig_cl* pConfig = m_entityOwner->GetAnimConfig();
		if ( pConfig == HK_NULL )
		{
			pConfig = VisAnimConfig_cl::CreateSkeletalConfig(mesh);
			m_entityOwner->SetAnimConfig( pConfig );
		}

		pConfig->SetFlags(pConfig->GetFlags() | MULTITHREADED_ANIMATION);

		// Create mapping
		VisSkeleton_cl* visionSkeleton = mesh->GetSkeleton();
		const hkaSkeleton* havokSkeleton = m_character->getSetup()->m_animationSkeleton;

		for( int i = 0; i < havokSkeleton->m_bones.getSize(); i++ )
		{
			const VHashString &boneName = havokSkeleton->m_bones[i].m_name.cString();
			int visionBoneIndex = visionSkeleton->GetBoneIndexByName( boneName );
			m_boneIndexList.pushBack( visionBoneIndex );
		}
	}
}
void SimpleSkeletalAnimatedObject_cl::LayerTwoAnimations()
{
  // Layer two animations (using a LayerMixer node). We use this to fade-in an upper body animation 
  // on top of a full body animation. The mixer gets the two animation controls as input and generates
  // the layered result. The animation tree looks as follows:
  //
  // - FinalSkeletalResult
  //    - LayerMixerNode
  //       - SkeletalAnimControl (WalkDagger Animation; influences full body)
  //       - SkeletalAnimControl (RunDagger Animation: influences upper body only)
  //
  // The weight of the layered upper body animation is set on the mixer instance.
  //

  // Create a new AnimConfig instance
  VDynamicMesh *pMesh = GetMesh();
  VisSkeleton_cl *pSkeleton = pMesh->GetSkeleton();
  VisAnimFinalSkeletalResult_cl* pFinalSkeletalResult;
  VisAnimConfig_cl* pConfig = VisAnimConfig_cl::CreateSkeletalConfig(pMesh, &pFinalSkeletalResult);

  // get skeletal animation sequence
  VisSkeletalAnimSequence_cl* pAnimSequenceWalkDagger = static_cast<VisSkeletalAnimSequence_cl*>(
    pMesh->GetSequence("Walk_Dagger", VIS_MODELANIM_SKELETAL));
  VisSkeletalAnimSequence_cl* pAnimSequenceDrawDagger = static_cast<VisSkeletalAnimSequence_cl*>(
    pMesh->GetSequence("Draw_Dagger", VIS_MODELANIM_SKELETAL));

  if (pAnimSequenceWalkDagger == NULL || pAnimSequenceDrawDagger == NULL)
    return;

  // Create the two animation controls: WalkDagger: full body animation; DrawDagger: upper body animation.
  // Use a helper function to create the animation controls.
  VSmartPtr<VisSkeletalAnimControl_cl> spWalkDaggerAnimControl = VisSkeletalAnimControl_cl::Create(
    pMesh->GetSkeleton(), pAnimSequenceWalkDagger, VANIMCTRL_LOOP|VSKELANIMCTRL_DEFAULTS, 1.0f, true);
  VSmartPtr<VisSkeletalAnimControl_cl> spDrawDaggerAnimControl = VisSkeletalAnimControl_cl::Create(
    pMesh->GetSkeleton(), pAnimSequenceDrawDagger, VSKELANIMCTRL_DEFAULTS, 1.0f, true);

  // create the layer node which layers the two animations
  m_spLayerMixerNode = new VisAnimLayerMixerNode_cl(pMesh->GetSkeleton());
  m_spLayerMixerNode->AddMixerInput(spWalkDaggerAnimControl, 1.0f);
  int iMixerInputDrawDagger = m_spLayerMixerNode->AddMixerInput(spDrawDaggerAnimControl, 0.0f);
  
  // set a per bone weighting list for the DrawDagger (upper body) slot in the mixer. It shall overlay the
  // upper body of the character and thus only influence the upper body bones.
  int iBoneCount = pSkeleton->GetBoneCount();
  VASSERT(iBoneCount < 256);

  float fPerBoneWeightingList[256];
  memset(fPerBoneWeightingList, 0, sizeof(float)*iBoneCount);

  pSkeleton->SetBoneWeightRecursive(1.f, pSkeleton->GetBoneIndexByName("skeleton1:Spine"), fPerBoneWeightingList);
  m_spLayerMixerNode->ApplyPerBoneWeightingMask(iMixerInputDrawDagger, iBoneCount, fPerBoneWeightingList);

  // finally set the mixer as the root animation node
  pFinalSkeletalResult->SetSkeletalAnimInput(m_spLayerMixerNode);
  SetAnimConfig(pConfig);

  // fade-in the upper body animation
  //m_spLayerMixerNode->EaseIn(iMixerInputDrawDagger, 0.4f, true);
}
bool VAnimationEventEffectTrigger::CommonInit()
{
  // Initialize base component
  if (!IVTransitionEventTrigger::CommonInit())
    return false;
  
  // Get owner entity
  VisBaseEntity_cl *pEntity = (VisBaseEntity_cl *)m_pOwner;
  if (pEntity == NULL)
    return false;

  // Fill the event trigger info
  if (m_iEventTriggerInfoCount <= 0)
  {
    VEventEffectTriggerInfo_t* info = NULL;
    if(m_pActiveTriggerInfo == NULL) //make sure it does not get created more than once
    {
      // Create new list with only one entry and set properties
      info = new VEventEffectTriggerInfo_t();
    }
    else
    {
      info = (VEventEffectTriggerInfo_t*)m_pActiveTriggerInfo;
    }

    info->m_vPositionOffset = PositionOffset;
    info->m_vOrientationOffset= OrientationOffset;


    // Get effect file
    info->m_spEffectFile = VisParticleGroupManager_cl::GlobalManager().LoadFromFile(EffectFilename);
    if (info->m_spEffectFile == NULL || !GetEventTriggerInfoBaseData(info))
    {
      V_SAFE_DELETE(info);
      m_pActiveTriggerInfo = NULL;
      return false;
    }

    // Get Bone Index if specified
    if (!AttachToBone.IsEmpty())
    {
      VDynamicMesh* pMesh = pEntity->GetMesh();
      if (pMesh == NULL)
        return false;
      VisSkeleton_cl *pSkeleton = pMesh->GetSkeleton();
      if (pSkeleton == NULL)
        return false;

      info->m_iAttachToBone = pSkeleton->GetBoneIndexByName(AttachToBone);
    }

    // Set it as the active event trigger info
    m_pActiveTriggerInfo = info;
  }

  return true;
}
 inline void BoneBoundingBox(VisBaseEntity_cl *pEntity, const char * szSpecificBone = NULL, VColorRef color = V_RGBA_WHITE)
 {
   if(m_bEnabled && pEntity!=NULL && pEntity->GetMesh()!=NULL)
   {
     VisSkeleton_cl *pSkeleton = pEntity->GetMesh()->GetSkeleton();
     if(pSkeleton && pSkeleton->GetBoneIndexByName(szSpecificBone)>0)
     {
       if(szSpecificBone==NULL)  pEntity->DrawBoneBoundingBoxes(color);
       else                      pEntity->DrawBoneBoundingBox(szSpecificBone, color);
     }
   }
 }
예제 #6
0
bool AttachedDagger_cl::Attach(VisBaseEntity_cl *pAnchorEntity, const char *szAnchorBoneName, const hkvQuat &localRotation, const hkvVec3 &localTranslation)
{
  if (m_bIsAttached)
    Detach();

  if (!pAnchorEntity || !szAnchorBoneName)
    return false;

  // find index of bone the weapon is attached to
  VisSkeleton_cl *pSkeleton = pAnchorEntity->GetMesh()->GetSkeleton();
  m_iAnchorBoneIndex = pSkeleton->GetBoneIndexByName(szAnchorBoneName);

  // store attachment settings
  m_LocalRotation = localRotation;
  m_LocalTranslation = localTranslation;
  m_pAnchorEntity = pAnchorEntity;
  m_bIsAttached = true;

  // initial update
  Update();

  return true;
}
예제 #7
0
void AnimatedWarrior_cl::InitFunction()
{
  SetCastShadows(TRUE);
  
  SetupAnimations();
  if (!m_bModelValid)
    return;

	m_pCharacterController = new vHavokCharacterController();
	m_pCharacterController->Initialize();

	hkvAlignedBBox bbox;
	GetMesh()->GetCollisionBoundingBox(bbox);

  float r = bbox.getSizeX() * 0.5f;
	m_pCharacterController->Capsule_Radius = r;
	m_pCharacterController->Character_Top.set(0,0,bbox.m_vMax.z - r);
  m_pCharacterController->Character_Bottom.set(0,0,bbox.m_vMin.z + r);

 	m_pCharacterController->Max_Slope = 75.0f;

  if (!m_bEnabled)
    m_pCharacterController->SetEnabled(FALSE);

	AddComponent(m_pCharacterController);

  //// setup animation system
  // create config
  VDynamicMesh* pMesh = GetMesh();
  VASSERT(pMesh);
  VisSkeleton_cl* pSkeleton = pMesh->GetSkeleton();
  VASSERT(pSkeleton);

  // create mixer structure, we keep pointers on the mixers to add and remove inputs
  m_spLayerMixer = new VisAnimLayerMixerNode_cl(pSkeleton);

  m_pNormalizeMixer = new VisAnimNormalizeMixerNode_cl(pSkeleton);
  m_spLayerMixer->AddMixerInput(m_pNormalizeMixer, 1.f);

  //// create per bone weighting list for upper body
  int iBoneCount = pSkeleton->GetBoneCount();
  float* fPerBoneWeightingList = new float[iBoneCount];
  memset(fPerBoneWeightingList, 0, sizeof(float)*iBoneCount);

  // set all bone weights above the spine to 1
  pSkeleton->SetBoneWeightRecursive(1.f, pSkeleton->GetBoneIndexByName("skeleton1:Spine"), fPerBoneWeightingList);

  int iMixerInputIndex = -1;

  for(int i=0; i<UPPERBODY_CONTROLCOUNT; i++)
  {
    m_spUpperBodyControls[i] = new VisSkeletalAnimControl_cl(pSkeleton, VSKELANIMCTRL_DEFAULTS);
    m_spUpperBodyControls[i]->AddEventListener(this); // we want to receive all events from sequence and control
    iMixerInputIndex = m_spLayerMixer->AddMixerInput(m_spUpperBodyControls[i], 0.f);
    m_spLayerMixer->ApplyPerBoneWeightingMask(iMixerInputIndex, iBoneCount, fPerBoneWeightingList);
  }
  
  V_SAFE_DELETE_ARRAY(fPerBoneWeightingList);

  // set the start animation
  BlendOverFullBodyAnimation(0.f, ANIMID_IDLE, 1.f, 0.f);
 
  SetFullBodyState(m_pFullBodyIdleState[FBSTATETYPE_NORMAL]);
  SetUpperBodyState(m_pUpperBodyIdleState);

  // initialize variables for upperbody fadein/fadeout
  m_eUpperBodyFadeState = FADESTATE_NONE;

  // setup neck bone for head rotation
  m_iHeadBoneIndex = pSkeleton->GetBoneIndexByName("skeleton1:Neck");
  m_fHeadRotationAngles[0] = 0.f; m_fHeadRotationAngles[1] = 0.f; m_fHeadRotationAngles[2] = 0.f;
  m_bHeadInMovement = false;

  // setup the torch
  hkvVec3 vDummyOrigin;
  m_pTorch = (AttachedTorch_cl *) Vision::Game.CreateEntity( "AttachedTorch_cl", vDummyOrigin );
  
  HideTorch();

  // attach the torch to the bone
  //hkvVec3 localTranslation(-11.f, -4.5f, 25.f);
  hkvVec3 localTranslation(-11.f, 5.5f, 0.f);
  float euler[3] = {90, 0, 185};
  hkvQuat localRotation;
  localRotation.setFromEulerAngles (euler[2], euler[1], euler[0]); // pass as roll, pitch, yaw
  m_pTorch->Attach(this, "skeleton1:RightHand", localRotation, localTranslation);

  SetEnabled(true);
}
void vHavokBehaviorComponent::OnAfterHavokUpdate()
{
	if( m_character == HK_NULL || m_entityOwner == HK_NULL )
	{
		return;
	}

	// Update WFM of skin or override it
	if ( m_useBehaviorWorldFromModel )
	{
		const hkQsTransform& worldFromModel = m_character->getWorldFromModel();

		// Copy the Behavior result into vision
		hkvMat3 visionRotation;
		hkvVec3 visionTranslation;
		vHavokConversionUtils::HkQuatToVisMatrix( worldFromModel.getRotation(), visionRotation );
		vHavokConversionUtils::PhysVecToVisVecWorld( worldFromModel.getTranslation(), visionTranslation );
		m_entityOwner->SetPosition( visionTranslation );
		m_entityOwner->SetRotationMatrix( visionRotation );
	}
	else
	{
		// Override Behavior results.
		// This will currently cause Behavior data being sent to HBT during remote debug to be one frame off.
		// However, the only other solution with the current APIs is to disable motion accumulation on *all*
		// Characters.  A slight delay/offset in the special case of remote debugging in HBT isn't worth that change.
		UpdateHavokTransformFromVision();
	}

	if( m_entityOwner->GetMesh() == HK_NULL || m_entityOwner->GetMesh()->GetSkeleton() == HK_NULL )
	{
		return;
	}

	VisAnimConfig_cl* animConfig = m_entityOwner->GetAnimConfig();
	if( !animConfig )
	{
		return;
	}

	VisAnimFinalSkeletalResult_cl* skeletalResult = animConfig->GetFinalResult();
	if( !skeletalResult )
	{
		return;
	}

	// Try updating the bone index list in case a mesh was added
	if( m_boneIndexList.getSize() == 0 )
	{
		UpdateAnimationAndBoneIndexList();

		// Exit early if there's no bone index list
		if( m_boneIndexList.getSize() == 0 )
		{
			return;
		}
	}

	// Convert pose to Havok model space
	const hkQsTransform* poseLocal = m_character->getPoseLocal();
	hkArray<hkQsTransform> poseModel( m_character->getNumPoseLocal() );
	hkaSkeletonUtils::transformLocalPoseToModelPose( m_character->getNumPoseLocal(), m_character->getSetup()->m_animationSkeleton->m_parentIndices.begin(), poseLocal, poseModel.begin() );
	const hkQsTransform* pose = poseModel.begin();

	float const inverseCharacterScale = 1.0f / m_character->getSetup()->getData()->m_scale;

	// Convert pose to vision units
	VisSkeleton_cl* visionSkeleton = m_entityOwner->GetMesh()->GetSkeleton();

	
	for( int havokBoneIndex = 0; havokBoneIndex < m_character->getNumPoseLocal(); havokBoneIndex++ )
	{
		// Find the bone index
		int visionBoneIndex = m_boneIndexList[havokBoneIndex];
		if( visionBoneIndex != -1 )
		{
			HK_ON_DEBUG( VisSkeletalBone_cl* bone = visionSkeleton->GetBone(visionBoneIndex) );
			HK_ASSERT2(0x68b6649, hkString::strCmp( bone->m_sBoneName.AsChar(), m_character->getSetup()->m_animationSkeleton->m_bones[havokBoneIndex].m_name.cString() ) == 0, "" );

			const hkQsTransform& transform = pose[havokBoneIndex];

			// Convert Havok pose to Vision pose
			hkvQuat quat;
			quat.setIdentity();
			vHavokConversionUtils::HkQuatToVisQuat( transform.getRotation(), quat );
			hkvVec3 scale; vHavokConversionUtils::PhysVecToVisVec_noscale( transform.getScale(), scale );
			hkvVec3 translation; vHavokConversionUtils::PhysVecToVisVecWorld( transform.getTranslation(), translation );

			// Behavior propagates character scale through the skeleton; need to compensate when scaling to Vision
			scale *= inverseCharacterScale;

			// Set the skeletal result
			skeletalResult->SetCustomBoneScaling( visionBoneIndex, scale, VIS_REPLACE_BONE | VIS_OBJECT_SPACE );
			skeletalResult->SetCustomBoneRotation( visionBoneIndex, quat, VIS_REPLACE_BONE | VIS_OBJECT_SPACE );
			skeletalResult->SetCustomBoneTranslation( visionBoneIndex, translation, VIS_REPLACE_BONE | VIS_OBJECT_SPACE );
		}
	}

#if 0

	// Draw skeleton
	for( int i = 0; i < visionSkeleton->GetBoneCount(); i++ )
	{
		VisSkeletalBone_cl* bone = visionSkeleton->GetBone(i);
		if( bone->m_iParentIndex != -1 )
		{
			hkvVec3 translation, subTranslation;
			hkvQuat rotation, subRotation;
			m_entityOwner->GetBoneCurrentWorldSpaceTransformation( i, translation, rotation );
			m_entityOwner->GetBoneCurrentWorldSpaceTransformation( bone->m_iParentIndex, subTranslation, subRotation );

			Vision::Game.DrawSingleLine( translation.x, translation.y, translation.z, subTranslation.x, subTranslation.y, subTranslation.z );
		}
	}

#endif

}