Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,417 @@
/* 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/Body2D.h"
#include "hpl1/engine/graphics/Mesh2d.h"
#include "hpl1/engine/math/Math.h"
#include "hpl1/engine/physics/CollideData2D.h"
#include "hpl1/engine/physics/Collider2D.h"
#include "hpl1/engine/scene/Entity2D.h"
#include "hpl1/engine/scene/Node2D.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cBody2D::cBody2D(const tString &asName, cMesh2D *apMesh, cVector2f avSize, cCollider2D *apCollider, int alID)
: iEntity2D(asName) {
mvSize = avSize;
mpMesh = apMesh;
mpCollider = apCollider;
mpCollMesh = mpMesh->CreateCollisonMesh(0, mvSize);
mpBaseCollMesh = mpMesh->CreateCollisonMesh(0, mvSize);
/*for(int i=0;i<(int)mpCollMesh->mvPos.size();i++)
{
Log("Pos%d: %s\n", i,mpCollMesh->mvPos[i].ToString().c_str());
}
for(int i=0;i<(int)mpCollMesh->mvNormal.size();i++)
{
Log("Norm%d: %s\n", i,mpCollMesh->mvNormal[i].ToString().c_str());
}*/
// Log("------------\n");
// Set some default values to the properties
mfMaxVel = 0;
mfAcc = 1;
mfAirFriction = 0.005f;
mfGroundFriction = 0.3f;
mfGravity = 0.4f;
mfMaxGravityVel = 3;
mbCollidable = false;
mbCollides = true;
mbMoved = false;
mbOnGround = false;
mbGroundFrictionX = false;
mbGroundFrictionY = false;
mvCollideCount = 0;
mvMovement = 0;
mbAttachToGround = false;
mbAttachBodies = true;
mpParentBody = NULL;
mpNode = NULL;
mlID = alID;
mlCollideFlag = eFlagBit_0;
mlCollideType = eFlagBit_1;
}
//-----------------------------------------------------------------------
cBody2D::~cBody2D() {
hplDelete(mpCollMesh);
hplDelete(mpBaseCollMesh);
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cBody2D::UpdateLogic(float afTimeStep) {
cVector3f vStartPos = GetPosition();
if (mbAttachToGround) {
if (mpParentBody != NULL) {
// What can be done is to add this to the force, and then att the end redcue the same amout
// This will allow the body to add the velocity to it's jumps for example.
cVector3f vMovement = mpParentBody->GetMovement(); // mpParentBody->GetPosition() - mpParentBody->GetLastPosition();
SetPosition(GetPosition() + vMovement);
}
}
cCollideData2D CollideData;
// Update Gravity
mbGroundFrictionX = false;
if (mbCollides && mfGravity > 0) {
cVector3f vTempPos = GetPosition();
float fXSize = mvSize.x;
cRect2f Rect(vTempPos.x - fXSize / 2, vTempPos.y + mfGravity,
fXSize, mvSize.y / 2);
if (mpCollider->CollideRect(Rect, GetCollideFlag(), NULL)) {
// We are still on ground.
mbOnGround = true;
mbGroundFrictionX = true;
// Log("Standing on ground\n");
} else {
// If the player used to be on ground, add some extra force
if (mbOnGround) {
mvForce.y += mfGravity * 2;
}
mbOnGround = false;
mvForce.y += mfGravity;
if (mvForce.y > mfMaxGravityVel)
mvForce.y = mfMaxGravityVel;
}
}
// Add the Y Axis and check for collision
AddPosXY(cVector2f(0, mvForce.y));
if (mbCollides) {
UpdateCollisionMesh();
UpdateBoundingBox();
if (mpCollider->CollideBody(this, &CollideData)) {
if (mvLastCollidePos.y == GetPosition().y)
mvCollideCount.y++;
if (mvForce.y > 0) {
if (mbAttachToGround) {
// If collided with a body, make it the new reference frame.
if (CollideData.mlstBodies.size() > 0) {
tBody2DListIt it = CollideData.mlstBodies.begin();
if (*it != mpParentBody) {
if (mpParentBody != NULL)
DetachBody(mpParentBody);
SetParentBody(*it);
(*it)->AttachBody(this);
// Log("Attaching!\n");
}
} else {
if (mpParentBody != NULL) {
DetachBody(mpParentBody);
mpParentBody = NULL;
// Log("Detaching!\n");
}
}
}
mbOnGround = true;
mvForce.y = 0;
}
if (mvCollideCount.y > 0) {
mvForce.y = 0;
}
mvLastCollidePos.y = GetPosition().y;
mbGroundFrictionX = true;
} else {
mvCollideCount.y = 0;
if (!mbOnGround)
mvLastCollidePos.y = -10000;
// mbGroundFrictionX = false;
}
if (mbOnGround == false && mbAttachToGround) {
if (mpParentBody != NULL) {
DetachBody(mpParentBody);
mpParentBody = NULL;
// Log("Detaching!\n");
}
}
}
// Add the X Axis and check for collision
AddPosXY(cVector2f(mvForce.x, 0));
if (mbCollides) {
UpdateCollisionMesh();
UpdateBoundingBox();
if (mpCollider->CollideBody(this, NULL)) {
if (mvLastCollidePos.x == GetPosition().x)
mvCollideCount.x++;
if (mvCollideCount.x > 0) {
mvForce.x = 0;
}
mvLastCollidePos.x = GetPosition().x;
} else {
mvCollideCount.x = 0;
mvLastCollidePos.x = -10000;
}
}
// Update the force
float fAngle = 0, fStrength = 0;
cMath::GetAngleFromVector(mvForce, &fAngle, &fStrength);
fStrength -= mfAirFriction; // This is the air friction.
// It should be combined with the friction of the collided material.
if (fStrength < 0)
fStrength = 0;
SetForce(fAngle, fStrength);
// Don't do any friction if the body has moved.
// if(!mbMoved) Or?
{
if (mbGroundFrictionX && mvForce.x != 0) {
// Log("GroundFriction!\n");
// Log("Force: %s\n",mvForce.ToString().c_str());
if (mvForce.x > 0) {
mvForce.x -= mfGroundFriction;
if (mvForce.x < 0)
mvForce.x = 0;
} else {
mvForce.x += mfGroundFriction;
if (mvForce.x > 0)
mvForce.x = 0;
}
// Log("Force: %s\n",mvForce.ToString().c_str());
}
}
mvMovement = GetPosition() - vStartPos;
/*tBody2DListIt BodyIt = mlstAttachedBodies.begin();
for(;BodyIt != mlstAttachedBodies.end();BodyIt++)
{
cBody2D* pBody = *BodyIt;
pBody->SetPosition(pBody->GetPosition() + vMovement);
}*/
if (mpNode) {
mpNode->SetPosition(GetWorldPosition());
}
mbMoved = false;
}
//-----------------------------------------------------------------------
void cBody2D::Move(float afValue) {
float fAngle = 0, fStrength = 0;
cVector2f vForwardVec = cMath::GetVectorFromAngle2D(mvRotation.z, 1);
cVector2f vMovement = cMath::ProjectVector2D(mvForce, vForwardVec);
cMath::GetAngleFromVector(vMovement, &fAngle, &fStrength);
if (fStrength < mfMaxVel) {
float fTempAcc = mfAcc;
if (fStrength + fTempAcc > mfMaxVel) {
fTempAcc -= (fStrength + fTempAcc) - mfMaxVel;
}
mvForce += vForwardVec * fTempAcc;
mbMoved = true;
}
}
//-----------------------------------------------------------------------
void cBody2D::AddForce(float afAngle, float afStrength) {
cVector2f vForce = cMath::GetVectorFromAngle2D(afAngle, afStrength);
AddForce(vForce);
}
//-----------------------------------------------------------------------
void cBody2D::AddForce(const cVector2f &avForce) {
mvForce += avForce;
}
//-----------------------------------------------------------------------
void cBody2D::SetForce(float afAngle, float afStrength) {
cVector2f vForce = cMath::GetVectorFromAngle2D(afAngle, afStrength);
SetForce(vForce);
}
//-----------------------------------------------------------------------
void cBody2D::SetForce(const cVector2f &avForce) {
mvForce = avForce;
}
//-----------------------------------------------------------------------
const cRect2f &cBody2D::GetBoundingBox() {
return mBoundingBox;
}
//-----------------------------------------------------------------------
bool cBody2D::UpdateBoundingBox() {
cVector2f vSize;
/*if(mvRotation.z != 0)
{
//Only Temp...
float fMaxSize = sqrt(mvSize.x*mvSize.x + mvSize.y*mvSize.y);
vSize.x = fMaxSize;
vSize.y = fMaxSize;
}
else*/
{
vSize = mvSize;
}
mBoundingBox = cRect2f(cVector2f(GetWorldPosition().x - vSize.x / 2,
GetWorldPosition().y - vSize.y / 2),
vSize);
return true;
}
//-----------------------------------------------------------------------
void cBody2D::UpdateCollisionMesh() {
cVector2f vPos(GetPosition().x, GetPosition().y);
for (int i = 0; i < (int)mpCollMesh->mvPos.size(); i++) {
mpCollMesh->mvPos[i] = vPos + mpBaseCollMesh->mvPos[i];
}
}
//-----------------------------------------------------------------------
cCollisionMesh2D *cBody2D::GetCollisionMesh() {
return mpCollMesh;
}
//-----------------------------------------------------------------------
void cBody2D::AttachBody(cBody2D *apBody) {
mlstAttachedBodies.push_back(apBody);
}
//-----------------------------------------------------------------------
void cBody2D::DetachBody(cBody2D *apBody) {
tBody2DListIt it = mlstAttachedBodies.begin();
for (; it != mlstAttachedBodies.end(); it++) {
if (*it == apBody) {
mlstAttachedBodies.erase(it);
break;
}
}
}
//-----------------------------------------------------------------------
void cBody2D::SetParentBody(cBody2D *apBody) {
mpParentBody = apBody;
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cBody2D::AddPosXY(cVector2f avPosAdd) {
cVector3f vPos = GetPosition();
vPos += avPosAdd;
SetPosition(vPos);
}
//-----------------------------------------------------------------------
} // namespace hpl

View File

@@ -0,0 +1,186 @@
/* 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.
*/
#ifndef HPL_BODY_H
#define HPL_BODY_H
#include "hpl1/engine/math/MathTypes.h"
#include "common/list.h"
#include "hpl1/engine/scene/Entity2D.h"
#include "common/stablemap.h"
namespace hpl {
class cMesh2D;
class cNode2D;
class cCollider2D;
class cCollisionMesh2D;
class cBody2D;
typedef Common::List<cBody2D *> tBody2DList;
typedef tBody2DList::iterator tBody2DListIt;
class cBody2D : public iEntity2D {
public:
cBody2D(const tString &asName, cMesh2D *apMesh, cVector2f avSize, cCollider2D *apCollider, int alID);
~cBody2D();
const cRect2f &GetBoundingBox();
bool UpdateBoundingBox();
void Move(float afValue);
void UpdateLogic(float afTimeStep);
tString GetEntityType() { return "Body"; };
cVector3f &GetPosition() { return mvPosition; }
cVector3f &GetLastPosition() { return mvLastPosition; }
void ResetLastPosition() { mvLastPosition = mvPosition; }
float GetVelocity();
float GetMaxVelocity() { return mfMaxVel; }
float GetAcceleration() { return mfAcc; }
float GetGravity() { return mfGravity; }
float GetMaxGravityVel() { return mfMaxGravityVel; }
bool GetCollidable() { return mbCollidable; }
bool GetCollides() { return mbCollides; }
float GetAirFriction() { return mfAirFriction; }
float GetGroundFriction() { return mfGroundFriction; }
const cVector2f &GetSize() { return mvSize; }
const cVector3f &GetMovement() { return mvMovement; }
void SetMaxVelocity(float afMaxVel) { mfMaxVel = afMaxVel; }
void SetAcceleration(float afAcc) { mfAcc = afAcc; }
void SetGravity(float afGravity) { mfGravity = afGravity; }
void SetMaxGravityVel(float afMaxGravityVel) { mfMaxGravityVel = afMaxGravityVel; }
void SetCollidable(bool abCollidable) { mbCollidable = abCollidable; }
void SetCollides(bool abCollides) { mbCollides = abCollides; }
void SetAirFriction(float afAirFriction) { mfAirFriction = afAirFriction; }
void SetGroundFriction(float afGroundFriction) { mfGroundFriction = afGroundFriction; }
void AddForce(float afAngle, float afStrength);
void AddForce(const cVector2f &avForce);
void SetForce(float afAngle, float afStrength);
void SetForce(const cVector2f &avForce);
const cVector2f &GetForce() const { return mvForce; }
/**
* Sets the things that the body can collide with, default is eFlagBit_0 (tiles)
* \param alFlag
*/
void SetCollideFlag(tFlag alFlag) { mlCollideFlag = alFlag; }
tFlag GetCollideFlag() { return mlCollideFlag; }
/**
* Sets if the body is attached to moving obejcts and moves with the, default is false.
* \param abX
*/
void SetAttachToGround(bool abX) { mbAttachToGround = abX; }
bool GetAttachToGround() { return mbAttachToGround; }
/**
* Sets if other objects can attach themselves to this body. Default is true.
* \param abX
*/
void SetAttachBodies(bool abX) { mbAttachBodies = abX; }
bool GetAttachBodies() { return mbAttachBodies; }
void AttachBody(cBody2D *apBody);
void DetachBody(cBody2D *apBody);
void SetParentBody(cBody2D *apBody);
/**
* Sets the types of collider the body is, default is eFlagBit_1. On collision checking, the
* other objects specify what it can collide with. And for every body this value is checked.
* \param alFlag
*/
void SetCollideType(tFlag alFlag) { mlCollideType = alFlag; }
tFlag GetCollideType() { return mlCollideType; }
void AttachNode(cNode2D *apNode) { mpNode = apNode; }
void DetachNode() { mpNode = NULL; }
int GetID() { return mlID; }
bool OnGround() { return mbOnGround; }
void UpdateCollisionMesh();
cCollisionMesh2D *GetCollisionMesh();
private:
float mfMaxVel;
float mfAcc;
float mfGravity;
float mfMaxGravityVel;
float mfAirFriction;
float mfGroundFriction;
bool mbCollides;
bool mbCollidable;
bool mbMoved;
cVector3f mvMovement;
bool mbAttachToGround;
bool mbAttachBodies;
tBody2DList mlstAttachedBodies;
cBody2D *mpParentBody;
int mlID;
tFlag mlCollideFlag;
tFlag mlCollideType;
cMesh2D *mpMesh;
cCollider2D *mpCollider;
cNode2D *mpNode;
cCollisionMesh2D *mpCollMesh;
cCollisionMesh2D *mpBaseCollMesh;
bool mbOnGround;
bool mbGroundFrictionX;
bool mbGroundFrictionY;
cVector2f mvForce;
cVector2f mvSize;
cVector2l mvCollideCount;
cVector2f mvLastCollidePos;
void AddPosXY(cVector2f avPosAdd);
};
} // namespace hpl
#endif // HPL_BODY_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,415 @@
/* 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.
*/
#ifndef HPL_CHARACTER_BODY_H
#define HPL_CHARACTER_BODY_H
#include "hpl1/engine/math/MathTypes.h"
#include "hpl1/engine/physics/PhysicsWorld.h"
namespace hpl {
class iPhysicsWorld;
class iCollideShape;
class iPhysicsBody;
class cCamera3D;
class iCharacterBody;
class iEntity3D;
enum eCharDir {
eCharDir_Forward = 0,
eCharDir_Right = 1,
eCharDir_LastEnum = 2
};
class iCharacterBodyCallback {
public:
virtual ~iCharacterBodyCallback() = default;
virtual void OnHitGround(iCharacterBody *apCharBody, const cVector3f &avVel) = 0;
virtual void OnGravityCollide(iCharacterBody *apCharBody, iPhysicsBody *apCollideBody,
cCollideData *apCollideData) = 0;
};
//------------------------------------------------
class cCharacterBodyRay : public iPhysicsRayCallback {
public:
cCharacterBodyRay();
void Clear();
bool OnIntersect(iPhysicsBody *pBody, cPhysicsRayParams *apParams);
float mfMinDist;
bool mbCollide;
};
//------------------------------------------------
class cCharacterBodyCollideGravity : public iPhysicsWorldCollisionCallback {
public:
cCharacterBodyCollideGravity();
void OnCollision(iPhysicsBody *apBody, cCollideData *apCollideData);
iCharacterBody *mpCharBody;
};
//------------------------------------------------
class cCharacterBodyCollidePush : public iPhysicsWorldCollisionCallback {
public:
cCharacterBodyCollidePush();
void OnCollision(iPhysicsBody *apBody, cCollideData *apCollideData);
iCharacterBody *mpCharBody;
};
//-----------------------------------
kSaveData_BaseClass(iCharacterBody) {
kSaveData_ClassInit(iCharacterBody) public : tString msName;
float mfMass;
bool mbGravityActive;
float mfMaxGravitySpeed;
bool mbActive;
bool mbCollideCharacter;
cVector3f mvPosition;
cVector3f mvLastPosition;
float mfMaxPosMoveSpeed[2];
float mfMaxNegMoveSpeed[2];
float mfMoveSpeed[2];
float mfMoveAcc[2];
float mfMoveDeacc[2];
bool mbMoving[2];
float mfPitch;
float mfYaw;
bool mbOnGround;
float mfMaxPushMass;
float mfPushForce;
bool mbPushIn2D;
cVector3f mvForce;
cVector3f mvVelolcity;
cVector3f mvSize;
cMatrixf m_mtxMove;
int mlEntityId;
cMatrixf m_mtxEntityOffset;
int mlEntitySmoothPosNum;
float mfMaxStepHeight;
float mfStepClimbSpeed;
float mfClimbForwardMul;
float mfClimbHeightAdd;
bool mbClimbing;
float mfGroundFriction;
float mfAirFriction;
int mlBodyId;
cContainerList<int> mvExtraBodyIds;
virtual iSaveObject *CreateSaveObject(cSaveObjectHandler * apSaveObjectHandler, cGame * apGame);
virtual int GetSaveCreatePrio();
};
//------------------------------------------------
class iCharacterBody : public iSaveObject {
typedef iSaveObject super;
friend class cSaveData_iCharacterBody;
friend class cCharacterBodyCollideGravity;
public:
iCharacterBody(const tString &asName, iPhysicsWorld *apWorld, const cVector3f avSize);
virtual ~iCharacterBody();
const tString &GetName() { return msName; }
///////////////////////////////////////
// Properties
float GetMass();
void SetMass(float afMass);
void SetActive(bool abX);
bool IsActive() { return mbActive; }
cVector3f GetSize();
void SetCollideCharacter(bool abX);
bool GetCollideCharacter() { return mbCollideCharacter; }
void SetTestCollision(bool abX) { mbTestCollision = abX; }
bool GetTestCollision() { return mbTestCollision; }
void SetMaxPositiveMoveSpeed(eCharDir aDir, float afX);
float GetMaxPositiveMoveSpeed(eCharDir aDir);
void SetMaxNegativeMoveSpeed(eCharDir aDir, float afX);
float GetMaxNegativeMoveSpeed(eCharDir aDir);
void SetMoveSpeed(eCharDir aDir, float afX);
float GetMoveSpeed(eCharDir aDir);
void SetMoveAcc(eCharDir aDir, float afX);
float GetMoveAcc(eCharDir aDir);
void SetMoveDeacc(eCharDir aDir, float afX);
float GetMoveDeacc(eCharDir aDir);
cVector3f GetVelocity(float afFrameTime);
void SetPosition(const cVector3f &avPos, bool abSmooth = false);
const cVector3f &GetPosition();
const cVector3f &GetLastPosition();
void SetFeetPosition(const cVector3f &avPos, bool abSmooth = false);
cVector3f GetFeetPosition();
void SetYaw(float afX);
void AddYaw(float afX);
float GetYaw();
void SetPitch(float afX);
void AddPitch(float afX);
float GetPitch();
cVector3f GetForward();
cVector3f GetRight();
cVector3f GetUp();
cMatrixf &GetMoveMatrix();
void SetGravityActive(bool abX);
bool GravityIsActive();
void SetMaxGravitySpeed(float afX);
float GetMaxGravitySpeed();
bool GetCustomGravityActive();
void SetCustomGravityActive(bool abX);
void SetCustomGravity(const cVector3f &avCustomGravity);
cVector3f GetCustomGravity();
void SetMaxPushMass(float afX) { mfMaxPushMass = afX; }
void SetPushForce(float afX) { mfPushForce = afX; }
float GetMaxPushMass() { return mfMaxPushMass; }
float GetPushForce() { return mfPushForce; }
bool GetPushIn2D() { return mbPushIn2D; }
void SetPushIn2D(bool abX) { mbPushIn2D = abX; }
void AddForceVelocity(const cVector3f &avVel) { mvVelolcity += avVel; }
void SetForceVelocity(const cVector3f &avVel) { mvVelolcity = avVel; }
cVector3f GetForceVelocity() { return mvVelolcity; }
int AddExtraSize(const cVector3f &avSize);
void SetActiveSize(int alNum);
///////////////////////////////////////
// Actions
void SetForce(const cVector3f &avForce);
void AddForce(const cVector3f &avForce);
cVector3f GetForce();
void Move(eCharDir aDir, float afMul, float afTimeStep);
void Update(float afTimeStep);
///////////////////////////////////////
// Other
void SetCamera(cCamera3D *apCam);
cCamera3D *GetCamera();
void SetCameraPosAdd(const cVector3f &avAdd);
cVector3f GetCameraPosAdd();
void SetCameraSmoothPosNum(int alNum) { mlCameraSmoothPosNum = alNum; }
int GetCameraSmoothPosNum() { return mlCameraSmoothPosNum; }
void SetEntity(iEntity3D *apEntity);
iEntity3D *GetEntity();
void SetEntityOffset(const cMatrixf &a_mtxOffset);
const cMatrixf &GetEntityOffset();
void SetEntityPostOffset(const cMatrixf &a_mtxOffset);
const cMatrixf &GetEntityPostOffset();
void SetEntitySmoothPosNum(int alNum) { mlEntitySmoothPosNum = alNum; }
int GetEntitySmoothPosNum() { return mlEntitySmoothPosNum; }
void SetUserData(void *apUserData) { mpUserData = apUserData; }
void *GetUserData() { return mpUserData; }
void SetCallback(iCharacterBodyCallback *apCallback) { mpCallback = apCallback; }
void SetEnableNearbyBodies(bool abX) { mbEnableNearbyBodies = abX; }
bool GetEnableNearbyBodies() { return mbEnableNearbyBodies; }
iPhysicsBody *GetBody() { return mpBody; }
iCollideShape *GetShape();
iPhysicsBody *GetExtraBody(size_t alIdx) { return mvExtraBodies[alIdx]; }
bool IsOnGround();
float GetMaxStepSize() { return mfMaxStepHeight; }
void SetMaxStepSize(float afSize) { mfMaxStepHeight = afSize; }
void SetStepClimbSpeed(float afX) { mfStepClimbSpeed = afX; }
float GetStepClimbSpeed() { return mfStepClimbSpeed; }
void SetAccurateClimbing(bool abX) { mbAccurateClimbing = abX; }
bool GetAccurateClimbing() { return mbAccurateClimbing; }
void SetClimbForwardMul(float afX) { mfClimbForwardMul = afX; }
float GetClimbForwardMul() { return mfClimbForwardMul; }
void SetClimbHeightAdd(float afX) { mfClimbHeightAdd = afX; }
float GetClimbHeightAdd() { return mfClimbHeightAdd; }
void SetGroundFriction(float afX) { mfGroundFriction = afX; }
float GetGroundFriction() { return mfGroundFriction; }
void SetAirFriction(float afX) { mfAirFriction = afX; }
float GetAirFriction() { return mfAirFriction; }
bool IsClimbing() { return mbClimbing; }
void SetAttachedBody(iPhysicsBody *apBody);
iPhysicsBody *GetAttachedBody() { return mpAttachedBody; }
// O=nly sue when you know what you are doing, Update calls these
void UpdateMoveMarix();
void UpdateCamera();
void UpdateEntity();
void UpdateAttachment();
// SaveObject implementation
virtual iSaveData *CreateSaveData();
virtual void SaveToSaveData(iSaveData *apSaveData);
virtual void LoadFromSaveData(iSaveData *apSaveData);
virtual void SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame);
protected:
tString msName;
float mfMass;
bool mbActive;
bool mbCollideCharacter;
bool mbTestCollision;
bool mbGravityActive;
float mfMaxGravitySpeed;
bool mbCustomGravity;
cVector3f mvCustomGravity;
cVector3f mvPosition;
cVector3f mvLastPosition;
float mfMaxPosMoveSpeed[2];
float mfMaxNegMoveSpeed[2];
float mfMoveSpeed[2];
float mfMoveAcc[2];
float mfMoveDeacc[2];
bool mbMoving[2];
float mfPitch;
float mfYaw;
bool mbOnGround;
float mfMaxPushMass;
float mfPushForce;
bool mbPushIn2D;
float mfCheckStepClimbCount;
float mfCheckStepClimbInterval;
cVector3f mvForce;
cVector3f mvVelolcity;
cVector3f mvSize;
cMatrixf m_mtxMove;
cCamera3D *mpCamera;
cVector3f mvCameraPosAdd;
int mlCameraSmoothPosNum;
tVector3fList mlstCameraPos;
iEntity3D *mpEntity;
cMatrixf m_mtxEntityOffset;
cMatrixf m_mtxEntityPostOffset;
int mlEntitySmoothPosNum;
tVector3fList mlstEntityPos;
float mfGroundFriction;
float mfAirFriction;
void *mpUserData;
iPhysicsBody *mpAttachedBody;
cMatrixf m_mtxAttachedPrevMatrix;
bool mbAttachmentJustAdded;
iCharacterBodyCallback *mpCallback;
cCharacterBodyRay *mpRayCallback;
cCharacterBodyCollideGravity *mpCollideCallbackGravity;
cCharacterBodyCollidePush *mpCollideCallbackPush;
float mfMaxStepHeight;
float mfStepClimbSpeed;
float mfClimbForwardMul;
float mfClimbHeightAdd;
bool mbClimbing;
bool mbAccurateClimbing;
bool mbEnableNearbyBodies;
iPhysicsBody *mpBody;
iPhysicsWorld *mpWorld;
Common::Array<iPhysicsBody *> mvExtraBodies;
};
} // namespace hpl
#endif // HPL_CHARACTER_BODY_H

