implemented cBuoyancy
This commit is contained in:
parent
e9cafe340a
commit
ae69aaf5ce
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
195
src/vehicles/Floater.cpp
Normal 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
45
src/vehicles/Floater.h
Normal 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;
|
Loading…
Reference in New Issue
Block a user