293 lines
10 KiB
C++
293 lines
10 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/Physics.h"
|
|
#include "hpl1/engine/physics/LowLevelPhysics.h"
|
|
|
|
#include "hpl1/engine/physics/PhysicsWorld.h"
|
|
#include "hpl1/engine/physics/SurfaceData.h"
|
|
#include "hpl1/engine/system/String.h"
|
|
#include "hpl1/engine/system/low_level_system.h"
|
|
|
|
#include "hpl1/engine/impl/tinyXML/tinyxml.h"
|
|
|
|
namespace hpl {
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CONSTRUCTORS
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
cPhysics::cPhysics(iLowLevelPhysics *apLowLevelPhysics) : iUpdateable("HPL_Physics") {
|
|
mpLowLevelPhysics = apLowLevelPhysics;
|
|
|
|
mpGameWorld = NULL;
|
|
|
|
mlMaxImpacts = 6;
|
|
mfImpactDuration = 0.4f;
|
|
|
|
mbLog = false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
cPhysics::~cPhysics() {
|
|
Log("Exiting Physics Module\n");
|
|
Log("--------------------------------------------------------\n");
|
|
|
|
STLDeleteAll(mlstWorlds);
|
|
STLMapDeleteAll(m_mapSurfaceData);
|
|
|
|
Log("--------------------------------------------------------\n\n");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PUBLIC METHODS
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cPhysics::Init(cResources *apResources) {
|
|
mpResources = apResources;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cPhysics::Update(float afTimeStep) {
|
|
UpdateImpactCounts(afTimeStep);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
iPhysicsWorld *cPhysics::CreateWorld(bool abAddSurfaceData) {
|
|
iPhysicsWorld *pWorld = mpLowLevelPhysics->CreateWorld();
|
|
mlstWorlds.push_back(pWorld);
|
|
|
|
if (abAddSurfaceData) {
|
|
tSurfaceDataMapIt it = m_mapSurfaceData.begin();
|
|
for (; it != m_mapSurfaceData.end(); ++it) {
|
|
cSurfaceData *apData = it->second;
|
|
apData->ToMaterial(pWorld);
|
|
}
|
|
}
|
|
|
|
return pWorld;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cPhysics::DestroyWorld(iPhysicsWorld *apWorld) {
|
|
STLFindAndDelete(mlstWorlds, apWorld);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
bool cPhysics::CanPlayImpact() {
|
|
if ((int)mlstImpactCounts.size() >= mlMaxImpacts)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
void cPhysics::AddImpact() {
|
|
mlstImpactCounts.push_back(cPhysicsImpactCount());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
cSurfaceData *cPhysics::CreateSurfaceData(const tString &asName) {
|
|
cSurfaceData *pData = hplNew(cSurfaceData, (asName, this, mpResources));
|
|
|
|
m_mapSurfaceData.insert(tSurfaceDataMap::value_type(asName, pData));
|
|
|
|
return pData;
|
|
}
|
|
|
|
cSurfaceData *cPhysics::GetSurfaceData(const tString &asName) {
|
|
tSurfaceDataMapIt it = m_mapSurfaceData.find(asName);
|
|
if (it == m_mapSurfaceData.end())
|
|
return NULL;
|
|
|
|
return it->second;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
bool cPhysics::LoadSurfaceData(const tString &asFile) {
|
|
//////////////////////////////////
|
|
// Open document
|
|
TiXmlDocument *pXmlDoc = hplNew(TiXmlDocument, (asFile.c_str()));
|
|
if (pXmlDoc->LoadFile() == false) {
|
|
Error("Couldn't load XML file '%s'!\n", asFile.c_str());
|
|
hplDelete(pXmlDoc);
|
|
return false;
|
|
}
|
|
|
|
/////////////////////////
|
|
// Get the root.
|
|
TiXmlElement *pRootElem = pXmlDoc->RootElement();
|
|
|
|
//////////////////////////
|
|
// Iterate children
|
|
TiXmlElement *pChildElem = pRootElem->FirstChildElement("Material");
|
|
for (; pChildElem != NULL; pChildElem = pChildElem->NextSiblingElement("Material")) {
|
|
tString sName = cString::ToString(pChildElem->Attribute("Name"), "");
|
|
if (sName == "")
|
|
continue;
|
|
|
|
cSurfaceData *pData = CreateSurfaceData(sName);
|
|
|
|
// Get properties
|
|
pData->SetElasticity(cString::ToFloat(pChildElem->Attribute("Elasticity"), 0.5f));
|
|
pData->SetKineticFriction(cString::ToFloat(pChildElem->Attribute("KineticFriction"), 0.3f));
|
|
pData->SetStaticFriction(cString::ToFloat(pChildElem->Attribute("StaticFriction"), 0.3f));
|
|
|
|
pData->SetPriority(cString::ToInt(pChildElem->Attribute("Priority"), 0));
|
|
|
|
pData->SetElasticityCombMode(GetCombMode(pChildElem->Attribute("ElasticityMode")));
|
|
pData->SetFrictionCombMode(GetCombMode(pChildElem->Attribute("FrictionMode")));
|
|
|
|
pData->GetStepType(cString::ToString(pChildElem->Attribute("StepType"), ""));
|
|
|
|
pData->SetMinScrapeSpeed(cString::ToFloat(pChildElem->Attribute("MinScrapeSpeed"), 0.7f));
|
|
pData->SetMinScrapeFreq(cString::ToFloat(pChildElem->Attribute("MinScrapeFreq"), 0.7f));
|
|
pData->SetMinScrapeFreqSpeed(cString::ToFloat(pChildElem->Attribute("MinScrapeFreqSpeed"), 0.7f));
|
|
pData->SetMiddleScrapeSpeed(cString::ToFloat(pChildElem->Attribute("MiddleScrapeSpeed"), 1.2f));
|
|
pData->SetMaxScrapeFreqSpeed(cString::ToFloat(pChildElem->Attribute("MaxScrapeFreqSpeed"), 3));
|
|
pData->SetMaxScrapeFreq(cString::ToFloat(pChildElem->Attribute("MaxScrapeFreq"), 2));
|
|
pData->SetMinScrapeContacts(cString::ToInt(pChildElem->Attribute("MinScrapeContacts"), 4));
|
|
pData->SetScrapeSoundName(cString::ToString(pChildElem->Attribute("ScrapeSoundName"), ""));
|
|
|
|
pData->SetMinRollSpeed(cString::ToFloat(pChildElem->Attribute("MinRollSpeed"), 0.7f));
|
|
pData->SetMinRollFreq(cString::ToFloat(pChildElem->Attribute("MinRollFreq"), 0.7f));
|
|
pData->SetMinRollVolume(cString::ToFloat(pChildElem->Attribute("MinRollVolume"), 0.7f));
|
|
pData->SetMinRollFreqSpeed(cString::ToFloat(pChildElem->Attribute("MinRollFreqSpeed"), 0.7f));
|
|
pData->SetMiddleRollSpeed(cString::ToFloat(pChildElem->Attribute("MiddleRollSpeed"), 1.2f));
|
|
pData->SetMaxRollFreqSpeed(cString::ToFloat(pChildElem->Attribute("MaxRollFreqSpeed"), 3));
|
|
pData->SetMaxRollFreq(cString::ToFloat(pChildElem->Attribute("MaxRollFreq"), 2));
|
|
pData->SetMaxRollVolume(cString::ToFloat(pChildElem->Attribute("MaxRollVolume"), 2));
|
|
pData->SetRollSoundName(cString::ToString(pChildElem->Attribute("RollSoundName"), ""));
|
|
|
|
// Axes
|
|
tString sAxisVec = cString::ToString(pChildElem->Attribute("RollAxis"), "");
|
|
tStringVec vAxes;
|
|
tFlag axisFlags = 0;
|
|
cString::GetStringVec(sAxisVec, vAxes);
|
|
for (size_t i = 0; i < vAxes.size(); ++i) {
|
|
tString sAxis = cString::ToLowerCase(vAxes[i]);
|
|
if (sAxis == "x")
|
|
axisFlags |= eRollAxisFlag_X;
|
|
else if (sAxis == "y")
|
|
axisFlags |= eRollAxisFlag_Y;
|
|
else if (sAxis == "z")
|
|
axisFlags |= eRollAxisFlag_Z;
|
|
}
|
|
pData->SetRollAxisFlags(axisFlags);
|
|
|
|
/////////////////////////
|
|
// Get Impact data
|
|
TiXmlElement *pImpactElem = pChildElem->FirstChildElement("Impact");
|
|
for (; pImpactElem != NULL; pImpactElem = pImpactElem->NextSiblingElement("Impact")) {
|
|
float fMinSpeed = cString::ToFloat(pImpactElem->Attribute("MinSpeed"), 1);
|
|
|
|
cSurfaceImpactData *pImpactData = pData->CreateImpactData(fMinSpeed);
|
|
|
|
pImpactData->SetSoundName(cString::ToString(pImpactElem->Attribute("SoundName"), ""));
|
|
pImpactData->SetPSName(cString::ToString(pImpactElem->Attribute("PSName"), ""));
|
|
pImpactData->SetPSPrio(cString::ToInt(pImpactElem->Attribute("PSPrio"), 10));
|
|
}
|
|
|
|
/////////////////////////
|
|
// Get Hit data
|
|
TiXmlElement *pHitElem = pChildElem->FirstChildElement("Hit");
|
|
for (; pHitElem != NULL; pHitElem = pHitElem->NextSiblingElement("Hit")) {
|
|
float fMinSpeed = cString::ToFloat(pHitElem->Attribute("MinSpeed"), 1);
|
|
|
|
cSurfaceImpactData *pHitData = pData->CreateHitData(fMinSpeed);
|
|
|
|
pHitData->SetSoundName(cString::ToString(pHitElem->Attribute("SoundName"), ""));
|
|
pHitData->SetPSName(cString::ToString(pHitElem->Attribute("PSName"), ""));
|
|
pHitData->SetPSPrio(cString::ToInt(pHitElem->Attribute("PSPrio"), 10));
|
|
}
|
|
|
|
/*Log("Added %s e: %f sf: %f kf: %f emode: %d fmode: %d\n", pData->GetName().c_str(),
|
|
pData->GetElasticity(), pData->GetStaticFriction(), pData->GetKineticFriction(),
|
|
pData->GetElasticityCombMode(), pData->GetFrictionCombMode());*/
|
|
}
|
|
|
|
hplDelete(pXmlDoc);
|
|
return true;
|
|
|
|
return true;
|
|
}
|
|
//-----------------------------------------------------------------------
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PRIVATE METHODS
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
ePhysicsMaterialCombMode cPhysics::GetCombMode(const char *apName) {
|
|
if (apName == NULL)
|
|
return ePhysicsMaterialCombMode_Average;
|
|
|
|
tString sMode = cString::ToLowerCase(apName);
|
|
|
|
if (sMode == "average")
|
|
return ePhysicsMaterialCombMode_Average;
|
|
if (sMode == "min")
|
|
return ePhysicsMaterialCombMode_Min;
|
|
if (sMode == "max")
|
|
return ePhysicsMaterialCombMode_Max;
|
|
if (sMode == "multiply")
|
|
return ePhysicsMaterialCombMode_Multiply;
|
|
|
|
return ePhysicsMaterialCombMode_Average;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void cPhysics::UpdateImpactCounts(float afTimeStep) {
|
|
tPhysicsImpactCountListIt it = mlstImpactCounts.begin();
|
|
while (it != mlstImpactCounts.end()) {
|
|
it->mfCount += afTimeStep;
|
|
if (it->mfCount > mfImpactDuration) {
|
|
it = mlstImpactCounts.erase(it);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
} // namespace hpl
|