View File

@@ -0,0 +1,58 @@
/* 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.
*/
#ifndef HPL_COLLIDE_DATA_H
#define HPL_COLLIDE_DATA_H
#include "hpl1/engine/math/MathTypes.h"
#include "hpl1/engine/system/SystemTypes.h"
namespace hpl {
class cCollidePoint {
public:
cVector3f mvPoint;
cVector3f mvNormal;
float mfDepth;
};
typedef Common::Array<cCollidePoint> tCollidePointVec;
typedef tCollidePointVec::iterator tCollidePointVecIt;
class cCollideData {
public:
tCollidePointVec mvContactPoints;
int mlNumOfPoints;
void SetMaxSize(int alSize) {
mvContactPoints.resize(alSize);
}
};
} // namespace hpl
#endif // HPL_COLLIDE_DATA_H

View File

@@ -0,0 +1,65 @@
/* 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.
*/
#ifndef HPL_COLLIDE_DATA_2D_H
#define HPL_COLLIDE_DATA_2D_H
#include "common/list.h"
#include "hpl1/engine/math/MathTypes.h"
#include "hpl1/engine/physics/Body2D.h"
#include "hpl1/engine/scene/Tile.h"
#include "hpl1/engine/system/SystemTypes.h"
namespace hpl {
class cCollidedTile {
public:
cCollidedTile(cTile *apTile, int alLayer) : mpTile(apTile), mlLayer(alLayer) {}
cTile *mpTile;
int mlLayer;
};
typedef Common::List<cCollidedTile> tCollidedTileList;
typedef tCollidedTileList::iterator tCollidedTileListIt;
class cCollideData2D {
public:
tCollidedTileList mlstTiles;
tBody2DList mlstBodies;
cVector2f mvPushVec;
void Clear() {
mlstBodies.clear();
mlstTiles.clear();
mvPushVec = 0;
}
};
} // namespace hpl
#endif // HPL_COLLIDE_DATA_2D_H

View File

@@ -0,0 +1,94 @@
/* 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.
*/
#ifndef HPL_COLLIDE_SHAPE_H
#define HPL_COLLIDE_SHAPE_H
#include "hpl1/engine/math/BoundingVolume.h"
#include "hpl1/engine/math/MathTypes.h"
namespace hpl {
enum eCollideShapeType {
eCollideShapeType_Null,
eCollideShapeType_Box,
eCollideShapeType_Sphere,
eCollideShapeType_Cylinder,
eCollideShapeType_Capsule,
eCollideShapeType_ConvexHull,
eCollideShapeType_Mesh,
eCollideShapeType_Compound,
eCollideShapeType_LastEnum
};
class iPhysicsWorld;
class iCollideShape {
public:
iCollideShape(iPhysicsWorld *apWorld) : mlUserCount(0), mpWorld(apWorld) {}
virtual ~iCollideShape() {}
virtual iCollideShape *GetSubShape(int alIdx) = 0;
virtual int GetSubShapeNum() = 0;
cVector3f GetSize() { return mvSize; }
float GetRadius() { return mvSize.x; }
float GetHeight() { return mvSize.y; }
float GetWidth() { return mvSize.x; }
float GetDepth() { return mvSize.z; }
const cMatrixf &GetOffset() { return m_mtxOffset; }
eCollideShapeType GetType() { return mType; }
void IncUserCount() { mlUserCount++; }
void DecUserCount() { mlUserCount--; }
bool HasUsers() { return mlUserCount > 0; }
int GetUserCount() { return mlUserCount; }
float GetVolume() { return mfVolume; }
cBoundingVolume &GetBoundingVolume() { return mBoundingVolume; }
protected:
cVector3f mvSize;
eCollideShapeType mType;
cMatrixf m_mtxOffset;
int mlUserCount;
iPhysicsWorld *mpWorld;
float mfVolume;
cBoundingVolume mBoundingVolume;
};
} // namespace hpl
#endif // HPL_COLLIDE_SHAPE_H

View File

@@ -0,0 +1,447 @@
/* 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/Collider2D.h"
#include "hpl1/engine/graphics/Mesh2d.h"
#include "hpl1/engine/math/Math.h"
#include "hpl1/engine/physics/Body2D.h"
#include "hpl1/engine/physics/CollideData2D.h"
#include "hpl1/engine/scene/GridMap2D.h"
#include "hpl1/engine/scene/TileMap.h"
#include "hpl1/engine/scene/World2D.h"
#include "hpl1/engine/system/low_level_system.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cCollider2D::cCollider2D() {
mpWorld = NULL;
}
//-----------------------------------------------------------------------
cCollider2D::~cCollider2D() {
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
tFlag cCollider2D::CollideBody(cBody2D *apBody, cCollideData2D *apData) {
tFlag lCollision = eFlagBit_None;
cRect2f CollideRect = apBody->GetBoundingBox();
cCollisionMesh2D *pCollMesh = apBody->GetCollisionMesh();
cVector2f vPushVector;
cVector2f vLastPushVector;
/////// TEST COLLISION WITH TILES
// float fTileSize = mpWorld->GetTileMap()->GetTileSize();
// cRect2f TileRect = cRect2f(0, 0, fTileSize, fTileSize);
for (int i = 0; i < mpWorld->GetTileMap()->GetTileLayerNum(); i++) {
if (mpWorld->GetTileMap()->GetTileLayer(i)->HasCollision() == false)
continue;
iTileMapIt *pTileIt = mpWorld->GetTileMap()->GetRectIterator(CollideRect, i);
while (pTileIt->HasNext()) {
cTile *pTile = pTileIt->Next();
// TileRect.x = pTile->GetPosition().x - fTileSize / 2;
// TileRect.y = pTile->GetPosition().y - fTileSize / 2;
// This can be used for material properties.
// cTileDataNormal *pTData = static_cast<cTileDataNormal*>(pTile->GetTileData());
if (pTile->GetCollisionMesh() == NULL)
continue;
if (Collide(pCollMesh, pTile->GetCollisionMesh(), vPushVector)) {
if (apData)
apData->mlstTiles.push_back(cCollidedTile(pTile, i));
cVector3f vD;
vD = apBody->GetPosition() - pTile->GetPosition();
if ((vD.x * vPushVector.x + vD.y * vPushVector.y) < 0.0f)
vPushVector = vPushVector * -1;
cVector3f vPos = apBody->GetPosition();
bool bAlterX = true;
bool bAlterY = true;
// reverse the latest push, maybe pos here instead?
if (lCollision) {
// If the current X push is grater use it instead.
if (ABS(vPushVector.x) > ABS(vLastPushVector.x)) {
vPos.x -= vLastPushVector.x;
} else {
bAlterX = false;
}
// If the current Y push is grater use it instead.
if (ABS(vPushVector.y) > ABS(vLastPushVector.y)) {
vPos.y -= vLastPushVector.y;
bAlterY = true;
} else {
bAlterY = false;
}
}
if (bAlterX)
vPos.x += vPushVector.x;
if (bAlterY)
vPos.y += vPushVector.y;
apBody->SetPosition(vPos);
apBody->ResetLastPosition();
apBody->UpdateCollisionMesh();
// not really needed until layer change
CollideRect = apBody->GetBoundingBox();
lCollision |= eFlagBit_0;
vLastPushVector = vPushVector;
// break;
}
}
hplDelete(pTileIt);
// if(bCollision)break;
}
/////// TEST COLLISION WITH BODIES
iGridMap2DIt *pBodyIt = mpWorld->GetGridMapBodies()->GetRectIterator(CollideRect);
while (pBodyIt->HasNext()) {
cBody2D *pBody = static_cast<cBody2D *>(pBodyIt->Next());
if (apBody == pBody)
continue;
// eFlagBit_0 is probably just temporary.
if (pBody->IsActive() && pBody->GetCollideType() & apBody->GetCollideFlag()) {
pBody->UpdateCollisionMesh(); // Temp
if (Collide(pCollMesh, pBody->GetCollisionMesh(), vPushVector)) {
if (apData)
apData->mlstBodies.push_back(pBody);
cVector3f vD;
vD = apBody->GetPosition() - pBody->GetPosition();
if ((vD.x * vPushVector.x + vD.y * vPushVector.y) < 0.0f)
vPushVector = vPushVector * -1;
cVector3f vPos = apBody->GetPosition();
vPos += vPushVector;
apBody->SetPosition(vPos);
apBody->ResetLastPosition();
// apBody->UpdateCollisionMesh();
// not really needed until layer change
CollideRect = apBody->GetBoundingBox();
lCollision |= eFlagBit_0;
break;
}
}
}
hplDelete(pBodyIt);
/// Do some stuff when colliding
if (lCollision) {
/*cVector3f vPos = apBody->GetPosition() + vPushVector;
apBody->SetPosition(vPos);
apBody->ResetLastPosition();*/
mDebug.mvPushVec = vPushVector;
// mDebug.mvPushPos = cVector2f(apBody->GetPosition().x,apBody->GetPosition().y);
}
return lCollision;
}
//-----------------------------------------------------------------------
tFlag cCollider2D::CollideRect(cRect2f &aRect, tFlag alCollideFlags, cCollideData2D *apData) {
tFlag lCollision = eFlagBit_None;
cRect2f CollideRect = aRect;
cCollisionMesh2D *pCollMesh = hplNew(cCollisionMesh2D, ());
pCollMesh->mvPos.resize(4);
pCollMesh->mvNormal.resize(4);
SetCollideMesh(pCollMesh, aRect);
cVector2f vPushVector;
cVector2f vLastPushVector;
//// Check for all tiles if the flag is set
if (alCollideFlags & eFlagBit_0) {
// float fTileSize = mpWorld->GetTileMap()->GetTileSize();
// cRect2f TileRect = cRect2f(0, 0, fTileSize, fTileSize);
for (int i = 0; i < mpWorld->GetTileMap()->GetTileLayerNum(); i++) {
if (mpWorld->GetTileMap()->GetTileLayer(i)->HasCollision() == false)
continue;
iTileMapIt *pTileIt = mpWorld->GetTileMap()->GetRectIterator(CollideRect, i);
while (pTileIt->HasNext()) {
cTile *pTile = pTileIt->Next();
// TileRect.x = pTile->GetPosition().x - fTileSize / 2;
// TileRect.y = pTile->GetPosition().y - fTileSize / 2;
if (pTile->GetCollisionMesh() == NULL)
continue;
if (apData)
apData->mlstTiles.push_back(cCollidedTile(pTile, i));
if (Collide(pCollMesh, pTile->GetCollisionMesh(), vPushVector)) {
cVector3f vD;
vD = cVector3f(aRect.x, aRect.y, 0) - pTile->GetPosition();
if ((vD.x * vPushVector.x + vD.y * vPushVector.y) < 0.0f)
vPushVector = vPushVector * -1;
cVector3f vPos;
vPos.x = aRect.x;
vPos.y = aRect.y;
// reverse the latest push, maybe pos here instead?
if (lCollision) {
vPos -= vLastPushVector;
}
vPos += vPushVector;
aRect.x = vPos.x;
aRect.y = vPos.y;
SetCollideMesh(pCollMesh, aRect);
CollideRect = aRect;
lCollision |= eFlagBit_0;
vLastPushVector = vPushVector;
}
}
hplDelete(pTileIt);
}
}
iGridMap2DIt *pBodyIt = mpWorld->GetGridMapBodies()->GetRectIterator(CollideRect);
while (pBodyIt->HasNext()) {
cBody2D *pBody = static_cast<cBody2D *>(pBodyIt->Next());
if (pBody->IsActive() && pBody->GetCollideType() & alCollideFlags) {
if (cMath::BoxCollision(CollideRect, pBody->GetBoundingBox())) {
if (Collide(pCollMesh, pBody->GetCollisionMesh(), vPushVector)) {
if (apData)
apData->mlstBodies.push_back(pBody);
lCollision |= pBody->GetCollideType();
/*Perhaps fix the push vector here?*/
}
}
}
}
hplDelete(pBodyIt);
/// Do some stuff when colliding
if (lCollision) {
if (apData)
apData->mvPushVec = vPushVector;
}
hplDelete(pCollMesh);
return lCollision;
}
//-----------------------------------------------------------------------
tFlag cCollider2D::CollideLine(const cVector2f &avStart, const cVector2f &avEnd, tFlag alCollideFlags,
cCollideData2D *apData) {
tFlag lCollision = eFlagBit_None;
//// Check for all tiles if the flag is set
if (alCollideFlags & eFlagBit_0) {
/*float fTileSize = */ mpWorld->GetTileMap()->GetTileSize();
for (int i = 0; i < mpWorld->GetTileMap()->GetTileLayerNum(); i++) {
if (mpWorld->GetTileMap()->GetTileLayer(i)->HasCollision() == false)
continue;
iTileMapIt *pTileIt = mpWorld->GetTileMap()->GetLineIterator(avStart, avEnd, i);
while (pTileIt->HasNext()) {
cTile *pTile = pTileIt->Next();
if (pTile->GetCollisionMesh() == NULL)
continue;
// Log("Found tile!\n");
if (apData)
apData->mlstTiles.push_back(cCollidedTile(pTile, i));
lCollision |= eFlagBit_0;
}
hplDelete(pTileIt);
}
}
// hplDelete(pCollMesh);
return lCollision;
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cCollider2D::SetCollideMesh(cCollisionMesh2D *apMesh, cRect2f &aRect) {
apMesh->mvPos[0] = cVector2f(aRect.x, aRect.y);
apMesh->mvPos[1] = cVector2f(aRect.x + aRect.w, aRect.y);
apMesh->mvPos[2] = cVector2f(aRect.x + aRect.w, aRect.y + aRect.h);
apMesh->mvPos[3] = cVector2f(aRect.x, aRect.y + aRect.w);
apMesh->mvNormal[0] = cVector2f(0, -1);
apMesh->mvNormal[1] = cVector2f(1, 0);
apMesh->mvNormal[2] = cVector2f(0, 1);
apMesh->mvNormal[3] = cVector2f(-1, 0);
}
//-----------------------------------------------------------------------
cVector2f FindMTD(cVector2f *pPushVector, int alNumVectors) {
cVector2f MTD = pPushVector[0];
float mind2 = pPushVector[0].x * pPushVector[0].x + pPushVector[0].y * pPushVector[0].y;
for (int i = 1; i < alNumVectors; i++) {
float fD2 = pPushVector[i].x * pPushVector[i].x + pPushVector[i].y * pPushVector[i].y;
if (fD2 < mind2) {
mind2 = fD2;
MTD = pPushVector[i];
}
}
return MTD;
}
//-----------------------------------------------------------------------
bool cCollider2D::Collide(cCollisionMesh2D *apMeshA, cCollisionMesh2D *apMeshB, cVector2f &avMTD) {
cVector2f vAxis[32];
int lAxisNum = 0;
// Check separating planes for A
for (int i = 0; i < (int)apMeshA->mvNormal.size(); i++) {
vAxis[lAxisNum] = apMeshA->mvNormal[i];
if (AxisSeparateMeshes(vAxis[lAxisNum], apMeshA, apMeshB)) {
return false;
}
lAxisNum++;
}
// Check separating planes for B
for (int i = 0; i < (int)apMeshB->mvNormal.size(); i++) {
vAxis[lAxisNum] = apMeshB->mvNormal[i];
if (AxisSeparateMeshes(vAxis[lAxisNum], apMeshA, apMeshB)) {
return false;
}
lAxisNum++;
}
avMTD = FindMTD(vAxis, lAxisNum);
return true;
}
//-----------------------------------------------------------------------
bool cCollider2D::AxisSeparateMeshes(cVector2f &avAxis, cCollisionMesh2D *apMeshA,
cCollisionMesh2D *apMeshB) {
float fMinA, fMaxA;
float fMinB, fMaxB;
CalculateInterval(avAxis, apMeshA, fMinA, fMaxA);
CalculateInterval(avAxis, apMeshB, fMinB, fMaxB);
if (fMinA >= fMaxB || fMinB >= fMaxA)
return true;
float fD0 = fMaxA - fMinB;
float fD1 = fMaxB - fMinA;
float fDepth = (fD0 < fD1) ? fD0 : fD1;
avAxis *= fDepth;
return false;
}
//-----------------------------------------------------------------------
void cCollider2D::CalculateInterval(const cVector2f &avAxis, cCollisionMesh2D *apMesh,
float &afMin, float &afMax) {
float fTemp = avAxis.x * apMesh->mvPos[0].x + avAxis.y * apMesh->mvPos[0].y;
afMin = fTemp;
afMax = fTemp;
for (int i = 1; i < (int)apMesh->mvPos.size(); i++) {
fTemp = avAxis.x * apMesh->mvPos[i].x + avAxis.y * apMesh->mvPos[i].y;
if (fTemp < afMin) {
afMin = fTemp;
} else if (fTemp > afMax) {
afMax = fTemp;
}
}
}
//-----------------------------------------------------------------------
} // namespace hpl

View File

@@ -0,0 +1,89 @@
/* 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.
*/
#ifndef HPL_COLLIDER2D_H
#define HPL_COLLIDER2D_H
#include "hpl1/engine/math/MathTypes.h"
#include "hpl1/engine/system/SystemTypes.h"
namespace hpl {
class cMesh2D;
class cWorld2D;
class cBody2D;
class cCollideData2D;
class cCollisionMesh2D;
class cCollider2DDebug {
public:
cVector2f mvPushVec;
cVector2f mvPushPos;
};
class cCollider2D {
public:
cCollider2D();
~cCollider2D();
void SetWorld(cWorld2D *apWorld) { mpWorld = apWorld; }
/**
* Collides a body with the world and returns a flag of what object has collided.
* \param *apBody
* \return 0= no collision, eFlagBit0 = Tiles, all other bits are custom.
*/
tFlag CollideBody(cBody2D *apBody, cCollideData2D *apData);
/**
* Collides a custom rect with the world
* \param aRect
* \param alCollideFlags Specifies what things to check for collision with.
* \return
*/
tFlag CollideRect(cRect2f &aRect, tFlag alCollideFlags, cCollideData2D *apData);
tFlag CollideLine(const cVector2f &avStart, const cVector2f &avEnd, tFlag alCollideFlags,
cCollideData2D *apData);
cCollider2DDebug mDebug;
private:
cWorld2D *mpWorld;
void SetCollideMesh(cCollisionMesh2D *apMesh, cRect2f &aRect);
bool Collide(cCollisionMesh2D *apMeshA, cCollisionMesh2D *apMeshB, cVector2f &avMTD);
bool AxisSeparateMeshes(cVector2f &avAxis, cCollisionMesh2D *apMeshA,
cCollisionMesh2D *apMeshB);
void CalculateInterval(const cVector2f &avAxis, cCollisionMesh2D *apMesh,
float &afMin, float &afMax);
};
} // namespace hpl
#endif // HPL_COLLIDER2D_H

