599 lines
17 KiB
C++
599 lines
17 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program 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.
|
|
*
|
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2006-2010 - Frictional Games
|
|
*
|
|
* This file is part of HPL1 Engine.
|
|
*/
|
|
|
|
#include "hpl1/engine/physics/SurfaceData.h"
|
|
|
|
#include "hpl1/engine/math/Math.h"
|
|
#include "hpl1/engine/physics/Physics.h"
|
|
#include "hpl1/engine/physics/PhysicsBody.h"
|
|
#include "hpl1/engine/physics/PhysicsWorld.h"
|
|
#include "hpl1/engine/system/low_level_system.h"
|
|
|
|
#include "hpl1/engine/scene/SoundEntity.h"
|
|
#include "hpl1/engine/scene/World3D.h"
|
|
#include "hpl1/engine/sound/Sound.h"
|
|
#include "hpl1/engine/sound/SoundChannel.h"
|
|
#include "hpl1/engine/sound/SoundHandler.h"
|
|
|
|
#include "hpl1/engine/resources/ParticleManager.h"
|
|
#include "hpl1/engine/resources/Resources.h"
|
|
#include "hpl1/engine/resources/SoundEntityManager.h"
|
|
|
|
namespace hpl {
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CONSTRUCTORS
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
cSurfaceData::cSurfaceData(const tString &asName, cPhysics *apPhysics, cResources *apResources) {
|
|
msName = asName;
|
|
mpPhysics = apPhysics;
|
|
mpResources = apResources;
|
|
|
|
// Setup default properties
|
|
mFrictionMode = ePhysicsMaterialCombMode_Average;
|
|
mElasticityMode = ePhysicsMaterialCombMode_Average;
|
|
|
|
mfElasticity = 0.5f;
|
|
mfStaticFriction = 0.3f;
|
|
mfKineticFriction = 0.3f;
|
|
|
|
mlPriority = 0;
|
|
|
|
mfMinScrapeSpeed = 0.6f;
|
|
mfMinScrapeFreq = 0.7f;
|
|
mfMinScrapeFreqSpeed = 1;
|
|
mfMaxScrapeFreq = 2;
|
|
mfMaxScrapeFreqSpeed = 3;
|
|
mfMiddleScrapeSpeed = 2;
|
|
msScrapeSoundName = "";
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
cSurfaceData::~cSurfaceData() {
|
|
STLDeleteAll(mvImpactData);
|
|
STLDeleteAll(mvHitData);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PUBLIC METHODS
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cSurfaceData::OnImpact(float afSpeed, const cVector3f &avPos, int alContacts, iPhysicsBody *apBody) {
|
|
if (mpPhysics->CanPlayImpact() == false) {
|
|
return;
|
|
}
|
|
|
|
apBody->SetHasImpact(true);
|
|
|
|
cWorld3D *pWorld = mpPhysics->GetGameWorld();
|
|
if (pWorld == NULL) {
|
|
return;
|
|
}
|
|
|
|
cSurfaceImpactData *pData = NULL;
|
|
for (size_t i = 0; i < mvImpactData.size(); i++) {
|
|
if (mvImpactData[i]->GetMinSpeed() <= afSpeed) {
|
|
pData = mvImpactData[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pData == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (pData->GetSoundName() != "") {
|
|
mpPhysics->AddImpact();
|
|
|
|
cSoundEntity *pEntity = pWorld->CreateSoundEntity("Impact",
|
|
pData->GetSoundName(), true);
|
|
if (pEntity) {
|
|
// TODO: Offset the sound a bit so that it is not played inside a static object.
|
|
pEntity->SetPosition(avPos);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cSurfaceData::OnSlide(float afSpeed, const cVector3f &avPos, int alContacts, iPhysicsBody *apBody,
|
|
iPhysicsBody *apSlideAgainstBody) {
|
|
if (alContacts < mlMinScrapeContacts)
|
|
return;
|
|
|
|
// Make sure that only one body can update the scrape.
|
|
if (apBody->GetScrapeBody() != NULL &&
|
|
apSlideAgainstBody != apBody->GetScrapeBody()) {
|
|
return;
|
|
}
|
|
|
|
cWorld3D *pWorld = mpPhysics->GetGameWorld();
|
|
if (pWorld == NULL)
|
|
return;
|
|
|
|
cSoundHandler *pSoundHandler = pWorld->GetSound()->GetSoundHandler();
|
|
if (pSoundHandler->GetSilent())
|
|
return;
|
|
|
|
// Check if sound exist in world.
|
|
if (pWorld->SoundEntityExists(apBody->GetScrapeSoundEntity()) == false) {
|
|
apBody->SetScrapeSoundEntity(NULL);
|
|
}
|
|
|
|
// Check if body is still, in that case stop set speed to 0
|
|
if (apBody->GetMass() != 0) {
|
|
if (apBody->GetPreveScrapeMatrix() == apBody->GetLocalMatrix()) {
|
|
afSpeed = 0;
|
|
}
|
|
apBody->SetPreveScrapeMatrix(apBody->GetLocalMatrix());
|
|
}
|
|
|
|
// If the body all ready has a scrape sound
|
|
if (apBody->GetScrapeSoundEntity() != NULL) {
|
|
// check if the sound should be stopped
|
|
float fMin = cMath::Max(mfMinScrapeSpeed - 0.7f, 0.02f);
|
|
if (ABS(afSpeed) < fMin) {
|
|
apBody->GetScrapeSoundEntity()->FadeOut(4.3f);
|
|
apBody->SetScrapeSoundEntity(NULL);
|
|
apBody->SetScrapeBody(NULL);
|
|
// Log("Stopped scrape '%s' %d on body '%s' IN SURFACEDATA!\n",msScrapeSoundName.c_str(),
|
|
// (size_t)apBody->GetScrapeSoundEntity(),
|
|
// apBody->GetName().c_str());
|
|
} else {
|
|
apBody->SetHasSlide(true);
|
|
|
|
// Change frequency according to speed.
|
|
float fAbsSpeed = ABS(afSpeed);
|
|
float fFreq = 1;
|
|
|
|
// Higher than middle
|
|
if (fAbsSpeed >= mfMiddleScrapeSpeed) {
|
|
if (fAbsSpeed >= mfMaxScrapeFreqSpeed) {
|
|
fFreq = mfMaxScrapeFreq;
|
|
} else {
|
|
// Calculate how close the speed is to max.
|
|
float fT = (fAbsSpeed - mfMiddleScrapeSpeed) /
|
|
(mfMaxScrapeFreqSpeed - mfMiddleScrapeSpeed);
|
|
|
|
fFreq = (1 - fT) + fT * mfMaxScrapeFreq;
|
|
}
|
|
}
|
|
// Below middle
|
|
else {
|
|
if (fAbsSpeed <= mfMinScrapeFreqSpeed) {
|
|
fFreq = mfMinScrapeFreq;
|
|
} else {
|
|
// Calculate how close the speed is to max.
|
|
float fT = (mfMiddleScrapeSpeed - fAbsSpeed) /
|
|
(mfMiddleScrapeSpeed - mfMinScrapeFreqSpeed);
|
|
|
|
fFreq = (1 - fT) + fT * mfMinScrapeFreq;
|
|
}
|
|
}
|
|
|
|
// Log("Speed: %f Freq: %f\n",fAbsSpeed,fFreq);
|
|
cSoundEntry *pEntry = apBody->GetScrapeSoundEntity()->GetSoundEntry(eSoundEntityType_Main);
|
|
if (pEntry) {
|
|
pEntry->mfNormalSpeed = fFreq;
|
|
apBody->GetScrapeSoundEntity()->SetPosition(avPos);
|
|
}
|
|
}
|
|
} else {
|
|
if (mfMinScrapeSpeed <= ABS(afSpeed) && msScrapeSoundName != "") {
|
|
apBody->SetHasSlide(true);
|
|
|
|
cSoundEntity *pEntity = pWorld->CreateSoundEntity("Scrape",
|
|
msScrapeSoundName, true);
|
|
if (pEntity) {
|
|
pEntity->FadeIn(3.3f);
|
|
pEntity->SetPosition(avPos);
|
|
|
|
pEntity->SetIsSaved(false);
|
|
|
|
apBody->SetScrapeSoundEntity(pEntity);
|
|
apBody->SetScrapeBody(apSlideAgainstBody);
|
|
|
|
// Log("Starting scrape '%s' %d on body '%s'\n",msScrapeSoundName.c_str(),
|
|
// (size_t)pEntity,
|
|
// apBody->GetName().c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cSurfaceData::CreateImpactEffect(float afSpeed, const cVector3f &avPos, int alContacts,
|
|
cSurfaceData *apSecondSurface) {
|
|
if (afSpeed == 0)
|
|
return;
|
|
|
|
cSurfaceImpactData *pDataA = NULL;
|
|
cSurfaceImpactData *pDataB = NULL;
|
|
|
|
cWorld3D *pWorld = mpPhysics->GetGameWorld();
|
|
if (pWorld == NULL) {
|
|
return;
|
|
}
|
|
|
|
cSoundHandler *pSoundHandler = pWorld->GetSound()->GetSoundHandler();
|
|
if (pSoundHandler->GetSilent())
|
|
return;
|
|
|
|
/////////////////////////////
|
|
// Get first surface
|
|
for (size_t i = 0; i < mvImpactData.size(); i++) {
|
|
if (mvImpactData[i]->GetMinSpeed() <= afSpeed) {
|
|
pDataA = mvImpactData[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////
|
|
// Get second surface
|
|
if (apSecondSurface != this && apSecondSurface != NULL) {
|
|
for (size_t i = 0; i < apSecondSurface->mvImpactData.size(); i++) {
|
|
if (apSecondSurface->mvImpactData[i]->GetMinSpeed() <= afSpeed) {
|
|
pDataB = apSecondSurface->mvImpactData[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
tString sPS = "";
|
|
|
|
if (pDataA && !pDataB) {
|
|
sPS = pDataA->GetPSName();
|
|
} else if (!pDataA && pDataB) {
|
|
sPS = pDataB->GetPSName();
|
|
} else if (pDataA && pDataB) {
|
|
if (pDataA->GetPSPrio() >= pDataB->GetPSPrio())
|
|
sPS = pDataA->GetPSName();
|
|
else
|
|
sPS = pDataB->GetPSName();
|
|
}
|
|
|
|
if (sPS != "") {
|
|
cMatrixf mtxPos = cMath::MatrixTranslate(avPos);
|
|
pWorld->CreateParticleSystem("ImpactPS", sPS, 1, mtxPos);
|
|
|
|
// Log("Mat1: '%s' Mat2: '%s' Speed %f particle system '%s' pos: %s\n",
|
|
// GetName().c_str(),
|
|
// apSecondSurface->GetName().c_str(),
|
|
// afSpeed,sPS.c_str(),
|
|
// mtxPos.GetTranslation().ToString().c_str());
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cSurfaceData::UpdateRollEffect(iPhysicsBody *apBody) {
|
|
if (msRollSoundName == "" || mRollAxisFlags == 0)
|
|
return;
|
|
|
|
/////////////////////////////////
|
|
// Get the max angular speed
|
|
cVector3f vAngularSpeed = cMath::MatrixMul(apBody->GetLocalMatrix().GetRotation(),
|
|
apBody->GetAngularVelocity());
|
|
float fRollingSpeed = 0;
|
|
// X
|
|
if (mRollAxisFlags & eRollAxisFlag_X)
|
|
fRollingSpeed = ABS(vAngularSpeed.x);
|
|
// Y
|
|
if (mRollAxisFlags & eRollAxisFlag_Y)
|
|
if (fRollingSpeed < ABS(vAngularSpeed.y))
|
|
fRollingSpeed = ABS(vAngularSpeed.y);
|
|
// Z
|
|
if (mRollAxisFlags & eRollAxisFlag_Z)
|
|
if (fRollingSpeed < ABS(vAngularSpeed.z))
|
|
fRollingSpeed = ABS(vAngularSpeed.z);
|
|
|
|
// Log("Rollspeed: %f\n",fRollingSpeed);
|
|
|
|
if (fRollingSpeed == 0 && apBody->GetRollSoundEntity() == NULL)
|
|
return;
|
|
|
|
/////////////////////////////////
|
|
// Update roll sound
|
|
cWorld3D *pWorld = mpPhysics->GetGameWorld();
|
|
if (pWorld == NULL)
|
|
return;
|
|
|
|
cSoundHandler *pSoundHandler = pWorld->GetSound()->GetSoundHandler();
|
|
if (pSoundHandler->GetSilent())
|
|
return;
|
|
|
|
// Check if sound exist in world.
|
|
if (pWorld->SoundEntityExists(apBody->GetRollSoundEntity()) == false) {
|
|
apBody->SetRollSoundEntity(NULL);
|
|
}
|
|
|
|
// If the body all ready has a Roll sound
|
|
if (apBody->GetRollSoundEntity() != NULL) {
|
|
// check if the sound should be stopped
|
|
float fMin = cMath::Max(mfMinRollSpeed - 0.7f, 0.02f);
|
|
if (fRollingSpeed < fMin ||
|
|
apBody->HasCollision() == false) {
|
|
apBody->GetRollSoundEntity()->FadeOut(4.3f);
|
|
apBody->SetRollSoundEntity(NULL);
|
|
// Log("Stopped Roll '%s' on body '%s'\n",msRollSoundName.c_str(),
|
|
// apBody->GetName().c_str());
|
|
} else {
|
|
// Change frequency according to speed.
|
|
float fAbsSpeed = fRollingSpeed;
|
|
float fFreq = 1;
|
|
float fVolume = 1;
|
|
|
|
// Higher than middle
|
|
if (fAbsSpeed >= mfMiddleRollSpeed) {
|
|
if (fAbsSpeed >= mfMaxRollFreqSpeed) {
|
|
fFreq = mfMaxRollFreq;
|
|
fVolume = mfMaxRollVolume;
|
|
} else {
|
|
// Calculate how close the speed is to max.
|
|
float fT = (fAbsSpeed - mfMiddleRollSpeed) /
|
|
(mfMaxRollFreqSpeed - mfMiddleRollSpeed);
|
|
|
|
fFreq = (1 - fT) + fT * mfMaxRollFreq;
|
|
fVolume = (1 - fT) + fT * mfMaxRollVolume;
|
|
}
|
|
}
|
|
// Below middle
|
|
else {
|
|
if (fAbsSpeed <= mfMinRollFreqSpeed) {
|
|
fFreq = mfMinRollFreq;
|
|
fVolume = mfMinRollVolume;
|
|
} else {
|
|
// Calculate how close the speed is to max.
|
|
float fT = (mfMiddleRollSpeed - fAbsSpeed) /
|
|
(mfMiddleRollSpeed - mfMinRollFreqSpeed);
|
|
|
|
fFreq = (1 - fT) + fT * mfMinRollFreq;
|
|
fVolume = (1 - fT) + fT * mfMinRollVolume;
|
|
}
|
|
}
|
|
|
|
// Log("Speed: %f Freq: %f\n",fAbsSpeed,fFreq);
|
|
cSoundEntity *pSound = apBody->GetRollSoundEntity();
|
|
cSoundEntry *pEntry = pSound->GetSoundEntry(eSoundEntityType_Main);
|
|
if (pEntry) {
|
|
pEntry->mfNormalSpeed = fFreq;
|
|
|
|
// pEntry->mfNormalVolume = cMath::Max(fVolume * pSound->GetVolume(),1.0f);
|
|
pEntry->mfNormalVolumeFadeDest = cMath::Min(fVolume * pSound->GetVolume(), 1.0f);
|
|
pEntry->mfNormalVolumeFadeSpeed = 4.0f;
|
|
|
|
apBody->GetRollSoundEntity()->SetPosition(apBody->GetWorldPosition());
|
|
|
|
// Log("Updated Roll on body '%s' w speed %f to f: %f v: %f\n",apBody->GetName().c_str(),
|
|
// fRollingSpeed,fFreq,fVolume);
|
|
} else {
|
|
}
|
|
}
|
|
} else {
|
|
if (mfMinRollSpeed <= fRollingSpeed && apBody->HasCollision()) {
|
|
cSoundEntity *pEntity = pWorld->CreateSoundEntity("Roll",
|
|
msRollSoundName, true);
|
|
if (pEntity) {
|
|
pEntity->FadeIn(3.3f);
|
|
pEntity->SetPosition(apBody->GetWorldPosition());
|
|
|
|
pEntity->SetIsSaved(false);
|
|
|
|
apBody->SetRollSoundEntity(pEntity);
|
|
|
|
// Log("Starting Roll '%s' on body '%s'\n",msRollSoundName.c_str(),
|
|
// apBody->GetName().c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cSurfaceData::SetElasticity(float afElasticity) {
|
|
mfElasticity = afElasticity;
|
|
}
|
|
|
|
float cSurfaceData::GetElasticity() const {
|
|
return mfElasticity;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cSurfaceData::SetStaticFriction(float afElasticity) {
|
|
mfStaticFriction = afElasticity;
|
|
}
|
|
|
|
float cSurfaceData::GetStaticFriction() const {
|
|
return mfStaticFriction;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cSurfaceData::SetKineticFriction(float afElasticity) {
|
|
mfKineticFriction = afElasticity;
|
|
}
|
|
|
|
float cSurfaceData::GetKineticFriction() const {
|
|
return mfKineticFriction;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cSurfaceData::SetPriority(int alPriority) {
|
|
mlPriority = alPriority;
|
|
}
|
|
|
|
int cSurfaceData::GetPriority() const {
|
|
return mlPriority;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cSurfaceData::SetFrictionCombMode(ePhysicsMaterialCombMode aMode) {
|
|
mFrictionMode = aMode;
|
|
}
|
|
|
|
ePhysicsMaterialCombMode cSurfaceData::GetFrictionCombMode() const {
|
|
return mFrictionMode;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cSurfaceData::SetElasticityCombMode(ePhysicsMaterialCombMode aMode) {
|
|
mElasticityMode = aMode;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
ePhysicsMaterialCombMode cSurfaceData::GetElasticityCombMode() const {
|
|
return mElasticityMode;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cSurfaceData::PreloadData() {
|
|
if (msRollSoundName != "")
|
|
mpResources->GetSoundEntityManager()->Preload(msRollSoundName);
|
|
if (msScrapeSoundName != "")
|
|
mpResources->GetSoundEntityManager()->Preload(msScrapeSoundName);
|
|
|
|
for (size_t i = 0; i < mvImpactData.size(); ++i) {
|
|
if (mvImpactData[i]->msSoundName != "") {
|
|
mpResources->GetSoundEntityManager()->Preload(mvImpactData[i]->msSoundName);
|
|
}
|
|
if (mvImpactData[i]->msPSName != "") {
|
|
mpResources->GetParticleManager()->Preload(mvImpactData[i]->msPSName);
|
|
}
|
|
}
|
|
for (size_t i = 0; i < mvHitData.size(); ++i) {
|
|
if (mvHitData[i]->msSoundName != "")
|
|
mpResources->GetSoundEntityManager()->Preload(mvHitData[i]->msSoundName);
|
|
if (mvHitData[i]->msPSName != "")
|
|
mpResources->GetParticleManager()->Preload(mvHitData[i]->msPSName);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
iPhysicsMaterial *cSurfaceData::ToMaterial(iPhysicsWorld *apWorld) {
|
|
iPhysicsMaterial *pMat = NULL;
|
|
|
|
pMat = apWorld->GetMaterialFromName(msName);
|
|
|
|
if (pMat == NULL) {
|
|
pMat = apWorld->CreateMaterial(msName);
|
|
}
|
|
|
|
pMat->SetElasticity(mfElasticity);
|
|
pMat->SetKineticFriction(mfKineticFriction);
|
|
pMat->SetStaticFriction(mfStaticFriction);
|
|
|
|
pMat->SetElasticityCombMode(mElasticityMode);
|
|
pMat->SetFrictionCombMode(mFrictionMode);
|
|
|
|
pMat->SetSurfaceData(this);
|
|
|
|
return pMat;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
cSurfaceImpactData *cSurfaceData::CreateImpactData(float afMinSpeed) {
|
|
cSurfaceImpactData *pData = hplNew(cSurfaceImpactData, ());
|
|
pData->mfMinSpeed = afMinSpeed;
|
|
|
|
mvImpactData.push_back(pData);
|
|
|
|
return pData;
|
|
}
|
|
|
|
cSurfaceImpactData *cSurfaceData::GetImpactData(int alIdx) {
|
|
return mvImpactData[alIdx];
|
|
}
|
|
|
|
int cSurfaceData::GetImpactDataNum() {
|
|
return (int)mvImpactData.size();
|
|
}
|
|
|
|
cSurfaceImpactData *cSurfaceData::GetImpactDataFromSpeed(float afSpeed) {
|
|
for (size_t i = 0; i < mvImpactData.size(); ++i) {
|
|
if (afSpeed >= mvImpactData[i]->GetMinSpeed()) {
|
|
return mvImpactData[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
cSurfaceImpactData *cSurfaceData::CreateHitData(float afMinSpeed) {
|
|
cSurfaceImpactData *pData = hplNew(cSurfaceImpactData, ());
|
|
pData->mfMinSpeed = afMinSpeed;
|
|
|
|
mvHitData.push_back(pData);
|
|
|
|
return pData;
|
|
}
|
|
|
|
cSurfaceImpactData *cSurfaceData::GetHitData(int alIdx) {
|
|
return mvHitData[alIdx];
|
|
}
|
|
|
|
int cSurfaceData::GetHitDataNum() {
|
|
return (int)mvHitData.size();
|
|
}
|
|
|
|
cSurfaceImpactData *cSurfaceData::GetHitDataFromSpeed(float afSpeed) {
|
|
for (size_t i = 0; i < mvHitData.size(); ++i) {
|
|
if (afSpeed >= mvHitData[i]->GetMinSpeed()) {
|
|
return mvHitData[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PRIVATE METHODS
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------
|
|
} // namespace hpl
|