/* * Copyright (C) 2006-2010 - Frictional Games * * This file is part of Penumbra Overture. * * Penumbra Overture is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Penumbra Overture is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Penumbra Overture. If not, see . */ #include "HapticGameCamera.h" #include "Init.h" #include "Player.h" #include "MapHandler.h" #include "GameEntity.h" #include "GameLiquidArea.h" #include "ButtonHandler.h" ////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cHapticGameCamera::cHapticGameCamera(cInit *apInit, cPlayer *apPlayer) { mpInit = apInit; mpLowLevelHaptic = mpInit->mpGame->GetHaptic()->GetLowLevel(); mpScene = mpInit->mpGame->GetScene(); mfFrameW = 200; mfFrameH = 180; mbUseFrame = true; mfFrameForceStrength = 0.0002f; mfFrameMoveSpeedX = 0.00033f; mfFrameMoveSpeedY = 0.0002f; mfInteractModeCameraSpeed = 1; mfActionModeCameraSpeed = 1; mfFrameMaxForce = 0.3f;//1; mfFrameMaxMoveSpeed = 0.1f; mvCentrePos = cVector3f(0,-25,0); mpForce = apInit->mpGame->GetHaptic()->GetLowLevel()->CreateImpulseForce(0); mpForce->SetForce(0); mpVtxProgram = mpInit->mpGame->GetResources()->GetGpuProgramManager()->CreateProgram( "Diffuse_Color_vp.cg","main", eGpuProgramType_Vertex); mpPlayer = apPlayer; Reset(); } //----------------------------------------------------------------------- cHapticGameCamera::~cHapticGameCamera() { } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cHapticGameCamera::OnWorldLoad() { cMesh *pMesh = mpInit->mpGame->GetResources()->GetMeshManager()->CreateMesh("player_gui_hand.dae"); mpHandEntity = mpScene->GetWorld3D()->CreateMeshEntity("Hand",pMesh); float fRadius = mpLowLevelHaptic->GetProxyRadius(); mpHandEntity->SetMatrix(cMath::MatrixScale(fRadius)); mpHandEntity->SetVisible(mbHandVisible); mpHandEntity->SetCastsShadows(true); mpHandShape = mpScene->GetWorld3D()->GetPhysicsWorld()->CreateSphereShape(GetHandReachRadius(),NULL); mvPrevPrxoyPos = mpLowLevelHaptic->GetProxyPosition(); //Disable all shapes cHapticShapeIterator it = mpLowLevelHaptic->GetShapeIterator(); while(it.HasNext()) { iHapticShape *pShape = it.Next(); pShape->SetEnabled(false); } } void cHapticGameCamera::OnWorldExit() { mpHandShape = NULL; mpHandEntity = NULL; } //----------------------------------------------------------------------- void cHapticGameCamera::Reset() { mpHandShape = NULL; mpHandEntity = NULL; mbIsTurning = false; mbActive = true; mbCamMove = true; mbHandVisible = true; mbRenderActive = true; mlContactCount =0; mbAtEdge = false; mType = eHapticGameCameraType_Frame; } //----------------------------------------------------------------------- void cHapticGameCamera::SetActive(bool abX) { if(mbActive == abX) return; mbActive = abX; if(mbActive) { if(mpHandEntity) mpHandEntity->SetVisible(mbHandVisible); mpInit->mpGame->GetHaptic()->GetLowLevel()->SetRenderingActive(mbRenderActive); } else { mpForce->SetActive(false); if(mpHandEntity)mpHandEntity->SetVisible(false); mpInit->mpGame->GetHaptic()->GetLowLevel()->SetRenderingActive(false); } } //----------------------------------------------------------------------- void cHapticGameCamera::SetType(eHapticGameCameraType aType) { mType = aType; } //----------------------------------------------------------------------- void cHapticGameCamera::Update(float afTimeStep) { if( mpPlayer->IsActive() == false || mpInit->mpButtonHandler->GetState() != eButtonHandlerState_Game) { //Log("Player is not active!!\n"); mpForce->SetActive(false); mpLowLevelHaptic->SetRenderingActive(false); if(mpHandEntity) mpHandEntity->SetActive(false); return; } if(mbActive==false){ mpLowLevelHaptic->SetRenderingActive(false); return; } if(mpHandEntity) mpHandEntity->SetActive(mbHandVisible); if(mbHandVisible && mbAtEdge==false) mpLowLevelHaptic->SetRenderingActive(mbRenderActive); else mpLowLevelHaptic->SetRenderingActive(false); UpdateCameraOrientation(afTimeStep); UpdateHand(afTimeStep); UpdateProxyCovered(afTimeStep); UpdateProxyInteraction(afTimeStep); cInput *pInput = mpInit->mpGame->GetInput(); if(pInput->IsTriggerd("InteractMode")) { mpLowLevelHaptic->SetRenderingActive(false); } } //----------------------------------------------------------------------- void cHapticGameCamera::OnPostSceneDraw() { if(mpHandEntity==NULL) return; if(mbHandVisible==false) return; if(mbActive==false) return; if(mpHandEntity->IsVisible()==false) return; cCamera3D *pCam = static_cast(mpScene->GetCamera()); iLowLevelGraphics *pLowGfx = mpInit->mpGame->GetGraphics()->GetLowLevel(); eCrossHairState crossHairState = mpPlayer->GetCrossHairState(); if( crossHairState != eCrossHairState_Inactive && crossHairState != eCrossHairState_None) { pLowGfx->SetMatrix(eMatrix_ModelView,cMath::MatrixMul( pCam->GetViewMatrix(), mpHandEntity->GetWorldMatrix())); cSubMesh *pSubMesh = mpHandEntity->GetMesh()->GetSubMesh(0); iVertexBuffer *pVtxBuff = pSubMesh->GetVertexBuffer(); pLowGfx->SetDepthTestActive(true); pLowGfx->SetDepthTestFunc(eDepthTestFunc_LessOrEqual); pLowGfx->SetBlendActive(true); pLowGfx->SetBlendFunc(eBlendFunc_One,eBlendFunc_One); pLowGfx->SetTexture(0, pSubMesh->GetMaterial()->GetTexture(eMaterialTexture_Diffuse)); mpVtxProgram->Bind(); mpVtxProgram->SetMatrixf( "worldViewProj",eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); pVtxBuff->Bind(); pVtxBuff->Draw(); pVtxBuff->Draw(); pVtxBuff->UnBind(); mpVtxProgram->UnBind(); pLowGfx->SetTexture(0, NULL); pLowGfx->SetBlendActive(false); pLowGfx->SetDepthTestActive(true); } } //----------------------------------------------------------------------- bool cHapticGameCamera::ShowCrosshair() { if(mbActive==false) return true; if(mbHandVisible==false) return true; return false; } //----------------------------------------------------------------------- void cHapticGameCamera::SetHandVisible(bool abX) { if(mbHandVisible == abX) return; mbHandVisible = abX; if(mpHandEntity) { mpHandEntity->SetVisible(mbHandVisible); } } bool cHapticGameCamera::GetHandVisible() { return mbHandVisible; } /** * The radius from proxy center that will be able to affect entities. */ float cHapticGameCamera::GetHandReachRadius() { return mpLowLevelHaptic->GetProxyRadius()*7.0f; } //----------------------------------------------------------------------- void cHapticGameCamera::SetRenderActive(bool abX) { if(mbRenderActive == abX) return; mbRenderActive = abX; if(mbActive) mpLowLevelHaptic->SetRenderingActive(mbRenderActive); } //----------------------------------------------------------------------- void cHapticGameCamera::SetInteractModeCameraSpeed(float afSpeed) { mfInteractModeCameraSpeed = afSpeed; mfFrameMoveSpeedX = 0.00033f * mfInteractModeCameraSpeed; mfFrameMoveSpeedY = 0.0002f * mfInteractModeCameraSpeed; } void cHapticGameCamera::SetActionModeCameraSpeed(float afSpeed) { mfActionModeCameraSpeed = afSpeed; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cHapticGameCamera::UpdateCameraOrientation(float afTimeStep) { cCamera3D *pCamera = static_cast(mpScene->GetCamera()); cVector3f vLocalPoxy = cMath::MatrixMul(pCamera->GetViewMatrix(), mpLowLevelHaptic->GetProxyPosition()); //Log("Local %s\n",vLocalPoxy.ToString().c_str()); if(vLocalPoxy.z >-0.34){ //mpLowLevelHaptic->SetRenderingActive(false); return; } mbAtEdge = false; /////////////////////////// // Frame Type cVector3f vForce(0); cVector2f vSpeed(0); if(mType == eHapticGameCameraType_Frame) { if(mbUseFrame==false) return; /////////////////////////////////// //Get force and movement cVector2f vPos = mpLowLevelHaptic->GetProxyScreenPos(cVector2f(800,600)); if(vPos.x < mfFrameW){ vSpeed.x = (mfFrameW - vPos.x) * -mfFrameMoveSpeedX; vForce.x = (mfFrameW - vPos.x)*mfFrameForceStrength; } if(vPos.x > (800 - mfFrameW)){ vSpeed.x = (vPos.x - (800 - mfFrameW)) * mfFrameMoveSpeedX; vForce.x = (vPos.x - (800 - mfFrameW))*-mfFrameForceStrength; } if(vPos.y < mfFrameH){ vSpeed.y = (mfFrameH - vPos.y) * -mfFrameMoveSpeedY; vForce.y = (mfFrameH - vPos.y)*-mfFrameForceStrength; } if(vPos.y > (600-mfFrameW)){ vSpeed.y = (vPos.y - (600-mfFrameW)) * mfFrameMoveSpeedY; vForce.y = (vPos.y - (600-mfFrameW))*mfFrameForceStrength; } /////////////////////////////////// //Set Max speed if(vSpeed.x > mfFrameMaxMoveSpeed) vSpeed.x = mfFrameMaxMoveSpeed; if(vSpeed.x < -mfFrameMaxMoveSpeed) vSpeed.x = -mfFrameMaxMoveSpeed; if(vSpeed.y > mfFrameMaxMoveSpeed) vSpeed.y = mfFrameMaxMoveSpeed; if(vSpeed.y < -mfFrameMaxMoveSpeed) vSpeed.y = -mfFrameMaxMoveSpeed; if(mbCamMove) { mpPlayer->AddYaw(vSpeed.x * mpInit->mfHapticMoveScreenSpeedMul); mpPlayer->AddPitch(vSpeed.y * mpInit->mfHapticMoveScreenSpeedMul); } /////////////////////////////////// //Set Max Force if(vForce.x > mfFrameMaxForce) vForce.x = mfFrameMaxForce; if(vForce.x < -mfFrameMaxForce) vForce.x = -mfFrameMaxForce; if(vForce.y > mfFrameMaxForce) vForce.y = mfFrameMaxForce; if(vForce.y < -mfFrameMaxForce) vForce.y = -mfFrameMaxForce; //////////////////////////////////// //Turn on Force if(vForce != 0) { mpForce->SetActive(true); mpForce->SetForce(vForce); //Do this better. mbHapticWasActive = mpLowLevelHaptic->IsRenderingActive(); mbIsTurning = true; } else { mpForce->SetActive(false); mbIsTurning = false; } ////////////////////////////////////////// //Turn off rendering bool bAtEdge = false; if(vPos.x < mfFrameW*.1f){ bAtEdge = true; } if(vPos.x > (800 - mfFrameW*.1f)){ bAtEdge = true; } if(vPos.y < mfFrameH*.1f){ bAtEdge = true; } if(vPos.y > (600-mfFrameH*.1f)){ bAtEdge = true; } mbAtEdge = bAtEdge; /*if(bAtEdge) { mpLowLevelHaptic->SetRenderingActive(false); } else { mpLowLevelHaptic->SetRenderingActive(mbRenderActive); }*/ } /////////////////////////// // Centre Type else if(mType == eHapticGameCameraType_Centre) { cVector3f vDevicePos = mpLowLevelHaptic->GetHardwarePosition(); cVector3f vDeltaPos = mvCentrePos - vDevicePos; float fLength = vDeltaPos.Length() -0.9f; if(fLength > 0.0f) { cVector3f vDir = cMath::Vector3Normalize(vDeltaPos); //Force cVector3f vForce = vDir * fLength * 0.012f; mpForce->SetActive(true); mpForce->SetForce(vForce); //Movement if(mbCamMove) { cVector3f vMov = vDir * fLength * 0.0015f * mfActionModeCameraSpeed; mpPlayer->AddPitch(vMov.y); mpPlayer->AddYaw(-vMov.x); } } else { mpForce->SetActive(false); } } } //----------------------------------------------------------------------- void cHapticGameCamera::UpdateHand(float afTimeStep) { /////////////////////////// // GUI Hand cVector3f vProxyPos = mpLowLevelHaptic->GetProxyPosition(); mlstProxyPos.push_back(vProxyPos); if(mlstProxyPos.size() > 8) mlstProxyPos.pop_front(); vProxyPos =0; std::list::iterator it = mlstProxyPos.begin(); for(; it != mlstProxyPos.end(); ++it) { vProxyPos += *it; } vProxyPos = vProxyPos / (float)mlstProxyPos.size(); mpHandEntity->SetPosition(vProxyPos); } //----------------------------------------------------------------------- void cHapticGameCamera::UpdateProxyCovered(float afTimeStep) { ///////////////////////////////////// // Check if proxy is covered /*if(false)//cHaptic::GetIsUsed()) { if(mState == ePlayerState_Normal && mpHapticCamera->IsTurning()==false) { cVector3f vStart = mpCamera->GetPosition(); cVector3f vEnd = mpHandEntity->GetWorldPosition(); //Log("Casting ray!\n"); gTempCheckProxy.mbCollided =false; pPhysicsWorld->CastRay(&gTempCheckProxy,vStart,vEnd,false,false,false); if(gTempCheckProxy.mbCollided) { //Log("Disable!\n"); mpLowLevelHaptic->SetRenderingActive(false); } else { //Log("Enabel!\n"); mpLowLevelHaptic->SetRenderingActive(true); } } }*/ } //----------------------------------------------------------------------- void cHapticGameCamera::UpdateProxyInteraction(float afTimeStep) { cVector3f vProxyPos = mpLowLevelHaptic->GetProxyPosition(); cVector3f vProxyVel = (vProxyPos - mvPrevPrxoyPos) / afTimeStep; float fProxySpeed = vProxyVel.Length(); cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); bool bHadContact = false; ///////////////////////////////// //Disable previously enabled cHapticShapeIterator shapeIt = mpLowLevelHaptic->GetShapeIterator(); while(shapeIt.HasNext()) { iHapticShape *pShape = shapeIt.Next(); pShape->SetEnabled(false); } ////////////////////////////////// // Iterate physics bodies cBoundingVolume bv; bv.SetSize(GetHandReachRadius()*2); bv.SetPosition(vProxyPos); cPortalContainerEntityIterator it = pWorld->GetPortalContainer()->GetEntityIterator(&bv); while(it.HasNext()) { iPhysicsBody *pBody = static_cast(it.Next()); if(pBody->IsCharacter()) continue; if(pBody->IsActive()==false) continue; if(pBody->GetHapticShape()==NULL) { if(cMath::PointBVCollision(vProxyPos,*pBody->GetBV())==false) continue; ///////////////////////////////// //Special case for water iGameEntity *pEntity = (iGameEntity*)pBody->GetUserData(); if(pEntity==NULL || pEntity->GetType() != eGameEntityType_LiquidArea) continue; cGameLiquidArea *pLiquid = static_cast(pEntity); bHadContact = true; if( mlContactCount <=0) { float fY = pBody->GetWorldPosition().y + pBody->GetShape()->GetSize().y/2; cVector3f vWaterPos = vProxyPos; vProxyPos.y = fY; cSurfaceData *pSurface = pLiquid->GetPhysicsMaterial()->GetSurfaceData(); cSurfaceImpactData *pImpact = pSurface->GetImpactDataFromSpeed(fProxySpeed * 0.3f); if(pImpact == NULL) continue; if(pImpact->GetPSName() != "") { pWorld->CreateParticleSystem( "Splash", pImpact->GetPSName(),1, cMath::MatrixTranslate(vWaterPos)); } if(pImpact->GetSoundName() != "") { cSoundEntity *pSound = pWorld->CreateSoundEntity("Splash", pImpact->GetSoundName(),true); if(pSound) pSound->SetPosition(vWaterPos); } } continue; } ///////////////////////////////////// //Get Shape iHapticShape *pContactShape = pBody->GetHapticShape(); pContactShape->SetEnabled(true); //mlstActiveShapes.push_back(pContactShape); ////////////////////////////////////// //Check if any of the haptic shapes are touched. if(mpLowLevelHaptic->ShapeIsInContact(pContactShape)) { bHadContact = true; } else { continue; } ///////////////////////////////////////// // Add force to body and play material effects //Log("Body: %s Force: %s\n", pBody->GetName().c_str(), // pContactShape->GetAppliedForce().ToString().c_str()); //Force pBody->AddForceAtPosition( pContactShape->GetAppliedForce() * 60.0f,//33.0f, vProxyPos); //Effects cSurfaceData *pSurface = pBody->GetMaterial()->GetSurfaceData(); if(mlContactCount <=0 && pSurface) { //Sound cSurfaceImpactData* pImpact = pSurface->GetImpactDataFromSpeed(fProxySpeed*0.3f); if(pImpact) { cSoundEntity *pSound = pWorld->CreateSoundEntity( "Hit",pImpact->GetSoundName(), true); pSound->SetWorldPosition(vProxyPos); } //Particle system (and other effects) pSurface->CreateImpactEffect(fProxySpeed*0.3f,vProxyPos,1,NULL); } } //////////////////////////// //Update contact count if(bHadContact) { mlContactCount = 10; } else { mlContactCount--; if(mlContactCount<=0) mlContactCount=0; } mvPrevPrxoyPos = vProxyPos; } //-----------------------------------------------------------------------