View File

@@ -0,0 +1,47 @@
/* 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.
*/
#ifndef HPL_LOWLEVELPHYSICS_H
#define HPL_LOWLEVELPHYSICS_H
#include "hpl1/engine/math/MathTypes.h"
#include "hpl1/engine/system/SystemTypes.h"
namespace hpl {
class iPhysicsWorld;
class iLowLevelPhysics {
public:
virtual ~iLowLevelPhysics() {}
virtual iPhysicsWorld *CreateWorld() = 0;
};
} // namespace hpl
#endif // HPL_LOWLEVELPHYSICS_H

View File

@@ -0,0 +1,292 @@
/* 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

View File

@@ -0,0 +1,122 @@
/* 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.
*/
#ifndef HPL_Physics_H
#define HPL_Physics_H
#include "common/list.h"
#include "hpl1/engine/game/Updateable.h"
#include "hpl1/engine/physics/PhysicsMaterial.h"
#include "hpl1/engine/system/SystemTypes.h"
#include "common/stablemap.h"
namespace hpl {
class iLowLevelPhysics;
class iPhysicsWorld;
class cSurfaceData;
class cWorld3D;
class cResources;
//------------------------------------------------
typedef Common::List<iPhysicsWorld *> tPhysicsWorldList;
typedef tPhysicsWorldList::iterator tPhysicsWorldListIt;
typedef Common::StableMap<tString, cSurfaceData *> tSurfaceDataMap;
typedef tSurfaceDataMap::iterator tSurfaceDataMapIt;
//------------------------------------------------
class cPhysicsImpactCount {
public:
cPhysicsImpactCount() { mfCount = 0; }
float mfCount;
};
typedef Common::List<cPhysicsImpactCount> tPhysicsImpactCountList;
typedef tPhysicsImpactCountList::iterator tPhysicsImpactCountListIt;
//------------------------------------------------
class cPhysics : public iUpdateable {
public:
cPhysics(iLowLevelPhysics *apLowLevelPhysics);
~cPhysics();
void Init(cResources *apResources);
void Update(float afTimeStep);
iPhysicsWorld *CreateWorld(bool abAddSurfaceData);
void DestroyWorld(iPhysicsWorld *apWorld);
cSurfaceData *CreateSurfaceData(const tString &asName);
cSurfaceData *GetSurfaceData(const tString &asName);
bool LoadSurfaceData(const tString &asFile);
iLowLevelPhysics *GetLowLevel() { return mpLowLevelPhysics; }
void SetGameWorld(cWorld3D *apWorld) { mpGameWorld = apWorld; }
cWorld3D *GetGameWorld() { return mpGameWorld; }
void SetImpactDuration(float afX) { mfImpactDuration = afX; }
float GetImpactDuration() { return mfImpactDuration; }
void SetMaxImpacts(int alX) { mlMaxImpacts = alX; }
int GetMaxImpacts() { return mlMaxImpacts; }
int GetNumOfImpacts() { return (int)mlstImpactCounts.size(); }
bool CanPlayImpact();
void AddImpact();
void SetDebugLog(bool abX) { mbLog = abX; }
bool GetDebugLog() { return mbLog; }
private:
ePhysicsMaterialCombMode GetCombMode(const char *apName);
void UpdateImpactCounts(float afTimeStep);
iLowLevelPhysics *mpLowLevelPhysics;
cResources *mpResources;
cWorld3D *mpGameWorld;
tPhysicsWorldList mlstWorlds;
tSurfaceDataMap m_mapSurfaceData;
tPhysicsImpactCountList mlstImpactCounts;
float mfImpactDuration;
int mlMaxImpacts;
bool mbLog;
};
} // namespace hpl
#endif // HPL_Physics_H

View File

@@ -0,0 +1,564 @@
/* 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/PhysicsBody.h"
#include "hpl1/engine/physics/CollideShape.h"
#include "hpl1/engine/physics/PhysicsJoint.h"
#include "hpl1/engine/physics/PhysicsMaterial.h"
#include "hpl1/engine/physics/PhysicsWorld.h"
#include "hpl1/engine/physics/SurfaceData.h"
#include "hpl1/engine/system/low_level_system.h"
#include "hpl1/engine/game/Game.h"
#include "hpl1/engine/scene/Scene.h"
#include "hpl1/engine/scene/World3D.h"
#include "hpl1/engine/scene/SoundEntity.h"
#include "hpl1/engine/sound/SoundChannel.h"
#include "hpl1/engine/sound/SoundHandler.h"
#include "hpl1/engine/scene/Node3D.h"
#include "common/algorithm.h"
#include "hpl1/engine/math/Math.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
iPhysicsBody::iPhysicsBody(const tString &asName, iPhysicsWorld *apWorld, iCollideShape *apShape)
: iEntity3D(asName) {
mpWorld = apWorld;
mpShape = apShape;
mpNode = NULL;
// Increment user count for the shape
apShape->IncUserCount();
mBoundingVolume.SetLocalMinMax(apShape->GetBoundingVolume().GetMin(),
apShape->GetBoundingVolume().GetMax());
// Set the default material so that body always has a material.
mpMaterial = mpWorld->GetMaterialFromName("Default");
mpCharacterBody = NULL;
mbBlocksSound = false;
mbBlocksLight = true;
mpScrapeBody = NULL;
mpScrapeSoundEntity = NULL;
mpRollSoundEntity = NULL;
mbHasImpact = false;
mbHasSlide = false;
mlSlideCount = 0;
mlImpactCount = 0;
mlBuoyancyId = -1;
mbCanAttachCharacter = false;
mpUserData = NULL;
mbPushedByCharacterGravity = false;
mbIsCharacter = false;
mbCollideCharacter = true;
mbIsRagDoll = false;
mbCollideRagDoll = true;
mbCollide = true;
mbVolatile = false;
mbDisableAfterSimulation = false;
mbHasCollision = false;
m_mtxPrevScrapeMatrix = cMatrixf::Identity;
// Log("Creating body %s\n",msName.c_str());
}
//-----------------------------------------------------------------------
iPhysicsBody::~iPhysicsBody() {
}
//-----------------------------------------------------------------------
void iPhysicsBody::Destroy() {
// Log("Start Destroying newton body '%s' %d\n",msName.c_str(),(size_t)this);
if (mpNode)
hplDelete(mpNode);
mpWorld->DestroyShape(mpShape);
// Log(" Joints\n");
for (int i = 0; i < (int)mvJoints.size(); i++) {
iPhysicsJoint *pJoint = mvJoints[i];
pJoint->RemoveBody(this);
if (pJoint->GetParentBody() == NULL && pJoint->GetChildBody() == NULL) {
mpWorld->DestroyJoint(pJoint);
}
// Skip removing for now, just makes things messy...
/*if( pJoint->GetParentBody() == this ||
(pJoint->GetParentBody() == NULL && pJoint->GetChildBody()== this) )
{
//Log(" Destroy joint %d\n",(size_t)pJoint);
mpWorld->DestroyJoint(pJoint);
}
else if(pJoint->GetParentBody() == this)
{
//Remove this body from the joint
pJoint->RemoveBody(this);
}*/
}
// Log("Deleted body '%s'\n",msName.c_str());
if (mpScrapeSoundEntity && mpWorld->GetWorld3D()->SoundEntityExists(mpScrapeSoundEntity))
mpWorld->GetWorld3D()->DestroySoundEntity(mpScrapeSoundEntity);
if (mpRollSoundEntity && mpWorld->GetWorld3D()->SoundEntityExists(mpRollSoundEntity))
mpWorld->GetWorld3D()->DestroySoundEntity(mpRollSoundEntity);
DeleteLowLevel();
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cVector3f iPhysicsBody::GetVelocityAtPosition(cVector3f avPos) {
return GetLinearVelocity() + cMath::Vector3Cross(GetAngularVelocity(), avPos - GetLocalPosition());
}
//-----------------------------------------------------------------------
void iPhysicsBody::AddJoint(iPhysicsJoint *apJoint) {
mvJoints.push_back(apJoint);
}
iPhysicsJoint *iPhysicsBody::GetJoint(int alIndex) {
return mvJoints[alIndex];
}
int iPhysicsBody::GetJointNum() {
return (int)mvJoints.size();
}
void iPhysicsBody::RemoveJoint(iPhysicsJoint *apJoint) {
Common::Array<iPhysicsJoint *>::iterator it = mvJoints.begin();
for (; it != mvJoints.end(); ++it) {
if (*it == apJoint) {
mvJoints.erase(it);
break;
}
}
}
//-----------------------------------------------------------------------
void iPhysicsBody::UpdateBeforeSimulate(float afTimeStep) {
// if(msName == "headalive01_throat2") Log("headalive01_throat2 Active: %d\n", IsActive());
// if(msName == "headalive01_throat") Log("headalive01_throat Active: %d\n", IsActive());
// Reset that the body has had contact
SetHasSlide(false);
SetHasImpact(false);
mbHasCollision = false;
}
void iPhysicsBody::UpdateAfterSimulate(float afTimeStep) {
//////////////////////////////////
// Check disabling from callback
if (mbDisableAfterSimulation) {
mbDisableAfterSimulation = false;
SetEnabled(false);
}
//////////////////////////////////
// Check slide sound
if (HasSlide() == false) {
if (GetScrapeSoundEntity()) {
if (mlSlideCount <= 0) {
// Log("Stopped scrape %d on body '%s' IN BODY!\n", (size_t)GetScrapeSoundEntity(),
// GetName().c_str());
if (mpWorld->GetWorld3D())
if (mpWorld->GetWorld3D()->SoundEntityExists(GetScrapeSoundEntity())) {
GetScrapeSoundEntity()->FadeOut(5.2f);
}
SetScrapeSoundEntity(NULL);
SetScrapeBody(NULL);
} else if (mlSlideCount > 0) {
mlSlideCount--;
}
}
} else {
mlSlideCount = 8;
}
//////////////////////////////////
// Update rolling sound
if (mpMaterial)
mpMaterial->GetSurfaceData()->UpdateRollEffect(this);
}
//-----------------------------------------------------------------------
cNode3D *iPhysicsBody::GetNode() {
return mpNode;
}
cNode3D *iPhysicsBody::CreateNode() {
if (mpNode)
return mpNode;
mpNode = hplNew(cNode3D, ());
return mpNode;
}
//-----------------------------------------------------------------------
void iPhysicsBody::AddBodyCallback(iPhysicsBodyCallback *apCallback) {
mlstBodyCallbacks.push_back(apCallback);
}
void iPhysicsBody::RemoveBodyCallback(iPhysicsBodyCallback *apCallback) {
tPhysicsBodyCallbackListIt it = mlstBodyCallbacks.begin();
for (; it != mlstBodyCallbacks.end(); ++it) {
if (apCallback == *it) {
mlstBodyCallbacks.erase(it);
break;
}
}
}
//-----------------------------------------------------------------------
bool iPhysicsBody::OnBeginCollision(iPhysicsBody *apBody) {
if (mlstBodyCallbacks.empty())
return true;
bool bReturn = true;
// Log("Checking before collide callbacks for '%s' ",apBody->GetName().c_str());
tPhysicsBodyCallbackListIt it = mlstBodyCallbacks.begin();
for (; it != mlstBodyCallbacks.end(); ++it) {
iPhysicsBodyCallback *pCallback = *it;
// Log("Callback %d ,",(size_t)pCallback);
if (pCallback->OnBeginCollision(this, apBody) == false)
bReturn = false;
}
// Log(" END\n");
return bReturn;
}
//-----------------------------------------------------------------------
void iPhysicsBody::OnCollide(iPhysicsBody *apBody, cPhysicsContactData *apContactData) {
mbHasCollision = true;
if (mlstBodyCallbacks.empty())
return;
// Log("Checking on collide callbacks for '%s' ",apBody->GetName().c_str());
tPhysicsBodyCallbackListIt it = mlstBodyCallbacks.begin();
for (; it != mlstBodyCallbacks.end(); ++it) {
iPhysicsBodyCallback *pCallback = *it;
// Log("Callback %d ,",(size_t)pCallback);
pCallback->OnCollide(this, apBody, apContactData);
}
// Log(" END\n");
}
//-----------------------------------------------------------------------
iPhysicsMaterial *iPhysicsBody::GetMaterial() {
return mpMaterial;
}
//-----------------------------------------------------------------------
iCollideShape *iPhysicsBody::GetShape() {
return mpShape;
}
//-----------------------------------------------------------------------
void iPhysicsBody::AddAttachedCharacter(iCharacterBody *apChar) {
RemoveAttachedCharacter(apChar);
mlstAttachedCharacters.push_back(apChar);
}
void iPhysicsBody::RemoveAttachedCharacter(iCharacterBody *apChar) {
Common::List<iCharacterBody *>::iterator it = mlstAttachedCharacters.begin();
for (; it != mlstAttachedCharacters.end(); ++it) {
if (apChar == *it) {
mlstAttachedCharacters.erase(it);
break;
}
}
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// SAVE OBJECT STUFF
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
kBeginSerializeBase(cSaveData_iCollideShape)
kSerializeVar(mType, eSerializeType_Int32)
kSerializeVar(m_mtxOffset, eSerializeType_Matrixf)
kSerializeVar(mvSize, eSerializeType_Vector3f)
kEndSerialize()
//-----------------------------------------------------------------------
kBeginSerialize(cSaveData_iPhysicsBody, cSaveData_iEntity3D)
kSerializeClassContainer(mlstShapes, cSaveData_iCollideShape, eSerializeType_Class)
kSerializeVar(msMaterial, eSerializeType_String)
kSerializeVar(mbBlocksSound, eSerializeType_Bool)
kSerializeVar(mbIsCharacter, eSerializeType_Bool)
kSerializeVar(mbCollideCharacter, eSerializeType_Bool)
kSerializeVar(mvLinearVelocity, eSerializeType_Vector3f)
kSerializeVar(mvAngularVelocity, eSerializeType_Vector3f)
kSerializeVar(mfLinearDamping, eSerializeType_Float32)
kSerializeVar(mfAngularDamping, eSerializeType_Float32)
kSerializeVar(mfMaxLinearSpeed, eSerializeType_Float32)
kSerializeVar(mfMaxAngularSpeed, eSerializeType_Float32)
kSerializeVar(mfMass, eSerializeType_Float32)
kSerializeVar(mbEnabled, eSerializeType_Bool)
kSerializeVar(mbAutoDisable, eSerializeType_Bool)
kSerializeVar(mbContinuousCollision, eSerializeType_Bool)
kSerializeVar(mbGravity, eSerializeType_Bool)
kSerializeVar(mbCollide, eSerializeType_Bool)
kEndSerialize()
//-----------------------------------------------------------------------
static iCollideShape *_CreateShape(cSaveData_iCollideShape *apData, iPhysicsWorld *apWorld) {
switch ((eCollideShapeType)apData->mType) {
case eCollideShapeType_Box:
return apWorld->CreateBoxShape(apData->mvSize, &apData->m_mtxOffset);
case eCollideShapeType_Sphere:
return apWorld->CreateSphereShape(apData->mvSize, &apData->m_mtxOffset);
case eCollideShapeType_Cylinder:
return apWorld->CreateCylinderShape(apData->mvSize.x, apData->mvSize.y, &apData->m_mtxOffset);
case eCollideShapeType_Capsule:
return apWorld->CreateCapsuleShape(apData->mvSize.x, apData->mvSize.y, &apData->m_mtxOffset);
case eCollideShapeType_Null:
case eCollideShapeType_ConvexHull:
case eCollideShapeType_Mesh:
case eCollideShapeType_Compound:
case eCollideShapeType_LastEnum:
break;
}
Warning("Invalid shape type %d!\n", apData->mType);
return NULL;
}
static iCollideShape *CreateCollideShapeFromSave(cContainerList<cSaveData_iCollideShape> *apShapeList,
iPhysicsWorld *apWorld) {
cContainerListIterator<cSaveData_iCollideShape> it = apShapeList->GetIterator();
if (apShapeList->Size() == 1) {
return _CreateShape(&it.Next(), apWorld);
} else {
tCollideShapeVec vShapes;
while (it.HasNext()) {
vShapes.push_back(_CreateShape(&it.Next(), apWorld));
}
return apWorld->CreateCompundShape(vShapes);
}
}
iSaveObject *cSaveData_iPhysicsBody::CreateSaveObject(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
iPhysicsWorld *pWorld = apGame->GetScene()->GetWorld3D()->GetPhysicsWorld();
// Get the collider
iCollideShape *pShape = CreateCollideShapeFromSave(&mlstShapes, pWorld);
if (pShape == NULL)
return NULL;
iPhysicsBody *pBody = pWorld->CreateBody(msName, pShape);
return pBody;
}
//-----------------------------------------------------------------------
int cSaveData_iPhysicsBody::GetSaveCreatePrio() {
return 0;
}
//-----------------------------------------------------------------------
iSaveData *iPhysicsBody::CreateSaveData() {
return hplNew(cSaveData_iPhysicsBody, ());
}
//-----------------------------------------------------------------------
void iPhysicsBody::SaveToSaveData(iSaveData *apSaveData) {
kSaveData_SaveToBegin(iPhysicsBody);
// Collider
CreateSaveCollideShapes(&pData->mlstShapes);
// Material
pData->msMaterial = mpMaterial == NULL ? "" : mpMaterial->GetName();
// Save vars
kSaveData_SaveTo(mbBlocksSound);
kSaveData_SaveTo(mbIsCharacter);
kSaveData_SaveTo(mbCollideCharacter);
// Save interface properties
pData->mvLinearVelocity = GetLinearVelocity();
pData->mvAngularVelocity = GetAngularVelocity();
pData->mfLinearDamping = GetLinearDamping();
pData->mfAngularDamping = GetAngularDamping();
pData->mfMaxLinearSpeed = GetMaxLinearSpeed();
pData->mfMaxAngularSpeed = GetMaxAngularSpeed();
pData->mfMass = GetMass();
pData->mbEnabled = GetEnabled();
pData->mbAutoDisable = GetAutoDisable();
pData->mbContinuousCollision = GetContinuousCollision();
pData->mbGravity = GetGravity();
pData->mbCollide = GetCollide();
}
//-----------------------------------------------------------------------
void iPhysicsBody::LoadFromSaveData(iSaveData *apSaveData) {
kSaveData_LoadFromBegin(iPhysicsBody);
// Material
if (pData->msMaterial != "") {
iPhysicsMaterial *pMat = mpWorld->GetMaterialFromName(pData->msMaterial);
if (pMat)
SetMaterial(pMat);
}
// Save vars
kSaveData_LoadFrom(mbBlocksSound);
kSaveData_LoadFrom(mbIsCharacter);
kSaveData_LoadFrom(mbCollideCharacter);
// Save interface properties
SetLinearVelocity(pData->mvLinearVelocity);
SetAngularVelocity(pData->mvAngularVelocity);
SetLinearDamping(pData->mfLinearDamping);
SetAngularDamping(pData->mfAngularDamping);
SetMaxLinearSpeed(pData->mfMaxLinearSpeed);
SetMaxAngularSpeed(pData->mfMaxAngularSpeed);
SetMass(pData->mfMass);
SetEnabled(pData->mbEnabled);
SetAutoDisable(pData->mbAutoDisable);
SetContinuousCollision(pData->mbContinuousCollision);
SetGravity(pData->mbGravity);
SetCollide(pData->mbCollide);
}
//-----------------------------------------------------------------------
void iPhysicsBody::SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
kSaveData_SetupBegin(iPhysicsBody);
}
//-----------------------------------------------------------------------
void iPhysicsBody::CreateSaveCollideShapes(cContainerList<cSaveData_iCollideShape> *apShapeList) {
if (mpShape->GetType() == eCollideShapeType_Compound) {
for (int i = 0; i < mpShape->GetSubShapeNum(); ++i) {
iCollideShape *pShape = mpShape->GetSubShape(i);
cSaveData_iCollideShape Shape;
Shape.mType = (int)pShape->GetType();
Shape.m_mtxOffset = pShape->GetOffset();
Shape.mvSize = pShape->GetSize();
apShapeList->Add(Shape);
}
} else {
cSaveData_iCollideShape Shape;
Shape.mType = (int)mpShape->GetType();
Shape.m_mtxOffset = mpShape->GetOffset();
Shape.mvSize = mpShape->GetSize();
apShapeList->Add(Shape);
}
}
//-----------------------------------------------------------------------
} // namespace hpl

View File

