/* * 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 "StdAfx.h" #include "GameLiquidArea.h" #include "Init.h" #include "MapHandler.h" #include "Player.h" #include "EffectHandler.h" #include "GlobalInit.h" ////////////////////////////////////////////////////////////////////////// // LOADER ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cAreaLoader_GameLiquidArea::cAreaLoader_GameLiquidArea(const tString &asName, cInit *apInit) : iArea3DLoader(asName) { mpInit = apInit; } cAreaLoader_GameLiquidArea::~cAreaLoader_GameLiquidArea() { } //----------------------------------------------------------------------- iEntity3D* cAreaLoader_GameLiquidArea::Load(const tString &asName, const cVector3f &avSize, const cMatrixf &a_mtxTransform,cWorld3D *apWorld) { cGameLiquidArea *pArea = hplNew( cGameLiquidArea, (mpInit,asName) ); pArea->m_mtxOnLoadTransform = a_mtxTransform; //Create physics data iPhysicsWorld *pPhysicsWorld = apWorld->GetPhysicsWorld(); iCollideShape* pShape = pPhysicsWorld->CreateBoxShape(avSize,NULL); std::vector vBodies; vBodies.push_back(pPhysicsWorld->CreateBody(asName,pShape)); vBodies[0]->SetCollide(false); vBodies[0]->SetCollideCharacter(false); vBodies[0]->SetMatrix(a_mtxTransform); vBodies[0]->SetUserData(pArea); pArea->SetBodies(vBodies); mpInit->mpMapHandler->AddGameEntity(pArea); pArea->Setup(); //Return something else later perhaps. return NULL; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////////////////////// cGameLiquidArea::cGameLiquidArea(cInit *apInit,const tString& asName) : iGameEntity(apInit,asName) { mType = eGameEntityType_LiquidArea; mfDensity = 100; mfLinearViscosity = 1; mfAngularViscosity = 1; mbHasInteraction = false; mpPhysicsMaterial = NULL; mbHasWaves = true; mfWaveAmp = 0.04f; mfWaveFreq = 3; mfTimeCount =0; } //----------------------------------------------------------------------- cGameLiquidArea::~cGameLiquidArea(void) { } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameLiquidArea::SetPhysicsMaterial(const tString asName) { if(asName == "") return; iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); mpPhysicsMaterial = pPhysicsWorld->GetMaterialFromName(asName); if(mpPhysicsMaterial==NULL){ Error("Liquid '%s' could not find material '%s'\n",GetName().c_str(), mpPhysicsMaterial->GetName().c_str()); } } //----------------------------------------------------------------------- void cGameLiquidArea::OnPlayerPick() { } //----------------------------------------------------------------------- void cGameLiquidArea::Update(float afTimeStep) { if(IsActive()==false) return; iPhysicsBody *pAreaBody = mvBodies[0]; cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); iPhysicsWorld *pPhysicsWorld = pWorld->GetPhysicsWorld(); cCamera3D *pCam = mpInit->mpPlayer->GetCamera(); float fSurfaceY = mvBodies[0]->GetWorldPosition().y + mvBodies[0]->GetShape()->GetSize().y /2; cCollideData collideData; collideData.SetMaxSize(1); mfTimeCount += afTimeStep; //////////////////////////////////////////////////////// //Update waves //////////////////////////////////////////////////////// //Check if player camera is in water. if(cMath::PointBVCollision(pCam->GetPosition(),*pAreaBody->GetBV())) { if(mpInit->mpEffectHandler->GetUnderwater()->IsActive()==false) { mpInit->mpEffectHandler->GetUnderwater()->SetActive(true); mpInit->mpEffectHandler->GetUnderwater()->SetColor(mColor); } } else { mpInit->mpEffectHandler->GetUnderwater()->SetActive(false); } //////////////////////////////////////////////////////// //Iterate all bodies in world and check for intersection cPortalContainerEntityIterator bodyIt = pWorld->GetPortalContainer()->GetEntityIterator( pAreaBody->GetBoundingVolume()); while(bodyIt.HasNext()) { iPhysicsBody *pBody = static_cast(bodyIt.Next()); iGameEntity *pEntity = (iGameEntity*)pBody->GetUserData(); if(pBody->GetCollide() && pBody->IsActive()) { if(pBody->GetMass()==0 && pBody->IsCharacter()==false) continue; ///////////////////////// //Bounding volume check if(cMath::CheckCollisionBV(*pBody->GetBV(), *pAreaBody->GetBV())==false) { pBody->SetBuoyancyActive(false); continue; } /////////////////////////////// //Check for collision if(pPhysicsWorld->CheckShapeCollision(pBody->GetShape(),pBody->GetLocalMatrix(), pAreaBody->GetShape(), pAreaBody->GetLocalMatrix(),collideData,1)==false) { pBody->SetBuoyancyActive(false); continue; } if(pBody->IsCharacter()) { iCharacterBody *pCharBody = pBody->GetCharacterBody(); float fToSurface = cMath::Abs(fSurfaceY - pCharBody->GetFeetPosition().y); float fCharHeight = pCharBody->GetSize().y; if(fToSurface > fCharHeight) fToSurface = fCharHeight; float fRadius = pCharBody->GetSize().x/2; float fVolume = fToSurface*fRadius*fRadius*kPif; float fWaterWeight = fVolume * mfDensity; cVector3f vForce = pPhysicsWorld->GetGravity() * -fWaterWeight; //Log("Tosurface: %f Vol: %f\n",fToSurface,fVolume); pCharBody->AddForce(vForce); if(pBody->GetBuoyancyActive()==false) { SplashEffect(pBody); pBody->SetBuoyancyActive(true); } } else { if(pBody->GetBuoyancyActive()==false) { pBody->SetBuoyancySurface(mSurfacePlane); pBody->SetBuoyancyDensity(mfDensity); pBody->SetBuoyancyLinearViscosity(mfLinearViscosity); pBody->SetBuoyancyAngularViscosity(mfAngularViscosity); SplashEffect(pBody); //Log("Splash body: %s\n",pBody->GetName().c_str()); pBody->SetBuoyancyActive(true); } if(mbHasWaves){ cVector3f vPos = cMath::MatrixMul(pBody->GetLocalMatrix(),pBody->GetMassCentre()); float fAddX = sin(mfTimeCount * mfWaveFreq + vPos.x * 15)*mfWaveAmp; float fAddZ = sin(mfTimeCount * mfWaveFreq + vPos.z * 15)*mfWaveAmp; //pBody->AddForce(cVector3f(0, 9.8f * (fAddZ+fAddX)*pBody->GetMass()*2, 0)); //pBody->AddForce(cVector3f(0, 9.8f * cMath::RandRectf(-0.1, 0.1f)*pBody->GetMass()*2, 0)); //Log("F:%f Amp %f\n",fAddZ+fAddX,mfWaveAmp); //pBody->AddTorque(cVector3f((fAddZ+fAddX)*pBody->GetMass(), (fAddZ+fAddX)*pBody->GetMass(), // (fAddZ+fAddX)*pBody->GetMass())); cPlanef tempPlane; tempPlane.FromNormalPoint( cVector3f(0,1,0), cVector3f(0,fSurfaceY + fAddX + fAddZ,0)); pBody->SetBuoyancySurface(tempPlane); pBody->SetEnabled(true); } } } } } //----------------------------------------------------------------------- void cGameLiquidArea::Setup() { //Log("SETUP!\n"); float fHeight = mvBodies[0]->GetShape()->GetSize().y; cVector3f vPos = mvBodies[0]->GetWorldPosition(); mSurfacePlane.FromNormalPoint( cVector3f(0,1,0), cVector3f(0,vPos.y,0) + cVector3f(0,fHeight/2,0)); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameLiquidArea::SplashEffect(iPhysicsBody *apBody) { if(mpPhysicsMaterial==NULL) return; cSurfaceData *pSurface = mpPhysicsMaterial->GetSurfaceData(); float fSpeed; if(apBody->IsCharacter()) fSpeed = apBody->GetCharacterBody()->GetForceVelocity().Length(); else fSpeed = apBody->GetLinearVelocity().Length(); cSurfaceImpactData *pImpact = pSurface->GetImpactDataFromSpeed(fSpeed); if(pImpact == NULL) return; cVector3f vPos = cMath::MatrixMul(apBody->GetLocalMatrix(),apBody->GetMassCentre()); vPos.y = mvBodies[0]->GetWorldPosition().y + mvBodies[0]->GetShape()->GetSize().y/2; cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); if(pImpact->GetPSName() != "") { pWorld->CreateParticleSystem("Splash", pImpact->GetPSName(),1, cMath::MatrixTranslate(vPos)); } if(pImpact->GetSoundName() != "") { cSoundEntity *pSound = pWorld->CreateSoundEntity("Splash",pImpact->GetSoundName(),true); if(pSound) { pSound->SetPosition(vPos); } } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // SAVE OBJECT STUFF ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- kBeginSerialize(cGameLiquidArea_SaveData,iGameEntity_SaveData) kSerializeVar(mvSize,eSerializeType_Vector3f) kSerializeVar(mfDensity,eSerializeType_Float32) kSerializeVar(mfLinearViscosity,eSerializeType_Float32) kSerializeVar(mfAngularViscosity,eSerializeType_Float32) kSerializeVar(msPhysicsMaterial,eSerializeType_String) kSerializeVar(mColor,eSerializeType_Color) kSerializeVar(mbHasWaves, eSerializeType_Bool) kSerializeVar(mSurfacePlane,eSerializeType_Planef) kEndSerialize() //----------------------------------------------------------------------- iGameEntity* cGameLiquidArea_SaveData::CreateEntity() { return NULL; } //----------------------------------------------------------------------- iGameEntity_SaveData* cGameLiquidArea::CreateSaveData() { return hplNew( cGameLiquidArea_SaveData, () ); } //----------------------------------------------------------------------- void cGameLiquidArea::SaveToSaveData(iGameEntity_SaveData *apSaveData) { __super::SaveToSaveData(apSaveData); cGameLiquidArea_SaveData *pData = static_cast(apSaveData); kCopyToVar(pData, mfDensity); kCopyToVar(pData, mfLinearViscosity); kCopyToVar(pData, mfAngularViscosity); kCopyToVar(pData, mSurfacePlane); kCopyToVar(pData, mColor); kCopyToVar(pData, mbHasWaves); if(mpPhysicsMaterial) pData->msPhysicsMaterial = mpPhysicsMaterial->GetName(); else pData->msPhysicsMaterial = ""; pData->mvSize = mvBodies[0]->GetShape()->GetSize(); } //----------------------------------------------------------------------- void cGameLiquidArea::LoadFromSaveData(iGameEntity_SaveData *apSaveData) { __super::LoadFromSaveData(apSaveData); cGameLiquidArea_SaveData *pData = static_cast(apSaveData); kCopyFromVar(pData, mfDensity); kCopyFromVar(pData, mfLinearViscosity); kCopyFromVar(pData, mfAngularViscosity); kCopyFromVar(pData, mSurfacePlane); kCopyFromVar(pData, mColor); kCopyFromVar(pData, mbHasWaves); SetPhysicsMaterial(pData->msPhysicsMaterial); } //----------------------------------------------------------------------- void cGameLiquidArea::SetupSaveData(iGameEntity_SaveData *apSaveData) { __super::SetupSaveData(apSaveData); cGameLiquidArea_SaveData *pData = static_cast(apSaveData); } //-----------------------------------------------------------------------