implemented cBuoyancy

This commit is contained in:
aap 2019-07-23 22:55:23 +02:00
parent e9cafe340a
commit ae69aaf5ce
5 changed files with 243 additions and 2 deletions

View File

@ -73,7 +73,7 @@ public:
uint32 bRemoveFromWorld : 1;
uint32 bHasHitWall : 1;
uint32 bImBeingRendered : 1;
uint32 m_flagD8 : 1;
uint32 m_flagD8 : 1; // used by cBuoyancy::ProcessBuoyancy
uint32 bIsSubway : 1; // set when subway, but maybe different meaning?
uint32 bDrawLast : 1;
uint32 m_flagD40 : 1;

View File

@ -1240,7 +1240,7 @@ STARTPATCHES
InjectHook(0x554FE0, &CWaterLevel::Shutdown, PATCH_JUMP);
InjectHook(0x555010, &CWaterLevel::CreateWavyAtomic, PATCH_JUMP);
InjectHook(0x5552A0, &CWaterLevel::DestroyWavyAtomic, PATCH_JUMP);
InjectHook(0x5552C0, &CWaterLevel::GetWaterLevel, PATCH_JUMP);
InjectHook(0x5552C0, (bool (*)(float,float,float,float*,bool))&CWaterLevel::GetWaterLevel, PATCH_JUMP);
InjectHook(0x555440, &CWaterLevel::GetWaterLevelNoWaves, PATCH_JUMP);
InjectHook(0x5554E0, &CWaterLevel::RenderWater, PATCH_JUMP);
InjectHook(0x556C30, &CWaterLevel::RenderOneFlatSmallWaterPoly, PATCH_JUMP);

View File

@ -82,6 +82,7 @@ public:
static void CreateWavyAtomic();
static void DestroyWavyAtomic();
static bool GetWaterLevel(float fX, float fY, float fZ, float *pfOutLevel, bool bDontCheckZ);
static bool GetWaterLevel(CVector coors, float *pfOutLevel, bool bDontCheckZ) { return GetWaterLevel(coors.x, coors.y, coors.z, pfOutLevel, bDontCheckZ); }
static bool GetWaterLevelNoWaves(float fX, float fY, float fZ, float *pfOutLevel);
static void RenderWater();
static void RenderOneFlatSmallWaterPoly (float fX, float fY, float fZ, RwRGBA const &color);

195
src/vehicles/Floater.cpp Normal file
View File

@ -0,0 +1,195 @@
#include "common.h"
#include "patcher.h"
#include "Timer.h"
#include "WaterLevel.h"
#include "ModelIndices.h"
#include "Physical.h"
#include "Vehicle.h"
#include "Floater.h"
cBuoyancy &mod_Buoyancy = *(cBuoyancy*)0x8F2674;
//static float fVolMultiplier = 1.0f;
static float &fVolMultiplier = *(float*)0x601394;
// 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 *impulse, CVector *point)
{
m_numSteps = 2.0f;
if(!CWaterLevel::GetWaterLevel(phys->GetPosition(), &m_waterlevel, phys->m_flagD8))
return false;
m_matrix = phys->GetMatrix();
PreCalcSetup(phys, buoyancy);
SimpleCalcBuoyancy();
float f = CalcBuoyancyForce(phys, impulse, point);
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_impulse = 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_impulse = m_impulse*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 *impulse, CVector *point)
{
if(!m_haveVolume)
return false;
*impulse = Multiply3x3(m_matrix, m_impulse);
*point = CVector(0.0f, 0.0f, m_volumeUnderWater*m_buoyancy*CTimer::GetTimeStep());
return true;
}
STARTPATCHES
InjectHook(0x546270, &cBuoyancy::ProcessBuoyancy, PATCH_JUMP);
InjectHook(0x546360, &cBuoyancy::PreCalcSetup, PATCH_JUMP);
InjectHook(0x5466F0, &cBuoyancy::SimpleCalcBuoyancy, PATCH_JUMP);
InjectHook(0x546820, &cBuoyancy::SimpleSumBuoyancyData, PATCH_JUMP);
InjectHook(0x546620, &cBuoyancy::FindWaterLevel, PATCH_JUMP);
InjectHook(0x5465A0, &cBuoyancy::CalcBuoyancyForce, PATCH_JUMP);
ENDPATCHES

45
src/vehicles/Floater.h Normal file
View File

@ -0,0 +1,45 @@
#pragma once
class Physical;
enum tWaterLevel
{
FLOATER_ABOVE_WATER,
FLOATER_IN_WATER,
FLOATER_UNDER_WATER,
};
class cBuoyancy
{
public:
CVector m_position;
CMatrix m_matrix;
int m_field_54;
CVector m_positionZ;
float m_waterlevel;
float m_waterLevelInc;
float m_buoyancy;
CVector m_dimMax;
CVector m_dimMin;
float m_numPartialVolumes;
int m_field_8C;
int m_field_90;
int m_field_94;
bool m_haveVolume;
CVector m_step;
CVector m_stepRatio;
float m_numSteps;
bool m_flipAverage;
char m_field_B9;
bool m_isBoat;
float m_volumeUnderWater;
CVector m_impulse;
bool ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *impulse, CVector *point);
void PreCalcSetup(CPhysical *phys, float buoyancy);
void SimpleCalcBuoyancy(void);
float SimpleSumBuoyancyData(CVector &waterLevel, tWaterLevel waterPosition);
void FindWaterLevel(const CVector &zpos, CVector *waterLevel, tWaterLevel *waterPosition);
bool CalcBuoyancyForce(CPhysical *phys, CVector *impulse, CVector *point);
};
extern cBuoyancy &mod_Buoyancy;