@@ -0,0 +1,332 @@
/* 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.
*/
#ifndef HPL_PHYSICS_BODY_H
#define HPL_PHYSICS_BODY_H
#include "hpl1/engine/graphics/GraphicsTypes.h"
#include "hpl1/engine/scene/Entity3D.h"
namespace hpl {
class iPhysicsWorld;
class iCollideShape;
class iPhysicsMaterial;
class iLowLevelGraphics;
class cNode3D;
class cSoundEntity;
class iPhysicsJoint;
class cPhysicsContactData;
class iCharacterBody;
//------------------------------------------
class iPhysicsBody;
class iPhysicsBodyCallback {
public:
virtual ~iPhysicsBodyCallback() {}
virtual bool OnBeginCollision(iPhysicsBody *apBody, iPhysicsBody *apCollideBody) = 0;
virtual void OnCollide(iPhysicsBody *apBody, iPhysicsBody *apCollideBody,
cPhysicsContactData *apContactData) = 0;
};
typedef Common::List<iPhysicsBodyCallback *> tPhysicsBodyCallbackList;
typedef tPhysicsBodyCallbackList::iterator tPhysicsBodyCallbackListIt;
//------------------------------------------
class cSaveData_iCollideShape : public iSerializable {
kSerializableClassInit(cSaveData_iCollideShape) public : int mType;
cMatrixf m_mtxOffset;
cVector3f mvSize;
};
//------------------------------------------
kSaveData_ChildClass(iEntity3D, iPhysicsBody) {
kSaveData_ClassInit(iPhysicsBody) public : cContainerList<cSaveData_iCollideShape> mlstShapes;
tString msMaterial;
bool mbBlocksSound;
bool mbIsCharacter;
bool mbCollideCharacter;
cVector3f mvLinearVelocity;
cVector3f mvAngularVelocity;
float mfLinearDamping;
float mfAngularDamping;
float mfMaxLinearSpeed;
float mfMaxAngularSpeed;
float mfMass;
bool mbEnabled;
bool mbAutoDisable;
bool mbContinuousCollision;
bool mbGravity;
bool mbCollide;
virtual iSaveObject *CreateSaveObject(cSaveObjectHandler * apSaveObjectHandler, cGame * apGame);
virtual int GetSaveCreatePrio();
};
//------------------------------------------
struct cPhysicsBody_Buoyancy {
cPhysicsBody_Buoyancy() : mbActive(false), mfDensity(1),
mfLinearViscosity(1), mfAngularViscosity(1) {}
bool mbActive;
float mfDensity;
float mfLinearViscosity;
float mfAngularViscosity;
cPlanef mSurface;
};
//------------------------------------------
class iPhysicsBody : public iEntity3D {
typedef iEntity3D super;
public:
iPhysicsBody(const tString &asName, iPhysicsWorld *apWorld, iCollideShape *apShape);
virtual ~iPhysicsBody();
void Destroy();
virtual void SetMaterial(iPhysicsMaterial *apMaterial) = 0;
iPhysicsMaterial *GetMaterial();
cNode3D *GetNode();
cNode3D *CreateNode();
iCollideShape *GetShape();
void AddJoint(iPhysicsJoint *apJoint);
iPhysicsJoint *GetJoint(int alIndex);
int GetJointNum();
void RemoveJoint(iPhysicsJoint *apJoint);
virtual void SetLinearVelocity(const cVector3f &avVel) = 0;
virtual cVector3f GetLinearVelocity() const = 0;
virtual void SetAngularVelocity(const cVector3f &avVel) = 0;
virtual cVector3f GetAngularVelocity() const = 0;
virtual void SetLinearDamping(float afDamping) = 0;
virtual float GetLinearDamping() const = 0;
virtual void SetAngularDamping(float afDamping) = 0;
virtual float GetAngularDamping() const = 0;
virtual void SetMaxLinearSpeed(float afSpeed) = 0;
virtual float GetMaxLinearSpeed() const = 0;
virtual void SetMaxAngularSpeed(float afDamping) = 0;
virtual float GetMaxAngularSpeed() const = 0;
virtual cMatrixf GetInertiaMatrix() = 0;
cVector3f GetVelocityAtPosition(cVector3f avPos);
virtual void SetMass(float afMass) = 0;
virtual float GetMass() const = 0;
virtual void SetMassCentre(const cVector3f &avCentre) = 0;
virtual cVector3f GetMassCentre() const = 0;
virtual void AddForce(const cVector3f &avForce) = 0;
virtual void AddForceAtPosition(const cVector3f &avForce, const cVector3f &avPos) = 0;
virtual void AddTorque(const cVector3f &avTorque) = 0;
virtual void AddImpulse(const cVector3f &avImpulse) = 0;
virtual void AddImpulseAtPosition(const cVector3f &avImpulse, const cVector3f &avPos) = 0;
virtual void SetEnabled(bool abEnabled) = 0;
virtual bool GetEnabled() const = 0;
virtual void SetAutoDisable(bool abEnabled) = 0;
virtual bool GetAutoDisable() const = 0;
#if 0
virtual void SetAutoDisableLinearThreshold(float afThresold) = 0;
virtual float GetAutoDisableLinearThreshold() const = 0;
virtual void SetAutoDisableAngularThreshold(float afThresold) = 0;
virtual float GetAutoDisableAngularThreshold() const = 0;
virtual void SetAutoDisableNumSteps(int alNum) = 0;
virtual int GetAutoDisableNumSteps() const = 0;
#endif
virtual void SetContinuousCollision(bool abOn) = 0;
virtual bool GetContinuousCollision() = 0;
virtual void SetGravity(bool abEnabled) = 0;
virtual bool GetGravity() const = 0;
virtual void RenderDebugGeometry(iLowLevelGraphics *apLowLevel, const cColor &aColor) = 0;
void UpdateBeforeSimulate(float afTimeStep);
void UpdateAfterSimulate(float afTimeStep);
cBoundingVolume *GetBV() { return &mBoundingVolume; }
void SetBlocksSound(bool abX) { mbBlocksSound = abX; }
bool GetBlocksSound() { return mbBlocksSound; }
void SetBlocksLight(bool abX) { mbBlocksLight = abX; }
bool GetBlocksLight() { return mbBlocksLight; }
void SetScrapeSoundEntity(cSoundEntity *apEntity) { mpScrapeSoundEntity = apEntity; }
cSoundEntity *GetScrapeSoundEntity() { return mpScrapeSoundEntity; }
void SetScrapeBody(iPhysicsBody *apBody) { mpScrapeBody = apBody; }
iPhysicsBody *GetScrapeBody() { return mpScrapeBody; }
const cMatrixf &GetPreveScrapeMatrix() { return m_mtxPrevScrapeMatrix; }
void SetPreveScrapeMatrix(const cMatrixf &a_mtxMtx) { m_mtxPrevScrapeMatrix = a_mtxMtx; }
void SetRollSoundEntity(cSoundEntity *apEntity) { mpRollSoundEntity = apEntity; }
cSoundEntity *GetRollSoundEntity() { return mpRollSoundEntity; }
void SetHasImpact(bool abX) { mbHasImpact = abX; }
bool HasImpact() { return mbHasImpact; }
void SetHasSlide(bool abX) { mbHasSlide = abX; }
bool HasSlide() { return mbHasSlide; }
bool HasCollision() { return mbHasCollision; }
void SetUserData(void *apUserData) { mpUserData = apUserData; }
void *GetUserData() { return mpUserData; }
void AddBodyCallback(iPhysicsBodyCallback *apCallback);
void RemoveBodyCallback(iPhysicsBodyCallback *apCallback);
bool OnBeginCollision(iPhysicsBody *apBody);
void OnCollide(iPhysicsBody *apBody, cPhysicsContactData *apContactData);
void SetCollide(bool abX) { mbCollide = abX; }
bool GetCollide() { return mbCollide; }
void SetIsCharacter(bool abX) { mbIsCharacter = abX; }
bool IsCharacter() { return mbIsCharacter; }
void SetCollideCharacter(bool abX) { mbCollideCharacter = abX; }
bool GetCollideCharacter() { return mbCollideCharacter; }
void SetCharacterBody(iCharacterBody *apCharBody) { mpCharacterBody = apCharBody; }
iCharacterBody *GetCharacterBody() { return mpCharacterBody; }
void SetIsRagDoll(bool abX) { mbIsRagDoll = abX; }
bool IsRagDoll() { return mbIsRagDoll; }
void SetCollideRagDoll(bool abX) { mbCollideRagDoll = abX; }
bool GetCollideRagDoll() { return mbCollideRagDoll; }
void SetVolatile(bool abX) { mbVolatile = abX; }
bool IsVolatile() { return mbVolatile; }
void SetPushedByCharacterGravity(bool abX) { mbPushedByCharacterGravity = abX; }
bool GetPushedByCharacterGravity() { return mbPushedByCharacterGravity; }
void SetBuoyancyId(int alX) { mlBuoyancyId = alX; }
void SetBuoyancyActive(bool abX) { mBuoyancy.mbActive = abX; }
void SetBuoyancyDensity(float afX) { mBuoyancy.mfDensity = afX; }
void SetBuoyancyLinearViscosity(float afX) { mBuoyancy.mfLinearViscosity = afX; }
void SetBuoyancyAngularViscosity(float afX) { mBuoyancy.mfAngularViscosity = afX; }
void SetBuoyancySurface(const cPlanef &aP) { mBuoyancy.mSurface = aP; }
int GetBuoyancyId() { return mlBuoyancyId; }
bool GetBuoyancyActive() { return mBuoyancy.mbActive; }
float GetBuoyancyDensity() { return mBuoyancy.mfDensity; }
float GetBuoyancyLinearViscosity() { return mBuoyancy.mfLinearViscosity; }
float GetBuoyancyAngularViscosity() { return mBuoyancy.mfAngularViscosity; }
cPlanef SetBuoyancySurface() { return mBuoyancy.mSurface; }
void SetCanAttachCharacter(bool abX) { mbCanAttachCharacter = abX; }
bool GetCanAttachCharacter() { return mbCanAttachCharacter; }
void AddAttachedCharacter(iCharacterBody *apChar);
void RemoveAttachedCharacter(iCharacterBody *apChar);
iPhysicsWorld *GetWorld() { return mpWorld; }
void DisableAfterSimulation() { mbDisableAfterSimulation = true; }
// Entity implementation
tString GetEntityType() { return "Body"; }
// SaveObject implementation
virtual iSaveData *CreateSaveData();
virtual void SaveToSaveData(iSaveData *apSaveData);
virtual void LoadFromSaveData(iSaveData *apSaveData);
virtual void SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame);
virtual void DeleteLowLevel() = 0;
protected:
void CreateSaveCollideShapes(cContainerList<cSaveData_iCollideShape> *apShapeList);
iPhysicsWorld *mpWorld;
iCollideShape *mpShape;
iPhysicsMaterial *mpMaterial;
cNode3D *mpNode;
iCharacterBody *mpCharacterBody;
Common::Array<iPhysicsJoint *> mvJoints;
Common::List<iCharacterBody *> mlstAttachedCharacters;
iPhysicsBody *mpScrapeBody;
cSoundEntity *mpScrapeSoundEntity;
cSoundEntity *mpRollSoundEntity;
cMatrixf m_mtxPrevScrapeMatrix;
bool mbHasImpact;
bool mbHasSlide;
int mlSlideCount;
int mlImpactCount;
bool mbPushedByCharacterGravity;
bool mbBlocksSound;
bool mbBlocksLight;
bool mbIsCharacter;
bool mbCollideCharacter;
bool mbIsRagDoll;
bool mbCollideRagDoll;
bool mbVolatile;
bool mbCanAttachCharacter;
cPhysicsBody_Buoyancy mBuoyancy;
int mlBuoyancyId;
bool mbDisableAfterSimulation;
bool mbHasCollision;
tPhysicsBodyCallbackList mlstBodyCallbacks;
void *mpUserData;
bool mbCollide;
};
} // namespace hpl
#endif // HPL_PHYSICS_BODY_H

View File

@@ -0,0 +1,349 @@
/* 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/PhysicsController.h"
#include "hpl1/engine/physics/PhysicsBody.h"
#include "hpl1/engine/physics/PhysicsJoint.h"
#include "hpl1/engine/physics/PhysicsWorld.h"
#include "hpl1/engine/math/Math.h"
#include "hpl1/engine/system/low_level_system.h"
namespace hpl {
bool iPhysicsController::mbUseInputMatrixFix = false;
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
iPhysicsController::iPhysicsController(const tString &asName, iPhysicsWorld *apWorld) {
msName = asName;
mpWorld = apWorld;
mpBody = NULL;
mpJoint = NULL;
mbActive = false;
mPidController.SetErrorNum(10);
mbMulMassWithOutput = false;
mfMaxOutput = 0;
mbLogInfo = false;
mbPaused = false;
}
//-----------------------------------------------------------------------
iPhysicsController::~iPhysicsController() {
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void iPhysicsController::SetPidIntegralSize(int alSize) {
mPidController.SetErrorNum(alSize);
}
//-----------------------------------------------------------------------
void iPhysicsController::Update(float afTimeStep) {
if (mbActive == false || mbPaused)
return;
if (mpBody == NULL)
return;
cVector3f vInput = GetInputValue(mInputType);
// Get the local input.
if (mbUseInputMatrixFix == false ||
(mInputType != ePhysicsControllerInput_JointAngle && mInputType != ePhysicsControllerInput_JointDist)) {
vInput = cMath::MatrixMul(cMath::MatrixInverse(mpBody->GetLocalMatrix().GetRotation()), vInput);
}
float fValue = GetAxisValue(mInputAxis, vInput);
float fError = mfDestValue - fValue;
float fOutput = GetOutputValue(fError, fValue, afTimeStep);
if (mfMaxOutput > 0) {
if (fOutput > 0)
fOutput = cMath::Min(fOutput, mfMaxOutput);
else
fOutput = cMath::Max(fOutput, -mfMaxOutput);
}
if (mbLogInfo)
Log("%s | Input: %f Dest: %f Error: %f OutPut: %f\n", msName.c_str(), fValue, mfDestValue, fError, fOutput);
AddOutputValue(mOutputType, mOutputAxis, fOutput);
////////////////////////////////////////
// Check if dest vale is reached
if (mEndType == ePhysicsControllerEnd_OnDest && mpJoint) {
if (ABS(fValue - mfDestValue) < kEpsilonf) {
mbActive = false;
iPhysicsController *pNext = mpJoint->GetController(msNextController);
if (pNext)
pNext->SetActive(true);
}
}
}
//-----------------------------------------------------------------------
void iPhysicsController::SetActive(bool abX) {
if (abX == mbActive)
return;
mPidController.Reset();
mbActive = abX;
}
//////////////////////////////////////////////////////////////////////////
// PROTECTED METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cVector3f iPhysicsController::GetInputValue(ePhysicsControllerInput aInput) {
switch (aInput) {
case ePhysicsControllerInput_AngularSpeed:
return mpBody ? mpBody->GetAngularVelocity() : 0;
case ePhysicsControllerInput_LinearSpeed:
return mpBody ? mpBody->GetLinearVelocity() : 0;
case ePhysicsControllerInput_JointAngle:
return mpJoint ? mpJoint->GetAngle() : 0;
case ePhysicsControllerInput_JointDist:
return mpJoint ? mpJoint->GetDistance() : 0;
case ePhysicsControllerInput_LastEnum:
break;
}
return 0;
}
//-----------------------------------------------------------------------
float iPhysicsController::GetOutputValue(float afError, float afInput, float afTimeStep) {
if (mType == ePhysicsControllerType_Pid) {
mPidController.p = mfA;
mPidController.i = mfB;
mPidController.d = mfC;
return mPidController.Output(afError, afTimeStep);
} else {
return afError * mfA - afInput * mfB;
}
return 0;
}
//-----------------------------------------------------------------------
void iPhysicsController::AddOutputValue(ePhysicsControllerOutput aOutput,
ePhysicsControllerAxis aAxis,
float afVal) {
cVector3f vVec(0, 0, 0);
switch (aAxis) {
case ePhysicsControllerAxis_X:
vVec.x = afVal;
break;
case ePhysicsControllerAxis_Y:
vVec.y = afVal;
break;
case ePhysicsControllerAxis_Z:
vVec.z = afVal;
break;
case ePhysicsControllerAxis_LastEnum:
break;
}
if (mbMulMassWithOutput)
vVec = vVec * mpBody->GetMass();
// Set the output to body space
vVec = cMath::MatrixMul(mpBody->GetLocalMatrix().GetRotation(), vVec);
switch (aOutput) {
case ePhysicsControllerOutput_Torque:
mpBody->AddTorque(vVec);
break;
case ePhysicsControllerOutput_Force:
mpBody->AddForce(vVec);
break;
case ePhysicsControllerOutput_LastEnum:
break;
}
}
//-----------------------------------------------------------------------
float iPhysicsController::GetAxisValue(ePhysicsControllerAxis aAxis, const cVector3f &avVec) {
switch (aAxis) {
case ePhysicsControllerAxis_X:
return avVec.x;
case ePhysicsControllerAxis_Y:
return avVec.y;
case ePhysicsControllerAxis_Z:
return avVec.z;
case ePhysicsControllerAxis_LastEnum:
break;
}
return 0;
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// SAVE OBJECT STUFF
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
kBeginSerializeBase(cSaveData_iPhysicsController)
kSerializeVar(msName, eSerializeType_String)
kSerializeVar(mlBodyId, eSerializeType_Int32)
kSerializeVar(mlJointId, eSerializeType_Int32)
kSerializeVar(mfA, eSerializeType_Float32)
kSerializeVar(mfB, eSerializeType_Float32)
kSerializeVar(mfC, eSerializeType_Float32)
kSerializeVar(mfDestValue, eSerializeType_Float32)
kSerializeVar(mfMaxOutput, eSerializeType_Float32)
kSerializeVar(mbMulMassWithOutput, eSerializeType_Bool)
kSerializeVar(mType, eSerializeType_Int32)
kSerializeVar(mInputType, eSerializeType_Int32)
kSerializeVar(mInputAxis, eSerializeType_Int32)
kSerializeVar(mOutputType, eSerializeType_Int32)
kSerializeVar(mOutputAxis, eSerializeType_Int32)
kSerializeVar(mEndType, eSerializeType_Int32)
kSerializeVar(msNextController, eSerializeType_String)
kSerializeVar(mbActive, eSerializeType_Bool)
kSerializeVar(mbPaused, eSerializeType_Bool)
kEndSerialize()
//-----------------------------------------------------------------------
iSaveData *iPhysicsController::CreateSaveData() {
return hplNew(cSaveData_iPhysicsController, ());
}
//-----------------------------------------------------------------------
void iPhysicsController::SaveToSaveData(iSaveData *apSaveData) {
kSaveData_SaveToBegin(iPhysicsController);
kSaveData_SaveTo(msName);
kSaveData_SaveTo(mfA);
kSaveData_SaveTo(mfB);
kSaveData_SaveTo(mfC);
kSaveData_SaveTo(mfDestValue);
kSaveData_SaveTo(mfMaxOutput);
kSaveData_SaveTo(mbMulMassWithOutput);
kSaveData_SaveTo(mType);
kSaveData_SaveTo(mInputType);
kSaveData_SaveTo(mInputAxis);
kSaveData_SaveTo(mOutputType);
kSaveData_SaveTo(mOutputAxis);
kSaveData_SaveTo(mEndType);
kSaveData_SaveTo(msNextController);
kSaveData_SaveTo(mbActive);
kSaveData_SaveTo(mbPaused);
kSaveData_SaveObject(mpBody, mlBodyId);
kSaveData_SaveObject(mpJoint, mlJointId);
}
//-----------------------------------------------------------------------
void iPhysicsController::LoadFromSaveData(iSaveData *apSaveData) {
kSaveData_LoadFromBegin(iPhysicsController);
kSaveData_LoadFrom(msName);
kSaveData_LoadFrom(mfA);
kSaveData_LoadFrom(mfB);
kSaveData_LoadFrom(mfC);
kSaveData_LoadFrom(mfDestValue);
kSaveData_LoadFrom(mfMaxOutput);
kSaveData_LoadFrom(mbMulMassWithOutput);
mType = (ePhysicsControllerType)pData->mType;
mInputType = (ePhysicsControllerInput)pData->mInputType;
mInputAxis = (ePhysicsControllerAxis)pData->mInputAxis;
mOutputType = (ePhysicsControllerOutput)pData->mOutputType;
mOutputAxis = (ePhysicsControllerAxis)pData->mOutputAxis;
mEndType = (ePhysicsControllerEnd)pData->mEndType;
kSaveData_LoadFrom(msNextController);
kSaveData_LoadFrom(mbActive);
kSaveData_LoadFrom(mbPaused);
}
//-----------------------------------------------------------------------
void iPhysicsController::SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
kSaveData_SetupBegin(iPhysicsController);
kSaveData_LoadObject(mpBody, mlBodyId, iPhysicsBody *);
kSaveData_LoadObject(mpJoint, mlJointId, iPhysicsJoint *);
}
//-----------------------------------------------------------------------
} // namespace hpl

View File

@@ -0,0 +1,234 @@
/* 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.
*/
#ifndef HPL_PHYSICS_CONTROLLER_H
#define HPL_PHYSICS_CONTROLLER_H
#include "hpl1/engine/math/MathTypes.h"
#include "hpl1/engine/math/PidController.h"
#include "hpl1/engine/math/Spring.h"
#include "hpl1/engine/game/SaveGame.h"
namespace hpl {
//-------------------------------------------
enum ePhysicsControllerType {
ePhysicsControllerType_Pid,
ePhysicsControllerType_Spring,
ePhysicsControllerType_LastEnum
};
//-------------------------------------------
enum ePhysicsControllerInput {
ePhysicsControllerInput_JointAngle,
ePhysicsControllerInput_JointDist,
ePhysicsControllerInput_LinearSpeed,
ePhysicsControllerInput_AngularSpeed,
ePhysicsControllerInput_LastEnum
};
//-------------------------------------------
enum ePhysicsControllerOutput {
ePhysicsControllerOutput_Force,
ePhysicsControllerOutput_Torque,
ePhysicsControllerOutput_LastEnum
};
//-------------------------------------------
enum ePhysicsControllerAxis {
ePhysicsControllerAxis_X,
ePhysicsControllerAxis_Y,
ePhysicsControllerAxis_Z,
ePhysicsControllerAxis_LastEnum
};
//-------------------------------------------
enum ePhysicsControllerEnd {
ePhysicsControllerEnd_Null,
ePhysicsControllerEnd_OnDest,
ePhysicsControllerEnd_OnMin,
ePhysicsControllerEnd_OnMax,
ePhysicsControllerEnd_LastEnum
};
//-------------------------------------------
kSaveData_BaseClass(iPhysicsController) {
kSaveData_ClassInit(iPhysicsController) public : tString msName;
int mlBodyId;
int mlJointId;
float mfA;
float mfB;
float mfC;
float mfDestValue;
float mfMaxOutput;
bool mbMulMassWithOutput;
int mType;
int mInputType;
int mInputAxis;
int mOutputType;
int mOutputAxis;
int mEndType;
tString msNextController;
bool mbActive;
bool mbPaused;
iSaveObject *CreateSaveObject(cSaveObjectHandler * apSaveObjectHandler, cGame * apGame) { return NULL; }
int GetSaveCreatePrio() { return 0; }
};
//-------------------------------------------
class iPhysicsWorld;
class iPhysicsJoint;
class iPhysicsBody;
class iPhysicsController : public iSaveObject {
typedef iSaveObject super;
public:
iPhysicsController(const tString &asName, iPhysicsWorld *apWorld);
virtual ~iPhysicsController();
void Update(float afTimeStep);
const tString &GetName() { return msName; }
void SetJoint(iPhysicsJoint *apJoint) { mpJoint = apJoint; }
iPhysicsJoint *GetJoint() { return mpJoint; }
void SetBody(iPhysicsBody *apBody) { mpBody = apBody; }
iPhysicsBody *GetBody() { return mpBody; }
bool IsActive() { return mbActive; }
void SetActive(bool abX);
/*
* p in Pid and k in springs
*/
void SetA(float afA) { mfA = afA; }
/*
* i in Pid and b in springs
*/
void SetB(float afB) { mfB = afB; }
/*
* d in Pid and not used in springs
*/
void SetC(float afC) { mfC = afC; }
void SetPidIntegralSize(int alSize);
void SetType(ePhysicsControllerType aType) { mType = aType; }
void SetDestValue(float afX) { mfDestValue = afX; }
float GetDestValue() { return mfDestValue; }
void SetMaxOutput(float afX) { mfMaxOutput = afX; }
void SetInputType(ePhysicsControllerInput aInput, ePhysicsControllerAxis aAxis) {
mInputType = aInput;
mInputAxis = aAxis;
}
void SetOutputType(ePhysicsControllerOutput aOutput, ePhysicsControllerAxis aAxis) {
mOutputType = aOutput;
mOutputAxis = aAxis;
}
void SetMulMassWithOutput(bool abX) { mbMulMassWithOutput = abX; }
void SetEndType(ePhysicsControllerEnd aEnd) { mEndType = aEnd; }
ePhysicsControllerEnd GetEndType() { return mEndType; }
void SetNextController(const tString &asName) { msNextController = asName; }
const tString &GetNextController() { return msNextController; }
void SetLogInfo(bool abX) { mbLogInfo = abX; }
void SetPaused(bool abX) { mbPaused = abX; }
static bool mbUseInputMatrixFix;
// SaveObject implementation
virtual iSaveData *CreateSaveData();
virtual void SaveToSaveData(iSaveData *apSaveData);
virtual void LoadFromSaveData(iSaveData *apSaveData);
virtual void SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame);
protected:
cVector3f GetInputValue(ePhysicsControllerInput aInput);
float GetOutputValue(float afError, float afInput, float afTimeStep);
void AddOutputValue(ePhysicsControllerOutput aOutput, ePhysicsControllerAxis aAxis,
float afVal);
float GetAxisValue(ePhysicsControllerAxis aAxis, const cVector3f &avVec);
iPhysicsWorld *mpWorld;
tString msName;
iPhysicsBody *mpBody;
iPhysicsJoint *mpJoint;
float mfA, mfB, mfC;
float mfDestValue;
float mfMaxOutput;
bool mbMulMassWithOutput;
ePhysicsControllerType mType;
ePhysicsControllerInput mInputType;
ePhysicsControllerAxis mInputAxis;
ePhysicsControllerOutput mOutputType;
ePhysicsControllerAxis mOutputAxis;
ePhysicsControllerEnd mEndType;
tString msNextController;
cPidControllerf mPidController;
bool mbActive;
bool mbPaused;
bool mbLogInfo;
};
} // namespace hpl
#endif // HPL_PHYSICS_CONTROLLER_H

