void vHavokShapeFactory::GetHktDependencies(VResourceSnapshot &snapshot, VisBaseEntity_cl *pEntity) { VASSERT(pEntity != NULL); // Get wrapped rigid body vHavokRigidBody *pWrappedRigidBody = pEntity->Components().GetComponentOfType<vHavokRigidBody>(); if (pWrappedRigidBody == NULL) return; // Get shape vHavokPhysicsModule *pModule = vHavokPhysicsModule::GetInstance(); VASSERT(pModule != NULL); pModule->MarkForRead(); const hkpRigidBody *pRigidBody = pWrappedRigidBody->GetHkRigidBody(); if (pRigidBody == NULL) { pModule->UnmarkForRead(); return; } const hkpShape *pShape = pRigidBody->getCollidable()->getShape(); pModule->UnmarkForRead(); // Only convex/ mesh rigid bodies have a cached HKT file const hkClass* loadedClassType = hkVtableClassRegistry::getInstance().getClassFromVirtualInstance(pShape); if (loadedClassType!=&hkvConvexVerticesShapeClass && loadedClassType!=&hkvBvCompressedMeshShapeClass) return; // Get mesh VDynamicMesh *pMesh = pEntity->GetMesh(); if (pMesh == NULL) return; // Get scale hkvVec3 vScale = pEntity->GetScaling(); bool shrinkToFit = pWrappedRigidBody->Havok_TightFit; // Get HKT file dependency for convex/ mesh rigid body if (loadedClassType == &hkvConvexVerticesShapeClass) { VStaticString<FS_MAX_PATH> szCachedShapeName(pMesh->GetFilename()); vHavokCachedShape::GetConvexShapePath(szCachedShapeName, vScale, shrinkToFit); IVFileInStream *pIn = Vision::File.Open(szCachedShapeName); if (pIn) { snapshot.AddFileDependency(pMesh, szCachedShapeName, pIn->GetSize() ); pIn->Close(); } } else if(loadedClassType == &hkvBvCompressedMeshShapeClass) { VStaticString<FS_MAX_PATH> szCachedShapeName(pMesh->GetFilename()); vHavokCachedShape::GetMeshShapePath(szCachedShapeName, vScale, VisStaticMeshInstance_cl::VIS_COLLISION_BEHAVIOR_CUSTOM, (VisWeldingType_e)pWrappedRigidBody->Havok_WeldingType); IVFileInStream *pIn = Vision::File.Open(szCachedShapeName); if (pIn) { snapshot.AddFileDependency(pMesh, szCachedShapeName, pIn->GetSize() ); pIn->Close(); } } }
// ---------------------------------------------------------------------------- void vHavokChainAnimation::CommonInit() { CommonDeinit(); if (!m_pOwner || !m_pOwner->IsOfType(V_RUNTIME_CLASS(VisBaseEntity_cl))) return; Vision::Callbacks.OnUpdateSceneFinished += this; m_pOwnerEntity = static_cast<VisBaseEntity_cl*>(m_pOwner); VisAnimConfig_cl *pAnimConfig = m_pOwnerEntity->GetAnimConfig(); // If there is no AnimConfig, but we can get a skeleton, create the AnimConfig. if (!pAnimConfig) { VDynamicMesh *pMesh = m_pOwnerEntity->GetMesh(); VisSkeleton_cl *pSkeleton = pMesh ? pMesh->GetSkeleton() : NULL; if (pSkeleton) { VisAnimFinalSkeletalResult_cl* pFinalSkeletalResult; pAnimConfig = VisAnimConfig_cl::CreateSkeletalConfig(pMesh, &pFinalSkeletalResult); m_pOwnerEntity->SetAnimConfig(pAnimConfig); } } }
bool VAnimationComponent::AddAnimationSequence(const char * szAnimSequence) { if (szAnimSequence == NULL || GetOwner() == NULL) return false; VDynamicMesh * pMesh = ((VisBaseEntity_cl *)m_pOwner)->GetMesh(); if(pMesh==NULL) { hkvLog::Warning("AddAnimationSequence: No mesh present!"); return false; } VASSERT_MSG(pMesh->GetSequenceSetCollection()!=NULL, "No animation sequence set present!"); VisAnimSequenceSet_cl *pSet = Vision::Animations.GetSequenceSetManager()->LoadAnimSequenceSet(szAnimSequence); if(pSet==NULL) { hkvLog::Warning("AddAnimationSequence: Could not load '%s' animation sequence.", szAnimSequence); return false; } pMesh->GetSequenceSetCollection()->Add(pSet); return true; }
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::LookAt() { // start a single animation StartSingleAnimation(true); // start a simple skeletal animation bool bLooped = true; int iFlags = VSKELANIMCTRL_DEFAULTS; if (bLooped) iFlags |= VANIMCTRL_LOOP; m_spSingleAnimControl = VisAnimConfig_cl::StartSkeletalAnimation(this, "Run", iFlags); // find the head bone index VDynamicMesh *pMesh = GetMesh(); m_iHeadBoneIndex = pMesh->GetSkeleton()->GetBoneIndexByName("skeleton1:Head"); // create a rotation matrix that defines the actual orientation of the head. This is model specific and can // only be found out by trial and error (typically 0, 90 or 180 deg). In our case the head is rotated by 180 degrees; Without this additional // orientation that model would follow the target with the backside of the head. m_RelativeHeadOrientation.setFromEulerAngles (90, 0, 270); // create an entity that rotates around the model m_pLookAtTarget = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3::ZeroVector(), "Models/MagicBall.model"); m_fLookAtRotationPhase = 0.f; }
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; }
void MergedModelFactory_cl::PreviewModel() { DeleteModels(); m_pPreviewModelEntities = new VisBaseEntity_cl*[BARBARIAN_MAX]; m_pPreviewModelEntities[BARBARIAN_BODY] = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3(0.f, 0.f, 0.f), "Barbarian_Body.model"); m_pPreviewModelEntities[BARBARIAN_ARM] = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3(0.f, 0.f, 0.f), "Barbarian_Arm.model"); m_pPreviewModelEntities[BARBARIAN_SHOULDER] = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3(0.f, 0.f, 0.f), "Barbarian_Shoulder.model"); m_pPreviewModelEntities[BARBARIAN_LEGS] = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3(0.f, 0.f, 0.f), "Barbarian_Legs.model"); m_pPreviewModelEntities[BARBARIAN_KNEE] = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3(0.f, 0.f, 0.f), "Barbarian_Knee.model"); m_pPreviewModelEntities[BARBARIAN_ACCESSOIRE] = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3(0.f, 0.f, 0.f), "Barbarian_Accessoire.model"); m_pPreviewModelEntities[BARBARIAN_BELT] = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3(0.f, 0.f, 0.f), "Barbarian_Belt.model"); m_pPreviewModelEntities[BARBARIAN_CLOTH] = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3(0.f, 0.f, 0.f), "Barbarian_Cloth.model"); m_pPreviewModelEntities[BARBARIAN_BEARD] = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3(0.f, 0.f, 0.f), "Barbarian_Beard.model"); m_pPreviewModelEntities[BARBARIAN_AXE] = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3(0.f, 0.f, 0.f), "Barbarian_Axe.model"); m_pPreviewModelEntities[BARBARIAN_SWORD] = Vision::Game.CreateEntity("VisBaseEntity_cl", hkvVec3(0.f, 0.f, 0.f), "Barbarian_Sword.model"); // Setup animation system VDynamicMesh* pBodyMesh = m_pPreviewModelEntities[BARBARIAN_BODY]->GetMesh(); VisSkeletalAnimSequence_cl* pSequence = static_cast<VisSkeletalAnimSequence_cl*>(pBodyMesh->GetSequence("Idle", VIS_MODELANIM_SKELETAL)); // Create shared skeletal anim control to animate all models in sync VisSkeletalAnimControl_cl* pSkeletalAnimControl = VisSkeletalAnimControl_cl::Create(pBodyMesh->GetSkeleton(), pSequence, VSKELANIMCTRL_DEFAULTS | VANIMCTRL_LOOP); for (int i = 0; i < BARBARIAN_MAX; i++) { // Create anim config per entity VisAnimFinalSkeletalResult_cl* pFinalSkeletalResult = NULL; VisAnimConfig_cl* pConfig = VisAnimConfig_cl::CreateSkeletalConfig(m_pPreviewModelEntities[i]->GetMesh(), &pFinalSkeletalResult); pConfig->SetFlags(pConfig->GetFlags() | APPLY_MOTION_DELTA); // Anim config uses shared skeletal anim control as input pFinalSkeletalResult->SetSkeletalAnimInput(pSkeletalAnimControl); m_pPreviewModelEntities[i]->SetAnimConfig(pConfig); m_pPreviewModelEntities[i]->SetPosition(m_vPos); m_pPreviewModelEntities[i]->SetOrientation(m_vOri); #ifndef _VISION_PSP2 m_pPreviewModelEntities[i]->SetCastShadows(TRUE); #endif } m_pCameraEntity->AttachToParent(m_pPreviewModelEntities[BARBARIAN_BODY]); m_pPlayerCamera->ResetOldPosition(); m_pPlayerCamera->Follow = true; m_pPlayerCamera->Zoom = false; m_pPlayerCamera->InitialYaw = -90.f; UpdatePreview(); }
// ************************************************** // OVERRIDDEN ENTITY FUNCTIONS // ************************************************** void TransitionBarbarian_cl::InitFunction() { if (!HasMesh()) return; SetCastShadows(TRUE); // Setup all animation sequences SetupAnimations(); if (!m_bModelValid) return; if( !m_pPhys) { m_pPhys = new vHavokCharacterController(); m_pPhys->Initialize(); hkvAlignedBBox bbox; VDynamicMesh *pMesh = GetMesh(); pMesh->GetCollisionBoundingBox(bbox); float r = bbox.getSizeX() * 0.5f; m_pPhys->Capsule_Radius = r; m_pPhys->Character_Top.set(0,0,bbox.m_vMax.z - r); m_pPhys->Character_Bottom.set(0,0,bbox.m_vMin.z + r); m_pPhys->Max_Slope = 75.0f; AddComponent(m_pPhys); // pPhys->SetDebugRendering(TRUE); } // Get Model VDynamicMesh* pModel = GetMesh(); VASSERT(pModel); // Transition table to use VTransitionTable *pTable = VTransitionManager::GlobalManager().LoadTransitionTable(pModel,"Barbarian.vTransition"); VASSERT(pTable && pTable->IsLoaded()); // Setup the state machine component and pass the filename of the transition file // in which the transitions between the various animation states are defined. m_pStateMachine = new VTransitionStateMachine(); m_pStateMachine->Init(this, pTable); AddComponent(m_pStateMachine); // Set initial state m_pStateMachine->SetState(m_pSkeletalSequenceList[ANIMID_IDLE]); }
// ************************************************** // SETUP ANIMATIONS // ************************************************** void TransitionBarbarian_cl::SetupAnimations() { m_bModelValid = false; VDynamicMesh *pModel = GetMesh(); VVERIFY_OR_RET(pModel); m_pSkeletalSequenceList[ANIMID_IDLE] = (VisSkeletalAnimSequence_cl*)pModel->GetSequence("Idle", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_pSkeletalSequenceList[ANIMID_IDLE]); m_pSkeletalSequenceList[ANIMID_WALK] = (VisSkeletalAnimSequence_cl*)pModel->GetSequence("Walk", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_pSkeletalSequenceList[ANIMID_WALK]); m_pSkeletalSequenceList[ANIMID_RUN] = (VisSkeletalAnimSequence_cl*)pModel->GetSequence("Run", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_pSkeletalSequenceList[ANIMID_RUN]); m_bModelValid = true; }
void SimpleSkeletalAnimatedObject_cl::ForwardKinematics() { // Apply forward kinematics to the head "Neck" bone, using a bone modifier node. The bone modifier // gets a skeletal animation as input, modifies the translation of the neck bone and generates the // combined result. The animation tree looks as follows: // // - FinalSkeletalResult // - BoneModifierNode (modifies the neck bone) // - SkeletalAnimControl (Walk Animation) // // The translation of the neck bone is set on the bone modifier node. // // Create a new AnimConfig instance VDynamicMesh *pMesh = GetMesh(); VisAnimFinalSkeletalResult_cl* pFinalSkeletalResult; VisAnimConfig_cl* pConfig = VisAnimConfig_cl::CreateSkeletalConfig(pMesh, &pFinalSkeletalResult); // Get skeletal animation sequence. VisSkeletalAnimSequence_cl* pAnimSequenceWalk = static_cast<VisSkeletalAnimSequence_cl*>(pMesh->GetSequence("Walk", VIS_MODELANIM_SKELETAL)); if (pAnimSequenceWalk == NULL) return; // Create the animation control to play the walk animation (via a helper function). VSmartPtr<VisSkeletalAnimControl_cl> spWalkAnimControl = VisSkeletalAnimControl_cl::Create( pMesh->GetSkeleton(), pAnimSequenceWalk, VANIMCTRL_LOOP|VSKELANIMCTRL_DEFAULTS, 1.0f, true); // Create the bone modifier node that translates the head bone. Set the animation control instance // as the input for this node. m_spBoneModifierNode = new VisAnimBoneModifierNode_cl(pMesh->GetSkeleton()); m_spBoneModifierNode->SetModifierInput(spWalkAnimControl); hkvQuat customBoneRotation; // set the neck bone translation on the bone modifier node m_iNeckBoneIndex = pMesh->GetSkeleton()->GetBoneIndexByName("skeleton1:Neck"); customBoneRotation.setFromEulerAngles (0, -45, 0); m_spBoneModifierNode->SetCustomBoneRotation(m_iNeckBoneIndex, customBoneRotation, VIS_MODIFY_BONE); // finally set the bone modifier as the root animation node pFinalSkeletalResult->SetSkeletalAnimInput(m_spBoneModifierNode); SetAnimConfig(pConfig); // The bone modifier node is now part of the animation tree. You can at any time update the translation // on the bone modifier. The animation system will take care of generating the proper final result. }
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); }
VisMeshBuffer_cl *VRendererNodeHelper::GetSphereMeshBuffer() { if (m_spSphereMeshBuffer != NULL) return m_spSphereMeshBuffer; VDynamicMesh *pMesh = Vision::Game.LoadDynamicMesh("\\Models\\MagicBall.model", true, false); VASSERT(pMesh!=NULL); m_spSphereMeshBuffer = new VisMeshBuffer_cl(); m_spSphereMeshBuffer->SetPrimitiveType(VisMeshBuffer_cl::MB_PRIMTYPE_INDEXED_TRILIST); #ifdef HK_DEBUG m_spSphereMeshBuffer->SetFilename("<DeferredShadingSphereMesh>"); #endif VisMBVertexDescriptor_t descr; descr.Reset(); descr.m_iPosOfs = 0 | VERTEXDESC_FORMAT_FLOAT3; descr.m_iStride = sizeof(float)*3; // get model properties int iVertexCount = pMesh->GetNumOfVertices(); int iIndexCount = pMesh->GetNumOfTriangles() * 3; // copy vertex buffer, normalize vertex positions m_spSphereMeshBuffer->AllocateVertices(descr, iVertexCount); float *pDestVerts = (float *)m_spSphereMeshBuffer->LockVertices(VIS_LOCKFLAG_DISCARDABLE); pMesh->CopyMeshVertices(pDestVerts, descr, 0, iVertexCount); for (int i=0; i<iVertexCount*3; i+=3) { hkvVec3 vPos(pDestVerts[i], pDestVerts[i+1], pDestVerts[i+2]); vPos.normalizeIfNotZero(); memcpy(&pDestVerts[i], vPos.data, 3*sizeof(float)); } m_spSphereMeshBuffer->UnLockVertices(); // copy index buffer m_spSphereMeshBuffer->AllocateIndexList(iIndexCount); unsigned short *pDestIndices = (unsigned short *)m_spSphereMeshBuffer->LockIndices(VIS_LOCKFLAG_DISCARDABLE); pMesh->CopyMeshIndices(pDestIndices, (VisSurface_cl *)NULL); m_spSphereMeshBuffer->UnLockIndices(); return m_spSphereMeshBuffer; }
// ************************************************** // SETUP ANIMATIONS // ************************************************** void TransitionCharacter_cl::SetupAnimations() { m_bModelValid = false; VDynamicMesh *pMesh = GetMesh(); VVERIFY_OR_RET(pMesh); // idle animations m_spSkeletalSequenceList[ANIMID_IDLE] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Idle", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_IDLE]); // run animations m_spSkeletalSequenceList[ANIMID_RUN] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Run", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_RUN]); // walk animations m_spSkeletalSequenceList[ANIMID_WALK] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Walk", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_WALK]); // turn animations m_spSkeletalSequenceList[ANIMID_TURN] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Turn", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_TURN]); // walk backwards animation m_spSkeletalSequenceList[ANIMID_WALKBACKWARDS] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Run_BWD", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_WALKBACKWARDS]); m_bModelValid = true; }
bool VisClothDeformer_cl::UpdateDeformerResult(VisVertexAnimResult_cl* pVertexAnimResult) { VISION_PROFILE_FUNCTION(VIS_PROFILE_ANIMSYS_RESULT_VERTEX_ANIM); if(m_spMesh == NULL) return false; //// fill vertexanimresult with the mesh data // destination buffer float *pDestVertexPosition; const int iDestVertexPositionStride = pVertexAnimResult->GetDestVertexPosition(pDestVertexPosition); float *pDestVertexNormal; const int iDestVertexNormalStride = pVertexAnimResult->GetDestVertexNormal(pDestVertexNormal); int iVertexCount = m_spMesh->GetVertexCount(); VDynamicMesh *pMesh = pVertexAnimResult->GetMesh(); VASSERT(pMesh->GetNumOfVertices() == m_spMesh->GetVertexCount()); VisObjectVertexDelta_t *pVertexDelta = m_spMesh->GetVertexDeltaList(); // copy mesh vertices into vertexanim result hkvVec3 tempNormal(hkvNoInitialization); hkvVec3 vTranslate; if (m_pParentObject) vTranslate = m_pParentObject->GetPosition(); for(int i=0; i<iVertexCount; i++, pVertexDelta++, ADVANCE_VERTEXPOINTERS) { pDestVertexPosition[0] = pVertexDelta->delta[0] - vTranslate.x; pDestVertexPosition[1] = pVertexDelta->delta[1] - vTranslate.y; pDestVertexPosition[2] = pVertexDelta->delta[2] - vTranslate.z; tempNormal.set(pVertexDelta->normal[0], pVertexDelta->normal[1], pVertexDelta->normal[2]); tempNormal.normalizeIfNotZero(); pDestVertexNormal[0] = tempNormal.x; pDestVertexNormal[1] = tempNormal.y; pDestVertexNormal[2] = tempNormal.z; } return true; }
// Render shaders on entities void VPostProcessTranslucencies::DrawEntitiesShaders(const VisEntityCollection_cl &EntityCollection, VPassType_e ePassType) { VisDrawCallInfo_t SurfaceShaderList[RLP_MAX_ENTITY_SURFACESHADERS]; unsigned int iNumEntities = EntityCollection.GetNumEntries(); unsigned int i; Vision::RenderLoopHelper.BeginEntityRendering(); for (i=0; i<iNumEntities; i++) { VisBaseEntity_cl *pEntity = EntityCollection.GetEntry(i); // Foreground entities will be handled separately if (pEntity->IsObjectAlwaysInForegroundEnabled()) continue; if ( pEntity->HasShadersForPass(ePassType) ) { // Get a list of the corresponding pass type surface shaders VisShaderSet_cl *pShaderSet = pEntity->GetActiveShaderSet(); if (pShaderSet == NULL) continue; int iNumSurfaceShaders = pShaderSet->GetShaderAssignmentList(SurfaceShaderList, ePassType, RLP_MAX_ENTITY_SURFACESHADERS); VASSERT(iNumSurfaceShaders < RLP_MAX_ENTITY_SURFACESHADERS); if (iNumSurfaceShaders == 0) continue; VDynamicMesh *pMesh = pEntity->GetMesh(); // If the model has lit surfaces, and if the shaders makes use of the lighting information, we need to set up // the global lights. if (pMesh != NULL && pMesh->HasLitSurfaces() && (pShaderSet->GetCombinedTrackingMask()&(VSHADER_TRACKING_LIGHTGRID_PS|VSHADER_TRACKING_LIGHTGRID_GS|VSHADER_TRACKING_LIGHTGRID_VS)) ) { Vision::RenderLoopHelper.TrackLightGridInfo(pEntity); } // Render the entity with the surface shader list Vision::RenderLoopHelper.RenderEntityWithSurfaceShaderList(pEntity, iNumSurfaceShaders, SurfaceShaderList); } } Vision::RenderLoopHelper.EndEntityRendering(); }
void SimpleSkeletalAnimatedObject_cl::BlendTwoAnimations() { // Blend two animations using a NormalizeMixer node. The mixer gets the two animations as input // and generates the blended result. The animation tree looks as follows: // // - FinalSkeletalResult // - NormalizeMixerNode // - SkeletalAnimControl (Walk Animation) // - SkeletalAnimControl (Run Animation) // // The weights of the two animations are set on the mixer instance. // // create a new AnimConfig instance VDynamicMesh *pMesh = GetMesh(); VisAnimFinalSkeletalResult_cl* pFinalSkeletalResult; VisAnimConfig_cl* pConfig = VisAnimConfig_cl::CreateSkeletalConfig(pMesh, &pFinalSkeletalResult); // get skeletal animation sequence VisSkeletalAnimSequence_cl* pAnimSequenceWalk = static_cast<VisSkeletalAnimSequence_cl*>( pMesh->GetSequence("Walk", VIS_MODELANIM_SKELETAL)); VisSkeletalAnimSequence_cl* pAnimSequenceRun = static_cast<VisSkeletalAnimSequence_cl*>( pMesh->GetSequence("Run", VIS_MODELANIM_SKELETAL)); if(pAnimSequenceWalk == NULL || pAnimSequenceRun == NULL) return; // create two animation controls: walk and run (use a helper function for creating them) VSmartPtr<VisSkeletalAnimControl_cl> spWalkAnimControl = VisSkeletalAnimControl_cl::Create( pMesh->GetSkeleton(), pAnimSequenceWalk, VANIMCTRL_LOOP|VSKELANIMCTRL_DEFAULTS, 1.0f, true); VSmartPtr<VisSkeletalAnimControl_cl> spRunAnimControl = VisSkeletalAnimControl_cl::Create( pMesh->GetSkeleton(), pAnimSequenceRun, VANIMCTRL_LOOP|VSKELANIMCTRL_DEFAULTS, 1.0f, true); // create the mixer node that blends the two animations // (set initial weight to show walk animation only) m_spNormalizeMixerNode = new VisAnimNormalizeMixerNode_cl(pMesh->GetSkeleton()); m_iMixerInputWalk = m_spNormalizeMixerNode->AddMixerInput(spWalkAnimControl, 1.0f); m_iMixerInputRun = m_spNormalizeMixerNode->AddMixerInput(spRunAnimControl, 0.0f); // finally set the mixer as the root animation node pFinalSkeletalResult->SetSkeletalAnimInput(m_spNormalizeMixerNode); SetAnimConfig(pConfig); // blend from walk to run SetBlendWalkToRun(true); }
// Renders foreground entities (i.e. entities which have been flagged as "always in foreground") void VPostProcessTranslucencies::DrawTransparentForegroundEntities(const VisEntityCollection_cl &EntityCollection) { unsigned int iNumEntities = EntityCollection.GetNumEntries(); // this collection only contains foreground objects if (iNumEntities==0 || m_spForegroundFillPassTechnique==NULL) return; INSERT_PERF_MARKER_SCOPE("VisionRenderLoop_cl::DrawForegroundEntities"); unsigned int i; const hkvMat4* pLastProj = NULL; Vision::RenderLoopHelper.BeginEntityRendering(); const int iPassCount = m_spForegroundFillPassTechnique->GetShaderCount(); for (int iPass=0;iPass<=iPassCount;iPass++) // +1 passes, where the last one is the actual material pass { for (i=0; i<iNumEntities; i++) { VisBaseEntity_cl *pEntity = EntityCollection.GetEntry(i); // Render only Entities that are flagged as "always in foreground" VASSERT_MSG(pEntity->IsObjectAlwaysInForegroundEnabled(), "Only entities with this flag should be passed to this function"); if (pEntity->HasShadersForPass(VPT_TransparentPass)) { VDynamicMesh *pMesh = pEntity->GetMesh(); VisShaderSet_cl *pShaderSet = pEntity->GetActiveShaderSet(); VASSERT(pMesh && pShaderSet); const hkvMat4* pThisProj = pEntity->GetCustomProjectionMatrixForForegroundObject(); if (pThisProj != pLastProj) { VisRenderStates_cl::SetCurrentProjectionMatrix(pThisProj); pLastProj = pThisProj; } if (iPass<iPassCount) // depth fill pass { VCompiledShaderPass *pPass = m_spForegroundFillPassTechnique->GetShader(iPass); Vision::RenderLoopHelper.RenderEntityWithShaders(pEntity, 1, &pPass); } else // material pass { const VisDrawCallInfo_t *pAssignment; int iNumSurfaceShaders = pShaderSet->GetShaderAssignmentList(&pAssignment); // If the shaders make use of the lighting information, we need to track the light grid if (pMesh != NULL && pMesh->HasLitSurfaces() && (pShaderSet->GetCombinedTrackingMask() & (VSHADER_TRACKING_LIGHTGRID_PS|VSHADER_TRACKING_LIGHTGRID_GS|VSHADER_TRACKING_LIGHTGRID_VS)) ) { Vision::RenderLoopHelper.TrackLightGridInfo(pEntity); } // Render the entity with the surface shader list Vision::RenderLoopHelper.RenderEntityWithSurfaceShaderList(pEntity, iNumSurfaceShaders, pAssignment); } } } } Vision::RenderLoopHelper.EndEntityRendering(); // reset to context projection matrix if (pLastProj) { VisRenderStates_cl::SetCurrentProjectionMatrix(NULL); } }
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); }
BOOL VLineFollowerComponent::StartAnimation(const char *szAnimName) { VisBaseEntity_cl* pOwner = (VisBaseEntity_cl *)GetOwner(); if (!pOwner) return false; m_bPlayingAnim = false; // Check for animation sequences VDynamicMesh *pMesh = pOwner->GetMesh(); if (!pMesh || !pMesh->GetSequenceSetCollection() || !pMesh->GetSequenceSetCollection()->GetSequenceSetCount()) return false; VisAnimFinalSkeletalResult_cl* pFinalSkeletalResult = NULL; VisVertexAnimDeformer_cl* pVertexAnimDeformer = NULL; // Get the sequence(s) for vertex and skeletal animation VisSkeletalAnimSequence_cl* pAnimSequenceSkeletal = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence(szAnimName, VIS_MODELANIM_SKELETAL); VisVertexAnimSequence_cl* pAnimSequenceVertex = (VisVertexAnimSequence_cl*)pMesh->GetSequence(szAnimName, VIS_MODELANIM_VERTEX); // If no sequence with the given name is present if ((!pAnimSequenceSkeletal) && (!pAnimSequenceVertex)) { VisAnimSequenceSet_cl * pSequenceSet = pMesh->GetSequenceSetCollection()->GetSequenceSet(0); // Find the first skeletal or vertex animation and use it for (int i=0; i< pSequenceSet->GetSequenceCount(); ++i) { VisAnimSequence_cl* pTempAnimSequence = pSequenceSet->GetSequence(i); if (pTempAnimSequence->GetType() == VIS_MODELANIM_SKELETAL) { // If it is a skeletal animation, create a config for it VisAnimConfig_cl* pConfig = VisAnimConfig_cl::CreateSkeletalConfig(pMesh, &pFinalSkeletalResult); VisSkeletalAnimControl_cl* pSkeletalAnimControl = VisSkeletalAnimControl_cl::Create(pMesh->GetSkeleton(), (VisSkeletalAnimSequence_cl*)pTempAnimSequence, VANIMCTRL_LOOP|VSKELANIMCTRL_DEFAULTS, 1.0f, true); pFinalSkeletalResult->SetSkeletalAnimInput(pSkeletalAnimControl); pOwner->SetAnimConfig(pConfig); m_bPlayingAnim = true; return true; } else if (pTempAnimSequence->GetType() == VIS_MODELANIM_VERTEX) { // If it is a vertex animation, create a config for it VisAnimConfig_cl* pConfig = VisAnimConfig_cl::CreateVertexConfig(pMesh, &pVertexAnimDeformer); VisVertexAnimControl_cl* pVertexAnimControl = VisVertexAnimControl_cl::Create((VisVertexAnimSequence_cl*)pTempAnimSequence, VANIMCTRL_LOOP|VSKELANIMCTRL_DEFAULTS, 1.0f, true); pVertexAnimDeformer->AddVertexAnimControl(pVertexAnimControl, 1.0f); pOwner->SetAnimConfig(pConfig); m_bPlayingAnim = true; return true; } } // If neither a skeletal nor a vertex animation has been found, report failure return false; } // If both a vertex and a skeletal animation with the given name has been found // create a combined config for skeletal and vertex animation. VisAnimConfig_cl* pConfig = NULL; if ((pAnimSequenceSkeletal) && (pAnimSequenceVertex)) pConfig = VisAnimConfig_cl::CreateSkeletalVertexConfig(pMesh, &pFinalSkeletalResult, &pVertexAnimDeformer); // If it is just a skeletal animation, create a config for it if (pAnimSequenceSkeletal) { if (!pConfig) pConfig = VisAnimConfig_cl::CreateSkeletalConfig(pMesh, &pFinalSkeletalResult); // If a skeletal animation has been found create a control for it VisSkeletalAnimControl_cl* pSkeletalAnimControl = VisSkeletalAnimControl_cl::Create(pMesh->GetSkeleton(), pAnimSequenceSkeletal, VANIMCTRL_LOOP|VSKELANIMCTRL_DEFAULTS, 1.0f, true); // And set it as the input for the final skeletal result pFinalSkeletalResult->SetSkeletalAnimInput(pSkeletalAnimControl); } // If it is just a vertex animation, create a config for it if (pAnimSequenceVertex) { if (!pConfig) pConfig = VisAnimConfig_cl::CreateVertexConfig(pMesh, &pVertexAnimDeformer); // If a vertex animation has been found create a control for it VisVertexAnimControl_cl* pVertexAnimControl = VisVertexAnimControl_cl::Create(pAnimSequenceVertex, VANIMCTRL_LOOP|VSKELANIMCTRL_DEFAULTS, 1.0f, true); // And set add it to the vertex anim deformer pVertexAnimDeformer->AddVertexAnimControl(pVertexAnimControl, 1.0f); } // Set the current config pOwner->SetAnimConfig(pConfig); // Make sure we get the motion delta from the animation pOwner->GetAnimConfig()->SetFlags(pOwner->GetAnimConfig()->GetFlags() | APPLY_MOTION_DELTA | MULTITHREADED_ANIMATION); // And report success m_bPlayingAnim = true; return true; }
VBool SaveGame(int iNum) { if ( (iNum < 1) || (iNum > 4) ) { // we just allow 4 save games return FALSE; } int i; char pszSaveFileName[FS_MAX_PATH]; sprintf(pszSaveFileName,SAVEGAME_NAME, iNum); IVFileOutStream* pOut = Vision::File.Create(pszSaveFileName); // creating the file didn't work! if (!pOut) { return FALSE; } VArchive ar( pszSaveFileName, pOut, Vision::GetTypeManager() ); // serialize global game data ar << ARCHIVE_START_TAG; // magic number int iSavingVersion = Vision::GetArchiveVersion(); ar << iSavingVersion; // archive class version ar << g_iCurrentMap; // current map number ar << Vision::GetTimer()->GetTime(); // current time // count entities SerializeBaseEntity_cl *pSerEnt = NULL; VisBaseEntity_cl *pEnt = NULL; int iFullCtr = 0; int iReCreateCtr = 0; int iNumOfAllEntities = VisBaseEntity_cl::ElementManagerGetSize(); for (i = 0; i < iNumOfAllEntities; i++) { pEnt = VisBaseEntity_cl::ElementManagerGet(i); if ( pEnt ) { if ( pEnt->IsOfType(SerializeBaseEntity_cl::GetClassTypeId()) ) { pSerEnt = static_cast<SerializeBaseEntity_cl*>(pEnt); if ( pSerEnt->GetSerializeType() == SERIALIZE_FULL ) iFullCtr++; else iReCreateCtr++; } } } // serialize number of entities ar << iReCreateCtr; ar << iFullCtr; hkvVec3 vTemp; // do ReCreate serialization of entities for (i = 0; i < iNumOfAllEntities; i++) { pEnt = VisBaseEntity_cl::ElementManagerGet(i); if ( pEnt ) { if ( pEnt->IsOfType(SerializeBaseEntity_cl::GetClassTypeId()) ) { pSerEnt = (SerializeBaseEntity_cl *) pEnt; if ( pSerEnt->GetSerializeType() == SERIALIZE_RECREATE ) { char pszEntityParams[4000]; GetEntityParameters( pSerEnt, pszEntityParams ); VDynamicMesh* pMesh = pSerEnt->GetMesh(); ar << pSerEnt->GetClassFullName() << pSerEnt->GetEntityKey(); vTemp = pSerEnt->GetPosition(); vTemp.SerializeAsVisVector (ar); vTemp = pSerEnt->GetOrientation(); vTemp.SerializeAsVisVector (ar); const char *szFilename = pMesh ? pMesh->GetFilename() : NULL; ar << szFilename << pszEntityParams; } } } } // do full serialization of entities for (i = 0; i < iNumOfAllEntities; i++) { pEnt = VisBaseEntity_cl::ElementManagerGet(i); if ( pEnt ) { if ( pEnt->IsOfType(SerializeBaseEntity_cl::GetClassTypeId()) ) { pSerEnt = (SerializeBaseEntity_cl *) pEnt; if ( pSerEnt->GetSerializeType() == SERIALIZE_FULL ) { ar << pSerEnt; } } } } // store end tag - useful to verify a valid archive ar << ARCHIVE_END_TAG; ar.Close(); pOut->Close(); g_SaveSlot[iNum-1].SaveScreenShotPreview(); return TRUE; }
void VLineFollowerComponent::InitPhysics(float fPathPos) { VisBaseEntity_cl* pOwner = (VisBaseEntity_cl *)GetOwner(); if (!pOwner) return; hkvVec3 vPos; hkvVec3 vDir; hkvAlignedBBox bbox; m_fCurrentPathPos = fPathPos; if(m_pFollowPath) m_pFollowPath->EvalPoint(fPathPos, vPos, &vDir); else vPos = pOwner->GetPosition(); // to determine correct height on the ground, perform a ray-cast: if (Vision::GetApplication()->GetPhysicsModule()!=NULL && Model_CapsuleHeight>0) { hkvVec3 vRayStart(vPos.x,vPos.y,vPos.z+Model_CapsuleHeight); hkvVec3 vRayEnd(vPos.x,vPos.y,vPos.z-Model_CapsuleHeight); VisPhysicsHit_t hitPoint; if (Vision::GetApplication()->GetPhysicsModule()->Raycast(vRayStart, vRayEnd, hitPoint)) // hit? { vPos.z = hitPoint.vImpactPoint.z + 5.f*Vision::World.GetGlobalUnitScaling(); // add some margin } } VDynamicMesh *pMesh = pOwner->GetMesh(); if (pMesh) { pMesh->GetCollisionBoundingBox(bbox); vPos.z -= bbox.m_vMin.z; // Use model size if not set if (Model_CapsuleRadius<=0.f) Model_CapsuleRadius = hkvMath::Min( bbox.getSizeX(), bbox.getSizeY() )/2.f; if (Model_CapsuleHeight<=0.f) Model_CapsuleHeight = bbox.getSizeZ(); } else { // No model - set some sane values if not set if (Model_CapsuleRadius<=0.f) Model_CapsuleRadius = 40.f; if (Model_CapsuleHeight<=0.f) Model_CapsuleHeight = 90.f; } // Create the physics object pOwner->SetPosition(vPos); if (!m_pPhys) { m_pPhys = new vHavokCharacterController(); m_pPhys->Capsule_Radius = Model_CapsuleRadius; float h = Model_CapsuleHeight * 0.5f; float fPivot = Model_GroundOffset; m_pPhys->Character_Top.set(0, 0, h - fPivot); m_pPhys->Character_Bottom.set(0, 0, -h - fPivot); pOwner->AddComponent(m_pPhys); } // Update position m_pPhys->SetPosition(vPos); // Enable debug rendering m_pPhys->SetDebugRendering(Debug_RenderMesh); m_pPhys->SetDebugColor(V_RGBA_RED); }
void VMobileForwardRenderLoop::RenderLitGeometry(VisLightSource_cl *pLight, IVShadowMapComponent *pShadowMapComponent, bool bBasePass, bool bUsesLightClippingVolume, bool bEntities, bool bStaticGeometry) { if (!pLight) return; // Some local variables for storing surfaces, shaders, surface shaders, and the like. VCompiledTechnique *pTechnique = NULL; VisDrawCallInfo_t SurfaceShaderList[RLP_MAX_ENTITY_SURFACESHADERS]; VisRenderContext_cl *pContext = VisRenderContext_cl::GetCurrentContext(); const hkvVec3 &vCamPos = pContext->GetCamera()->GetPosition(); const float fFade = pLight->GetFadeWeight(vCamPos); VisStaticGeometryInstanceCollection_cl *pLitGeoInstanceCollection = NULL; VisEntityCollection_cl *pLitEntityCollection = NULL; if (bBasePass || pLight != m_pBasePassLight) { if (bStaticGeometry) { pLitGeoInstanceCollection = &s_LitGeoInstanceCollection; pLitGeoInstanceCollection->Clear(); } if (bEntities) { pLitEntityCollection = &s_LitEntityCollection; pLitEntityCollection->Clear(); } Vision::RenderLoopHelper.GetVisibleGeometryInLightsourceRange(pLitGeoInstanceCollection, pLitEntityCollection, NULL, *pLight); } else { if (bStaticGeometry) pLitGeoInstanceCollection = &m_AdditiveLitGeoInstanceCollection; if (bEntities) pLitEntityCollection = &m_AdditiveLitEntityCollection; } #ifdef SUPPORTS_SHADOW_MAPS VShadowMapGenSpotDir *pShadowMapGenDir = NULL; if (pShadowMapComponent) { VShadowMapGenerator *pShadowMapGen = pShadowMapComponent->GetShadowMapGenerator(); if (pShadowMapGen->GetProjectionType()==SHADOW_PROJECTION_ORTHOGRAPHIC) pShadowMapGenDir = static_cast<VShadowMapGenSpotDir*>(pShadowMapGen); } #endif // Set the stencil render state for reading light clipping volume information if(bUsesLightClippingVolume) { const VLightClippingVolumeComponent* pLightClippingComponent = pLight->Components().GetComponentOfBaseType<VLightClippingVolumeComponent>(); VASSERT(pLightClippingComponent != NULL && V_ARRAY_SIZE(m_lightClippingStencilStatesRead)==2); VisRenderStates_cl::SetDepthStencilState(m_lightClippingStencilStatesRead[pLightClippingComponent->GetClipHandedness()]); } else VisRenderStates_cl::SetDepthStencilState(m_dynLightDefaultState); // For all illuminated entities: Render a dynamic lighting pass now. if (pLight->GetLightInfluenceBitMaskEntity() != 0 && bEntities) { int iNumLitEntities = pLitEntityCollection->GetNumEntries(); Vision::RenderLoopHelper.BeginEntityRendering(); for (int j=0; j<iNumLitEntities; j++) { VisBaseEntity_cl *pEntity = pLitEntityCollection->GetEntry(j); if (!(pEntity->GetLightInfluenceBitMask() & pLight->GetLightInfluenceBitMaskEntity())) continue; VDynamicMesh *pMesh = pEntity->GetMesh(); VisSurface_cl **ppSurfaces = pEntity->GetSurfaceArray(); // Get list of all the surfaces in the model int iNumSubmeshes = pMesh->GetSubmeshCount(); int iNumSurfaceShaders = 0; // For all the surfaces... for (int k=0; k<iNumSubmeshes; k++) { VDynamicSubmesh *pSubmesh = pMesh->GetSubmesh(k); VisSurface_cl *pSurface = ppSurfaces[pSubmesh->m_iMaterialIndex]; // Full-bright surfaces can't be rendered in the compound base pass, since such surfaces are not illuminated. Since tagging // of already rendered geometry happens per entity instance, in case an entity contains full-bright surfaces, all surfaces // of this entity have to be rendered in the normal rendering pipeline. const VisLightingMethod_e eLightingMethod = pSurface->GetLightingMode(); if (bBasePass) { // Since entities can contain several surfaces with different lighting methods (full-bright, dynamic only, etc.), entities // with full-bright surfaces have to be also added to the additive lit entity collection, in order to ensure rendering of // dynamic only surfaces. if (eLightingMethod==VIS_LIGHTING_FULLBRIGHT) { iNumSurfaceShaders = 0; m_AdditiveLitEntityCollection.AppendEntry(pEntity); break; } } else { if (eLightingMethod == VIS_LIGHTING_FULLBRIGHT) continue; } // If not all surfaces have a primary opaque pass type in the base pass, then render corresponding entity // in the additive lighting pass. if (bBasePass && pSurface->GetResolvedPassType()!=VPT_PrimaryOpaquePass) { iNumSurfaceShaders = 0; m_AdditiveLitEntityCollection.AppendEntry(pEntity); break; } // Check whether entity is in current shadow volume for orthographic shadows. In that case the entity is rendered // without shadows since it is not in the relevant shadow volume. IVShadowMapComponent *pTmpShadowMapComponent = pShadowMapComponent; #ifdef SUPPORTS_SHADOW_MAPS if (pShadowMapGenDir) { if (!pShadowMapGenDir->IsEntityInsideOrthoShadowVolume(pEntity)) pTmpShadowMapComponent = NULL; } #endif pTechnique = GetLightShader(pLight, bBasePass, pSurface, fFade, pTmpShadowMapComponent); if (!pTechnique || !pTechnique->GetShaderCount()) // do not light this surface { // If base-pass lighting technique could not be retrieved, render lit entity in the additive pass. if (bBasePass && pLight->IsDynamic()) m_AdditiveLitEntityCollection.AppendEntry(pEntity); iNumSurfaceShaders = 0; break; } // Generate a list of surface shader from the combined surface/shader information VisDrawCallInfo_t &info(SurfaceShaderList[iNumSurfaceShaders++]); info.Set(pSubmesh, pSurface, pTechnique->m_Shaders.GetAt(0)); } // Finally, render the entity with a surface shader list. if (iNumSurfaceShaders>0) { Vision::RenderLoopHelper.RenderEntityWithSurfaceShaderList(pEntity, iNumSurfaceShaders, SurfaceShaderList); if (bBasePass) pEntity->Tag(); } } Vision::RenderLoopHelper.EndEntityRendering(); } // For all illuminated world primitives: Render a dynamic lighting pass now. if (pLight->GetLightInfluenceBitMaskWorld() != 0 && bStaticGeometry) { VisSurface_cl *pSurface; VisSurface_cl *pLastSurface = NULL; VCompiledTechnique *pLastTechnique = NULL; // We start collecting illuminated mesh instances. Whenever a relevant property changes, we set the // shader information, render all collected world instances, and start collecting from scratch. int iNumLitGeoInstances = pLitGeoInstanceCollection->GetNumEntries(); pLastSurface = NULL; s_RenderGeoInstanceCollection.Clear(); pLastTechnique = NULL; for (int j=0; j<iNumLitGeoInstances; j++) { VisStaticGeometryInstance_cl *pGI = pLitGeoInstanceCollection->GetEntry(j); pSurface = pGI->GetSurface(); VASSERT(pSurface); if (pSurface->IsFullbright()) continue; // If surface does not have a primary opaque pass type in the base pass, then render corresponding static // mesh instance in the additive lighting pass. if (bBasePass && pSurface->GetResolvedPassType()!=VPT_PrimaryOpaquePass) { m_AdditiveLitGeoInstanceCollection.AppendEntry(pGI); continue; } // Check whether mesh is in current shadow volume for orthographic shadows. In that case the mesh is rendered // without shadows since it is not in the relevant shadow volume. IVShadowMapComponent *pTmpShadowMapComponent = pShadowMapComponent; #ifdef SUPPORTS_SHADOW_MAPS if (pShadowMapGenDir) { if (!pShadowMapGenDir->IsMeshInsideOrthoShadowVolume(pGI)) pTmpShadowMapComponent = NULL; } #endif if (pLastSurface!=pSurface) { pTechnique = GetLightShader(pLight, bBasePass, pSurface, fFade, pTmpShadowMapComponent); pLastSurface = pSurface; } if (pTechnique == NULL || !pTechnique->GetShaderCount()) { // If base-pass lighting technique could not be retrieved, render lit mesh in the additive pass. if (bBasePass && pLight->IsDynamic()) m_AdditiveLitGeoInstanceCollection.AppendEntry(pGI); continue; } // If the state information is different from the previous one, we have to render the world primitives we // have collected so far if (pLastTechnique!=pTechnique) { if (s_RenderGeoInstanceCollection.GetNumEntries()!=0) { VASSERT(pLastTechnique != NULL); Vision::RenderLoopHelper.RenderStaticGeometryWithShader(s_RenderGeoInstanceCollection, *pLastTechnique->m_Shaders.GetAt(0)); if (bBasePass) s_RenderGeoInstanceCollection.TagEntries(); s_RenderGeoInstanceCollection.Clear(); } // Update the stored state information pLastTechnique = pTechnique; } // Naturally, we have to append the primitive to our collection (otherwise it won't be collected =) ). s_RenderGeoInstanceCollection.AppendEntry(pGI); } // If there's still something left in the collection, render it as well. if (s_RenderGeoInstanceCollection.GetNumEntries()!=0) { if (pLastTechnique && pLastTechnique->GetShaderCount()>0) { Vision::RenderLoopHelper.RenderStaticGeometryWithShader(s_RenderGeoInstanceCollection, *pLastTechnique->m_Shaders.GetAt(0)); if (bBasePass) s_RenderGeoInstanceCollection.TagEntries(); } s_RenderGeoInstanceCollection.Clear(); } } // Restore default render state VisRenderStates_cl::SetDepthStencilState(*VisRenderStates_cl::GetDepthStencilDefaultState()); }
// TODO: This doesn't handle opaque fullbright surfaces correctly yet, and translucent fullbright surfaces are simply ignored. void MirrorRenderLoop_cl::OnDoRenderLoop(void *pUserData) { INSERT_PERF_MARKER_SCOPE("MirrorRenderLoop_cl::OnDoRenderLoop"); #if defined (WIN32) || defined (_VISION_XENON) || defined (_VISION_PS3) || defined(_VISION_PSP2) || defined(_VISION_WIIU) if (Vision::Editor.GetIgnoreAdvancedEffects()) { // force a black reflection because it won't work with orthographic views Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_All, V_RGBA_BLACK); return; } #endif VisRenderContext_cl *pContext = Vision::Contexts.GetCurrentContext(); const int iRenderFlags = pContext->GetRenderFlags(); const float fFarClipDist = m_pMirror->GetActualFarClipDistance(); const VFogParameters &fog = Vision::World.GetFogParameters(); VColorRef clearColor = (fog.depthMode != VFogParameters::Off) ? fog.iDepthColor : Vision::Renderer.GetDefaultClearColor(); Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_All, clearColor); // set the oblique clipping plane... pContext->SetCustomProjectionMatrix (m_pMirror->GetObliqueClippingProjection().getPointer ()); const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesPrimaryOpaquePass; const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesSecondaryOpaquePass; const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesTransparentPass; const VisEntityCollection_cl *pVisEntities; // === Visibility Determination === IVisVisibilityCollector_cl *pVisColl = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector(); if (pVisColl == NULL) return; const VisVisibilityObjectCollection_cl *pVisObjectCollection = pVisColl->GetVisibleVisObjects(); hkvAlignedBBox box; int iVoCount = m_pMirror->GetVisibilityObjectCount(); int iFrustumCount = 0; bool bUseCommonFrustum = false; // === Determine Scissor Rect === hkvVec2 vMinScreenSpace, vMaxScreenSpace; const hkvAlignedBBox &worldSpaceBox = m_pMirror->GetBoundingBox(); hkvVec3 vCorners[8]; worldSpaceBox.getCorners (vCorners); VRectanglef scissorRect; bool bUseScissorRect = true; for (int i=0; i<8; i++) { float x2d, y2d; BOOL bInFrontOfCamera = pContext->Project2D(vCorners[i], x2d, y2d); if (bInFrontOfCamera) { scissorRect.Add(hkvVec2(x2d, y2d)); } else { bUseScissorRect = false; break; } } if (bUseScissorRect) Vision::RenderLoopHelper.SetScissorRect(&scissorRect); for (int iVo = 0; iVo < iVoCount; iVo++) { VisVisibilityObject_cl *pVisObj = m_pMirror->GetVisibilityObject(iVo); if (pVisObj != NULL && pVisObj->WasVisibleInAnyLastFrame()) { if (iFrustumCount <= MAX_SEPARATE_FRUSTA) { const hkvAlignedBBox &voBox = pVisObj->GetWorldSpaceBoundingBox(); box.expandToInclude(voBox); if (m_Frustum[iFrustumCount].Set(pContext->GetCamera()->GetPosition(), voBox, true, fFarClipDist)) { iFrustumCount++; } else { bUseCommonFrustum = true; } } else { const hkvAlignedBBox &voBox = pVisObj->GetWorldSpaceBoundingBox(); box.expandToInclude(voBox); bUseCommonFrustum = true; } } } if (bUseCommonFrustum) { iFrustumCount = 1; if (!m_Frustum[0].Set(pContext->GetCamera()->GetPosition(), box, true, fFarClipDist)) iFrustumCount = 0; } if (iFrustumCount>0) { for (int i=0; i<iFrustumCount; i++) { m_visiblePrimaryOpaquePassGeoInstances.Clear(); m_visibleSecondaryOpaquePassGeoInstances.Clear(); m_visibleTransparentOpaquePassGeoInstances.Clear(); m_visEntities.Clear(); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visiblePrimaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visibleSecondaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visibleTransparentOpaquePassGeoInstances); pVisColl->GetVisibleEntities()->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visEntities); if (iFrustumCount == 1) break; m_visiblePrimaryOpaquePassGeoInstances.TagEntries(); m_visibleSecondaryOpaquePassGeoInstances.TagEntries(); m_visibleTransparentOpaquePassGeoInstances.TagEntries(); m_visEntities.TagEntries(); } if (iFrustumCount > 1) { m_visiblePrimaryOpaquePassGeoInstances.Clear(); m_visibleSecondaryOpaquePassGeoInstances.Clear(); m_visibleTransparentOpaquePassGeoInstances.Clear(); m_visEntities.Clear(); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass)->GetTaggedEntries(m_visiblePrimaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass)->GetTaggedEntries(m_visibleSecondaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass)->GetTaggedEntries(m_visibleTransparentOpaquePassGeoInstances); pVisColl->GetVisibleEntities()->GetTaggedEntries(m_visEntities); } pVisibleGeoInstancesPrimaryOpaquePass = &m_visiblePrimaryOpaquePassGeoInstances; pVisibleGeoInstancesSecondaryOpaquePass = &m_visibleSecondaryOpaquePassGeoInstances; pVisibleGeoInstancesTransparentPass = &m_visibleTransparentOpaquePassGeoInstances; pVisEntities = &m_visEntities; } else { pVisibleGeoInstancesPrimaryOpaquePass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass); pVisibleGeoInstancesSecondaryOpaquePass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass); pVisibleGeoInstancesTransparentPass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass); pVisEntities = pVisColl->GetVisibleEntities(); } // === End Visibility Determination === if (m_pMirror->GetExecuteRenderHooks()) { VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY); Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data); } // Render opaque static geometry VASSERT(m_spDefaultLightMapping->m_Shaders.Count()==1); TRIGGER_MIRROR_HOOK(VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY) VisMirror_cl::VReflectionShaderSets_e shaderMode = m_pMirror->m_eReflectionShaderMode; DrawStaticGeometry(*pVisibleGeoInstancesPrimaryOpaquePass, VPT_PrimaryOpaquePass); DrawStaticGeometry(*pVisibleGeoInstancesSecondaryOpaquePass, VPT_SecondaryOpaquePass); // Render entities const VisEntityCollection_cl *pEntities = pVisEntities; int iCount = pEntities->GetNumEntries(); VASSERT(m_spDefaultLightGrid->m_Shaders.Count()==1); //VCompiledShaderPass *pLightgridShader = m_spDefaultLightGrid->m_Shaders.GetAt(0); int i; //bool bUseSimpleShader = shaderMode==VisMirror_cl::AlwaysSimple; Vision::RenderLoopHelper.BeginEntityRendering(); for (i=0;i<iCount;i++) { VisBaseEntity_cl *pEnt = pEntities->GetEntry(i); // Vision::RenderLoopHelper.TrackLightGridInfo(pEnt); // important: need to be done in RenderEntityWithSurfaceShaderList //if (bUseSimpleShader) //{ // Vision::RenderLoopHelper.RenderEntityWithShaders(pEnt,1,&pLightgridShader); //} //else { VisDrawCallInfo_t surfaceShaderList[RLP_MAX_ENTITY_SURFACES]; VDynamicMesh *pMesh = pEnt->GetMesh(); VisSurface_cl **ppSurfaces = pEnt->GetSurfaceArray(); int iNumSubmeshes = pMesh->GetSubmeshCount(); for (int j=0; j<iNumSubmeshes; j++) { VisDrawCallInfo_t &info(surfaceShaderList[j]); VBaseSubmesh* pSubmesh = pMesh->GetSubmesh(j); VisSurface_cl* pSurface = ppSurfaces[pSubmesh->m_iMaterialIndex]; info.Set(pSubmesh, pSurface, GetMirrorShader (pSurface, shaderMode)); } Vision::RenderLoopHelper.RenderEntityWithSurfaceShaderList(pEnt, iNumSubmeshes, surfaceShaderList); } } Vision::RenderLoopHelper.EndEntityRendering(); // Render Sky if (VSky::IsVisible()) { // The sky has to be rendered without oblique clipping pContext->SetCustomProjectionMatrix(NULL); Vision::RenderLoopHelper.RenderSky(); // set the oblique clipping plane after sky... pContext->SetCustomProjectionMatrix (m_pMirror->GetObliqueClippingProjection().getPointer ()); } if (m_pMirror->GetExecuteRenderHooks()) { VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_PRE_OCCLUSION_TESTS); Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data); } // Render Coronas / Lens Flares VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_CORONAS_AND_FLARES); Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data); TRIGGER_MIRROR_HOOK(VRH_PRE_OCCLUSION_TESTS) if (iRenderFlags&VIS_RENDERCONTEXT_FLAG_USE_OCCLUSIONQUERY) Vision::RenderLoopHelper.PerformHardwareOcclusionQuery(); if (iRenderFlags&VIS_RENDERCONTEXT_FLAG_USE_PIXELCOUNTER) Vision::RenderLoopHelper.PerformHardwarePixelCounterQuery(); DrawDynamicLight(); TRIGGER_MIRROR_HOOK(VRH_DECALS) TRIGGER_MIRROR_HOOK(VRH_CORONAS_AND_FLARES) TRIGGER_MIRROR_HOOK(VRH_PRE_TRANSPARENT_PASS_GEOMETRY) DrawStaticGeometry(*pVisibleGeoInstancesTransparentPass, VPT_TransparentPass); TRIGGER_MIRROR_HOOK(VRH_POST_TRANSPARENT_PASS_GEOMETRY) if (bUseScissorRect) Vision::RenderLoopHelper.SetScissorRect(NULL); }
// Simplified version of dynamic light rendering for mirrors void MirrorRenderLoop_cl::DrawDynamicLight() { INSERT_PERF_MARKER_SCOPE("MirrorRenderLoop_cl::DrawDynamicLight"); // Some local variables for storing surfaces, shaders, surface shaders, and the like. VisDrawCallInfo_t SurfaceShaderList[RLP_MAX_ENTITY_SURFACESHADERS]; VCompiledTechnique *pTechnique = NULL; VisMirror_cl::VReflectionShaderSets_e shaderMode = m_pMirror->m_eReflectionShaderMode; // Get all visible light sources IVisVisibilityCollector_cl *pVisColl = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector(); if (pVisColl == NULL) return; const VisLightSrcCollection_cl *pLightSourceCollection = pVisColl->GetVisibleLights(); unsigned int i; unsigned int iNumLights = pLightSourceCollection->GetNumEntries(); if (iNumLights == 0) return; // Set depth-stencil state VisRenderStates_cl::SetDepthStencilState(m_dynLightDefaultState); // For all visible lights... for (i=0; i<iNumLights; i++) { VisLightSource_cl *pLight = pLightSourceCollection->GetEntry(i); // We're only interested in dynamic lights if (!pLight->IsDynamic()) continue; // Clear the collections of geo instances and entities, since we want to build them from scratch for each light s_LitEntityCollection.Clear(); s_LitGeoInstanceCollection.Clear(); // See which geometry types have to cast shadows int iReceiverFlags = GetLightReceiverFlags(pLight); // If nothing receives light from this light source, we can proceed to the next light. if (!iReceiverFlags) continue; // ***************** Create lists of illuminated scene elements ***************** // If no shadows are cast, we simply illuminate all visible geometry within the range (spherical) of the light. VisEntityCollection_cl *pEntColl = NULL; if (iReceiverFlags & VIS_LIGHTSRCVIS_MODELS) pEntColl = &s_LitEntityCollection; VisStaticGeometryInstanceCollection_cl *pGeoInstanceColl = NULL; if (iReceiverFlags & VIS_LIGHTSRCVIS_PRIMITIVES) { pGeoInstanceColl = &s_LitGeoInstanceCollection; } Vision::RenderLoopHelper.GetVisibleGeometryInLightsourceRange(pGeoInstanceColl, pEntColl, NULL, *pLight); // For all illuminated entities: Render a dynamic lighting pass now. if (pLight->GetLightInfluenceBitMaskEntity()) { int j; int iNumLitEntities = s_LitEntityCollection.GetNumEntries(); Vision::RenderLoopHelper.BeginEntityRendering(); for (j=0; j<iNumLitEntities; j++) { VisBaseEntity_cl *pEntity = s_LitEntityCollection.GetEntry(j); // Ignore foreground entities (they don't trivially support additive lighting) if (pEntity->IsObjectAlwaysInForegroundEnabled()) continue; if (!(pEntity->GetLightInfluenceBitMask() & pLight->GetLightInfluenceBitMaskEntity())) continue; if (!pVisColl->IsEntityVisible(pEntity)) continue; VDynamicMesh *pMesh = pEntity->GetMesh(); // Get list of all the surfaces in the model int iNumSubmeshes = pMesh->GetSubmeshCount(); int iNumSurfaceShaders = 0; VisSurface_cl **ppSurfaceArray = pEntity->GetSurfaceArray(); // For all the surfaces... for (int k=0; k<iNumSubmeshes; k++) { VDynamicSubmesh *pSubmesh = pMesh->GetSubmesh(k); VASSERT(pSubmesh != NULL); VisSurface_cl* pSurface = &m_dummySurface; VisSurface_cl* pMeshSurface = pSubmesh->m_pSurface; VASSERT(pMeshSurface != NULL); bool bHasManualTemplateShaderAssignment = pMeshSurface->GetShaderMode() == VisSurface_cl::VSM_Template && pMeshSurface->GetMaterialTemplate() != NULL && pMeshSurface->GetMaterialTemplate()->HasManualAssignment(); if (shaderMode == VisMirror_cl::AlwaysSurfaceShaders || (shaderMode == VisMirror_cl::SimpleForAUTO && ( (pMeshSurface->GetShaderMode() == VisSurface_cl::VSM_Manual) || bHasManualTemplateShaderAssignment) ) ) { pSurface = ppSurfaceArray[pSubmesh->m_iMaterialIndex]; // use the real surface } pTechnique = Vision::GetApplication()->GetShaderProvider()->GetDynamicLightShader(pLight, pSurface, true); if (pTechnique==NULL) continue; VisDrawCallInfo_t &info(SurfaceShaderList[iNumSurfaceShaders++]); info.Set(pSubmesh, pSurface, pTechnique->m_Shaders.GetAt(0)); } // Finally, render the entity with a surface shader list. if (iNumSurfaceShaders>0) Vision::RenderLoopHelper.RenderEntityWithSurfaceShaderList(pEntity, iNumSurfaceShaders, SurfaceShaderList); } Vision::RenderLoopHelper.EndEntityRendering(); } // For all illuminated world primitives: Render a dynamic lighting pass now if (pLight->GetLightInfluenceBitMaskWorld() > 0) { // For all illuminated static geometry instances: Render a dynamic lighting pass now. int iNumLitGeoInstances = s_LitGeoInstanceCollection.GetNumEntries(); s_RenderGeoInstanceCollection.Clear(); // Render illuminated geometry instances. for (int j=0; j < iNumLitGeoInstances; j++) { VisStaticGeometryInstance_cl *pGI = s_LitGeoInstanceCollection.GetEntry(j); if (pGI->GetSurface()==NULL || pGI->GetSurface()->IsFullbright()) continue; // We have to append the primitive to our collection s_RenderGeoInstanceCollection.AppendEntry(pGI); } // render the collection const int iLitGeoCount = s_RenderGeoInstanceCollection.GetNumEntries(); if (iLitGeoCount > 0) { VCompiledTechnique *pLastTech = NULL; VisSurface_cl* pLastSurface = NULL; m_CustomGeoInstances.EnsureSize(iLitGeoCount); m_CustomGeoInstances.Clear(); for (int j=0; j < iLitGeoCount; j++) { VisStaticGeometryInstance_cl *pGI = s_RenderGeoInstanceCollection.GetEntry(j); GetLightShader (pLight, pGI, m_pMirror->m_eReflectionShaderMode, pLastSurface, pLastTech, pLastSurface, pTechnique); // The current technique has changed, so we have to render the previously gathered geometry. if (pLastTech != pTechnique) { if ((m_CustomGeoInstances.GetNumEntries() > 0) && (pLastTech != NULL) && (pLastTech->GetShaderCount() > 0)) { Vision::RenderLoopHelper.RenderStaticGeometryWithShader(m_CustomGeoInstances, *pLastTech->m_Shaders.GetAt(0) ); m_CustomGeoInstances.Clear(); } pLastTech = pTechnique; } m_CustomGeoInstances.AppendEntryFast(pGI); } // Render remaining geometry if ((m_CustomGeoInstances.GetNumEntries() > 0) && (pLastTech != NULL) && (pLastTech->GetShaderCount() > 0)) { Vision::RenderLoopHelper.RenderStaticGeometryWithShader(m_CustomGeoInstances, *pTechnique->m_Shaders.GetAt(0) ); } s_RenderGeoInstanceCollection.Clear(); } } } // Restore default render state VisRenderStates_cl::SetDepthStencilState(*VisRenderStates_cl::GetDepthStencilDefaultState()); }
void AnimatedWarrior_cl::SetupAnimations() { m_bModelValid = false; VDynamicMesh *pMesh = GetMesh(); VVERIFY_OR_RET(pMesh); VisAnimEventList_cl *pEventList = NULL; // idle animations m_spSkeletalSequenceList[ANIMID_IDLE] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Idle", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_IDLE]); m_spSkeletalSequenceList[ANIMID_IDLE_TORCH] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Idle_Look_Torch", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_IDLE_TORCH]); // run animation m_spSkeletalSequenceList[ANIMID_RUN] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Run", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_RUN]); pEventList = m_spSkeletalSequenceList[ANIMID_RUN]->GetEventList(); pEventList->AddEvent(0.0f, EVENT_ANIM_LEGSPARALLEL_FIRSTTIME); pEventList->AddEvent(0.396f, EVENT_ANIM_LEGSPARALLEL_SECONDTIME); // run with torch animation m_spSkeletalSequenceList[ANIMID_RUN_TORCH] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Run_Torch", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_RUN_TORCH]); pEventList = m_spSkeletalSequenceList[ANIMID_RUN_TORCH]->GetEventList(); pEventList->AddEvent(0.0f, EVENT_ANIM_LEGSPARALLEL_FIRSTTIME); pEventList->AddEvent(0.396f, EVENT_ANIM_LEGSPARALLEL_SECONDTIME); // walk animation m_spSkeletalSequenceList[ANIMID_WALK] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Walk", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_WALK]); pEventList = m_spSkeletalSequenceList[ANIMID_WALK]->GetEventList(); pEventList->AddEvent(0.0f, EVENT_ANIM_LEGSPARALLEL_FIRSTTIME); pEventList->AddEvent(0.495f, EVENT_ANIM_LEGSPARALLEL_SECONDTIME); // walk with torch animation m_spSkeletalSequenceList[ANIMID_WALK_TORCH] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Walk_Torch", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_WALK_TORCH]); pEventList = m_spSkeletalSequenceList[ANIMID_WALK_TORCH]->GetEventList(); pEventList->AddEvent(0.0f, EVENT_ANIM_LEGSPARALLEL_FIRSTTIME); pEventList->AddEvent(0.495f, EVENT_ANIM_LEGSPARALLEL_SECONDTIME); // turn animation m_spSkeletalSequenceList[ANIMID_TURN] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Turn", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_TURN]); // turn with torch animation m_spSkeletalSequenceList[ANIMID_TURN_TORCH] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Turn_Torch", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_TURN_TORCH]); // walk backwards animation m_spSkeletalSequenceList[ANIMID_WALKBACKWARDS] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Run_BWD_V2", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_WALKBACKWARDS]); // walk backwards with torch animation m_spSkeletalSequenceList[ANIMID_WALKBACKWARDS_TORCH] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Run_BWD_Torch_V2", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_WALKBACKWARDS_TORCH]); // upper body animations (torch) m_spSkeletalSequenceList[ANIMID_UPPERBODY_ARM] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Draw_Dagger", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_UPPERBODY_ARM]); m_spSkeletalSequenceList[ANIMID_UPPERBODY_ARM]->RemoveOffsetDeltaTrack(); pEventList = m_spSkeletalSequenceList[ANIMID_UPPERBODY_ARM]->GetEventList(); pEventList->AddEvent(m_spSkeletalSequenceList[ANIMID_UPPERBODY_ARM]->GetLength(), EVENT_ANIM_UPPERBODY_ARMING_FINISHED); m_spSkeletalSequenceList[ANIMID_UPPERBODY_DISARM] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Holster_Dagger", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_UPPERBODY_DISARM]); m_spSkeletalSequenceList[ANIMID_UPPERBODY_DISARM]->RemoveOffsetDeltaTrack(); pEventList = m_spSkeletalSequenceList[ANIMID_UPPERBODY_DISARM]->GetEventList(); pEventList->AddEvent(m_spSkeletalSequenceList[ANIMID_UPPERBODY_DISARM]->GetLength(), EVENT_ANIM_UPPERBODY_DISARMING_FINISHED); m_spSkeletalSequenceList[ANIMID_UPPERBODY_ATTACK] = (VisSkeletalAnimSequence_cl*)pMesh->GetSequence("Strike_Dagger", VIS_MODELANIM_SKELETAL); VVERIFY_OR_RET(m_spSkeletalSequenceList[ANIMID_UPPERBODY_ATTACK]); m_spSkeletalSequenceList[ANIMID_UPPERBODY_ATTACK]->RemoveOffsetDeltaTrack(); pEventList = m_spSkeletalSequenceList[ANIMID_UPPERBODY_ATTACK]->GetEventList(); pEventList->AddEvent(m_spSkeletalSequenceList[ANIMID_UPPERBODY_ATTACK]->GetLength(), EVENT_ANIM_UPPERBODY_ATTACK_FINISHED); m_bModelValid = true; }