Files
scummvm-cursorfix/engines/hpl1/engine/physics/Physics.cpp
2026-02-02 04:50:13 +01:00

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