View File

@@ -0,0 +1,702 @@
/* 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/PhysicsJoint.h"
#include "hpl1/engine/physics/CollideShape.h"
#include "hpl1/engine/physics/PhysicsBody.h"
#include "hpl1/engine/physics/PhysicsController.h"
#include "hpl1/engine/physics/PhysicsWorld.h"
#include "hpl1/engine/system/low_level_system.h"
#include "hpl1/engine/scene/SoundEntity.h"
#include "hpl1/engine/sound/Sound.h"
#include "hpl1/engine/sound/SoundChannel.h"
#include "hpl1/engine/sound/SoundHandler.h"
#include "hpl1/engine/scene/Scene.h"
#include "hpl1/engine/scene/World3D.h"
#include "hpl1/engine/game/Game.h"
#include "hpl1/engine/math/Math.h"
#include "hpl1/engine/game/ScriptFuncs.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
iPhysicsJoint::iPhysicsJoint(const tString &asName, iPhysicsBody *apParentBody, iPhysicsBody *apChildBody,
iPhysicsWorld *apWorld, const cVector3f &avPivotPoint)
: msName(asName), mpParentBody(apParentBody), mpChildBody(apChildBody), mpWorld(apWorld) {
mMaxLimit.msSound = "";
mMinLimit.msSound = "";
if (apParentBody) {
apParentBody->AddJoint(this);
m_mtxParentBodySetup = apParentBody->GetLocalMatrix();
} else {
m_mtxParentBodySetup = cMatrixf::Identity;
}
m_mtxPrevChild = cMatrixf::Identity;
m_mtxPrevParent = cMatrixf::Identity;
apChildBody->AddJoint(this);
m_mtxChildBodySetup = apChildBody->GetLocalMatrix();
cMatrixf m_mtxInvChild = cMath::MatrixInverse(apChildBody->GetLocalMatrix());
mvLocalPivot = cMath::MatrixMul(m_mtxInvChild, avPivotPoint);
mvStartPivotPoint = avPivotPoint;
msMoveSound = "";
mbHasCollided = false;
mpSound = NULL;
mpCallback = NULL;
mbAutoDeleteCallback = false;
mpUserData = NULL;
mbBreakable = false;
mfBreakForce = 0;
msBreakSound = "";
mbBroken = false;
mfStickyMinDistance = 0;
mfStickyMaxDistance = 0;
mlLimitStepCount = 0;
mlSpeedCount = 0;
mbLimitAutoSleep = false;
mfLimitAutoSleepDist = 0.02f;
mlLimitAutoSleepNumSteps = 10;
// Log("Created joint '%s'\n",msName.c_str());
}
iPhysicsJoint::~iPhysicsJoint() {
if (mbAutoDeleteCallback && mpCallback)
hplDelete(mpCallback);
// Destroy all controllers.
tPhysicsControllerMapIt it = m_mapControllers.begin();
for (; it != m_mapControllers.end(); ++it) {
mpWorld->DestroyController(it->second);
}
if (mpChildBody)
mpChildBody->RemoveJoint(this);
if (mpParentBody)
mpParentBody->RemoveJoint(this);
if (mpSound)
mpWorld->GetWorld3D()->DestroySoundEntity(mpSound);
// Log("Deleted joint '%s'\n",msName.c_str());
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
/**
* This should only be used by PhysicsBody.
*/
void iPhysicsJoint::RemoveBody(iPhysicsBody *apBody) {
if (mpParentBody == apBody)
mpParentBody = NULL;
if (mpChildBody == apBody)
mpChildBody = NULL;
}
//-----------------------------------------------------------------------
void iPhysicsJoint::AddController(iPhysicsController *apController) {
// Add controller top map
m_mapControllers.insert(tPhysicsControllerMap::value_type(apController->GetName(), apController));
// Set properties
apController->SetBody(mpChildBody);
apController->SetJoint(this);
}
//-----------------------------------------------------------------------
iPhysicsController *iPhysicsJoint::GetController(const tString &asName) {
tPhysicsControllerMapIt it = m_mapControllers.find(asName);
if (it == m_mapControllers.end())
return NULL;
return it->second;
}
//-----------------------------------------------------------------------
bool iPhysicsJoint::ChangeController(const tString &asName) {
iPhysicsController *pNewCtrl = GetController(asName);
if (pNewCtrl == NULL)
return false;
tPhysicsControllerMapIt it = m_mapControllers.begin();
for (; it != m_mapControllers.end(); ++it) {
iPhysicsController *pCtrl = it->second;
if (pCtrl == pNewCtrl) {
pCtrl->SetActive(true);
} else {
pCtrl->SetActive(false);
}
}
return true;
}
//-----------------------------------------------------------------------
void iPhysicsJoint::SetAllControllersPaused(bool abX) {
tPhysicsControllerMapIt it = m_mapControllers.begin();
for (; it != m_mapControllers.end(); ++it) {
iPhysicsController *pCtrl = it->second;
pCtrl->SetPaused(abX);
}
}
//-----------------------------------------------------------------------
cPhysicsControllerIterator iPhysicsJoint::GetControllerIterator() {
return cPhysicsControllerIterator(&m_mapControllers);
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PROTECTED METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void iPhysicsJoint::OnMaxLimit() {
if (mbHasCollided == false && mpCallback) {
mpCallback->OnMaxLimit(this);
}
//////////////////////////////////////////////////
// Check if any of the controllers has a OnMax end.
if (mbHasCollided == false) {
// Log("OnMax!\n");
tPhysicsControllerMapIt it = m_mapControllers.begin();
for (; it != m_mapControllers.end(); ++it) {
iPhysicsController *pCtrl = it->second;
// Log("Ctrl %s: %d\n",pCtrl->GetName().c_str(),(int)pCtrl->GetEndType());
if (pCtrl->IsActive() && pCtrl->GetEndType() == ePhysicsControllerEnd_OnMax) {
pCtrl->SetActive(false);
iPhysicsController *pNextCtrl = GetController(pCtrl->GetNextController());
if (pNextCtrl)
pNextCtrl->SetActive(true);
else
Warning("Controller '%s' does not exist in joint '%s'\n", pCtrl->GetNextController().c_str(), msName.c_str());
}
}
}
LimitEffect(&mMaxLimit);
}
//-----------------------------------------------------------------------
void iPhysicsJoint::OnMinLimit() {
if (mbHasCollided == false && mpCallback) {
mpCallback->OnMinLimit(this);
}
//////////////////////////////////////////////////
// Check if any of the controllers has a OnMin end.
if (mbHasCollided == false) {
// Log("OnMin!\n");
tPhysicsControllerMapIt it = m_mapControllers.begin();
for (; it != m_mapControllers.end(); ++it) {
iPhysicsController *pCtrl = it->second;
if (pCtrl->IsActive() && pCtrl->GetEndType() == ePhysicsControllerEnd_OnMin) {
pCtrl->SetActive(false);
iPhysicsController *pNextCtrl = GetController(pCtrl->GetNextController());
if (pNextCtrl)
pNextCtrl->SetActive(true);
else
Warning("Controller '%s' does not exist in joint '%s'\n", pCtrl->GetNextController().c_str(), msName.c_str());
}
}
}
LimitEffect(&mMinLimit);
}
//-----------------------------------------------------------------------
void iPhysicsJoint::CalcSoundFreq(float afSpeed, float *apFreq, float *apVol) {
float fAbsSpeed = ABS(afSpeed);
float fFreq = 1;
float fVolume = 1;
// Higher than middle
if (fAbsSpeed >= mfMiddleMoveSpeed) {
if (fAbsSpeed >= mfMaxMoveFreqSpeed) {
fFreq = mfMaxMoveFreq;
fVolume = mfMaxMoveVolume;
} else {
// Calculate how close the speed is to max.
float fT = (fAbsSpeed - mfMiddleMoveSpeed) /
(mfMaxMoveFreqSpeed - mfMiddleMoveSpeed);
fFreq = (1 - fT) + fT * mfMaxMoveFreq;
fVolume = mfMiddleMoveVolume * (1 - fT) + fT * mfMaxMoveVolume;
}
}
// Below middle
else {
if (fAbsSpeed <= mfMinMoveFreqSpeed) {
fFreq = mfMinMoveFreq;
fVolume = mfMinMoveVolume;
} else {
// Calculate how close the speed is to max.
float fT = (mfMiddleMoveSpeed - fAbsSpeed) /
(mfMiddleMoveSpeed - mfMinMoveFreqSpeed);
fFreq = (1 - fT) + fT * mfMinMoveFreq;
fVolume = mfMiddleMoveVolume * (1 - fT) + fT * mfMinMoveVolume;
}
}
*apFreq = fFreq;
*apVol = fVolume;
}
//-----------------------------------------------------------------------
void iPhysicsJoint::OnPhysicsUpdate() {
// Get the pivot point, if there is no parent, it is stuck.
if (mpParentBody)
mvPivotPoint = cMath::MatrixMul(mpChildBody->GetLocalMatrix(), mvLocalPivot);
cWorld3D *pWorld3D = mpWorld->GetWorld3D();
if (pWorld3D == NULL)
return;
if (msMoveSound == "")
return;
if (mpWorld->GetWorld3D()->GetSound()->GetSoundHandler()->GetSilent())
return;
//////////////////////////////////////
// Get the speed
cVector3f vVel(0, 0, 0);
// Linear
if (mMoveSpeedType == ePhysicsJointSpeed_Linear) {
if (mpParentBody) {
vVel = mpChildBody->GetLinearVelocity() - mpParentBody->GetLinearVelocity();
} else {
vVel = mpChildBody->GetLinearVelocity();
}
}
// Angular
else {
if (mpParentBody) {
vVel = mpChildBody->GetAngularVelocity() - mpParentBody->GetAngularVelocity();
} else {
vVel = mpChildBody->GetAngularVelocity();
}
}
// Check so the body is not still
if (mpParentBody) {
if (m_mtxPrevChild == mpChildBody->GetLocalMatrix() &&
m_mtxPrevParent == mpParentBody->GetLocalMatrix()) {
vVel = 0;
}
m_mtxPrevChild = mpChildBody->GetLocalMatrix();
m_mtxPrevParent = mpParentBody->GetLocalMatrix();
} else {
if (m_mtxPrevChild == mpChildBody->GetLocalMatrix()) {
vVel = 0;
}
m_mtxPrevChild = mpChildBody->GetLocalMatrix();
}
float fSpeed = vVel.Length();
if (pWorld3D->SoundEntityExists(mpSound) == false) {
mpSound = NULL;
}
//////////////////////////////////////
// Create and update sound if speed is high enough
// Joint has sound
if (mpSound) {
// Log("Updating %s\n",mpSound->GetName().c_str());
float fMin = cMath::Max(mfMinMoveSpeed - 0.2f, 0.1f);
if (fSpeed <= fMin) {
mpSound->FadeOut(4.3f);
mpSound = NULL;
} else {
// Log("Getting entry!\n");
cSoundEntry *pEntry = mpSound->GetSoundEntry(eSoundEntityType_Main);
if (pEntry) {
// Log("Update entry!\n");
float fFreq, fVolume;
CalcSoundFreq(fSpeed, &fFreq, &fVolume);
pEntry->mfNormalSpeed = fFreq;
pEntry->mfNormalVolumeMul = fVolume;
// Log("Speed: %f Vol: %f Freq: %f\n",fSpeed,fVolume,fFreq);
} else {
// Log("Null entry!\n");
}
mpSound->SetPosition(mvPivotPoint);
}
}
//////////////////////
// Joint has no sound
else {
/////////////////////////////
// Speed is over limit
if (fSpeed > mfMinMoveSpeed) {
if (mlSpeedCount >= 3) {
mlSpeedCount = 0;
mpSound = pWorld3D->CreateSoundEntity("MoveSound", msMoveSound, true);
if (mpSound) {
mpSound->SetIsSaved(false);
mpSound->FadeIn(3.3f);
}
// Log("Starting!\n");
} else {
mlSpeedCount++;
}
}
/////////////////////////////
// Speed is under limit
else {
mlSpeedCount = 0;
}
}
}
//-----------------------------------------------------------------------
void iPhysicsJoint::LimitEffect(cJointLimitEffect *pEffect) {
cWorld3D *pWorld3D = mpWorld->GetWorld3D();
if (pWorld3D && pEffect->msSound != "") {
cVector3f vVel(0, 0, 0);
if (mpParentBody)
vVel = mpChildBody->GetLinearVelocity() - mpParentBody->GetLinearVelocity();
else
vVel = mpChildBody->GetLinearVelocity();
float fSpeed = vVel.Length();
if (fSpeed > pEffect->mfMaxSpeed)
fSpeed = pEffect->mfMaxSpeed;
// Log("Speed: %f\n",fSpeed);
if (fSpeed >= pEffect->mfMinSpeed && mbHasCollided == false && pEffect->msSound != "") {
float fVolume = (fSpeed - pEffect->mfMinSpeed) / (pEffect->mfMaxSpeed - pEffect->mfMinSpeed);
cSoundEntity *pSound = pWorld3D->CreateSoundEntity("LimitSound", pEffect->msSound, true);
if (pSound) {
pSound->SetVolume(fVolume);
pSound->SetPosition(mpChildBody->GetLocalPosition());
}
}
}
mbHasCollided = true;
}
//-----------------------------------------------------------------------
void iPhysicsJoint::OnNoLimit() {
mbHasCollided = false;
}
//-----------------------------------------------------------------------
void iPhysicsJoint::Break() {
mbBroken = true;
mbBreakable = true;
}
//-----------------------------------------------------------------------
bool iPhysicsJoint::CheckBreakage() {
if (mbBreakable == false)
return false;
float fForcesSize = GetForce().Length();
if (fForcesSize >= mfBreakForce || mbBroken) {
if (msBreakSound != "") {
cWorld3D *pWorld3D = mpWorld->GetWorld3D();
cSoundEntity *pSound = pWorld3D->CreateSoundEntity("BreakSound", msBreakSound, true);
if (pSound)
pSound->SetPosition(mvPivotPoint);
}
return true;
}
return false;
}
//-----------------------------------------------------------------------
void iPhysicsJoint::CheckLimitAutoSleep(iPhysicsJoint *apJoint,
const float afMin, const float afMax,
const float afDist) {
if (apJoint->mbLimitAutoSleep) {
float fMinDiff = ABS(afMin - afDist);
float fMaxDiff = ABS(afMax - afDist);
if (fMaxDiff < apJoint->mfLimitAutoSleepDist ||
fMinDiff < apJoint->mfLimitAutoSleepDist) {
if (apJoint->mlLimitStepCount >= apJoint->mlLimitAutoSleepNumSteps)
apJoint->mpChildBody->DisableAfterSimulation();
else
apJoint->mlLimitStepCount++;
} else {
apJoint->mlLimitStepCount = 0;
}
}
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// SAVE OBJECT STUFF
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
kBeginSerializeBase(cJointLimitEffect)
kSerializeVar(msSound, eSerializeType_String)
kSerializeVar(mfMinSpeed, eSerializeType_Float32)
kSerializeVar(mfMaxSpeed, eSerializeType_Float32)
kEndSerialize()
//-----------------------------------------------------------------------
kBeginSerializeVirtual(cSaveData_iPhysicsJoint, iSaveData)
kSerializeVar(msName, eSerializeType_String)
kSerializeVar(mlParentBodyId, eSerializeType_Int32)
kSerializeVar(mlChildBodyId, eSerializeType_Int32)
kSerializeVar(m_mtxParentBodySetup, eSerializeType_Matrixf)
kSerializeVar(m_mtxChildBodySetup, eSerializeType_Matrixf)
kSerializeVar(mvPinDir, eSerializeType_Vector3f)
kSerializeVar(mvStartPivotPoint, eSerializeType_Vector3f)
kSerializeClassContainer(mlstControllers, cSaveData_iPhysicsController, eSerializeType_Class)
kSerializeVar(mMaxLimit, eSerializeType_Class)
kSerializeVar(mMinLimit, eSerializeType_Class)
kSerializeVar(msMoveSound, eSerializeType_String)
kSerializeVar(mfMinMoveSpeed, eSerializeType_Float32)
kSerializeVar(mfMinMoveFreq, eSerializeType_Float32)
kSerializeVar(mfMinMoveFreqSpeed, eSerializeType_Float32)
kSerializeVar(mfMinMoveVolume, eSerializeType_Float32)
kSerializeVar(mfMaxMoveFreq, eSerializeType_Float32)
kSerializeVar(mfMaxMoveFreqSpeed, eSerializeType_Float32)
kSerializeVar(mfMaxMoveVolume, eSerializeType_Float32)
kSerializeVar(mfMiddleMoveSpeed, eSerializeType_Float32)
kSerializeVar(mfMiddleMoveVolume, eSerializeType_Float32)
kSerializeVar(mMoveSpeedType, eSerializeType_Int32)
kSerializeVar(mbBreakable, eSerializeType_Bool)
kSerializeVar(mfBreakForce, eSerializeType_Float32)
kSerializeVar(msBreakSound, eSerializeType_String)
kSerializeVar(mbBroken, eSerializeType_Bool)
kSerializeVar(msCallbackMaxFunc, eSerializeType_String)
kSerializeVar(msCallbackMinFunc, eSerializeType_String)
kSerializeVar(mbAutoDeleteCallback, eSerializeType_Bool)
kEndSerialize()
//-----------------------------------------------------------------------
iSaveData *iPhysicsJoint::CreateSaveData() {
return NULL;
}
//-----------------------------------------------------------------------
void iPhysicsJoint::SaveToSaveData(iSaveData *apSaveData) {
kSaveData_SaveToBegin(iPhysicsJoint);
//////////////////////////
// Variables
kSaveData_SaveTo(msName);
kSaveData_SaveTo(m_mtxParentBodySetup);
kSaveData_SaveTo(m_mtxChildBodySetup);
kSaveData_SaveTo(mvPinDir);
kSaveData_SaveTo(mvStartPivotPoint);
kSaveData_SaveTo(mMaxLimit);
kSaveData_SaveTo(mMinLimit);
kSaveData_SaveTo(msMoveSound);
kSaveData_SaveTo(mfMinMoveSpeed);
kSaveData_SaveTo(mfMinMoveFreq);
kSaveData_SaveTo(mfMinMoveFreqSpeed);
kSaveData_SaveTo(mfMinMoveVolume);
kSaveData_SaveTo(mfMaxMoveFreq);
kSaveData_SaveTo(mfMaxMoveFreqSpeed);
kSaveData_SaveTo(mfMaxMoveVolume);
kSaveData_SaveTo(mfMiddleMoveSpeed);
kSaveData_SaveTo(mfMiddleMoveVolume);
kSaveData_SaveTo(mMoveSpeedType);
kSaveData_SaveTo(mbBreakable);
kSaveData_SaveTo(mfBreakForce);
kSaveData_SaveTo(msBreakSound);
kSaveData_SaveTo(mbBroken);
kSaveData_SaveTo(mbAutoDeleteCallback);
// Callback
if (mpCallback && mpCallback->IsScript()) {
cScriptJointCallback *pScriptCallback = static_cast<cScriptJointCallback *>(mpCallback);
pData->msCallbackMaxFunc = pScriptCallback->msMaxFunc;
pData->msCallbackMinFunc = pScriptCallback->msMinFunc;
} else {
pData->msCallbackMaxFunc = "";
pData->msCallbackMinFunc = "";
}
//////////////////////////
// Controllers
pData->mlstControllers.Clear();
tPhysicsControllerMapIt it = m_mapControllers.begin();
for (; it != m_mapControllers.end(); ++it) {
iPhysicsController *pController = it->second;
cSaveData_iPhysicsController saveController;
pController->SaveToSaveData(&saveController);
pData->mlstControllers.Add(saveController);
}
//////////////////////////
// Pointers
kSaveData_SaveObject(mpParentBody, mlParentBodyId);
kSaveData_SaveObject(mpChildBody, mlChildBodyId);
}
//-----------------------------------------------------------------------
void iPhysicsJoint::LoadFromSaveData(iSaveData *apSaveData) {
kSaveData_LoadFromBegin(iPhysicsJoint);
//////////////////////////
// Variables
kSaveData_LoadFrom(msName);
kSaveData_LoadFrom(m_mtxParentBodySetup);
kSaveData_LoadFrom(m_mtxChildBodySetup);
kSaveData_LoadFrom(mvPinDir);
kSaveData_LoadFrom(mvStartPivotPoint);
kSaveData_LoadFrom(mMaxLimit);
kSaveData_LoadFrom(mMinLimit);
kSaveData_LoadFrom(msMoveSound);
kSaveData_LoadFrom(mfMinMoveSpeed);
kSaveData_LoadFrom(mfMinMoveFreq);
kSaveData_LoadFrom(mfMinMoveFreqSpeed);
kSaveData_LoadFrom(mfMinMoveVolume);
kSaveData_LoadFrom(mfMaxMoveFreq);
kSaveData_LoadFrom(mfMaxMoveFreqSpeed);
kSaveData_LoadFrom(mfMaxMoveVolume);
kSaveData_LoadFrom(mfMiddleMoveSpeed);
kSaveData_LoadFrom(mfMiddleMoveVolume);
kSaveData_LoadFrom(mbBreakable);
kSaveData_LoadFrom(mfBreakForce);
kSaveData_LoadFrom(msBreakSound);
kSaveData_LoadFrom(mbBroken);
mMoveSpeedType = (ePhysicsJointSpeed)pData->mMoveSpeedType;
kSaveData_LoadFrom(mbAutoDeleteCallback);
//////////////////////////
// Controllers
cContainerListIterator<cSaveData_iPhysicsController> CtrlIt = pData->mlstControllers.GetIterator();
while (CtrlIt.HasNext()) {
cSaveData_iPhysicsController &saveCtrl = CtrlIt.Next();
iPhysicsController *pController = mpWorld->CreateController(saveCtrl.msName);
pController->LoadFromSaveData(&saveCtrl);
AddController(pController);
}
}
//-----------------------------------------------------------------------
void iPhysicsJoint::SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
kSaveData_SetupBegin(iPhysicsJoint);
if (pData->msCallbackMaxFunc != "" || pData->msCallbackMinFunc != "") {
cScriptJointCallback *pCallback = hplNew(cScriptJointCallback, (apGame->GetScene()));
pCallback->msMaxFunc = pData->msCallbackMaxFunc;
pCallback->msMinFunc = pData->msCallbackMinFunc;
SetCallback(pCallback, true);
}
}
//-----------------------------------------------------------------------
} // namespace hpl

