// Helper for OnRunGameLoop // The update loop is responsible for deleting "dead" entities and updating the core engine's variables void VisionApp_cl::RunUpdateLoop() { VISION_PROFILE_FUNCTION( VIS_PROFILE_GAMELOOP_UPDATELOOP ); // Delete "dead" entities from previous frame Vision::Game.FreeRemovedEntities(); const VisEntityCollection_cl &updatedEntities = Vision::Game.GetUpdatedEntities(); const int iNumEntities = updatedEntities.GetNumEntries(); int &i = updatedEntities.m_iIterator; // use this iterator to keep counter in-sync if collection changes during loop for (i=0; i<iNumEntities; i++) { VisBaseEntity_cl *pEntity = updatedEntities.GetEntry(i); if (!pEntity) continue; VISION_PROFILE_FUNCTION(VIS_PROFILE_GAMELOOP_MODULESYSHANDLE); // send notifications to module system (e.g. all children like bound entities, lights, particles, ...) pEntity->Handle(); // update visibility bounding box pEntity->UpdateVisBoundingBox(); // update core engine variables if ( pEntity->IsCoreUpdateRequired() ) pEntity->UpdateEntityChangedStatus(); // reset the status flags pEntity->ResetStatusFlags(); } }
VParticleWallmark* VWallmarkManager::CreateWallmark( VTextureObject *pTexture, VIS_TransparencyType eBlending, const hkvVec3& vCenter, const hkvMat3 &alignment, VColorRef color, float fLifetime, float fFadeOutTime, bool bApplyDeferredLighting) { VISION_PROFILE_FUNCTION(PROFILING_WALLMARK_CREATION); VParticleWallmark* p = CreateParticle(pTexture,eBlending,bApplyDeferredLighting,vCenter,true); p->pos[0] = vCenter.x; p->pos[1] = vCenter.y; p->pos[2] = vCenter.z; p->color = color; hkvVec3 normal = alignment.getAxis(0); hkvVec3 right = alignment.getAxis(1); hkvVec3 up = alignment.getAxis(2); p->size = up.getLength()*2.f; normal.normalizeIfNotZero(); p->normal[0] = normal.x; p->normal[1] = normal.y; p->normal[2] = normal.z; p->distortion[0] = right.x*2.f; p->distortion[1] = right.y*2.f; p->distortion[2] = right.z*2.f; p->velocity[0] = fLifetime + fFadeOutTime; p->velocity[1] = fFadeOutTime; p->velocity[2] = (float)color.a; // original alpha (255 based) return p; }
// Helper for OnRunGameLoop // Run the physics simulation void VisionApp_cl::RunPhysics(float fElapsedTime) { VISION_PROFILE_FUNCTION( VIS_PROFILE_PHYSICS_RUNSIMULATION ); IVisPhysicsModule_cl *pPhysicsModule = Vision::GetApplication()->GetPhysicsModule(); if ( pPhysicsModule ) pPhysicsModule->OnRunPhysics( fElapsedTime ); }
void VTerrainDecorationEntityModel::RenderBatchIR(VTerrainVisibilityCollectorComponent *pInfoComp, VTerrainDecorationInstance **pInstList, int iCount, RenderMode_e eRenderMode) { // IR Rendering VTerrainDecorationModelManager* pManager = (VTerrainDecorationModelManager *)GetParentManager(); VShaderEffectLib* pEffectLib = pManager->GetInfraredShaderLib(); if (iCount > 0 && pManager->m_iInstancingBatchCount > 0 && pEffectLib != NULL) { int iMaxInstanceCount, iInstanceStreamMask; VisSurface_cl* pSurface = m_spMesh->GetSurface(0); if (m_spInstancingTechIRPrePass == NULL) { // lazy IR shader init RecreateIRShaders(pSurface, pEffectLib); } if (m_spInstancingTechIRPrePass == NULL || m_spInstancingTechIRMainPass == NULL) return; const int iPrimitiveCount = m_spModelMesh->GetCurrentPrimitiveCount(); const int iVertexCount = m_spModelMesh->GetVertexCount(); const VisMeshBuffer_cl::MB_PrimitiveType_e ePrimType = m_spModelMesh->GetPrimitiveType(); bool bPrePass = (eRenderMode == RENDER_MODE_IR_PREPASS); VCompiledShaderPass* pShader = bPrePass? m_spInstancingTechIRPrePass->GetShader(0) : m_spInstancingTechIRMainPass->GetShader(0); const int iStreamMask = m_spModelMesh->GetStreamMask() & (pShader->GetStreamMask() | VERTEX_STREAM_INDEXBUFFER); VisMeshBuffer_cl* pInstanceMesh = pManager->GetInstanceBuffer(iMaxInstanceCount, iInstanceStreamMask); iInstanceStreamMask &= pShader->GetStreamMask(); // perform the rendering Vision::RenderLoopHelper.BeginMeshRendering(); Vision::RenderLoopHelper.BindDefaultStateGroups(pSurface, pShader); if (!bPrePass || pSurface->GetTransparencyType() != VIS_TRANSP_NONE) Vision::RenderLoopHelper.BindMeshTexture(pSurface->GetBaseTextureObject(), 0, NULL); while (iCount > 0) { int iRenderCount = hkvMath::Min(iCount, iMaxInstanceCount); // fill the instance buffer: { VISION_PROFILE_FUNCTION(VTerrainSectorManager::PROFILING_RENDERDECORARION_INSTANCE_SETUP); VModelInstanceData_t* pDest = (VModelInstanceData_t *)pInstanceMesh->LockVertices(VIS_LOCKFLAG_DISCARDABLE, 0, iRenderCount); for (int i = 0; i < iRenderCount; i++, pInstList++, pDest++) pDest->Set(*pInstList[0]); pInstanceMesh->UnLockVertices(); } iCount -= iRenderCount; RENDER_INSTANCES(iRenderCount, iStreamMask); } Vision::RenderLoopHelper.EndMeshRendering(); } }
// Helper for OnRunGameLoop // Fetch the physics results void VisionApp_cl::FetchPhysicsResults() { VISION_PROFILE_FUNCTION( VIS_PROFILE_PHYSICS_FETCHRESULTS ); IVisPhysicsModule_cl *pPhysicsModule = Vision::GetApplication()->GetPhysicsModule(); if ( pPhysicsModule ) pPhysicsModule->FetchPhysicsResults(); OnUpdatePhysicsFinished.TriggerCallbacks(); }
//Implement VisTypedEngineObject_cl::MessageFunction void VScriptComponent::MessageFunction(int iID, INT_PTR iParamA, INT_PTR iParamB) { VISION_PROFILE_FUNCTION(PROFILING_SCRIPTING); //TODO: Different category? // Return immediately when this component has no script instance if (!m_spInstance) return; if (iID == VIS_MSG_TRIGGER) { if (m_iFunctions&VSCRIPT_FUNC_ONTRIGGER) { VisTriggerSourceComponent_cl *pTriggerSrc = (VisTriggerSourceComponent_cl *)iParamA; VisTriggerTargetComponent_cl *pTriggerTgt = (VisTriggerTargetComponent_cl *)iParamB; m_spInstance->ExecuteFunctionArg("OnTrigger", "*ss",pTriggerSrc->GetComponentName(), pTriggerTgt->GetComponentName()); } return; } if (iID == VIS_MSG_TRANSITIONSTATEMACHINE) { if (m_iFunctions&VSCRIPT_FUNC_ONTRANSITIONEVENT) { m_spInstance->ExecuteFunctionArg("OnTransitionEvent", "*i", iParamA); } return; } if (iID == VIS_MSG_EVENT) // aka animation event { if (m_iFunctions&VSCRIPT_FUNC_ONANIMATIONEVENT) { VisAnimControl_cl *pSender = (VisAnimControl_cl *)iParamB; //do not call Lua function if the animation has been paused if(!pSender->IsPlaying() && m_pLastSenderAnimControl == pSender) return; m_pLastSenderAnimControl = pSender; //get the name of the animation sequence const char * szAnimSequence = pSender->GetAnimSequence() ? pSender->GetAnimSequence()->GetName() : NULL; if(Vision::Animations.IsStringEvent((int)iParamA)) { const char * szAnimationEventName = Vision::Animations.GetEventString((int)iParamA); m_spInstance->ExecuteFunctionArg("OnAnimationEvent", "*ss", szAnimationEventName, szAnimSequence); } else { m_spInstance->ExecuteFunctionArg("OnAnimationEvent", "*is", iParamA, szAnimSequence); } } return; } }
// Helper for OnRunGameLoop // Pre-physics loop: statistics, prethink, events & animations void VisionApp_cl::RunPreThink(float fElapsedTime) { { VISION_PROFILE_FUNCTION(VIS_PROFILE_GAMELOOP_PRETHINKFUNCTION); const VisEntityCollection_cl &relevantEntities = Vision::Game.GetPreThinkingEntities(); int &i = relevantEntities.m_iIterator; // use this iterator to keep counter in-sync if collection changes during loop for (i=0; i<relevantEntities.GetNumEntries(); i++) { VisBaseEntity_cl *pEntity = relevantEntities.GetEntry( i ); VASSERT(pEntity->GetPreThinkFunctionStatus()); // entity code prethink pEntity->PreThinkFunction(); } } OnUpdateAnimatonBegin.TriggerCallbacks(); // run animated entities { VISION_PROFILE_FUNCTION(VIS_PROFILE_ANIMSYS_OVERALL); VISION_PROFILE_FUNCTION(VIS_PROFILE_GAMELOOP_ANIMATION); const VisEntityCollection_cl &relevantEntities = Vision::Game.GetAnimatedEntities(); int &i = relevantEntities.m_iIterator; // use this iterator to keep counter in-sync if collection changes during loop for (i=0; i<relevantEntities.GetNumEntries(); i++) { VisBaseEntity_cl *pEntity = relevantEntities.GetEntry( i ); VASSERT(pEntity->GetAnimConfig()!=NULL); //Process the skeletal and muscle animations //(Do animation before physics so the motion deltas are available for physics) pEntity->HandleAnimations(fElapsedTime); } } OnUpdateAnimatonFinished.TriggerCallbacks(); }
//Implement IVisCallbackHandler_cl void VScriptComponent::OnHandleCallback(IVisCallbackDataObject_cl *pData) { VISION_PROFILE_FUNCTION(PROFILING_SCRIPTING); //TODO: Different category? VASSERT(m_spInstance); if (!m_spInstance || !Vision::Editor.IsAnimatingOrPlaying()) return; if (pData->m_pSender==&Vision::Callbacks.OnUpdateSceneBegin) { if (m_iFunctions & VSCRIPT_FUNC_ONUPDATESCENEBEGIN) m_spInstance->ExecuteFunctionArg("OnUpdateSceneBegin", "*"); return; } if (pData->m_pSender==&Vision::Callbacks.OnScriptThink) { if ((m_iFunctions & VSCRIPT_FUNC_ONTHINK) && !Vision::GetScriptManager()->IsPaused() && m_bScriptThinkEnabled) { m_spInstance->ExecuteFunctionArg("OnThink", "*"); } return; } if (pData->m_pSender==&Vision::Callbacks.OnUpdateSceneFinished) { if (m_iFunctions & VSCRIPT_FUNC_ONUPDATESCENEFINISHED) m_spInstance->ExecuteFunctionArg("OnUpdateSceneFinished", "*"); return; } if (pData->m_pSender==&Vision::Callbacks.OnAfterSceneLoaded) { if (m_iFunctions & VSCRIPT_FUNC_ONAFTERSCENELOADED) m_spInstance->ExecuteFunctionArg("OnAfterSceneLoaded", "*"); return; } if (pData->m_pSender==&Vision::Callbacks.OnBeforeSceneUnloaded) { if (m_iFunctions & VSCRIPT_FUNC_ONBEFORESCENEUNLOADED) m_spInstance->ExecuteFunctionArg("OnBeforeSceneUnloaded", "*"); return; } if (pData->m_pSender==&Vision::Callbacks.OnVideoChanged) { if (m_iFunctions & VSCRIPT_FUNC_ONVIDEOCHANGED) m_spInstance->ExecuteFunctionArg("OnVideoChanged", "*"); return; } }
// Helper for OnRunGameLoop // Post-physics loop: posthink & modulesystem-notifications void VisionApp_cl::RunThink(float fElapsedTime) { const VisEntityCollection_cl &relevantEntities = Vision::Game.GetThinkingEntities(); VISION_PROFILE_FUNCTION(VIS_PROFILE_GAMELOOP_THINKFUNCTION); int &i = relevantEntities.m_iIterator; // use this iterator to keep counter in-sync if collection changes during loop for (i=0; i<relevantEntities.GetNumEntries(); i++) { VisBaseEntity_cl *pEntity = relevantEntities.GetEntry(relevantEntities.m_iIterator); VASSERT(pEntity->GetThinkFunctionStatus()); // entity code postthink pEntity->ThinkFunction(); } }
BOOL VWallmarkManager::TryAlignWallmark( const hkvVec3& vCenter, const hkvVec3& vNormal, float fSize, float fRotation, hkvVec3& vNewCenter, hkvMat3 &alignment, float fEpsilon ) { VISION_PROFILE_FUNCTION(PROFILING_WALLMARK_CREATION); hkvVec3 vNewNormal(hkvNoInitialization); float fTraceRad = fSize; if (!IsTracePointOnPlane(vCenter,vNormal,fTraceRad,fEpsilon,vNewNormal)) return false; hkvVec3 vRight(hkvNoInitialization),vUp(hkvNoInitialization),vRotRight(hkvNoInitialization),vRotUp(hkvNoInitialization), vDummy(hkvNoInitialization); if (hkvMath::Abs (vNewNormal.x)>0.5f) vRight.set(0.f,1.f,0.f); else vRight.set(1.f,0.f,0.f); vUp = vNewNormal.cross(vRight); vRight = vNewNormal.cross(vUp); float fSin = hkvMath::sinDeg (fRotation); float fCos = hkvMath::cosDeg (fRotation); vRotRight = vRight * fCos + vUp * fSin; vRotUp = vRight * -fSin + vUp * fCos; vRotRight.setLength(fSize*0.5f); vRotUp.setLength(fSize*0.5f); alignment.setAxisXYZ (vNewNormal,vRotRight,vRotUp); vNewCenter = vCenter + vNewNormal*fEpsilon; // check corners: if (!IsTracePointOnPlane(vCenter+vRotRight+vRotUp,vNewNormal,fTraceRad,fEpsilon,vDummy)) return false; if (!IsTracePointOnPlane(vCenter+vRotRight-vRotUp,vNewNormal,fTraceRad,fEpsilon,vDummy)) return false; if (!IsTracePointOnPlane(vCenter-vRotRight+vRotUp,vNewNormal,fTraceRad,fEpsilon,vDummy)) return false; if (!IsTracePointOnPlane(vCenter-vRotRight-vRotUp,vNewNormal,fTraceRad,fEpsilon,vDummy)) return false; return TRUE; }
VDialog *VDialogResource::CreateInstance(IVGUIContext *pContext, VDialog *pParent, int iFlags) { VISION_PROFILE_FUNCTION(VGUIManager::PROFILING_BUILD); EnsureLoaded(); if (!m_pXMLNode || !IsLoaded()) // couldn't load XML file? { VASSERT(!"VDialogResource::CreateInstance failed because dialog resource is invalid"); return NULL; } char szPath[FS_MAX_PATH]; GetFilePath(szPath); const char *szClass = XMLHelper::Exchange_String(m_pXMLNode,"class",NULL,false); if (!szClass || !szClass[0]) szClass = "VDialog"; VType *pType = Vision::GetTypeManager()->GetType(szClass); if (!pType) { VASSERT(!"VDialogResource::CreateInstance failed because dialog class does not exist in type manager"); return NULL; } VDialog *pDlg = (VDialog *)pType->CreateInstance(); // sanity check if (!pDlg->IsOfType(Vision::GetTypeManager()->GetType("VDialog"))) Vision::Error.FatalError("class '%s' is not derived from base class VDialog",szClass); VASSERT(pParent==NULL || pParent->m_pContext==pContext); pDlg->InitDialog(pContext, this, pParent, iFlags); if (!pDlg->Build(m_pXMLNode, szPath,false)) { VASSERT(!"VDialogResource::CreateInstance failed because Build from XML node failed"); return NULL; } pDlg->OnBuildFinished(); pDlg->OnInitDialog(); return pDlg; }
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; }
void VTerrainDecorationEntityModel::RenderBatchOTW(VTerrainVisibilityCollectorComponent *pInfoComp, VTerrainDecorationInstance **pInstList, int iCount) { // OTW rendering VTerrainDecorationModelManager *pManager = (VTerrainDecorationModelManager *)GetParentManager(); if (m_spInstancingTech!=NULL && iCount>4 && pManager->m_iInstancingBatchCount>0 /* && bAllowInstancing*/) { VCompiledShaderPass *pShader = m_spInstancingTech->GetShader(0); Vision::RenderLoopHelper.BeginMeshRendering(); VisSurface_cl *pSurface = m_spMesh->GetSurface(0); Vision::RenderLoopHelper.BindSurfaceTextures(pSurface,pShader,NULL); Vision::RenderLoopHelper.BindDefaultStateGroups(pSurface,pShader); VisMeshBuffer_cl::MB_PrimitiveType_e ePrimType = m_spModelMesh->GetPrimitiveType(); int iPrimitiveCount = m_spModelMesh->GetCurrentPrimitiveCount(); int iVertexCount = m_spModelMesh->GetVertexCount(); int iMaxInstanceCount, iInstanceStreamMask; VisMeshBuffer_cl *pInstanceMesh = ((VTerrainDecorationModelManager *)GetParentManager())->GetInstanceBuffer(iMaxInstanceCount,iInstanceStreamMask); // lightmap version if (m_iLightmapSampler>=0 && pInfoComp!=NULL) { #ifdef HK_DEBUG const VStateGroupTexture *pStateGroupTexture = pShader->GetStateGroupTexture(VSS_PixelShader, m_iLightmapSampler); VASSERT(pStateGroupTexture!=NULL && pStateGroupTexture->m_cTextureType==TEXTURETYPE_LIGHTMAP); #endif VStateGroupSampler *pLMSampler = pShader->GetStateGroupSampler(VSS_PixelShader, m_iLightmapSampler); VTerrainSector *pLastSector = NULL; VTextureObject *pTerrainLightmap = NULL; const VTerrainConfig& config(pInfoComp->m_pTerrain->m_Config); VTerrainSectorManager §ormanager(pInfoComp->m_pTerrain->m_SectorManager); while (iCount>0) { int iWantedRenderCount = hkvMath::Min(iCount,iMaxInstanceCount); int iRenderCount = 0; // fill the instance buffer: { VISION_PROFILE_FUNCTION(VTerrainSectorManager::PROFILING_RENDERDECORARION_INSTANCE_SETUP); VModelInstanceData_t *pDest = (VModelInstanceData_t *)pInstanceMesh->LockVertices(VIS_LOCKFLAG_DISCARDABLE,0,iWantedRenderCount); // fill buffer up to lightmap change for (int i=0;i<iWantedRenderCount;i++,iRenderCount++,pDest++) { if (pLastSector!=pInstList[i]->m_pOwnerSector) { pLastSector = pInstList[i]->m_pOwnerSector; VTextureObject *pNewLightmap = pLastSector->m_pMeshPage[0].GetSurfaceSafe().m_spModelLightmaps[0]; if (pNewLightmap!=pTerrainLightmap) { if (iRenderCount>0) // start a new batch so break here break; } } pDest->Set(*pInstList[i]); } pInstanceMesh->UnLockVertices(); } // bind sector specific properties VTerrainSector *pStateSetupSector = pInstList[0]->m_pOwnerSector; // this is where the batch starts hkvVec4 vWorld2Sector(false); // transforms worldspace to sector 0..1 range config.GetWorldSpaceToSectorTransform(pStateSetupSector->m_iIndexX,pStateSetupSector->m_iIndexY,vWorld2Sector); sectormanager.SetWorld2SectorTransform(vWorld2Sector); // standard range -> lightmap const hkvVec4 vSector2LM = pStateSetupSector->GetLightmapScaleOffset(); VisRenderStates_cl::VSSetModelUVToLightmap(vSector2LM.data); Vision::RenderLoopHelper.BindMeshTexture(pStateSetupSector->m_pMeshPage[0].GetSurfaceSafe().m_spModelLightmaps[0],m_iLightmapSampler,pLMSampler); // advance by actual render counts pInstList += iRenderCount; iCount-=iRenderCount; RENDER_INSTANCES(iRenderCount, m_iModelStreams); } } else // non-lightmapped version { while (iCount>0) { int iRenderCount = hkvMath::Min(iCount,iMaxInstanceCount); // fill the instance buffer: { VISION_PROFILE_FUNCTION(VTerrainSectorManager::PROFILING_RENDERDECORARION_INSTANCE_SETUP); VModelInstanceData_t *pDest = (VModelInstanceData_t *)pInstanceMesh->LockVertices(VIS_LOCKFLAG_DISCARDABLE,0,iRenderCount); for (int i=0;i<iRenderCount;i++,pInstList++,pDest++) pDest->Set(*pInstList[0]); pInstanceMesh->UnLockVertices(); } iCount-=iRenderCount; RENDER_INSTANCES(iRenderCount, m_iModelStreams); } } Vision::RenderLoopHelper.EndMeshRendering(); return; } ////////////////////////////////////////////////////////// // Non-instancing version const VisDrawCallInfo_t *pSurfaceShaderList; VDynamicMesh *pMesh = m_spMesh; VASSERT(m_spVegetationShaders!=NULL); VisShaderSet_cl *pSet = m_spVegetationShaders; int iAsmCount = pSet->GetShaderAssignmentList(&pSurfaceShaderList); VColorRef iLastColor; #ifdef _VR_DX11 VisRenderStates_cl::SetVSConstantBuffer(7,&m_PerInstanceData); #endif if (m_bNeedsLightmap && pInfoComp!=NULL) { VTerrainSector *pLastSector = NULL; VTextureObject *pTerrainLightmap = NULL; const VTerrainConfig& config(pInfoComp->m_pTerrain->m_Config); VTerrainSectorManager §ormanager(pInfoComp->m_pTerrain->m_SectorManager); Vision::RenderLoopHelper.BeginEntityRendering(); for (int i=0;i<iCount;i++,pInstList++) { if (pLastSector!=(*pInstList)->m_pOwnerSector) { pLastSector = (*pInstList)->m_pOwnerSector; VTextureObject *pNewLightmap = pLastSector->m_pMeshPage[0].GetSurfaceSafe().m_spModelLightmaps[0]; if (pNewLightmap!=pTerrainLightmap) { // assign new model lightmaps const int iSrfCount = m_spMesh->GetSurfaceCount(); for (int j=0;j<iSrfCount;j++) m_spMesh->GetSurface(j)->m_spModelLightmaps[0] = pNewLightmap; // and also force a shader re-binding for (int j=0;j<iAsmCount;j++) pSurfaceShaderList[j].GetShader()->m_bModified=true; pTerrainLightmap = pNewLightmap; } hkvVec4 vWorld2Sector(false); // transforms worldspace to sector 0..1 range config.GetWorldSpaceToSectorTransform(pLastSector->m_iIndexX,pLastSector->m_iIndexY,vWorld2Sector); sectormanager.SetWorld2SectorTransform(vWorld2Sector); // standard range -> lightmap const hkvVec4 vSector2LM = pLastSector->GetLightmapScaleOffset(); VisRenderStates_cl::VSSetModelUVToLightmap(vSector2LM.data); } // per instance tint color if (i==0 || iLastColor!=(*pInstList)->m_InstanceColor) { iLastColor = (*pInstList)->m_InstanceColor; VPerInstanceData_t &data(m_PerInstanceData.BeginUpdate()); VColorRef::RGBA_To_Float((*pInstList)->m_InstanceColor, data.vPerInstanceColor); m_PerInstanceData.EndUpdate(); #ifndef _VR_DX11 VisRenderStates_cl::SetVSConstantBuffer(7,&m_PerInstanceData); #endif } // finally render object hkvMat4 transform((*pInstList)->m_Orientation,(*pInstList)->m_vPosition); Vision::RenderLoopHelper.RenderModelWithSurfaceShaderList(m_spMesh,transform.getPointer (),iAsmCount,pSurfaceShaderList); } VisRenderStates_cl::SetVSConstantBuffer(7,NULL); Vision::RenderLoopHelper.EndEntityRendering(); } else { Vision::RenderLoopHelper.BeginEntityRendering(); // no lightmaps -> simple loop for (int i=0;i<iCount;i++,pInstList++) { // per instance tint color if (i==0 || iLastColor!=(*pInstList)->m_InstanceColor) { iLastColor = (*pInstList)->m_InstanceColor; VPerInstanceData_t &data(m_PerInstanceData.BeginUpdate()); VColorRef::RGBA_To_Float((*pInstList)->m_InstanceColor, data.vPerInstanceColor); m_PerInstanceData.EndUpdate(); #ifndef _VR_DX11 VisRenderStates_cl::SetVSConstantBuffer(7,&m_PerInstanceData); #endif } hkvMat4 transform((*pInstList)->m_Orientation,(*pInstList)->m_vPosition); Vision::RenderLoopHelper.RenderModelWithSurfaceShaderList(m_spMesh,transform.getPointer(),iAsmCount,pSurfaceShaderList); } VisRenderStates_cl::SetVSConstantBuffer(7,NULL); Vision::RenderLoopHelper.EndEntityRendering(); } }
void VTerrainDecorationEntityModel::RenderBatchDepthShadow(VTerrainVisibilityCollectorComponent *pInfoComp, VTerrainDecorationInstance **pInstList, int iCount) { // depth shader rendering INSERT_PERF_MARKER_SCOPE("VTerrainDecorationEntityModel::RenderBatchDepthShadow"); VTerrainDecorationModelManager *pManager = (VTerrainDecorationModelManager *)GetParentManager(); if (m_spInstancingTechShadow!=NULL && iCount>4 && pManager->m_iInstancingBatchCount>0 /* && bAllowInstancing*/) { VCompiledShaderPass *pShader = m_spInstancingTechShadow->GetShader(0); Vision::RenderLoopHelper.BeginMeshRendering(); VisSurface_cl *pSurface = m_spMesh->GetSurface(0); Vision::RenderLoopHelper.BindSurfaceTextures(pSurface,pShader,NULL); Vision::RenderLoopHelper.BindDefaultStateGroups(pSurface,pShader); VisMeshBuffer_cl::MB_PrimitiveType_e ePrimType = m_spModelMesh->GetPrimitiveType(); int iPrimitiveCount = m_spModelMesh->GetCurrentPrimitiveCount(); int iVertexCount = m_spModelMesh->GetVertexCount(); int iMaxInstanceCount, iInstanceStreamMask; VisMeshBuffer_cl *pInstanceMesh = ((VTerrainDecorationModelManager *)GetParentManager())->GetInstanceBuffer(iMaxInstanceCount,iInstanceStreamMask); while (iCount>0) { int iRenderCount = hkvMath::Min(iCount,iMaxInstanceCount); // fill the instance buffer: { VISION_PROFILE_FUNCTION(VTerrainSectorManager::PROFILING_RENDERDECORARION_INSTANCE_SETUP); VModelInstanceData_t *pDest = (VModelInstanceData_t *)pInstanceMesh->LockVertices(VIS_LOCKFLAG_DISCARDABLE,0,iRenderCount); for (int i=0;i<iRenderCount;i++,pInstList++,pDest++) pDest->Set(*pInstList[0]); pInstanceMesh->UnLockVertices(); } iCount-=iRenderCount; RENDER_INSTANCES(iRenderCount, m_iModelStreams); } Vision::RenderLoopHelper.EndMeshRendering(); } else { // non-instancing version VisDrawCallInfo_t surfaceShaderList[RLP_MAX_ENTITY_SURFACESHADERS]; const int iNumSubmeshes = m_spMesh->GetSubmeshCount(); int iAsmCount = 0; for (int i=0;i<iNumSubmeshes;i++) { VDynamicSubmesh *pSubmesh = m_spMesh->GetSubmesh(i); VisDrawCallInfo_t &assignment(surfaceShaderList[iAsmCount]); if (pSubmesh->GetSurface()->m_spShadowmapFill==NULL) continue; assignment.Set(pSubmesh, pSubmesh->GetSurface(), pSubmesh->GetSurface()->m_spShadowmapFill->GetShader(0)); iAsmCount++; } Vision::RenderLoopHelper.BeginEntityRendering(); for (int i=0;i<iCount;i++) { hkvMat4 transform(pInstList[i]->m_Orientation,pInstList[i]->m_vPosition); Vision::RenderLoopHelper.RenderModelWithSurfaceShaderList(m_spMesh, transform.getPointer (),iAsmCount,surfaceShaderList); } Vision::RenderLoopHelper.EndEntityRendering(); } }
void VFmodManager::RunTick(float fTimeDelta) { if (!IsInitialized()) return; VISION_PROFILE_FUNCTION(PROFILING_FMOD_OVERALL); // profiling scope { VISION_PROFILE_FUNCTION(PROFILING_FMOD_PUREUPDATE); VASSERT(m_pEventSystem!=NULL); // update Fmod listener attributes VisObject3D_cl *pListener = m_pListenerObject ? m_pListenerObject : Vision::Camera.GetMainCamera(); if (!pListener) return; hkvVec3 vCamPos = pListener->GetPosition(); hkvVec3 vDir(pListener->GetObjDir()), vRight(pListener->GetObjDir_Right()), vUp(pListener->GetObjDir_Up()); vUp = -vUp; // compensate for coordinate system m_pEventSystem->set3DListenerAttributes(0, (FMOD_VECTOR *)&vCamPos, NULL, (FMOD_VECTOR *)&vDir, (FMOD_VECTOR *)&vUp); // no speed (yet) // update all sound objects SoundInstances().Update(); // update all events Events().Update(); // update Fmod event system m_fTimeLeftOver += fTimeDelta; if (m_fTimeLeftOver > m_config.fTimeStep) { m_pEventSystem->update(); #ifdef VFMOD_SUPPORTS_NETWORK if (m_config.bUseNetworkSystem) FMOD::NetEventSystem_Update(); #endif m_fTimeLeftOver = hkvMath::mod (m_fTimeLeftOver, m_config.fTimeStep); } } // do not purge sounds/ events in vForge, in order to allow toggling playback via hotspot button if (Vision::Editor.IsInEditor()) return; if (m_bAnyStopped) { VISION_PROFILE_FUNCTION(PROFILING_FMOD_PURGE); // all sounds/ events that have finished playing are removed from handling SoundInstances().PurgeNotPlaying(); Events().PurgeNotPlaying(); m_bAnyStopped = false; // reset any stopped flag } }
void VFmodManager::RunTick(float fTimeDelta) { VISION_PROFILE_FUNCTION(PROFILING_FMOD_OVERALL); if (!IsInitialized()) { if (!IsOutputDevicePresent()) InitDevice(); return; } // profiling scope { VISION_PROFILE_FUNCTION(PROFILING_FMOD_PUREUPDATE); VASSERT(m_pEventSystem!=NULL); // update Fmod listener attributes VisObject3D_cl *pListener = m_pListenerObject; if (pListener == NULL) { // The listener is the main camera. Check for teleportation since the last Fmod update, in // which case we won't use the position difference to calculate the listener speed. VisContextCamera_cl* pCamera = Vision::Camera.GetMainCamera(); VisRenderContext_cl* pContext = VisRenderContext_cl::GetMainRenderContext(); if (pCamera != NULL && pContext != NULL) { if (m_bLastListenerPositionValid && pCamera->GetLastTeleported() > m_iFrameOfLastUpdate) m_bLastListenerPositionValid = false; m_iFrameOfLastUpdate = pContext->GetLastRenderedFrame(); pListener = pCamera; } } if (!pListener) return; hkvVec3 vCamPos = pListener->GetPosition(); hkvVec3 vDir(pListener->GetObjDir()), vRight(pListener->GetObjDir_Right()), vUp(pListener->GetObjDir_Up()); // Determine the camera velocity based on the previous known position hkvVec3 vCamVel(m_bLastListenerPositionValid && (fTimeDelta > 0.f) ? (vCamPos - m_vLastListenerPosition) * (1.f / fTimeDelta) : hkvVec3::ZeroVector()); m_vLastListenerPosition = vCamPos; m_bLastListenerPositionValid = true; vUp = -vUp; // compensate for coordinate system m_pEventSystem->set3DListenerAttributes(0, (FMOD_VECTOR *)&vCamPos, (FMOD_VECTOR *)&vCamVel, (FMOD_VECTOR *)&vDir, (FMOD_VECTOR *)&vUp); // update all sound objects SoundInstances().Update(fTimeDelta); // update all events Events().Update(fTimeDelta); // update Fmod event system m_fTimeLeftOver += fTimeDelta; if (m_fTimeLeftOver > m_config.fTimeStep) { m_pEventSystem->update(); #ifdef VFMOD_SUPPORTS_NETWORK if (m_config.bUseNetworkSystem) FMOD::NetEventSystem_Update(); #endif m_fTimeLeftOver = hkvMath::mod (m_fTimeLeftOver, m_config.fTimeStep); } } // do not purge sounds/ events in vForge, in order to allow toggling playback via hotspot button if (Vision::Editor.IsInEditor()) return; if (m_bAnyStopped) { VISION_PROFILE_FUNCTION(PROFILING_FMOD_PURGE); // all sounds/ events that have finished playing are removed from handling SoundInstances().PurgeNotPlaying(); Events().PurgeNotPlaying(); m_bAnyStopped = false; // reset any stopped flag } }
void VCoronaManager::RenderAllVisibleCoronas() { #ifdef SUPPORTS_CORONAS VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext(); // Determine relevant render context and visibility collector IVisVisibilityCollector_cl *pVisCollector = pContext->GetVisibilityCollector(); if (!pVisCollector) return; VisRenderContext_cl *pOQContext = pVisCollector->GetOcclusionQueryRenderContext(); if (pOQContext != NULL) pContext = pOQContext; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_USE_PIXELCOUNTER) == 0) return; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_RENDER_CORONAS) == 0) return; INSERT_PERF_MARKER_SCOPE("VCoronaManager::RenderAllVisibleCoronas"); VISION_PROFILE_FUNCTION(PROFILING_CORONA_RENDER); // Force for the queries to finish so they are available in this frame. if (m_bTeleportedLastFrame && m_bForceQueryOnTeleport) { UpdateCoronas(VCUF_UPDATE | VCUF_FORCE_FETCH | VCUF_USE_OC_CONTEXT); } // Ensure size of corona state structure. int iContextIndex = pContext->GetNumber(); if (iContextIndex + 1 > m_State.GetSize()) m_State.SetSize(iContextIndex + 1, -1); VCoronaRenderContextState& state = m_State[iContextIndex]; int iCapacity = m_Instances.GetCapacity(); state.EnsureSize(iCapacity); const int iCoronasToRender = state.m_Candidates.GetSize(); // Sort candidates by texture? VTextureObject* pTexture = NULL; // Render all corona components Vision::RenderLoopHelper.BeginMeshRendering(); Vision::RenderLoopHelper.AddMeshStreams(m_spBillboardMesh,VERTEX_STREAM_POSITION); for (int i=0; i < iCoronasToRender; ++i) { VCoronaCandidate& coronaCandidate = state.m_Candidates.ElementAt(i); if (coronaCandidate.m_fCurrentVisibility > 0.0f) { RenderCorona (coronaCandidate, pTexture); } } Vision::RenderLoopHelper.EndMeshRendering(); m_bTeleportedLastFrame = (pContext->GetCamera()->GetLastTeleported() >= pContext->GetLastRenderedFrame()); #endif }
void VCoronaManager::UpdateCoronas(int iCoronaUpdateFlags) { #ifdef SUPPORTS_CORONAS VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext(); if ((iCoronaUpdateFlags & VCUF_USE_OC_CONTEXT) > 0) { // Determine relevant render context and visibility collector IVisVisibilityCollector_cl *pVisCollector = pContext->GetVisibilityCollector(); if (!pVisCollector) return; VisRenderContext_cl *pOQContext = pVisCollector->GetOcclusionQueryRenderContext(); if (pOQContext != NULL) pContext = pOQContext; } if (pContext == NULL) return; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_USE_PIXELCOUNTER) == 0) return; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_RENDER_CORONAS) == 0) return; // Get bitmask for this context. unsigned int iRenderFilterMask = pContext->GetRenderFilterMask(); // get the collection of visible lights. IVisVisibilityCollector_cl* pVisCollector = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector(); if (pVisCollector == NULL) return; VISION_PROFILE_FUNCTION(PROFILING_CORONA_UPDATE); // Get multi-sampling mode unsigned int iTexelsPerPixel = 1; VTextureObject* pDepthTex = pContext->GetDepthStencilTarget(); if(pDepthTex == NULL) { // If no depth stencil target is available, we might work without a renderer node and we're in the main context if(Vision::Renderer.GetCurrentRendererNode() == NULL && pContext == VisRenderContext_cl::GetMainRenderContext()) { // In this case get the multi-sampling type from the video config as it's used to set the actual backbuffer settings // where the main context will render to iTexelsPerPixel = hkvMath::Max(1, 1 << ((int)Vision::Video.GetCurrentConfig()->m_eMultiSample)); } } else if (pDepthTex->GetTextureType() == VTextureLoader::Texture2D) { iTexelsPerPixel = hkvMath::Max(1u, ((VisRenderableTexture_cl*)pDepthTex)->GetConfig()->m_iMultiSampling); } const VisLightSrcCollection_cl* pVisibleLights = pVisCollector->GetVisibleLights(); int iCandidates = 0; if (pVisibleLights != NULL) iCandidates = pVisibleLights->GetNumEntries(); // Ensure size of coronas state structure. int iContextIndex = pContext->GetNumber(); if (iContextIndex + 1 > m_State.GetSize()) m_State.SetSize(iContextIndex + 1, -1); VCoronaRenderContextState& state = m_State[iContextIndex]; int iCapacity = m_Instances.GetCapacity(); state.EnsureSize(iCapacity); // Add visible lights with a lens flare component to the candidate list for this frame if ((iCoronaUpdateFlags & VCUF_ADD) > 0) { for (int iCandidate = 0; iCandidate < iCandidates; ++iCandidate) { VisLightSource_cl* pLight = pVisibleLights->GetEntry(iCandidate); if (pLight) { VCoronaComponent *pComponent = pLight->Components().GetComponentOfBaseType<VCoronaComponent>(); if (pComponent != NULL && pComponent->IsEnabled() && !state.IsBitSet(pComponent->m_iIndex)) { // The component is not in m_Candidates yet, so we check whether it is a valid candidate bool bIsLightOnScreen = pComponent->IsValidCandidate(pContext); if (bIsLightOnScreen) { state.SetBit(pComponent->m_iIndex); pContext->SetPixelCounterResult(pComponent->m_CoronaPixelCounter.GetNumber(), 0); state.m_Candidates.Append(pComponent); } } } } } // Forces the retrieval all pending queries. pContext->FetchPixelCounterTestResults( (iCoronaUpdateFlags & VCUF_FORCE_FETCH) > 0 ); // Retrieve Queries and update status of lens flares if ((iCoronaUpdateFlags & VCUF_UPDATE) > 0) { for (int i=0; i < state.m_Candidates.GetSize(); ++i) { VCoronaCandidate& coronaCandidate = state.m_Candidates.ElementAt(i); VCoronaComponent* pCorona = coronaCandidate.m_pCorona; if (!pCorona || !pCorona->IsEnabled()) continue; if (pCorona->GetOwner()) { // Retrieve occlusion results of the last query unsigned int iElementIndex = pCorona->m_CoronaPixelCounter.GetNumber(); bool bRes = !pContext->IsPixelCounterQueryInProgress(iElementIndex); // Reschedule query if the old on could be retrieved or if a teleport forces us to re-query everything. if (bRes | ((iCoronaUpdateFlags & VCUF_FORCE_SCHEDULE) > 0) ) pContext->SchedulePixelCounterTest(iElementIndex); unsigned int iDrawnPixels = pContext->GetPixelCounterResult(iElementIndex) / iTexelsPerPixel; float fVisibility = (float)iDrawnPixels / ((int)pCorona->QueryRadius * (int)pCorona->QueryRadius * 4); // ATI fix for random insanely high return values. if (iDrawnPixels > ((unsigned int)pCorona->QueryRadius * 2 + 1) * ((unsigned int)pCorona->QueryRadius * 2 + 1)) { fVisibility = coronaCandidate.m_fLastVisibilityQuery; } if ((iCoronaUpdateFlags & VCUF_FORCE_FETCH) > 0) { // Force lens flare visibility to the current query value. coronaCandidate.m_fCurrentVisibility = fVisibility; coronaCandidate.m_fLastVisibilityQuery = fVisibility; pCorona->UpdateVisibility(coronaCandidate.m_fLastVisibilityQuery, coronaCandidate.m_fCurrentVisibility); } else if (!m_bTeleportedLastFrame) { coronaCandidate.m_fLastVisibilityQuery = fVisibility; pCorona->UpdateVisibility(coronaCandidate.m_fLastVisibilityQuery, coronaCandidate.m_fCurrentVisibility); } else { // if we were teleported, the last frame's query results must be invalidated coronaCandidate.m_fCurrentVisibility = 0.0f; coronaCandidate.m_fLastVisibilityQuery = 0.0f; } } } } // Removes coronas that are outside the frustum and no longer visible. if ((iCoronaUpdateFlags & VCUF_REMOVE) > 0) { for (int i=0; i < state.m_Candidates.GetSize();) { VCoronaCandidate& coronaCandidate = state.m_Candidates.ElementAt(i); VCoronaComponent* pCorona = coronaCandidate.m_pCorona; unsigned int iElementIndex = pCorona->m_CoronaPixelCounter.GetNumber(); // If the visibility reached zero and the corona is no longer potentially visible it is removed from the list if (!pCorona->IsEnabled() || !pCorona->GetOwner() || (pCorona->GetVisibleBitmask() & iRenderFilterMask) == 0 || (((VisLightSource_cl*)pCorona->GetOwner())->GetVisibleBitmask() & iRenderFilterMask) == 0 || ( coronaCandidate.m_fCurrentVisibility == 0.0f && !pCorona->IsValidCandidate(pContext) ) ) { state.RemoveBit(pCorona->m_iIndex); state.m_Candidates.SetAt(i, state.m_Candidates.GetAt(state.m_Candidates.GetSize()-1) ); state.m_Candidates.RemoveAt(state.m_Candidates.GetSize() -1); // Reset cache to zero, so we don't see the lens flare once it enters the frustum again. pContext->SetPixelCounterResult(iElementIndex, 0); } else { ++i; } } } #endif }
void VWallmarkManager::OnHandleCallback(IVisCallbackDataObject_cl *pData) { if (pData->m_pSender==&Vision::Callbacks.OnRenderHook) { VISION_PROFILE_FUNCTION(PROFILING_WALLMARK_RENDERING); // render projected wallmarks int iEntry = ((VisRenderHookDataObject_cl *)pData)->m_iEntryConst; if (iEntry == m_iPrimaryOpaquePassRenderOrder && ((m_eProjectedWMPassTypes & VPT_PrimaryOpaquePass) != 0)) RenderProjectedWallmarks(VPT_PrimaryOpaquePass); else if(iEntry == m_iSecondaryOpaquePassRenderOrder && ((m_eProjectedWMPassTypes & VPT_SecondaryOpaquePass) != 0)) RenderProjectedWallmarks(VPT_SecondaryOpaquePass); else if (iEntry == m_iTransparentPassRenderOrder && ((m_eProjectedWMPassTypes & VPT_TransparentPass)!=0)) RenderProjectedWallmarks(VPT_TransparentPass); return; } if (pData->m_pSender==&Vision::Callbacks.OnUpdateSceneFinished) { VISION_PROFILE_FUNCTION(PROFILING_WALLMARK_SIMULATION); // simulate particle wallmarks int iCount = m_AllWallmarkGroups.Count(); for (int i=0;i<iCount;i++) m_AllWallmarkGroups.GetAt(i)->TickFunction(Vision::GetTimer()->GetTimeDifference()); // simulate projected wallmarks iCount = m_FadingProjectedWallmarks.Count(); for (int i=0;i<iCount;i++) if (m_FadingProjectedWallmarks.GetAt(i)->TickFunction(Vision::GetTimer()->GetTimeDifference())) { m_FadingProjectedWallmarks.GetAt(i)->DisposeObject(); i--;iCount--; } return; } // respond to some zone streaming events (clean/rebuild wallmark primitive references) if (pData->m_pSender==&VisZoneResourceManager_cl::GlobalManager().OnResourceChanged) { VISION_PROFILE_FUNCTION(PROFILING_WALLMARK_CLEANUP); VisResourceInfoDataObject_cl *pResData = (VisResourceInfoDataObject_cl *)pData; if (pResData->m_iAction==VRESOURCECHANGEDFLAG_LOADEDRESOURCE) OnZoneLoaded((VisZoneResource_cl *)pResData->m_pResource); else if (pResData->m_iAction==VRESOURCECHANGEDFLAG_UNLOADINGRESOURCE) OnZoneUnloading((VisZoneResource_cl *)pResData->m_pResource); return; } // respond to deletion of static geometry instances (that are not part of zones) if (pData->m_pSender==&VisStaticGeometryInstance_cl::OnStaticGeometryInstanceDestroyed) { VISION_PROFILE_FUNCTION(PROFILING_WALLMARK_CLEANUP); VisStaticGeometryInstance_cl *pInst =((VisStaticGeometryInstanceObject_cl *)pData)->m_pInstance; if ((m_iGeomRefHashMask & GetGeomHashMask(pInst))!=0) // effective early out OnStaticGeometryDeleted(pInst); return; } // OnReassignShaders if (pData->m_pSender==&Vision::Callbacks.OnReassignShaders) { // Shaders will be re-created the next time they're used. DeleteWallmarkShaders(); // Re-create shaders for wallmarks with custom effects. const int iWallmarkCount = m_AllProjectedWallmarks.Count(); for (int i = 0; i < iWallmarkCount; i++) { VProjectedWallmark *pProjWallmark = m_AllProjectedWallmarks.GetAt(i); VCompiledEffectPtr spEffect = pProjWallmark->m_spCustomEffect; if (spEffect != NULL && spEffect->GetSourceEffect() != NULL) { const char *szFXName = spEffect->GetSourceEffect()->GetName(); const char *szParam = spEffect->m_sParamStr; int iFlags = spEffect->m_iCreationFlags; VCompiledEffect *pFX = Vision::Shaders.CreateEffect(szFXName,szParam,iFlags); pProjWallmark->SetCustomShaderEffect(pFX); } } return; } if (pData->m_pSender == &Vision::Callbacks.OnWorldDeInit) { // clean-up DeleteWallmarkShaders(); m_AllWallmarkGroups.Clear(); m_AllProjectedWallmarks.Clear(); m_FadingProjectedWallmarks.Clear(); m_iGeomRefHashMask = 0; m_eProjectedWMPassTypes = VPT_Undefined; return; } }
///////////////////////////////////////////////////////////////////////////// // RenderAllShadows : render all shadow instances ///////////////////////////////////////////////////////////////////////////// void VBlobShadowManager::RenderAllShadows() { // if enabled, a 2D bounding box is additionally used for clipping, which saves a lot of fillrate! // TODO: PSP2 - fix 2d clipping #if defined(_VISION_PSP2) static bool bClipScissor = false; #else static bool bClipScissor = true; #endif VisFrustum_cl viewFrustum; IVisVisibilityCollector_cl *pVisColl = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector(); if (pVisColl==NULL || pVisColl->GetBaseFrustum()==NULL) return; viewFrustum.CopyFrom((VisFrustum_cl&)*pVisColl->GetBaseFrustum()); // render all shadows VISION_PROFILE_FUNCTION(PROFILING_BS_OVERALL); // get the collection of visible (opaque) primitives. For each shadow instance determine // the primitives in this list, which intersect with the shadow box // (we do not want to render primitives that are not visible) const VisStaticGeometryInstanceCollection_cl *pVisibleGeom = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass); VRectanglef clipRect(false); VRectanglef screenRect(0.f,0.f,(float)Vision::Video.GetXRes(),(float)Vision::Video.GetYRes()); hkvVec3 vBoxCorner[8]; hkvVec2 vCorner2D(false); // now render the shadows: FOR_ALL_SHADOWS if (pShadow->GetOwner()) pShadow->SetBoundingBoxFromOwnerProperties(); // shadow box visible? if (!viewFrustum.Overlaps(pShadow->m_ShadowBox)) continue; // build 2D bounding box for scissor clipping if (bClipScissor) { VISION_PROFILE_FUNCTION(PROFILING_BS_SCISSORRECT); clipRect.Reset(); pShadow->m_ShadowBox.getCorners(vBoxCorner); for (int i=0; i<8; i++) { // if one vertex is behind camera, do not use clipping if (!Vision::Contexts.GetCurrentContext()->Project2D(vBoxCorner[i],vCorner2D.x,vCorner2D.y)) { Vision::RenderLoopHelper.SetScissorRect(NULL); goto render_shadow; } clipRect.Add(vCorner2D); } VASSERT(clipRect.IsValid()); clipRect = clipRect.GetIntersection(screenRect); if (!clipRect.IsValid()) continue; // do not render shadows at all if rect is outside the screen Vision::RenderLoopHelper.SetScissorRect(&clipRect); } render_shadow: // get the visible primitives in the shadow bounding box { VISION_PROFILE_FUNCTION(PROFILING_BS_DETERMINE_PRIMS); // affected static geometry: shadowGeom.Clear(); pVisibleGeom->DetermineEntriesTouchingBox(pShadow->m_ShadowBox,shadowGeom); } // split into geometry types: if (!shadowGeom.GetNumEntries()) continue; const VisStaticGeometryType_e relevantTypes[2] = {STATIC_GEOMETRY_TYPE_MESHINSTANCE,STATIC_GEOMETRY_TYPE_TERRAIN}; // two relevant geometry types: for (int iType=0; iType<2; iType++) { shadowGeomOfType.Clear(); shadowGeom.GetEntriesOfType(shadowGeomOfType,relevantTypes[iType]); VCompiledTechnique *pFX = GetDefaultTechnique(relevantTypes[iType]); if (shadowGeomOfType.GetNumEntries()==0 || pFX==NULL) continue; // for all the shader in the projection effect (usually 1 shader), render the primitive collection const int iShaderCount = pFX->GetShaderCount(); for (int j=0; j<iShaderCount; j++) { VBlobShadowShader *pShader = (VBlobShadowShader *)pFX->GetShader(j); { // code block for easier profiling VISION_PROFILE_FUNCTION(PROFILING_BS_PREPARE_SHADER); // prepare the shader, i.e. setup shadow specific projection planes, colors etc. pShader->UpdateShadow(pShadow); } { // code block for easier profiling VISION_PROFILE_FUNCTION(PROFILING_BS_RENDER_PRIMS); Vision::RenderLoopHelper.RenderStaticGeometryWithShader(shadowGeomOfType,*pShader); } } } }
// Game loop that updates the scene void VisionApp_cl::OnUpdateScene() { VISION_PROFILE_FUNCTION(VIS_PROFILE_GAMELOOP); IVisSceneManager_cl *pSceneManager = Vision::GetSceneManager(); VASSERT(pSceneManager); // Check whether we should use async physics IVisPhysicsModule_cl *pPhysicsModule = Vision::GetApplication()->GetPhysicsModule(); bool bAsyncPhysics; if (pPhysicsModule != NULL && pPhysicsModule->GetUseAsynchronousPhysics()) bAsyncPhysics = true; else bAsyncPhysics = false; //Timer is not longer updated here, because it needs to be updated right after the frame flip float fElapsedTime = Vision::GetTimer()->GetTimeDifference(); // Advance the scene update counter Vision::Game.SetUpdateSceneCount( Vision::Game.GetUpdateSceneCount() + 1 ); Vision::Callbacks.OnUpdateSceneBegin.TriggerCallbacks(); //Send any queued messages before we remove entities Vision::Game.ProcessMessageQueue(); // Delete "dead" entities from previous frame { VISION_PROFILE_FUNCTION( VIS_PROFILE_GAMELOOP_UPDATELOOP ); Vision::Game.FreeRemovedEntities(); } // Run the pre-physics loop: statistics, prethink, events & animations if ( Vision::Editor.IsPlaying() ) RunPreThink(fElapsedTime); //Process animation messages after processing animations Vision::Game.ProcessMessageQueue(); // Run the physics simulation (if physics simulation is set to synchronous) if ( Vision::Editor.IsPlaying() && !bAsyncPhysics) { RunPhysics(fElapsedTime); FetchPhysicsResults(); } // Run the post-physics loop: posthink if ( Vision::Editor.IsPlaying() ) RunThink(fElapsedTime); // for the editor, we call the EditorThinkFunction function in every mode for every entity: if (Vision::Editor.IsInEditor()) { const int iCount = VisBaseEntity_cl::ElementManagerGetSize(); for (int i=0;i<iCount;i++) { VisBaseEntity_cl *pEntity = VisBaseEntity_cl::ElementManagerGet(i); if (pEntity) pEntity->EditorThinkFunction(); } } // handle the lightsources (e.g. color animation) if (Vision::Editor.IsAnimatingOrPlaying()) VisLightSource_cl::HandleAllLightSources(fElapsedTime); // update the core engine and module system RunUpdateLoop(); Vision::Game.ResetUpdatedEntitiesList(); // Kick off asynchronous physics simulation if ( Vision::Editor.IsPlaying() && bAsyncPhysics ) { RunPhysics(fElapsedTime); } // Handle portal/visibility zone transitions VisObject3DVisData_cl::HandleAllNodeTransitions(); //Handle render contexts VisRenderContext_cl::HandleAllRenderContexts(fElapsedTime); //Animate textures (in animate mode) VisTextureAnimInstance_cl::HandleAllAnims(Vision::Editor.IsAnimatingOrPlaying() ? fElapsedTime : 0.f); // scroll sky only when animating scene IVSky *pSky = Vision::World.GetActiveSky(); if (pSky != NULL && Vision::Editor.IsAnimatingOrPlaying()) pSky->Tick(fElapsedTime); Vision::Callbacks.OnUpdateSceneFinished.TriggerCallbacks(); }