mirror of
https://github.com/GTAmodding/re3.git
synced 2024-11-26 19:53:44 +00:00
185 lines
4.9 KiB
C++
185 lines
4.9 KiB
C++
#include "common.h"
|
|
|
|
#include "Timer.h"
|
|
#include "WaterLevel.h"
|
|
#include "ModelIndices.h"
|
|
#include "Physical.h"
|
|
#include "Vehicle.h"
|
|
#include "Floater.h"
|
|
|
|
cBuoyancy mod_Buoyancy;
|
|
|
|
static float fVolMultiplier = 1.0f;
|
|
// amount of boat volume in bounding box
|
|
// 1.0-volume is the empty space in the bbox
|
|
static float fBoatVolumeDistribution[9] = {
|
|
// rear
|
|
0.75f, 0.9f, 0.75f,
|
|
0.95f, 1.0f, 0.95f,
|
|
0.3f, 0.7f, 0.3f
|
|
// bow
|
|
};
|
|
|
|
bool
|
|
cBuoyancy::ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *point, CVector *impulse)
|
|
{
|
|
m_numSteps = 2.0f;
|
|
|
|
if(!CWaterLevel::GetWaterLevel(phys->GetPosition(), &m_waterlevel, phys->bTouchingWater))
|
|
return false;
|
|
m_matrix = phys->GetMatrix();
|
|
|
|
PreCalcSetup(phys, buoyancy);
|
|
SimpleCalcBuoyancy();
|
|
float f = CalcBuoyancyForce(phys, point, impulse);
|
|
if(m_isBoat)
|
|
return true;
|
|
return f != 0.0f;
|
|
}
|
|
|
|
void
|
|
cBuoyancy::PreCalcSetup(CPhysical *phys, float buoyancy)
|
|
{
|
|
CColModel *colModel;
|
|
|
|
m_isBoat = phys->IsVehicle() && ((CVehicle*)phys)->IsBoat();
|
|
colModel = phys->GetColModel();
|
|
m_dimMin = colModel->boundingBox.min;
|
|
m_dimMax = colModel->boundingBox.max;
|
|
|
|
if(m_isBoat){
|
|
if(phys->GetModelIndex() == MI_PREDATOR){
|
|
m_dimMax.y *= 0.9f;
|
|
m_dimMin.y *= 0.9f;
|
|
}else if(phys->GetModelIndex() == MI_SPEEDER){
|
|
m_dimMax.y *= 1.1f;
|
|
m_dimMin.y *= 0.9f;
|
|
}else if(phys->GetModelIndex() == MI_REEFER){
|
|
m_dimMin.y *= 0.9f;
|
|
}else{
|
|
m_dimMax.y *= 0.9f;
|
|
m_dimMin.y *= 0.9f;
|
|
}
|
|
}
|
|
|
|
m_step = (m_dimMax - m_dimMin)/m_numSteps;
|
|
|
|
if(m_step.z > m_step.x && m_step.z > m_step.y){
|
|
m_stepRatio.x = m_step.x/m_step.z;
|
|
m_stepRatio.y = m_step.y/m_step.z;
|
|
m_stepRatio.z = 1.0f;
|
|
}else if(m_step.y > m_step.x && m_step.y > m_step.z){
|
|
m_stepRatio.x = m_step.x/m_step.y;
|
|
m_stepRatio.y = 1.0f;
|
|
m_stepRatio.z = m_step.z/m_step.y;
|
|
}else{
|
|
m_stepRatio.x = 1.0f;
|
|
m_stepRatio.y = m_step.y/m_step.x;
|
|
m_stepRatio.z = m_step.z/m_step.x;
|
|
}
|
|
|
|
m_haveVolume = false;
|
|
m_numPartialVolumes = 1.0f;
|
|
m_volumeUnderWater = 0.0f;
|
|
m_impulsePoint = CVector(0.0f, 0.0f, 0.0f);
|
|
m_position = phys->GetPosition();
|
|
m_positionZ = CVector(0.0f, 0.0f, m_position.z);
|
|
m_buoyancy = buoyancy;
|
|
m_waterlevel += m_waterLevelInc;
|
|
}
|
|
|
|
void
|
|
cBuoyancy::SimpleCalcBuoyancy(void)
|
|
{
|
|
float x, y;
|
|
int ix, i;
|
|
tWaterLevel waterPosition;
|
|
|
|
// Floater is divided into 3x3 parts. Process and sum each of them
|
|
ix = 0;
|
|
for(x = m_dimMin.x; x <= m_dimMax.x; x += m_step.x){
|
|
i = ix;
|
|
for(y = m_dimMin.y; y <= m_dimMax.y; y += m_step.y){
|
|
CVector waterLevel(x, y, 0.0f);
|
|
FindWaterLevel(m_positionZ, &waterLevel, &waterPosition);
|
|
fVolMultiplier = m_isBoat ? fBoatVolumeDistribution[i] : 1.0f;
|
|
if(waterPosition != FLOATER_ABOVE_WATER)
|
|
SimpleSumBuoyancyData(waterLevel, waterPosition);
|
|
i += 3;
|
|
}
|
|
ix++;
|
|
}
|
|
|
|
m_volumeUnderWater /= (m_dimMax.z - m_dimMin.z)*sq(m_numSteps+1.0f);
|
|
}
|
|
|
|
float
|
|
cBuoyancy::SimpleSumBuoyancyData(CVector &waterLevel, tWaterLevel waterPosition)
|
|
{
|
|
static float fThisVolume;
|
|
static CVector AverageOfWaterLevel;
|
|
static float fFraction;
|
|
static float fRemainingSlice;
|
|
|
|
float submerged = Abs(waterLevel.z - m_dimMin.z);
|
|
// subtract empty space from submerged volume
|
|
fThisVolume = submerged - (1.0f - fVolMultiplier);
|
|
if(fThisVolume < 0.0f)
|
|
return 0.0f;
|
|
|
|
if(m_isBoat){
|
|
fThisVolume *= fVolMultiplier;
|
|
if(fThisVolume < 0.5f)
|
|
fThisVolume = 2.0f*sq(fThisVolume);
|
|
if(fThisVolume < 1.0f)
|
|
fThisVolume = sq(fThisVolume);
|
|
fThisVolume = sq(fThisVolume);
|
|
}
|
|
|
|
m_volumeUnderWater += fThisVolume;
|
|
|
|
AverageOfWaterLevel.x = waterLevel.x * m_stepRatio.x;
|
|
AverageOfWaterLevel.y = waterLevel.y * m_stepRatio.y;
|
|
AverageOfWaterLevel.z = (waterLevel.z+m_dimMin.z)/2.0f * m_stepRatio.z;
|
|
|
|
if(m_flipAverage)
|
|
AverageOfWaterLevel = -AverageOfWaterLevel;
|
|
|
|
fFraction = 1.0f/m_numPartialVolumes;
|
|
fRemainingSlice = 1.0f - fFraction;
|
|
m_impulsePoint = m_impulsePoint*fRemainingSlice + AverageOfWaterLevel*fThisVolume*fFraction;
|
|
m_numPartialVolumes += 1.0f;
|
|
m_haveVolume = true;
|
|
return fThisVolume;
|
|
}
|
|
|
|
void
|
|
cBuoyancy::FindWaterLevel(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition)
|
|
{
|
|
*waterPosition = FLOATER_IN_WATER;
|
|
// waterLevel is a local x,y point
|
|
// m_position is the global position of our floater
|
|
// zpos is the global z coordinate of our floater
|
|
CVector xWaterLevel = Multiply3x3(m_matrix, *waterLevel);
|
|
CWaterLevel::GetWaterLevel(xWaterLevel.x + m_position.x, xWaterLevel.y + m_position.y, m_position.z,
|
|
&waterLevel->z, true);
|
|
waterLevel->z -= xWaterLevel.z + zpos.z; // make local
|
|
if(waterLevel->z > m_dimMax.z){
|
|
waterLevel->z = m_dimMax.z;
|
|
*waterPosition = FLOATER_UNDER_WATER;
|
|
}else if(waterLevel->z < m_dimMin.z){
|
|
waterLevel->z = m_dimMin.z;
|
|
*waterPosition = FLOATER_ABOVE_WATER;
|
|
}
|
|
}
|
|
|
|
bool
|
|
cBuoyancy::CalcBuoyancyForce(CPhysical *phys, CVector *point, CVector *impulse)
|
|
{
|
|
if(!m_haveVolume)
|
|
return false;
|
|
|
|
*point = Multiply3x3(m_matrix, m_impulsePoint);
|
|
*impulse = CVector(0.0f, 0.0f, m_volumeUnderWater*m_buoyancy*CTimer::GetTimeStep());
|
|
return true;
|
|
}
|