View File

@@ -0,0 +1,311 @@
/* 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.
*/
#ifndef HPL_PHYSICS_JOINT_H
#define HPL_PHYSICS_JOINT_H
#include "hpl1/engine/math/MathTypes.h"
#include "hpl1/engine/system/SystemTypes.h"
#include "common/stablemap.h"
#include "hpl1/engine/game/SaveGame.h"
#include "hpl1/engine/physics/PhysicsController.h"
namespace hpl {
class iPhysicsBody;
class iPhysicsWorld;
class cSoundEntity;
class iPhysicsJoint;
class iPhysicsController;
typedef Common::StableMap<tString, iPhysicsController *> tPhysicsControllerMap;
typedef tPhysicsControllerMap::iterator tPhysicsControllerMapIt;
typedef cSTLMapIterator<iPhysicsController *, tPhysicsControllerMap, tPhysicsControllerMapIt> cPhysicsControllerIterator;
//-----------------------------------
enum ePhysicsJointType {
ePhysicsJointType_Ball,
ePhysicsJointType_Hinge,
ePhysicsJointType_Slider,
ePhysicsJointType_Screw,
ePhysicsJointType_LastEnum
};
//-----------------------------------
enum ePhysicsJointSpeed {
ePhysicsJointSpeed_Linear,
ePhysicsJointSpeed_Angular,
ePhysicsJointSpeed_LastEnum
};
//-----------------------------------
class cJointLimitEffect : public iSerializable {
kSerializableClassInit(cJointLimitEffect) public : tString msSound;
float mfMinSpeed;
float mfMaxSpeed;
};
//-----------------------------------
class iPhysicsJointCallback {
public:
virtual ~iPhysicsJointCallback() {}
virtual void OnMinLimit(iPhysicsJoint *apJoint) = 0;
virtual void OnMaxLimit(iPhysicsJoint *apJoint) = 0;
// Ugly trick to support joint script callback.
virtual bool IsScript() { return false; }
};
//-----------------------------------
kSaveData_BaseClass(iPhysicsJoint) {
kSaveData_ClassInit(iPhysicsJoint) public : tString msName;
int mlParentBodyId;
int mlChildBodyId;
cMatrixf m_mtxParentBodySetup;
cMatrixf m_mtxChildBodySetup;
cVector3f mvPinDir;
cVector3f mvStartPivotPoint;
cContainerList<cSaveData_iPhysicsController> mlstControllers;
cJointLimitEffect mMaxLimit;
cJointLimitEffect mMinLimit;
tString msMoveSound;
float mfMinMoveSpeed;
float mfMinMoveFreq;
float mfMinMoveFreqSpeed;
float mfMinMoveVolume;
float mfMaxMoveFreq;
float mfMaxMoveFreqSpeed;
float mfMaxMoveVolume;
float mfMiddleMoveSpeed;
float mfMiddleMoveVolume;
int mMoveSpeedType;
bool mbBreakable;
float mfBreakForce;
tString msBreakSound;
bool mbBroken;
tString msCallbackMaxFunc;
tString msCallbackMinFunc;
bool mbAutoDeleteCallback;
};
//-----------------------------------
class iPhysicsJoint : public iSaveObject {
typedef iSaveObject super;
public:
iPhysicsJoint(const tString &asName, iPhysicsBody *apParentBody, iPhysicsBody *apChildBody,
iPhysicsWorld *apWorld, const cVector3f &avPivotPoint);
virtual ~iPhysicsJoint();
const tString &GetName() { return msName; }
iPhysicsBody *GetParentBody() { return mpParentBody; }
iPhysicsBody *GetChildBody() { return mpChildBody; }
void RemoveBody(iPhysicsBody *apBody);
cVector3f GetPivotPoint() { return mvPivotPoint; }
cVector3f GetPinDir() { return mvPinDir; }
virtual ePhysicsJointType GetType() = 0;
virtual void SetCollideBodies(bool abX) = 0;
virtual bool GetCollideBodies() = 0;
virtual void SetStiffness(float afX) = 0;
virtual float GetStiffness() = 0;
virtual cVector3f GetVelocity() = 0;
virtual cVector3f GetAngularVelocity() = 0;
virtual cVector3f GetForce() = 0;
virtual float GetDistance() = 0;
virtual float GetAngle() = 0;
cJointLimitEffect *GetMaxLimit() { return &mMaxLimit; }
cJointLimitEffect *GetMinLimit() { return &mMinLimit; }
void SetMoveSound(tString &asName) { msMoveSound = asName; }
void SetMoveSpeedType(ePhysicsJointSpeed aType) { mMoveSpeedType = aType; }
void SetMinMoveSpeed(float afX) { mfMinMoveSpeed = afX; }
void SetMinMoveFreq(float afX) { mfMinMoveFreq = afX; }
void SetMinMoveFreqSpeed(float afX) { mfMinMoveFreqSpeed = afX; }
void SetMinMoveVolume(float afX) { mfMinMoveVolume = afX; }
void SetMaxMoveFreq(float afX) { mfMaxMoveFreq = afX; }
void SetMaxMoveVolume(float afX) { mfMaxMoveVolume = afX; }
void SetMaxMoveFreqSpeed(float afX) { mfMaxMoveFreqSpeed = afX; }
void SetMiddleMoveSpeed(float afX) { mfMiddleMoveSpeed = afX; }
void SetMiddleMoveVolume(float afX) { mfMiddleMoveVolume = afX; }
void SetCallback(iPhysicsJointCallback *apCallback, bool abAutoDelete) {
mpCallback = apCallback;
mbAutoDeleteCallback = abAutoDelete;
}
iPhysicsJointCallback *GetCallback() { return mpCallback; }
bool CheckBreakage();
void SetBreakable(bool abX) { mbBreakable = abX; }
bool IsBreakable() { return mbBreakable; }
void SetBreakForce(float afForce) { mfBreakForce = afForce; }
float GetBreakForce() { return mfBreakForce; }
void SetBreakSound(const tString &asSound) { msBreakSound = asSound; }
void SetLimitAutoSleep(bool abX) { mbLimitAutoSleep = abX; }
void SetLimitAutoSleepDist(float afX) { mfLimitAutoSleepDist = afX; }
void SetLimitAutoSleepNumSteps(int alX) { mlLimitAutoSleepNumSteps = alX; }
bool GetLimitAutoSleep() { return mbLimitAutoSleep; }
float GetLimitAutoSleepDist() { return mfLimitAutoSleepDist; }
int GetLimitAutoSleepNumSteps() { return mlLimitAutoSleepNumSteps; }
void SetStickyMinDistance(float afX) { mfStickyMinDistance = afX; }
void SetStickyMaxDistance(float afX) { mfStickyMaxDistance = afX; }
float GetStickyMinDistance() { return mfStickyMinDistance; }
float GetStickyMaxDistance() { return mfStickyMaxDistance; }
void Break();
bool IsBroken() { return mbBroken; }
void SetUserData(void *apUserData) { mpUserData = apUserData; }
void AddController(iPhysicsController *apController);
iPhysicsController *GetController(const tString &asName);
bool ChangeController(const tString &asName);
cPhysicsControllerIterator GetControllerIterator();
void SetAllControllersPaused(bool abX);
void OnPhysicsUpdate();
void SetSound(cSoundEntity *apSound) { mpSound = apSound; }
cSoundEntity *GetSound() { return mpSound; }
// SaveObject implementation
virtual iSaveData *CreateSaveData();
virtual void SaveToSaveData(iSaveData *apSaveData);
virtual void LoadFromSaveData(iSaveData *apSaveData);
virtual void SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame);
protected:
tString msName;
iPhysicsBody *mpParentBody;
iPhysicsBody *mpChildBody;
iPhysicsWorld *mpWorld;
cMatrixf m_mtxParentBodySetup;
cMatrixf m_mtxChildBodySetup;
cVector3f mvPinDir;
cVector3f mvPivotPoint;
cVector3f mvStartPivotPoint;
cVector3f mvLocalPivot;
float mfStickyMinDistance;
float mfStickyMaxDistance;
tPhysicsControllerMap m_mapControllers;
cJointLimitEffect mMaxLimit;
cJointLimitEffect mMinLimit;
int mlSpeedCount;
cMatrixf m_mtxPrevChild;
cMatrixf m_mtxPrevParent;
tString msMoveSound;
float mfMinMoveSpeed;
float mfMinMoveFreq;
float mfMinMoveFreqSpeed;
float mfMinMoveVolume;
float mfMaxMoveFreq;
float mfMaxMoveFreqSpeed;
float mfMaxMoveVolume;
float mfMiddleMoveSpeed;
float mfMiddleMoveVolume;
ePhysicsJointSpeed mMoveSpeedType;
bool mbBreakable;
float mfBreakForce;
tString msBreakSound;
bool mbBroken;
bool mbLimitAutoSleep;
float mfLimitAutoSleepDist;
int mlLimitAutoSleepNumSteps;
cSoundEntity *mpSound;
bool mbHasCollided;
iPhysicsJointCallback *mpCallback;
bool mbAutoDeleteCallback;
int mlLimitStepCount;
void *mpUserData;
static void CheckLimitAutoSleep(iPhysicsJoint *apJoint, const float afMin, const float afMax,
const float afDist);
void OnMaxLimit();
void OnMinLimit();
void OnNoLimit();
void CalcSoundFreq(float afSpeed, float *apFreq, float *apVol);
void LimitEffect(cJointLimitEffect *pEffect);
};
} // namespace hpl
#endif // HPL_PHYSICS_JOINT_H

View File

@@ -0,0 +1,125 @@
/* 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/PhysicsJointBall.h"
#include "hpl1/engine/game/Game.h"
#include "hpl1/engine/scene/Scene.h"
#include "hpl1/engine/scene/World3D.h"
#include "hpl1/engine/physics/PhysicsBody.h"
#include "hpl1/engine/physics/PhysicsWorld.h"
#include "hpl1/engine/system/low_level_system.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// SAVE OBJECT STUFF
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
kBeginSerialize(cSaveData_iPhysicsJointBall, cSaveData_iPhysicsJoint)
kSerializeVar(mfMaxConeAngle, eSerializeType_Float32)
kSerializeVar(mfMaxTwistAngle, eSerializeType_Float32)
kSerializeVar(mvConePin, eSerializeType_Vector3f)
kEndSerialize()
//-----------------------------------------------------------------------
iSaveObject *cSaveData_iPhysicsJointBall::CreateSaveObject(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
iPhysicsWorld *apWorld = apGame->GetScene()->GetWorld3D()->GetPhysicsWorld();
cMatrixf mtxChildTemp, mtxParentTemp;
iPhysicsBody *pChildBody = static_cast<iPhysicsBody *>(apSaveObjectHandler->Get(mlChildBodyId));
if (pChildBody == NULL)
return NULL;
iPhysicsBody *pParentBody = NULL;
if (mlParentBodyId > 0)
pParentBody = static_cast<iPhysicsBody *>(apSaveObjectHandler->Get(mlParentBodyId));
mtxChildTemp = pChildBody->GetLocalMatrix();
if (pParentBody)
mtxParentTemp = pParentBody->GetLocalMatrix();
pChildBody->SetMatrix(m_mtxChildBodySetup);
if (pParentBody)
pParentBody->SetMatrix(m_mtxParentBodySetup);
iPhysicsJointBall *pJoint = apWorld->CreateJointBall(msName, mvStartPivotPoint, pParentBody, pChildBody);
pJoint->SetConeLimits(mvConePin, mfMaxConeAngle, mfMaxTwistAngle);
pChildBody->SetMatrix(mtxChildTemp);
if (pParentBody)
pParentBody->SetMatrix(mtxParentTemp);
return pJoint;
}
//-----------------------------------------------------------------------
int cSaveData_iPhysicsJointBall::GetSaveCreatePrio() {
return 1;
}
//-----------------------------------------------------------------------
iSaveData *iPhysicsJointBall::CreateSaveData() {
return hplNew(cSaveData_iPhysicsJointBall, ());
}
//-----------------------------------------------------------------------
void iPhysicsJointBall::SaveToSaveData(iSaveData *apSaveData) {
kSaveData_SaveToBegin(iPhysicsJointBall);
kSaveData_SaveTo(mfMaxConeAngle);
kSaveData_SaveTo(mfMaxTwistAngle);
kSaveData_SaveTo(mvConePin);
}
//-----------------------------------------------------------------------
void iPhysicsJointBall::LoadFromSaveData(iSaveData *apSaveData) {
kSaveData_LoadFromBegin(iPhysicsJointBall);
kSaveData_LoadFrom(mfMaxConeAngle);
kSaveData_LoadFrom(mfMaxTwistAngle);
kSaveData_LoadFrom(mvConePin);
}
//-----------------------------------------------------------------------
void iPhysicsJointBall::SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
kSaveData_SetupBegin(iPhysicsJointBall);
}
//-----------------------------------------------------------------------
} // namespace hpl

View File

@@ -0,0 +1,80 @@
/* 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.
*/
#ifndef HPL_PHYSICS_JOINT_BALL_H
#define HPL_PHYSICS_JOINT_BALL_H
#include "hpl1/engine/physics/PhysicsJoint.h"
namespace hpl {
//-----------------------------------
kSaveData_ChildClass(iPhysicsJoint, iPhysicsJointBall) {
kSaveData_ClassInit(iPhysicsJointBall) public : float mfMaxConeAngle;
float mfMaxTwistAngle;
cVector3f mvConePin;
virtual iSaveObject *CreateSaveObject(cSaveObjectHandler * apSaveObjectHandler, cGame * apGame);
virtual int GetSaveCreatePrio();
};
//-----------------------------------
class iPhysicsJointBall : public iPhysicsJoint {
typedef iPhysicsJoint super;
public:
iPhysicsJointBall(const tString &asName, iPhysicsBody *apParentBody, iPhysicsBody *apChildBody,
iPhysicsWorld *apWorld, const cVector3f &avPivotPoint)
: iPhysicsJoint(asName, apParentBody, apChildBody, apWorld, avPivotPoint) {}
virtual ~iPhysicsJointBall() {}
virtual void SetConeLimits(const cVector3f &avPin, float afMaxConeAngle, float afMaxTwistAngle) = 0;
virtual cVector3f GetAngles() = 0;
float GetMaxConeAngle() { return mfMaxConeAngle; }
float GetMaxTwistAngle() { return mfMaxTwistAngle; }
cVector3f GetConePin() { return mvConePin; }
ePhysicsJointType GetType() { return ePhysicsJointType_Ball; }
// SaveObject implementation
virtual iSaveData *CreateSaveData();
virtual void SaveToSaveData(iSaveData *apSaveData);
virtual void LoadFromSaveData(iSaveData *apSaveData);
virtual void SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame);
protected:
float mfMaxConeAngle;
float mfMaxTwistAngle;
cVector3f mvConePin;
};
} // namespace hpl
#endif // HPL_PHYSICS_JOINT_BALL_H

View File

@@ -0,0 +1,119 @@
/* 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/PhysicsJointHinge.h"
#include "hpl1/engine/game/Game.h"
#include "hpl1/engine/scene/Scene.h"
#include "hpl1/engine/scene/World3D.h"
#include "hpl1/engine/physics/PhysicsBody.h"
#include "hpl1/engine/physics/PhysicsWorld.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// SAVE OBJECT STUFF
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
kBeginSerialize(cSaveData_iPhysicsJointHinge, cSaveData_iPhysicsJoint)
kSerializeVar(mfMaxAngle, eSerializeType_Float32)
kSerializeVar(mfMinAngle, eSerializeType_Float32)
kEndSerialize()
//-----------------------------------------------------------------------
iSaveObject *cSaveData_iPhysicsJointHinge::CreateSaveObject(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
iPhysicsWorld *apWorld = apGame->GetScene()->GetWorld3D()->GetPhysicsWorld();
cMatrixf mtxChildTemp, mtxParentTemp;
iPhysicsBody *pChildBody = static_cast<iPhysicsBody *>(apSaveObjectHandler->Get(mlChildBodyId));
if (pChildBody == NULL)
return NULL;
iPhysicsBody *pParentBody = NULL;
if (mlParentBodyId > 0)
pParentBody = static_cast<iPhysicsBody *>(apSaveObjectHandler->Get(mlParentBodyId));
mtxChildTemp = pChildBody->GetLocalMatrix();
if (pParentBody)
mtxParentTemp = pParentBody->GetLocalMatrix();
pChildBody->SetMatrix(m_mtxChildBodySetup);
if (pParentBody)
pParentBody->SetMatrix(m_mtxParentBodySetup);
iPhysicsJointHinge *pJoint = apWorld->CreateJointHinge(msName, mvStartPivotPoint, mvPinDir, pParentBody, pChildBody);
pChildBody->SetMatrix(mtxChildTemp);
if (pParentBody)
pParentBody->SetMatrix(mtxParentTemp);
return pJoint;
}
//-----------------------------------------------------------------------
int cSaveData_iPhysicsJointHinge::GetSaveCreatePrio() {
return 1;
}
//-----------------------------------------------------------------------
iSaveData *iPhysicsJointHinge::CreateSaveData() {
return hplNew(cSaveData_iPhysicsJointHinge, ());
}
//-----------------------------------------------------------------------
void iPhysicsJointHinge::SaveToSaveData(iSaveData *apSaveData) {
kSaveData_SaveToBegin(iPhysicsJointHinge);
kSaveData_SaveTo(mfMaxAngle);
kSaveData_SaveTo(mfMinAngle);
}
//-----------------------------------------------------------------------
void iPhysicsJointHinge::LoadFromSaveData(iSaveData *apSaveData) {
kSaveData_LoadFromBegin(iPhysicsJointHinge);
kSaveData_LoadFrom(mfMaxAngle);
kSaveData_LoadFrom(mfMinAngle);
}
//-----------------------------------------------------------------------
void iPhysicsJointHinge::SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
kSaveData_SetupBegin(iPhysicsJointHinge);
}
//-----------------------------------------------------------------------
} // namespace hpl

View File

@@ -0,0 +1,76 @@
/* 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.
*/
#ifndef HPL_PHYSICS_JOINT_HINGE_H
#define HPL_PHYSICS_JOINT_HINGE_H
#include "hpl1/engine/physics/PhysicsJoint.h"
namespace hpl {
//-----------------------------------
kSaveData_ChildClass(iPhysicsJoint, iPhysicsJointHinge) {
kSaveData_ClassInit(iPhysicsJointHinge) public : float mfMaxAngle;
float mfMinAngle;
virtual iSaveObject *CreateSaveObject(cSaveObjectHandler * apSaveObjectHandler, cGame * apGame);
virtual int GetSaveCreatePrio();
};
//-----------------------------------
class iPhysicsJointHinge : public iPhysicsJoint {
typedef iPhysicsJoint super;
public:
iPhysicsJointHinge(const tString &asName, iPhysicsBody *apParentBody, iPhysicsBody *apChildBody,
iPhysicsWorld *apWorld, const cVector3f &avPivotPoint)
: iPhysicsJoint(asName, apParentBody, apChildBody, apWorld, avPivotPoint) {}
virtual ~iPhysicsJointHinge() {}
virtual void SetMaxAngle(float afAngle) = 0;
virtual void SetMinAngle(float afAngle) = 0;
virtual float GetMaxAngle() = 0;
virtual float GetMinAngle() = 0;
ePhysicsJointType GetType() { return ePhysicsJointType_Hinge; }
// SaveObject implementation
virtual iSaveData *CreateSaveData();
virtual void SaveToSaveData(iSaveData *apSaveData);
virtual void LoadFromSaveData(iSaveData *apSaveData);
virtual void SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame);
protected:
float mfMaxAngle;
float mfMinAngle;
};
} // namespace hpl
#endif // HPL_PHYSICS_JOINT_HINGE_H

View File

@@ -0,0 +1,122 @@
/* 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/PhysicsJointScrew.h"
#include "hpl1/engine/game/Game.h"
#include "hpl1/engine/scene/Scene.h"
#include "hpl1/engine/scene/World3D.h"
#include "hpl1/engine/physics/PhysicsBody.h"
#include "hpl1/engine/physics/PhysicsWorld.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// SAVE OBJECT STUFF
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
kBeginSerialize(cSaveData_iPhysicsJointScrew, cSaveData_iPhysicsJoint)
kSerializeVar(mfMaxDistance, eSerializeType_Float32)
kSerializeVar(mfMinDistance, eSerializeType_Float32)
kSerializeVar(mvPin, eSerializeType_Vector3f)
kEndSerialize()
//-----------------------------------------------------------------------
iSaveObject *cSaveData_iPhysicsJointScrew::CreateSaveObject(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
iPhysicsWorld *apWorld = apGame->GetScene()->GetWorld3D()->GetPhysicsWorld();
cMatrixf mtxChildTemp, mtxParentTemp;
iPhysicsBody *pChildBody = static_cast<iPhysicsBody *>(apSaveObjectHandler->Get(mlChildBodyId));
if (pChildBody == NULL)
return NULL;
iPhysicsBody *pParentBody = NULL;
if (mlParentBodyId > 0)
pParentBody = static_cast<iPhysicsBody *>(apSaveObjectHandler->Get(mlParentBodyId));
mtxChildTemp = pChildBody->GetLocalMatrix();
if (pParentBody)
mtxParentTemp = pParentBody->GetLocalMatrix();
pChildBody->SetMatrix(m_mtxChildBodySetup);
if (pParentBody)
pParentBody->SetMatrix(m_mtxParentBodySetup);
iPhysicsJointScrew *pJoint = apWorld->CreateJointScrew(msName, mvStartPivotPoint, mvPinDir, pParentBody, pChildBody);
pChildBody->SetMatrix(mtxChildTemp);
if (pParentBody)
pParentBody->SetMatrix(mtxParentTemp);
return pJoint;
}
//-----------------------------------------------------------------------
int cSaveData_iPhysicsJointScrew::GetSaveCreatePrio() {
return 1;
}
//-----------------------------------------------------------------------
iSaveData *iPhysicsJointScrew::CreateSaveData() {
return hplNew(cSaveData_iPhysicsJointScrew, ());
}
//-----------------------------------------------------------------------
void iPhysicsJointScrew::SaveToSaveData(iSaveData *apSaveData) {
kSaveData_SaveToBegin(iPhysicsJointScrew);
kSaveData_SaveTo(mfMaxDistance);
kSaveData_SaveTo(mfMinDistance);
kSaveData_SaveTo(mvPin);
}
//-----------------------------------------------------------------------
void iPhysicsJointScrew::LoadFromSaveData(iSaveData *apSaveData) {
kSaveData_LoadFromBegin(iPhysicsJointScrew);
kSaveData_LoadFrom(mfMaxDistance);
kSaveData_LoadFrom(mfMinDistance);
kSaveData_LoadFrom(mvPin);
}
//-----------------------------------------------------------------------
void iPhysicsJointScrew::SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
kSaveData_SetupBegin(iPhysicsJointScrew);
}
//-----------------------------------------------------------------------
} // namespace hpl

View File

@@ -0,0 +1,85 @@
/* 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.
*/
#ifndef HPL_PHYSICS_JOINT_SCREW_H
#define HPL_PHYSICS_JOINT_SCREW_H
#include "hpl1/engine/physics/PhysicsJoint.h"
namespace hpl {
//-----------------------------------
kSaveData_ChildClass(iPhysicsJoint, iPhysicsJointScrew) {
kSaveData_ClassInit(iPhysicsJointScrew) public : float mfMaxDistance;
float mfMinDistance;
cVector3f mvPin;
virtual iSaveObject *CreateSaveObject(cSaveObjectHandler * apSaveObjectHandler, cGame * apGame);
virtual int GetSaveCreatePrio();
};
//-----------------------------------
class iPhysicsJointScrew : public iPhysicsJoint {
typedef iPhysicsJoint super;
public:
iPhysicsJointScrew(const tString &asName, iPhysicsBody *apParentBody, iPhysicsBody *apChildBody,
iPhysicsWorld *apWorld, const cVector3f &avPivotPoint)
: iPhysicsJoint(asName, apParentBody, apChildBody, apWorld, avPivotPoint) {}
virtual ~iPhysicsJointScrew() {}
/**
* Set the maximum distance the bodies can be from each other, relative to the start dist between them
* This is true if pin points towards the child.
* In other words, distance increases as the distance between start pivot and current pivot
* increases in the opposite direction of the pin.
*/
virtual void SetMaxDistance(float afX) = 0;
virtual void SetMinDistance(float afX) = 0;
virtual float GetMaxDistance() = 0;
virtual float GetMinDistance() = 0;
ePhysicsJointType GetType() { return ePhysicsJointType_Screw; }
// SaveObject implementation
virtual iSaveData *CreateSaveData();
virtual void SaveToSaveData(iSaveData *apSaveData);
virtual void LoadFromSaveData(iSaveData *apSaveData);
virtual void SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame);
protected:
float mfMaxDistance;
float mfMinDistance;
cVector3f mvPin;
};
} // namespace hpl
#endif // HPL_PHYSICS_JOINT_SCREW_H

View File

@@ -0,0 +1,122 @@
/* 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/PhysicsJointSlider.h"
#include "hpl1/engine/game/Game.h"
#include "hpl1/engine/scene/Scene.h"
#include "hpl1/engine/scene/World3D.h"
#include "hpl1/engine/physics/PhysicsBody.h"
#include "hpl1/engine/physics/PhysicsWorld.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// SAVE OBJECT STUFF
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
kBeginSerialize(cSaveData_iPhysicsJointSlider, cSaveData_iPhysicsJoint)
kSerializeVar(mfMaxDistance, eSerializeType_Float32)
kSerializeVar(mfMinDistance, eSerializeType_Float32)
kSerializeVar(mvPin, eSerializeType_Vector3f)
kEndSerialize()
//-----------------------------------------------------------------------
iSaveObject *cSaveData_iPhysicsJointSlider::CreateSaveObject(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
iPhysicsWorld *apWorld = apGame->GetScene()->GetWorld3D()->GetPhysicsWorld();
cMatrixf mtxChildTemp, mtxParentTemp;
iPhysicsBody *pChildBody = static_cast<iPhysicsBody *>(apSaveObjectHandler->Get(mlChildBodyId));
if (pChildBody == NULL)
return NULL;
iPhysicsBody *pParentBody = NULL;
if (mlParentBodyId > 0)
pParentBody = static_cast<iPhysicsBody *>(apSaveObjectHandler->Get(mlParentBodyId));
mtxChildTemp = pChildBody->GetLocalMatrix();
if (pParentBody)
mtxParentTemp = pParentBody->GetLocalMatrix();
pChildBody->SetMatrix(m_mtxChildBodySetup);
if (pParentBody)
pParentBody->SetMatrix(m_mtxParentBodySetup);
iPhysicsJointSlider *pJoint = apWorld->CreateJointSlider(msName, mvStartPivotPoint, mvPinDir, pParentBody, pChildBody);
pChildBody->SetMatrix(mtxChildTemp);
if (pParentBody)
pParentBody->SetMatrix(mtxParentTemp);
return pJoint;
}
//-----------------------------------------------------------------------
int cSaveData_iPhysicsJointSlider::GetSaveCreatePrio() {
return 1;
}
//-----------------------------------------------------------------------
iSaveData *iPhysicsJointSlider::CreateSaveData() {
return hplNew(cSaveData_iPhysicsJointSlider, ());
}
//-----------------------------------------------------------------------
void iPhysicsJointSlider::SaveToSaveData(iSaveData *apSaveData) {
kSaveData_SaveToBegin(iPhysicsJointSlider);
kSaveData_SaveTo(mfMaxDistance);
kSaveData_SaveTo(mfMinDistance);
kSaveData_SaveTo(mvPin);
}
//-----------------------------------------------------------------------
void iPhysicsJointSlider::LoadFromSaveData(iSaveData *apSaveData) {
kSaveData_LoadFromBegin(iPhysicsJointSlider);
kSaveData_LoadFrom(mfMaxDistance);
kSaveData_LoadFrom(mfMinDistance);
kSaveData_LoadFrom(mvPin);
}
//-----------------------------------------------------------------------
void iPhysicsJointSlider::SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame) {
kSaveData_SetupBegin(iPhysicsJointSlider);
}
//-----------------------------------------------------------------------
} // namespace hpl

View File

@@ -0,0 +1,87 @@
/* 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.
*/
#ifndef HPL_PHYSICS_JOINT_SLIDER_H
#define HPL_PHYSICS_JOINT_SLIDER_H
#include "hpl1/engine/physics/PhysicsJoint.h"
namespace hpl {
//-----------------------------------
kSaveData_ChildClass(iPhysicsJoint, iPhysicsJointSlider) {
kSaveData_ClassInit(iPhysicsJointSlider) public : float mfMaxDistance;
float mfMinDistance;
cVector3f mvPin;
virtual iSaveObject *CreateSaveObject(cSaveObjectHandler * apSaveObjectHandler, cGame * apGame);
virtual int GetSaveCreatePrio();
};
//-----------------------------------
class iPhysicsJointSlider : public iPhysicsJoint {
typedef iPhysicsJoint super;
public:
iPhysicsJointSlider(const tString &asName, iPhysicsBody *apParentBody, iPhysicsBody *apChildBody,
iPhysicsWorld *apWorld, const cVector3f &avPivotPoint)
: iPhysicsJoint(asName, apParentBody, apChildBody, apWorld, avPivotPoint) {}
virtual ~iPhysicsJointSlider() {}
/**
* Set the maximum distance the bodies can be from each other, relative to the start dist between them
* This is true if pin points towards the child.
* In other words, distance increases as the distance between start pivot and current pivot
* increases in the opposite direction of the pin.
*/
virtual void SetMaxDistance(float afX) = 0;
/**
* Set the minimum distance the bodies can be from each other, relative to the start dist between them
* This is true if pin points towards the child.
*/
virtual void SetMinDistance(float afX) = 0;
virtual float GetMaxDistance() = 0;
virtual float GetMinDistance() = 0;
ePhysicsJointType GetType() { return ePhysicsJointType_Slider; }
// SaveObject implementation
virtual iSaveData *CreateSaveData();
virtual void SaveToSaveData(iSaveData *apSaveData);
virtual void LoadFromSaveData(iSaveData *apSaveData);
virtual void SaveDataSetup(cSaveObjectHandler *apSaveObjectHandler, cGame *apGame);
protected:
float mfMaxDistance;
float mfMinDistance;
cVector3f mvPin;
};
} // namespace hpl
#endif // HPL_PHYSICS_JOINT_SLIDER_H

View File

@@ -0,0 +1,115 @@
/* 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.
*/
#ifndef HPL_PHYSICS_MATERIAL_H
#define HPL_PHYSICS_MATERIAL_H
#include "hpl1/engine/math/MathTypes.h"
namespace hpl {
class iPhysicsWorld;
class cSurfaceData;
//----------------------------------------------------
//! Enum the different combination modes
//! This decides how two material properties are combined when colliding.
//! If the two differ the enum with the highest num.
enum ePhysicsMaterialCombMode {
//! result = (value1 + value2)/2
ePhysicsMaterialCombMode_Average = 0,
//! result = min(value1, value2)
ePhysicsMaterialCombMode_Min = 1,
//! result = value1 * value2
ePhysicsMaterialCombMode_Multiply = 2,
//! result = max(value1, value2)
ePhysicsMaterialCombMode_Max = 3,
//! Internal.
ePhysicsMaterialCombMode_LastEnum
};
//----------------------------------------------------
class cPhysicsContactData {
public:
cPhysicsContactData() {
mfMaxContactNormalSpeed = 0;
mfMaxContactTangentSpeed = 0;
mvContactNormal = cVector3f(0, 0, 0);
mvContactPosition = cVector3f(0, 0, 0);
mvForce = cVector3f(0, 0, 0);
}
float mfMaxContactNormalSpeed;
float mfMaxContactTangentSpeed;
cVector3f mvContactNormal;
cVector3f mvContactPosition;
cVector3f mvForce;
};
//----------------------------------------------------
class iPhysicsMaterial {
public:
iPhysicsMaterial(const tString &asName, iPhysicsWorld *apWorld)
: msName(asName), mpWorld(apWorld), mpSurfaceData(NULL),
mbPreloaded(false) {}
virtual ~iPhysicsMaterial() {}
const tString &GetName() const { return msName; }
virtual void SetElasticity(float afElasticity) = 0;
virtual float GetElasticity() const = 0;
virtual void SetStaticFriction(float afElasticity) = 0;
virtual float GetStaticFriction() const = 0;
virtual void SetKineticFriction(float afElasticity) = 0;
virtual float GetKineticFriction() const = 0;
virtual void SetFrictionCombMode(ePhysicsMaterialCombMode aMode) = 0;
virtual ePhysicsMaterialCombMode GetFrictionCombMode() const = 0;
virtual void SetElasticityCombMode(ePhysicsMaterialCombMode aMode) = 0;
virtual ePhysicsMaterialCombMode GetElasticityCombMode() const = 0;
void SetSurfaceData(cSurfaceData *apData) { mpSurfaceData = apData; }
cSurfaceData *GetSurfaceData() { return mpSurfaceData; }
void SetPreloaded(bool abX) { mbPreloaded = abX; }
bool IsPreloaded() { return mbPreloaded; }
protected:
iPhysicsWorld *mpWorld;
tString msName;
bool mbPreloaded;
cSurfaceData *mpSurfaceData;
};
} // namespace hpl
#endif // HPL_PHYSICS_MATERIAL_H

View File

@@ -0,0 +1,410 @@
/* 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/PhysicsWorld.h"
#include "hpl1/engine/graphics/LowLevelGraphics.h"
#include "hpl1/engine/math/Math.h"
#include "hpl1/engine/physics/CharacterBody.h"
#include "hpl1/engine/physics/CollideShape.h"
#include "hpl1/engine/physics/PhysicsBody.h"
#include "hpl1/engine/physics/PhysicsController.h"
#include "hpl1/engine/physics/PhysicsJoint.h"
#include "hpl1/engine/physics/PhysicsMaterial.h"
#include "hpl1/engine/physics/SurfaceData.h"
#include "hpl1/engine/scene/PortalContainer.h"
#include "hpl1/engine/scene/World3D.h"
#include "hpl1/engine/system/System.h"
#include "hpl1/engine/system/low_level_system.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
iPhysicsWorld::iPhysicsWorld() {
mbLogDebug = false;
mbSaveContactPoints = false;
}
//-----------------------------------------------------------------------
iPhysicsWorld::~iPhysicsWorld() {
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void iPhysicsWorld::Update(float afTimeStep) {
// Clear all contact points.
mvContactPoints.clear();
////////////////////////////////////
// Update controllers
tPhysicsControllerListIt CtrlIt = mlstControllers.begin();
for (; CtrlIt != mlstControllers.end(); ++CtrlIt) {
iPhysicsController *pCtrl = *CtrlIt;
pCtrl->Update(afTimeStep);
}
////////////////////////////////////
// Update character bodies
// unsigned int lTime = GetApplicationTime();
tCharacterBodyListIt CharIt = mlstCharBodies.begin();
for (; CharIt != mlstCharBodies.end(); ++CharIt) {
iCharacterBody *pBody = *CharIt;
// for(int i=0; i<20; ++i)
{
pBody->Update(afTimeStep); // 20.0f);
}
}
// LogUpdate(" Updating chars took %d ms\n",mpWorld3D->GetSystem()->GetLowLevel()->GetTime() - lTime);
////////////////////////////////////
// Update the rigid bodies before simulation.
tPhysicsBodyListIt BodyIt = mlstBodies.begin();
for (; BodyIt != mlstBodies.end(); ++BodyIt) {
iPhysicsBody *pBody = *BodyIt;
pBody->UpdateBeforeSimulate(afTimeStep);
}
////////////////////////////////////
// Simulate the physics
// lTime = GetApplicationTime();
Simulate(afTimeStep);
// LogUpdate(" Updating lowlevel physics took %d ms\n",mpWorld3D->GetSystem()->GetLowLevel()->GetTime() - lTime);
////////////////////////////////////
// Update the joints after simulation.
tPhysicsJointListIt JointIt = mlstJoints.begin();
for (; JointIt != mlstJoints.end();) {
iPhysicsJoint *pJoint = *JointIt;
pJoint->OnPhysicsUpdate();
if (pJoint->CheckBreakage()) {
JointIt = mlstJoints.erase(JointIt);
hplDelete(pJoint);
} else {
++JointIt;
}
}
////////////////////////////////////
// Update the rigid bodies after simulation.
BodyIt = mlstBodies.begin();
for (; BodyIt != mlstBodies.end(); ++BodyIt) {
iPhysicsBody *pBody = *BodyIt;
pBody->UpdateAfterSimulate(afTimeStep);
}
}
//-----------------------------------------------------------------------
void iPhysicsWorld::DestroyShape(iCollideShape *apShape) {
apShape->DecUserCount();
if (apShape->HasUsers() == false) {
STLFindAndDelete(mlstShapes, apShape);
}
}
//-----------------------------------------------------------------------
void iPhysicsWorld::DestroyBody(iPhysicsBody *apBody) {
// STLFindAndDelete(mlstBodies, apBody);
tPhysicsBodyListIt it = mlstBodies.begin();
for (; it != mlstBodies.end(); ++it) {
iPhysicsBody *pBody = *it;
if (pBody == apBody) {
if (mpWorld3D)
mpWorld3D->GetPortalContainer()->RemoveEntity(pBody);
pBody->Destroy();
hplDelete(pBody);
mlstBodies.erase(it);
return;
}
}
}
iPhysicsBody *iPhysicsWorld::GetBody(const tString &asName) {
return (iPhysicsBody *)STLFindByName(mlstBodies, asName);
}
cPhysicsBodyIterator iPhysicsWorld::GetBodyIterator() {
return cPhysicsBodyIterator(&mlstBodies);
}
//-----------------------------------------------------------------------
void iPhysicsWorld::GetBodiesInBV(cBoundingVolume *apBV, tPhysicsBodyList *apBodyList) {
tPhysicsBodyListIt BodyIt = mlstBodies.begin();
for (; BodyIt != mlstBodies.end(); ++BodyIt) {
iPhysicsBody *pBody = *BodyIt;
if (pBody->GetMass() > 0 && cMath::CheckCollisionBV(*apBV, *pBody->GetBV())) {
apBodyList->push_back(pBody);
}
}
}
void iPhysicsWorld::EnableBodiesInBV(cBoundingVolume *apBV, bool abEnabled) {
tPhysicsBodyListIt BodyIt = mlstBodies.begin();
for (; BodyIt != mlstBodies.end(); ++BodyIt) {
iPhysicsBody *pBody = *BodyIt;
if (pBody->GetMass() > 0 && cMath::CheckCollisionBV(*apBV, *pBody->GetBV())) {
// quick fix for oscillation, might skip
// if(pBody->GetJointNum()>0 && pBody->GetJoint(0)->GetLimitAutoSleep()) continue;
pBody->SetEnabled(abEnabled);
}
}
}
//-----------------------------------------------------------------------
void iPhysicsWorld::DestroyJoint(iPhysicsJoint *apJoint) {
STLFindAndDelete(mlstJoints, apJoint);
}
iPhysicsJoint *iPhysicsWorld::GetJoint(const tString &asName) {
return (iPhysicsJoint *)STLFindByName(mlstJoints, asName);
}
cPhysicsJointIterator iPhysicsWorld::GetJointIterator() {
return cPhysicsJointIterator(&mlstJoints);
}
//-----------------------------------------------------------------------
void iPhysicsWorld::DestroyCharacterBody(iCharacterBody *apBody) {
STLFindAndDelete(mlstCharBodies, apBody);
}
iPhysicsBody *iPhysicsWorld::GetCharacterBody(const tString &asName) {
return (iPhysicsBody *)STLFindByName(mlstCharBodies, asName);
}
//-----------------------------------------------------------------------
iPhysicsMaterial *iPhysicsWorld::GetMaterialFromName(const tString &asName) {
tPhysicsMaterialMapIt it = m_mapMaterials.find(asName);
if (it == m_mapMaterials.end()) {
return NULL;
}
iPhysicsMaterial *pMaterial = it->second;
if (pMaterial->IsPreloaded() == false && pMaterial->GetSurfaceData()) {
pMaterial->SetPreloaded(true);
pMaterial->GetSurfaceData()->PreloadData();
}
return pMaterial;
}
//-----------------------------------------------------------------------
cPhysicsMaterialIterator iPhysicsWorld::GetMaterialIterator() {
return cPhysicsMaterialIterator(&m_mapMaterials);
}
//-----------------------------------------------------------------------
void iPhysicsWorld::DestroyAll() {
STLDeleteAll(mlstCharBodies);
// Bodies
tPhysicsBodyListIt it = mlstBodies.begin();
for (; it != mlstBodies.end(); ++it) {
iPhysicsBody *pBody = *it;
pBody->Destroy();
hplDelete(pBody);
}
mlstBodies.clear();
STLDeleteAll(mlstShapes);
STLDeleteAll(mlstJoints);
STLDeleteAll(mlstControllers);
STLMapDeleteAll(m_mapMaterials);
}
//-----------------------------------------------------------------------
void iPhysicsWorld::AddSaveData(cSaveDataHandler *apHandler) {
////////////////////////////////
// Add all bodies
tPhysicsBodyListIt BodyIt = mlstBodies.begin();
for (; BodyIt != mlstBodies.end(); ++BodyIt) {
iPhysicsBody *pBody = *BodyIt;
if (pBody->IsSaved()) {
iSaveData *pData = pBody->CreateSaveData();
pBody->SaveToSaveData(pData);
apHandler->Add(pData);
}
}
////////////////////////////////
// Add all character bodies
tCharacterBodyListIt CharIt = mlstCharBodies.begin();
for (; CharIt != mlstCharBodies.end(); ++CharIt) {
iCharacterBody *pBody = *CharIt;
if (pBody->IsSaved()) {
iSaveData *pData = pBody->CreateSaveData();
pBody->SaveToSaveData(pData);
apHandler->Add(pData);
}
}
////////////////////////////////
// Add all joints
tPhysicsJointListIt JointIt = mlstJoints.begin();
for (; JointIt != mlstJoints.end(); ++JointIt) {
iPhysicsJoint *pJoint = *JointIt;
if (pJoint->IsSaved()) {
iSaveData *pData = pJoint->CreateSaveData();
pJoint->SaveToSaveData(pData);
apHandler->Add(pData);
}
}
}
//-----------------------------------------------------------------------
void iPhysicsWorld::DestroyController(iPhysicsController *apController) {
STLFindAndDelete(mlstControllers, apController);
}
//-----------------------------------------------------------------------
void iPhysicsWorld::RenderContactPoints(iLowLevelGraphics *apLowLevel, const cColor &aPointColor,
const cColor &aLineColor) {
for (size_t i = 0; i < mvContactPoints.size(); i++) {
apLowLevel->DrawSphere(mvContactPoints[i].mvPoint, 0.2f, aPointColor);
apLowLevel->DrawLine(mvContactPoints[i].mvPoint,
mvContactPoints[i].mvNormal * mvContactPoints[i].mfDepth * 0.2f,
aLineColor);
// Log("Rendering\n");
}
}
//-----------------------------------------------------------------------
bool iPhysicsWorld::CheckShapeWorldCollision(cVector3f *apNewPos,
iCollideShape *apShape, const cMatrixf &a_mtxTransform,
iPhysicsBody *apSkipBody, bool abSkipStatic, bool abIsCharacter,
iPhysicsWorldCollisionCallback *apCallback,
bool abCollideCharacter,
bool abDebug) {
cCollideData collideData;
cVector3f vPushVec(0, 0, 0);
bool bCollide = false;
cBoundingVolume boundingVolume = apShape->GetBoundingVolume();
boundingVolume.SetTransform(cMath::MatrixMul(a_mtxTransform, boundingVolume.GetTransform()));
// Log("MAIN Position: %s Size: %s\n",boundingVolume.GetWorldCenter().ToString().c_str(),
// boundingVolume.GetSize().ToString().c_str());
// if(abDebug)Log("--------------\n");
// tPhysicsBodyListIt it = mlstBodies.begin();
// for(; it != mlstBodies.end(); ++it)
cPortalContainerEntityIterator entIt = mpWorld3D->GetPortalContainer()->GetEntityIterator(&boundingVolume);
while (entIt.HasNext()) {
// iPhysicsBody *pBody = *it;
iPhysicsBody *pBody = static_cast<iPhysicsBody *>(entIt.Next());
// if(abDebug) Log("Checking %s\n",pBody->GetName().c_str());
if (pBody->IsCharacter() && abCollideCharacter == false)
continue;
if (pBody->IsActive() == false)
continue;
if (pBody == apSkipBody)
continue;
if (abSkipStatic && pBody->GetMass() == 0)
continue;
if (abIsCharacter && pBody->GetCollideCharacter() == false)
continue;
if (abIsCharacter == false && pBody->GetCollide() == false)
continue;
if (cMath::CheckCollisionBV(boundingVolume, *pBody->GetBV()) == false) {
// if(abDebug) Log(" BV not collided\n");
continue;
}
collideData.SetMaxSize(32);
bool bRet = CheckShapeCollision(apShape, a_mtxTransform, pBody->GetShape(), pBody->GetLocalMatrix(),
collideData, 32, true);
if (bRet) {
// if(abDebug) Log(" Collided with '%s'\n",pBody->GetName().c_str());
if (apCallback)
apCallback->OnCollision(pBody, &collideData);
for (int i = 0; i < collideData.mlNumOfPoints; i++) {
cCollidePoint &point = collideData.mvContactPoints[i];
cVector3f vPush = point.mvNormal * point.mfDepth;
if (ABS(vPushVec.x) < ABS(vPush.x))
vPushVec.x = vPush.x;
if (ABS(vPushVec.y) < ABS(vPush.y))
vPushVec.y = vPush.y;
if (ABS(vPushVec.z) < ABS(vPush.z))
vPushVec.z = vPush.z;
}
bCollide = true;
}
}
// Log("--------------\n");
if (apNewPos)
*apNewPos = a_mtxTransform.GetTranslation() + vPushVec;
return bCollide;
}
//-----------------------------------------------------------------------
} // namespace hpl

View File

@@ -0,0 +1,273 @@
/* 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.
*/
#ifndef HPL_PHYSICS_WORLD_H
#define HPL_PHYSICS_WORLD_H
#include "hpl1/engine/graphics/GraphicsTypes.h"
#include "hpl1/engine/math/MathTypes.h"
#include "hpl1/engine/system/SystemTypes.h"
#include "common/stablemap.h"
#include "hpl1/engine/physics/CollideData.h"
#include "hpl1/engine/game/SaveGame.h"
namespace hpl {
class iCollideShape;
class iVertexBuffer;
class iPhysicsBody;
class iLowLevelGraphics;
class iPhysicsMaterial;
class iCharacterBody;
class iPhysicsJoint;
class iPhysicsJointBall;
class iPhysicsJointHinge;
class iPhysicsJointScrew;
class iPhysicsJointSlider;
class iPhysicsController;
class cWorld3D;
class cBoundingVolume;
typedef Common::List<iCollideShape *> tCollideShapeList;
typedef tCollideShapeList::iterator tCollideShapeListIt;
typedef Common::Array<iCollideShape *> tCollideShapeVec;
typedef tCollideShapeVec::iterator tCollideShapeVecIt;
typedef Common::List<iPhysicsBody *> tPhysicsBodyList;
typedef tPhysicsBodyList::iterator tPhysicsBodyListIt;
typedef Common::List<iPhysicsJoint *> tPhysicsJointList;
typedef tPhysicsJointList::iterator tPhysicsJointListIt;
typedef Common::List<iPhysicsController *> tPhysicsControllerList;
typedef tPhysicsControllerList::iterator tPhysicsControllerListIt;
typedef Common::List<iCharacterBody *> tCharacterBodyList;
typedef tCharacterBodyList::iterator tCharacterBodyListIt;
typedef Common::StableMap<tString, iPhysicsMaterial *> tPhysicsMaterialMap;
typedef tPhysicsMaterialMap::iterator tPhysicsMaterialMapIt;
typedef cSTLMapIterator<iPhysicsMaterial *, tPhysicsMaterialMap, tPhysicsMaterialMapIt> cPhysicsMaterialIterator;
typedef cSTLIterator<iPhysicsBody *, tPhysicsBodyList, tPhysicsBodyListIt> cPhysicsBodyIterator;
typedef cSTLIterator<iPhysicsJoint *, tPhysicsJointList, tPhysicsJointListIt> cPhysicsJointIterator;
enum ePhysicsAccuracy {
ePhysicsAccuracy_Low,
ePhysicsAccuracy_Medium,
ePhysicsAccuracy_High,
ePhysicsAccuracy_LastEnum
};
//----------------------------------------------------
struct cPhysicsRayParams {
constexpr cPhysicsRayParams() {}
float mfT = 0;
float mfDist = 0;
cVector3f mvNormal = {0, 0, 0};
cVector3f mvPoint = {0, 0, 0};
};
class iPhysicsRayCallback {
public:
virtual ~iPhysicsRayCallback() = default;
virtual bool BeforeIntersect(iPhysicsBody *pBody) { return true; }
virtual bool OnIntersect(iPhysicsBody *pBody, cPhysicsRayParams *apParams) = 0;
};
class iPhysicsWorldCollisionCallback {
public:
virtual ~iPhysicsWorldCollisionCallback() = default;
virtual void OnCollision(iPhysicsBody *apBody, cCollideData *apCollideData) = 0;
};
//----------------------------------------------------
class iPhysicsWorld {
public:
iPhysicsWorld();
virtual ~iPhysicsWorld();
//########################################################################################
//! \name General
//########################################################################################
//! @{
void Update(float afTimeStep);
virtual void Simulate(float afTimeStep) = 0;
virtual void SetMaxTimeStep(float afTimeStep) = 0;
virtual float GetMaxTimeStep() = 0;
virtual void SetWorldSize(const cVector3f &avMin, const cVector3f &avMax) = 0;
virtual cVector3f GetWorldSizeMin() = 0;
virtual cVector3f GetWorldSizeMax() = 0;
virtual void SetGravity(const cVector3f &avGravity) = 0;
virtual cVector3f GetGravity() = 0;
virtual void SetAccuracyLevel(ePhysicsAccuracy aAccuracy) = 0;
virtual ePhysicsAccuracy GetAccuracyLevel() = 0;
//! @}
//########################################################################################
//! \name Shapes
//########################################################################################
//! @{
virtual iCollideShape *CreateNullShape() = 0;
virtual iCollideShape *CreateBoxShape(const cVector3f &avSize, cMatrixf *apOffsetMtx) = 0;
virtual iCollideShape *CreateSphereShape(const cVector3f &avRadii, cMatrixf *apOffsetMtx) = 0;
virtual iCollideShape *CreateCylinderShape(float afRadius, float afHeight, cMatrixf *apOffsetMtx) = 0;
virtual iCollideShape *CreateCapsuleShape(float afRadius, float afHeight, cMatrixf *apOffsetMtx) = 0;
virtual iCollideShape *CreateMeshShape(iVertexBuffer *apVtxBuffer) = 0;
virtual iCollideShape *CreateCompundShape(tCollideShapeVec &avShapes) = 0;
void DestroyShape(iCollideShape *apShape);
//! @}
//########################################################################################
//! \name Joints
//########################################################################################
//! @{
virtual iPhysicsJointBall *CreateJointBall(const tString &asName,
const cVector3f &avPivotPoint,
iPhysicsBody *apParentBody, iPhysicsBody *apChildBody) = 0;
virtual iPhysicsJointHinge *CreateJointHinge(const tString &asName,
const cVector3f &avPivotPoint, const cVector3f &avPinDir,
iPhysicsBody *apParentBody, iPhysicsBody *apChildBody) = 0;
virtual iPhysicsJointSlider *CreateJointSlider(const tString &asName,
const cVector3f &avPivotPoint, const cVector3f &avPinDir,
iPhysicsBody *apParentBody, iPhysicsBody *apChildBody) = 0;
virtual iPhysicsJointScrew *CreateJointScrew(const tString &asName,
const cVector3f &avPivotPoint, const cVector3f &avPinDir,
iPhysicsBody *apParentBody, iPhysicsBody *apChildBody) = 0;
void DestroyJoint(iPhysicsJoint *apJoint);
iPhysicsJoint *GetJoint(const tString &asName);
cPhysicsJointIterator GetJointIterator();
//! @}
//########################################################################################
//! \name Materials
//########################################################################################
//! @{
virtual iPhysicsMaterial *CreateMaterial(const tString &asName) = 0;
iPhysicsMaterial *GetMaterialFromName(const tString &asName);
cPhysicsMaterialIterator GetMaterialIterator();
//! @}
//########################################################################################
//! \name Bodies
//########################################################################################
//! @{
virtual iPhysicsBody *CreateBody(const tString &asName, iCollideShape *apShape) = 0;
void DestroyBody(iPhysicsBody *apBody);
iPhysicsBody *GetBody(const tString &asName);
cPhysicsBodyIterator GetBodyIterator();
virtual iCharacterBody *CreateCharacterBody(const tString &asName, const cVector3f &avSize) = 0;
void DestroyCharacterBody(iCharacterBody *apBody);
iPhysicsBody *GetCharacterBody(const tString &asName);
void GetBodiesInBV(cBoundingVolume *apBV, tPhysicsBodyList *apBodyList);
void EnableBodiesInBV(cBoundingVolume *apBV, bool abEnabled);
//! @}
//########################################################################################
//! \name Tools
//########################################################################################
//! @{
void SetLogDebug(bool abX) { mbLogDebug = abX; }
bool GetLogDebug() { return mbLogDebug; }
void AddSaveData(cSaveDataHandler *apHandler);
virtual iPhysicsController *CreateController(const tString &asName) = 0;
void DestroyController(iPhysicsController *apController);
tCollidePointVec *GetContactPoints() { return &mvContactPoints; }
void SetSaveContactPoints(bool abX) { mbSaveContactPoints = abX; }
bool GetSaveContactPoints() { return mbSaveContactPoints; }
void RenderContactPoints(iLowLevelGraphics *apLowLevel, const cColor &aPointColor,
const cColor &aLineColor);
virtual void CastRay(iPhysicsRayCallback *apCallback,
const cVector3f &avOrigin, const cVector3f &avEnd,
bool abCalcDist, bool abCalcNormal, bool abCalcPoint,
bool abUsePrefilter = false) = 0;
virtual void RenderDebugGeometry(iLowLevelGraphics *apLowLevel, const cColor &aColor) = 0;
virtual bool CheckShapeCollision(iCollideShape *apShapeA, const cMatrixf &a_mtxA,
iCollideShape *apShapeB, const cMatrixf &a_mtxB,
cCollideData &aCollideData, int alMaxPoints,
bool correctNormalDirection = false) = 0;
bool CheckShapeWorldCollision(cVector3f *apNewPos,
iCollideShape *apShape, const cMatrixf &a_mtxTransform,
iPhysicsBody *apSkipBody = NULL, bool abSkipStatic = false,
bool abIsCharacter = false,
iPhysicsWorldCollisionCallback *apCallback = NULL,
bool abCollideCharacter = true,
bool abDebug = false);
void DestroyAll();
cWorld3D *GetWorld3D() { return mpWorld3D; }
void SetWorld3D(cWorld3D *apWorld3D) { mpWorld3D = apWorld3D; }
//! @}
protected:
tCollideShapeList mlstShapes;
tPhysicsBodyList mlstBodies;
tCharacterBodyList mlstCharBodies;
tPhysicsMaterialMap m_mapMaterials;
tPhysicsJointList mlstJoints;
tPhysicsControllerList mlstControllers;
cWorld3D *mpWorld3D;
bool mbLogDebug;
tCollidePointVec mvContactPoints;
bool mbSaveContactPoints;
};
} // namespace hpl
#endif // HPL_PHYSICS_WORLD_H

View File

@@ -0,0 +1,598 @@
/* 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

View File

@@ -0,0 +1,202 @@
/* 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.
*/
#ifndef HPL_SURFACE_DATA_H
#define HPL_SURFACE_DATA_H
#include "hpl1/engine/math/MathTypes.h"
#include "hpl1/engine/physics/PhysicsMaterial.h"
namespace hpl {
#define eRollAxisFlag_X 1
#define eRollAxisFlag_Y 2
#define eRollAxisFlag_Z 4
class cPhysics;
class iPhysicsWorld;
class iPhysicsBody;
class cResources;
//----------------------------------------
class cSurfaceImpactData {
friend class cSurfaceData;
public:
float GetMinSpeed() { return mfMinSpeed; }
const tString &GetSoundName() { return msSoundName; }
void SetSoundName(const tString &asName) { msSoundName = asName; }
const tString &GetPSName() { return msPSName; }
void SetPSName(const tString &asName) { msPSName = asName; }
int GetPSPrio() { return mlPSPrio; }
void SetPSPrio(int alPrio) { mlPSPrio = alPrio; }
private:
float mfMinSpeed;
tString msSoundName;
tString msPSName;
int mlPSPrio;
};
typedef Common::Array<cSurfaceImpactData *> tSurfaceImpactDataVec;
typedef tSurfaceImpactDataVec::iterator tSurfaceImpactDataVecIt;
//----------------------------------------
class cSurfaceData {
public:
cSurfaceData(const tString &asName, cPhysics *apPhysics, cResources *apResources);
~cSurfaceData();
const tString &GetName() const { return msName; }
void OnImpact(float afSpeed, const cVector3f &avPos, int alContacts, iPhysicsBody *apBody);
void OnSlide(float afSpeed, const cVector3f &avPos, int alContacts, iPhysicsBody *apBody,
iPhysicsBody *apSlideAgainstBody);
void CreateImpactEffect(float afSpeed, const cVector3f &avPos, int alContacts,
cSurfaceData *apSecondSurface);
void UpdateRollEffect(iPhysicsBody *apBody);
void SetElasticity(float afElasticity);
float GetElasticity() const;
void SetStaticFriction(float afElasticity);
float GetStaticFriction() const;
void SetKineticFriction(float afElasticity);
float GetKineticFriction() const;
void SetPriority(int alPriority);
int GetPriority() const;
void SetFrictionCombMode(ePhysicsMaterialCombMode aMode);
ePhysicsMaterialCombMode GetFrictionCombMode() const;
void SetElasticityCombMode(ePhysicsMaterialCombMode aMode);
ePhysicsMaterialCombMode GetElasticityCombMode() const;
const tString &GetStepType() { return msStepType; }
void GetStepType(const tString &asX) { msStepType = asX; }
void SetMinScrapeSpeed(float afX) { mfMinScrapeSpeed = afX; }
void SetMinScrapeFreq(float afX) { mfMinScrapeFreq = afX; }
void SetMinScrapeFreqSpeed(float afX) { mfMinScrapeFreqSpeed = afX; }
void SetMaxScrapeFreq(float afX) { mfMaxScrapeFreq = afX; }
void SetMaxScrapeFreqSpeed(float afX) { mfMaxScrapeFreqSpeed = afX; }
void SetMiddleScrapeSpeed(float afX) { mfMiddleScrapeSpeed = afX; }
void SetMinScrapeContacts(int alX) { mlMinScrapeContacts = alX; }
void SetScrapeSoundName(const tString &asName) { msScrapeSoundName = asName; }
void SetMinRollSpeed(float afX) { mfMinRollSpeed = afX; }
void SetMinRollFreq(float afX) { mfMinRollFreq = afX; }
void SetMinRollVolume(float afX) { mfMinRollVolume = afX; }
void SetMinRollFreqSpeed(float afX) { mfMinRollFreqSpeed = afX; }
void SetMaxRollFreq(float afX) { mfMaxRollFreq = afX; }
void SetMaxRollVolume(float afX) { mfMaxRollVolume = afX; }
void SetMaxRollFreqSpeed(float afX) { mfMaxRollFreqSpeed = afX; }
void SetMiddleRollSpeed(float afX) { mfMiddleRollSpeed = afX; }
void SetRollSoundName(const tString &asName) { msRollSoundName = asName; }
void SetRollAxisFlags(tFlag aAxisFlags) { mRollAxisFlags = aAxisFlags; }
void PreloadData();
iPhysicsMaterial *ToMaterial(iPhysicsWorld *apWorld);
/**
* This must be added with the largest speed first.
**/
cSurfaceImpactData *CreateImpactData(float afMinSpeed);
cSurfaceImpactData *GetImpactData(int alIdx);
int GetImpactDataNum();
/**
* Gets the the appropriate impact data depending on speed. It gets the data with highest speed not higher than afSpeed
* \param afSpeed The speed value.
* \return
*/
cSurfaceImpactData *GetImpactDataFromSpeed(float afSpeed);
/**
* This must be added with the largest speed first.
**/
cSurfaceImpactData *CreateHitData(float afMinSpeed);
cSurfaceImpactData *GetHitData(int alIdx);
int GetHitDataNum();
/**
* Gets the the appropriate hit data depending on speed. It gets the data with highest speed not higher than afSpeed
* \param afSpeed The speed value.
* \return
*/
cSurfaceImpactData *GetHitDataFromSpeed(float afSpeed);
protected:
cResources *mpResources;
cPhysics *mpPhysics;
tString msName;
// Properties
ePhysicsMaterialCombMode mFrictionMode;
ePhysicsMaterialCombMode mElasticityMode;
float mfElasticity;
float mfStaticFriction;
float mfKineticFriction;
int mlPriority;
float mfMinScrapeSpeed;
float mfMinScrapeFreq;
float mfMinScrapeFreqSpeed;
float mfMaxScrapeFreq;
float mfMaxScrapeFreqSpeed;
float mfMiddleScrapeSpeed;
int mlMinScrapeContacts;
tString msScrapeSoundName;
float mfMinRollSpeed;
float mfMinRollFreq;
float mfMinRollVolume;
float mfMinRollFreqSpeed;
float mfMaxRollFreq;
float mfMaxRollVolume;
float mfMaxRollFreqSpeed;
float mfMiddleRollSpeed;
int mlMinRollContacts;
tString msRollSoundName;
tFlag mRollAxisFlags;
tString msStepType;
tSurfaceImpactDataVec mvImpactData;
tSurfaceImpactDataVec mvHitData;
};
} // namespace hpl
#endif // HPL_SURFACE_DATA_H