Merge remote-tracking branch 'upstream/miami' into miami

This commit is contained in:
Nikolay Korolev 2020-10-18 20:35:19 +03:00
commit bc42b3a78e
13 changed files with 1272 additions and 708 deletions

File diff suppressed because it is too large Load diff

View file

@ -34,21 +34,23 @@ class CPickup
{
public:
CVector m_vecPos;
uint32 m_nRevenue;
float m_fRevenue;
CObject *m_pObject;
CObject *m_pExtraObject;
uint16 m_nQuantity;
uint32 m_nQuantity;
uint32 m_nTimer;
int16 m_nMoneySpeed;
uint16 m_nMoneySpeed;
int16 m_eModelIndex;
uint16 m_nIndex;
char m_sTextKey[8];
ePickupType m_eType;
bool m_bRemoved;
uint8 m_effects;
uint8 m_effects:1;
uint8 m_effects2:1;
CObject *GiveUsAPickUpObject(int32 handle);
CObject *GiveUsAPickUpObject(CObject **object, CObject **extraObject, int32 handle, int32 extraHandle);
bool Update(CPlayerPed *player, CVehicle *vehicle, int playerId);
void GetRidOfObjects();
private:
bool IsMine() { return m_eType >= PICKUP_MINE_INACTIVE && m_eType <= PICKUP_FLOATINGPACKAGE_FLOATING; }
inline bool CanBePickedUp(CPlayerPed *player, int playerId);
@ -64,8 +66,9 @@ struct tPickupMessage
eWeaponType m_weaponType;
CVector2D m_dist;
CRGBA m_color;
uint8 m_bOutOfStock : 1;
uint8 m_bOutOfStock;
uint8 m_quantity;
uint16 money;
};
class CPickups
@ -111,13 +114,13 @@ public:
static CVector StaticCamCoors;
static uint32 StaticCamStartTime;
//TODO(MIAMI)
static void RemoveAllPickupsOfACertainWeaponGroupWithNoAmmo(eWeaponType) {}
static void RemoveAllPickupsOfACertainWeaponGroupWithNoAmmo(eWeaponType);
static CPickup *FindPickUpForThisObject(CEntity*);
};
extern uint16 AmmoForWeapon[20];
extern uint16 AmmoForWeapon_OnStreet[WEAPONTYPE_TOTALWEAPONS];
extern uint16 CostOfWeapon[20];
extern uint16 AmmoForWeapon[WEAPONTYPE_TOTALWEAPONS + 1];
extern uint16 AmmoForWeapon_OnStreet[WEAPONTYPE_TOTALWEAPONS + 1];
extern uint16 CostOfWeapon[WEAPONTYPE_TOTALWEAPONS + 3];
enum ePacmanPickupType
{

View file

@ -387,10 +387,8 @@ void CReplay::RecordThisFrame(void)
tBulletTracePacket* bt = (tBulletTracePacket*)&Record.m_pBase[Record.m_nOffset];
bt->type = REPLAYPACKET_BULLET_TRACES;
bt->index = i;
bt->frames = CBulletTraces::aTraces[i].m_framesInUse;
bt->lifetime = CBulletTraces::aTraces[i].m_lifeTime;
bt->inf = CBulletTraces::aTraces[i].m_vecCurrentPos;
bt->sup = CBulletTraces::aTraces[i].m_vecTargetPos;
bt->inf = CBulletTraces::aTraces[i].m_vecStartPos;
bt->sup = CBulletTraces::aTraces[i].m_vecEndPos;
Record.m_nOffset += sizeof(*bt);
}
tMiscPacket* misc = (tMiscPacket*)&Record.m_pBase[Record.m_nOffset];
@ -1117,10 +1115,8 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo
{
tBulletTracePacket* pb = (tBulletTracePacket*)&ptr[offset];
CBulletTraces::aTraces[pb->index].m_bInUse = true;
CBulletTraces::aTraces[pb->index].m_framesInUse = pb->frames;
CBulletTraces::aTraces[pb->index].m_lifeTime = pb->lifetime;
CBulletTraces::aTraces[pb->index].m_vecCurrentPos = pb->inf;
CBulletTraces::aTraces[pb->index].m_vecTargetPos = pb->sup;
CBulletTraces::aTraces[pb->index].m_vecStartPos = pb->inf;
CBulletTraces::aTraces[pb->index].m_vecEndPos = pb->sup;
buffer->m_nOffset += sizeof(tBulletTracePacket);
break;
}

View file

@ -31,6 +31,7 @@
#include "GameLogic.h"
#include "Garages.h"
#include "General.h"
#include "Glass.h"
#ifdef MISSION_REPLAY
#include "GenericGameStorage.h"
#endif
@ -1804,9 +1805,8 @@ void CMissionCleanup::Process()
if (!CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle)
TheCamera.Restore();
TheCamera.SetWideScreenOff();
// TODO(MIAMI)
//CSpecialFX::bLiftCam = false;
//CSpecialFX::bVideoCam = false;
CSpecialFX::bLiftCam = false;
CSpecialFX::bVideoCam = false;
CTimeCycle::StopExtraColour(0);
for (int i = 0; i < MISSION_AUDIO_SLOTS; i++)
DMAudio.ClearMissionAudio(i);
@ -12404,7 +12404,7 @@ int8 CRunningScript::ProcessCommands1200To1299(int32 command)
case COMMAND_SWITCH_SECURITY_CAMERA:
{
CollectParameters(&m_nIp, 1);
debug("SWITCH_SECURITY_CAMERA is not implemented\n"); // TODO(MIAMI)
CSpecialFX::bVideoCam = ScriptParams[0] != 0;
return 0;
}
//case COMMAND_IS_CHAR_IN_FLYING_VEHICLE:
@ -12844,7 +12844,7 @@ int8 CRunningScript::ProcessCommands1200To1299(int32 command)
case COMMAND_SWITCH_LIFT_CAMERA:
{
CollectParameters(&m_nIp, 1);
debug("SWITCH_LIFT_CAMERA is not implemented\n"); // TODO(MIAMI)
CSpecialFX::bLiftCam = ScriptParams[0] != 0;
return 0;
}
case COMMAND_CLOSE_ALL_CAR_DOORS:
@ -13013,12 +13013,12 @@ int8 CRunningScript::ProcessCommands1300To1399(int32 command)
case COMMAND_HAS_GLASS_BEEN_SHATTERED_NEARBY:
{
CollectParameters(&m_nIp, 3);
static bool bShowed = false;
if (!bShowed) {
debug("HAS_GLASS_BEEN_SHATTERED_NEARBY not implemented, default to TRUE\n"); // TODO(MIAMI)
bShowed = true;
}
UpdateCompareFlag(true);
bool shattered = false;
if ( CGlass::HasGlassBeenShatteredAtCoors(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2]) )
shattered = true;
UpdateCompareFlag(shattered);
return 0;
}
case COMMAND_ATTACH_CUTSCENE_OBJECT_TO_BONE:

View file

@ -5,6 +5,7 @@
#include "DMAudio.h"
#include "Record.h"
#include "Timer.h"
#include "SpecialFX.h"
uint32 CTimer::m_snTimeInMilliseconds;
PauseModeTime CTimer::m_snTimeInMillisecondsPauseMode = 1;
@ -141,7 +142,7 @@ void CTimer::Update(void)
}
}
if ( ms_fTimeStep < 0.01f && !GetIsPaused() )
if ( ms_fTimeStep < 0.01f && !GetIsPaused() && !CSpecialFX::bSnapShotActive)
ms_fTimeStep = 0.01f;
ms_fTimeStepNonClipped = ms_fTimeStep;

View file

@ -969,7 +969,7 @@ Render2dStuff(void)
else
CHud::Draw();
// TODO(Miami)
// CSpecialFX::Render2DFXs();
CSpecialFX::Render2DFXs();
CUserDisplay::OnscnTimer.ProcessForDisplay();
CMessages::Display();
CDarkel::DrawMessages();

View file

@ -40,10 +40,10 @@ CWeaponModelInfo::SetWeaponInfo(int32 weaponId)
m_atomics[2] = (RpAtomic*)weaponId;
}
int32
eWeaponType
CWeaponModelInfo::GetWeaponInfo(void)
{
return (int32)(uintptr)m_atomics[2];
return (eWeaponType)(uintptr)m_atomics[2];
}
void

View file

@ -1,6 +1,7 @@
#pragma once
#include "SimpleModelInfo.h"
#include "WeaponType.h"
class CWeaponModelInfo : public CSimpleModelInfo
{
@ -18,5 +19,5 @@ public:
void Init(void);
void SetWeaponInfo(int32 weaponId);
int32 GetWeaponInfo(void);
eWeaponType GetWeaponInfo(void);
};

View file

@ -14,6 +14,7 @@
#include "AnimBlendClumpData.h"
#include "AnimBlendAssociation.h"
#include "Fire.h"
#include "Glass.h"
#include "DMAudio.h"
#include "General.h"
#include "SurfaceTable.h"
@ -5865,7 +5866,7 @@ CPed::FightStrike(CVector &touchedNodePos, bool fightWithWeapon)
if (m_fightState == FIGHTSTATE_JUST_ATTACKED)
return false;
// TODO(Miami): BreakGlassPhysically
CGlass::BreakGlassPhysically(touchedNodePos, radius);
for (int i = 0; i < m_numNearPeds; i++) {
int8 pedFound = 0;
@ -15403,7 +15404,7 @@ CPed::ProcessObjective(void)
CVector distance = m_nextRoutePointPos - GetPosition();
distance.z = 0.0f;
if (m_objective == OBJECTIVE_GOTO_SHELTER_ON_FOOT) {
if (m_nMoveState == PEDMOVE_RUN && distance.Magnitude() < SQR(2.0f)) {
if (m_nMoveState == PEDMOVE_RUN && distance.MagnitudeSqr() < SQR(2.0f)) {
SetMoveState(PEDMOVE_WALK);
bIsRunning = false;
}
@ -15413,7 +15414,7 @@ CPed::ProcessObjective(void)
}
}
else if (m_objective == OBJECTIVE_GOTO_ICE_CREAM_VAN_ON_FOOT) {
if (m_nMoveState == PEDMOVE_RUN && distance.Magnitude() < SQR(4.0f)) {
if (m_nMoveState == PEDMOVE_RUN && distance.MagnitudeSqr() < SQR(4.0f)) {
SetMoveState(PEDMOVE_WALK);
bIsRunning = false;
}

View file

@ -3,6 +3,8 @@
#include "Glass.h"
#include "Timer.h"
#include "Object.h"
#include "Vehicle.h"
#include "Pools.h"
#include "General.h"
#include "AudioScriptObject.h"
#include "World.h"
@ -14,6 +16,7 @@
#include "ModelIndices.h"
#include "main.h"
#include "soundlist.h"
#include "SurfaceTable.h"
uint32 CGlass::NumGlassEntities;
@ -57,17 +60,17 @@ const CVector2D CoorsWithTriangle[NUM_GLASSTRIANGLES][3] =
#define TEMPBUFFERVERTHILIGHTOFFSET 0
#define TEMPBUFFERINDEXHILIGHTOFFSET 0
#define TEMPBUFFERVERTHILIGHTSIZE 128
#define TEMPBUFFERVERTHILIGHTSIZE 256
#define TEMPBUFFERINDEXHILIGHTSIZE 512
#define TEMPBUFFERVERTSHATTEREDOFFSET TEMPBUFFERVERTHILIGHTSIZE
#define TEMPBUFFERINDEXSHATTEREDOFFSET TEMPBUFFERINDEXHILIGHTSIZE
#define TEMPBUFFERVERTSHATTEREDSIZE 192
#define TEMPBUFFERVERTSHATTEREDSIZE 384
#define TEMPBUFFERINDEXSHATTEREDSIZE 768
#define TEMPBUFFERVERTREFLECTIONOFFSET TEMPBUFFERVERTSHATTEREDSIZE
#define TEMPBUFFERINDEXREFLECTIONOFFSET TEMPBUFFERINDEXSHATTEREDSIZE
#define TEMPBUFFERVERTREFLECTIONSIZE 256
#define TEMPBUFFERVERTREFLECTIONSIZE 512
#define TEMPBUFFERINDEXREFLECTIONSIZE 1024
int32 TempBufferIndicesStoredHiLight = 0;
@ -83,9 +86,15 @@ CFallingGlassPane::Update(void)
if ( CTimer::GetTimeInMilliseconds() >= m_nTimer )
{
// Apply MoveSpeed
if ( m_bCarGlass )
GetPosition() += m_vecMoveSpeed * CTimer::GetTimeStep() * 0.35f;
else
GetPosition() += m_vecMoveSpeed * CTimer::GetTimeStep();
// Apply Gravity
if ( m_bCarGlass )
m_vecMoveSpeed.z -= 0.01f * CTimer::GetTimeStep();
else
m_vecMoveSpeed.z -= 0.02f * CTimer::GetTimeStep();
// Apply TurnSpeed
@ -106,6 +115,8 @@ CFallingGlassPane::Update(void)
RwRGBA color = { 255, 255, 255, 255 };
if ( !m_bCarGlass )
{
static int32 nFrameGen = 0;
for ( int32 i = 0; i < 4; i++ )
@ -128,6 +139,7 @@ CFallingGlassPane::Update(void)
}
}
}
}
void
CFallingGlassPane::Render(void)
@ -147,6 +159,9 @@ CFallingGlassPane::Render(void)
// HiLight Polys
if ( m_bCarGlass && color < 64 )
color = 64;
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], color, color, color, color);
@ -186,9 +201,9 @@ CFallingGlassPane::Render(void)
if ( TempBufferIndicesStoredShattered >= TEMPBUFFERINDEXSHATTEREDSIZE-7 || TempBufferVerticesStoredShattered >= TEMPBUFFERVERTSHATTEREDSIZE-4 )
CGlass::RenderShatteredPolys();
uint8 shatteredColor = 255;
uint8 shatteredColor = 140;
if ( distToCamera > 30.0f )
shatteredColor = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 255);
shatteredColor = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 140);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], shatteredColor, shatteredColor, shatteredColor, shatteredColor);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], shatteredColor, shatteredColor, shatteredColor, shatteredColor);
@ -292,8 +307,8 @@ CGlass::FindFreePane(void)
}
void
CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector point,
float moveSpeed, bool cracked, bool explosion)
CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector center,
float moveSpeed, bool cracked, bool explosion, int32 stepmul, bool carGlass)
{
float upLen = up.Magnitude();
float rightLen = right.Magnitude();
@ -304,10 +319,10 @@ CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector rig
float rightSteps = rightLen + 0.75f;
if ( rightSteps < 1.0f ) rightSteps = 1.0f;
uint32 ysteps = (uint32)upSteps;
uint32 ysteps = stepmul * (uint32)upSteps;
if ( ysteps > 3 ) ysteps = 3;
uint32 xsteps = (uint32)rightSteps;
uint32 xsteps = stepmul * (uint32)rightSteps;
if ( xsteps > 3 ) xsteps = 3;
if ( explosion )
@ -338,11 +353,8 @@ CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector rig
pane->m_nTriIndex = i;
pane->GetRight() = (right * rightScl) / rightLen;
#ifdef FIX_BUGS
pane->GetUp() = (up * upScl) / upLen;
#else
pane->GetUp() = (up * upScl) / rightLen; // copypaste bug
#endif
CVector fwd = CrossProduct(pane->GetRight(), pane->GetUp());
fwd.Normalise();
@ -358,7 +370,7 @@ CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector rig
if ( moveSpeed != 0.0f )
{
CVector dist = pane->GetPosition() - point;
CVector dist = pane->GetPosition() - center;
dist.Normalise();
pane->m_vecMoveSpeed += moveSpeed * dist;
@ -371,10 +383,11 @@ CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector rig
switch ( type )
{
case 0:
case 2:
pane->m_nTimer = CTimer::GetTimeInMilliseconds();
break;
case 1:
float dist = (pane->GetPosition() - point).Magnitude();
float dist = (pane->GetPosition() - center).Magnitude();
pane->m_nTimer = uint32(dist*100 + CTimer::GetTimeInMilliseconds());
break;
}
@ -382,6 +395,7 @@ CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector rig
pane->m_fGroundZ = groundZ;
pane->m_bShattered = cracked;
pane->m_fStep = upLen / float(ysteps);
pane->m_bCarGlass = carGlass;
pane->m_bActive = true;
}
}
@ -613,10 +627,12 @@ CGlass::WindowRespondsToCollision(CEntity *entity, float amount, CVector speed,
CColModel *col = object->GetColModel();
ASSERT(col!=nil);
CVector a = object->GetMatrix() * col->vertices[0].Get();
CVector b = object->GetMatrix() * col->vertices[1].Get();
CVector c = object->GetMatrix() * col->vertices[2].Get();
CVector d = object->GetMatrix() * col->vertices[3].Get();
if ( col->numTriangles == 2 )
{
CVector a = col->vertices[0].Get();
CVector b = col->vertices[1].Get();
CVector c = col->vertices[2].Get();
CVector d = col->vertices[3].Get();
float minx = Min(Min(a.x, b.x), Min(c.x, d.x));
float maxx = Max(Max(a.x, b.x), Max(c.x, d.x));
@ -625,30 +641,34 @@ CGlass::WindowRespondsToCollision(CEntity *entity, float amount, CVector speed,
float minz = Min(Min(a.z, b.z), Min(c.z, d.z));
float maxz = Max(Max(a.z, b.z), Max(c.z, d.z));
CVector pa = object->GetMatrix() * CVector(minx, miny, minz);
CVector pb = object->GetMatrix() * CVector(maxx, maxy, minz);
if ( amount > 300.0f )
{
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_L, object->GetPosition());
GeneratePanesForWindow(0,
CVector(minx, miny, minz),
pa,
CVector(0.0f, 0.0f, maxz-minz),
CVector(maxx-minx, maxy-miny, 0.0f),
speed, point, 0.1f, !!object->bGlassCracked, explosion);
pb - pa,
speed, point, 0.1f, !!object->bGlassCracked, explosion, 1, false);
}
else
{
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_S, object->GetPosition());
GeneratePanesForWindow(1,
CVector(minx, miny, minz),
pa,
CVector(0.0f, 0.0f, maxz-minz),
CVector(maxx-minx, maxy-miny, 0.0f),
speed, point, 0.1f, !!object->bGlassCracked, explosion);
pb - pa,
speed, point, 0.1f, !!object->bGlassCracked, explosion, 1, false);
}
}
object->bGlassBroken = true;
object->GetMatrix().GetPosition().z = -100.0f;
object->bIsVisible = false;
object->bUsesCollision = true;
}
void
@ -658,7 +678,7 @@ CGlass::WindowRespondsToSoftCollision(CEntity *entity, float amount)
CObject *object = (CObject *)entity;
if ( amount > 50.0f && !object->bGlassCracked )
if ( entity->bUsesCollision && amount > 50.0f && !object->bGlassCracked )
{
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_CRACK, object->GetPosition());
object->bGlassCracked = true;
@ -673,6 +693,8 @@ CGlass::WasGlassHitByBullet(CEntity *entity, CVector point)
CObject *object = (CObject *)entity;
if ( IsGlass(object->GetModelIndex()) )
{
if ( object->bUsesCollision )
{
if ( !object->bGlassCracked )
{
@ -686,6 +708,7 @@ CGlass::WasGlassHitByBullet(CEntity *entity, CVector point)
}
}
}
}
void
CGlass::WindowRespondsToExplosion(CEntity *entity, CVector point)
@ -694,6 +717,8 @@ CGlass::WindowRespondsToExplosion(CEntity *entity, CVector point)
CObject *object = (CObject *)entity;
if ( object->bUsesCollision )
{
CVector distToGlass = object->GetPosition() - point;
float fDistToGlass = distToGlass.Magnitude();
@ -709,3 +734,286 @@ CGlass::WindowRespondsToExplosion(CEntity *entity, CVector point)
object->bGlassCracked = true;
}
}
}
void
CGlass::CarWindscreenShatters(CVehicle *vehicle, bool unk)
{
ASSERT(vehicle!=nil);
CColModel *col = vehicle->GetColModel();
ASSERT(col!=nil);
if ( col->numTriangles < 2 )
return;
CColTriangle *tria = nil;
int32 triIndex = -1;
CColTriangle *trib = nil;
for ( int32 i = 0; i < col->numTriangles; i++ )
{
CColTriangle *tri = &col->triangles[i];
if ( tri->surface == SURFACE_GLASS )
{
if ( tria )
{
trib = tri;
break;
}
triIndex = i;
tria = tri;
}
}
if ( trib == nil )
return;
CCollision::CalculateTrianglePlanes(col);
CColTrianglePlane *triPlanes = col->trianglePlanes;
if ( triPlanes == nil )
return;
CVector planeNormal;
triPlanes[triIndex].GetNormal(planeNormal);
planeNormal = Multiply3x3(vehicle->GetMatrix(), planeNormal);
CVector vec1 = CrossProduct(vehicle->GetRight(), planeNormal);
vec1.Normalise();
CVector vec2 = CrossProduct(planeNormal, vehicle->GetUp());
vec2.Normalise();
CVector v[6];
float proj1[6];
float proj2[6];
v[0] = col->vertices[tria->a].Get();
v[1] = col->vertices[tria->b].Get();
v[2] = col->vertices[tria->c].Get();
v[3] = col->vertices[trib->a].Get();
v[4] = col->vertices[trib->b].Get();
v[5] = col->vertices[trib->c].Get();
v[0] = vehicle->GetMatrix() * v[0];
v[1] = vehicle->GetMatrix() * v[1];
v[2] = vehicle->GetMatrix() * v[2];
v[3] = vehicle->GetMatrix() * v[3];
v[4] = vehicle->GetMatrix() * v[4];
v[5] = vehicle->GetMatrix() * v[5];
proj1[0] = DotProduct(v[0], vec1);
proj2[0] = DotProduct(v[0], vec2);
proj1[1] = DotProduct(v[1], vec1);
proj2[1] = DotProduct(v[1], vec2);
proj1[2] = DotProduct(v[2], vec1);
proj2[2] = DotProduct(v[2], vec2);
proj1[3] = DotProduct(v[3], vec1);
proj2[3] = DotProduct(v[3], vec2);
proj1[4] = DotProduct(v[4], vec1);
proj2[4] = DotProduct(v[4], vec2);
proj1[5] = DotProduct(v[5], vec1);
proj2[5] = DotProduct(v[5], vec2);
int32 originIndex = 0;
float max1 = proj1[0];
float max2 = proj2[0];
float origin = proj1[0] + proj2[0];
for ( int32 i = 1; i < 6; i++ )
{
float o = proj1[i] + proj2[i];
if ( o < origin )
{
origin = o;
originIndex = i;
}
if ( proj1[i] > max1 )
max1 = proj1[i];
if ( proj2[i] > max2 )
max2 = proj2[i];
}
float bound1 = max1 - proj1[originIndex];
float bound2 = max2 - proj2[originIndex];
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_L, vehicle->GetPosition());
CVector center = v[originIndex] + ((0.5f*bound1) * vec1) + ((0.5f*bound2) * vec2);
CVector speed = vehicle->m_vecMoveSpeed;
CVector right = bound2 * vec2;
CVector up = bound1 * vec1;
CVector pos = v[originIndex];
GeneratePanesForWindow(2, pos, up, right, speed, center, 0.1f, false, false, 2, true);
}
bool
CGlass::HasGlassBeenShatteredAtCoors(float x, float y, float z)
{
CEntity *entity = nil;
float dist = 20.0f;
int32 nStartX = Max(CWorld::GetSectorIndexX(x - 30.0f), 0);
int32 nStartY = Max(CWorld::GetSectorIndexY(y - 30.0f), 0);
int32 nEndX = Min(CWorld::GetSectorIndexX(x + 30.0f), NUMSECTORS_X-1);
int32 nEndY = Min(CWorld::GetSectorIndexY(y + 30.0f), NUMSECTORS_Y-1);
CWorld::AdvanceCurrentScanCode();
for ( int32 y = nStartY; y <= nEndY; y++ )
{
for ( int32 x = nStartX; x <= nEndX; x++ )
{
CSector *sector = CWorld::GetSector(x, y);
ASSERT(sector != nil);
FindWindowSectorList(sector->m_lists[ENTITYLIST_OBJECTS], &dist, &entity, x, y, z);
FindWindowSectorList(sector->m_lists[ENTITYLIST_DUMMIES], &dist, &entity, x, y, z);
}
}
if ( entity )
{
if ( entity->GetType() == ENTITY_TYPE_DUMMY )
return false;
return !!((CObject*)entity)->bGlassBroken;
}
return false;
}
void
CGlass::FindWindowSectorList(CPtrList &list, float *dist, CEntity **entity, float x, float y, float z)
{
ASSERT(dist!=nil);
ASSERT(entity!=nil);
CPtrNode *node = list.first;
while ( node != nil )
{
CEntity *ent = (CEntity *)node->item;
uint16 scanCode = ent->m_scanCode;
node = node->next;
ASSERT(ent!=nil);
if ( IsGlass(ent->GetModelIndex()) )
{
if ( scanCode != CWorld::GetCurrentScanCode() )
{
ent->m_scanCode = CWorld::GetCurrentScanCode();
float dst = (CVector(x,y,z) - ent->GetPosition()).Magnitude();
if ( dst < *dist )
{
*dist = dst;
*entity = ent;
}
}
}
}
}
void
CGlass::BreakGlassPhysically(CVector pos, float radius)
{
static uint32 breakTime = 0;
if ( CTimer::GetTimeInMilliseconds() < breakTime + 1000 && CTimer::GetTimeInMilliseconds() >= breakTime )
return;
CColSphere sphere;
sphere.piece = 0;
sphere.radius = radius;
sphere.surface = 0;
for ( int32 i = CPools::GetObjectPool()->GetSize() - 1; i >= 0; i-- )
{
CObject *object = CPools::GetObjectPool()->GetSlot(i);
if (object)
{
if ( IsGlass(object->GetModelIndex()) )
{
if ( object->bUsesCollision )
{
CColModel *col = object->GetColModel();
ASSERT(col!=nil);
if ( col->numTriangles < 2 )
continue;
bool hit = false;
CVector dist = pos - object->GetPosition();
sphere.center.x = DotProduct(dist, object->GetRight());
sphere.center.y = DotProduct(dist, object->GetForward());
sphere.center.z = DotProduct(dist, object->GetUp());
CCollision::CalculateTrianglePlanes(col);
for ( int32 j = 0; j < col->numTriangles; j++ )
{
if ( CCollision::TestSphereTriangle(sphere,
col->vertices, col->triangles[i], col->trianglePlanes[i]) )
{
hit = true;
}
}
if ( hit )
{
breakTime = CTimer::GetTimeInMilliseconds();
if ( object->bGlassCracked )
{
CVector a = col->vertices[0].Get();
CVector b = col->vertices[1].Get();
CVector c = col->vertices[2].Get();
CVector d = col->vertices[3].Get();
float minx = Min(Min(a.x, b.x), Min(c.x, d.x));
float maxx = Max(Max(a.x, b.x), Max(c.x, d.x));
float miny = Min(Min(a.y, b.y), Min(c.y, d.y));
float maxy = Max(Max(a.y, b.y), Max(c.y, d.y));
float minz = Min(Min(a.z, b.z), Min(c.z, d.z));
float maxz = Max(Max(a.z, b.z), Max(c.z, d.z));
CVector pa = object->GetMatrix() * CVector(minx, miny, minz);
CVector pb = object->GetMatrix() * CVector(maxx, maxy, minz);
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_S, object->GetPosition());
GeneratePanesForWindow(1,
pa,
CVector(0.0f, 0.0f, maxz-minz),
pb - pa,
CVector(0.0f, 0.0f, 0.0f), pos, 0.1f, !!object->bGlassCracked, false, 1, false);
object->bGlassBroken = true;
object->bIsVisible = false;
object->bUsesCollision = false;
}
else
{
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_CRACK, object->GetPosition());
object->bGlassCracked = true;
}
}
}
}
}
}
}

View file

@ -2,6 +2,7 @@
class CEntity;
class CVehicle;
class CPtrList;
class CFallingGlassPane : public CMatrix
{
@ -14,6 +15,7 @@ public:
uint8 m_nTriIndex;
bool m_bActive;
bool m_bShattered;
bool m_bCarGlass;
CFallingGlassPane() { }
~CFallingGlassPane() { }
@ -39,7 +41,7 @@ public:
static void Update(void);
static void Render(void);
static CFallingGlassPane *FindFreePane(void);
static void GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector point, float moveSpeed, bool cracked, bool explosion);
static void GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector center, float moveSpeed, bool cracked, bool explosion, int32 stepmul, bool carGlass);
static void AskForObjectToBeRenderedInGlass(CEntity *entity);
static void RenderEntityInGlass(CEntity *entity);
static int32 CalcAlphaWithNormal(CVector *normal);
@ -50,8 +52,8 @@ public:
static void WindowRespondsToSoftCollision(CEntity *entity, float amount);
static void WasGlassHitByBullet(CEntity *entity, CVector point);
static void WindowRespondsToExplosion(CEntity *entity, CVector point);
//TODO(MIAMI)
static void CarWindscreenShatters(CVehicle *vehicle, bool unk) {}
static void BreakGlassPhysically(CVector, float) {}
static void CarWindscreenShatters(CVehicle *vehicle, bool unk);
static bool HasGlassBeenShatteredAtCoors(float x, float y, float z);
static void FindWindowSectorList(CPtrList &list, float *dist, CEntity **entity, float x, float y, float z);
static void BreakGlassPhysically(CVector pos, float radius);
};

View file

@ -24,21 +24,44 @@
#include "ColStore.h"
#include "Coronas.h"
#include "Script.h"
#include "DMAudio.h"
RwIm3DVertex StreakVertices[4];
RwImVertexIndex StreakIndexList[12];
RwIm3DVertex TraceVertices[6];
RwImVertexIndex TraceIndexList[12];
RwIm3DVertex TraceVertices[10];
static RwImVertexIndex TraceIndexList[48] = {0, 5, 7, 0, 7, 2, 0, 7, 5, 0, 2, 7, 0, 4, 9, 0,
9, 5, 0, 9, 4, 0, 5, 9, 0, 1, 6, 0, 6, 5, 0, 6,
1, 0, 5, 6, 0, 3, 8, 0, 8, 5, 0, 8, 3, 0, 5, 8 };
bool CSpecialFX::bVideoCam;
bool CSpecialFX::bLiftCam;
bool CSpecialFX::bSnapShotActive;
int32 CSpecialFX::SnapShotFrames;
static RwTexture* gpSmokeTrailTexture;
void
CSpecialFX::Init(void)
{
CBulletTraces::Init();
RwIm3DVertexSetU(&TraceVertices[0], 0.0);
RwIm3DVertexSetV(&TraceVertices[0], 0.0);
RwIm3DVertexSetU(&TraceVertices[1], 1.0);
RwIm3DVertexSetV(&TraceVertices[1], 0.0);
RwIm3DVertexSetU(&TraceVertices[2], 1.0);
RwIm3DVertexSetV(&TraceVertices[2], 0.0);
RwIm3DVertexSetU(&TraceVertices[3], 1.0);
RwIm3DVertexSetV(&TraceVertices[3], 0.0);
RwIm3DVertexSetU(&TraceVertices[4], 1.0);
RwIm3DVertexSetV(&TraceVertices[4], 0.0);
RwIm3DVertexSetU(&TraceVertices[5], 0.0);
RwIm3DVertexSetU(&TraceVertices[6], 1.0);
RwIm3DVertexSetU(&TraceVertices[7], 1.0);
RwIm3DVertexSetU(&TraceVertices[8], 1.0);
RwIm3DVertexSetU(&TraceVertices[9], 1.0);
RwIm3DVertexSetU(&StreakVertices[0], 0.0f);
RwIm3DVertexSetV(&StreakVertices[0], 0.0f);
RwIm3DVertexSetU(&StreakVertices[1], 1.0f);
@ -47,7 +70,6 @@ CSpecialFX::Init(void)
RwIm3DVertexSetV(&StreakVertices[2], 0.0f);
RwIm3DVertexSetU(&StreakVertices[3], 1.0f);
RwIm3DVertexSetV(&StreakVertices[3], 0.0f);
StreakIndexList[0] = 0;
StreakIndexList[1] = 1;
StreakIndexList[2] = 2;
@ -61,43 +83,51 @@ CSpecialFX::Init(void)
StreakIndexList[10] = 2;
StreakIndexList[11] = 3;
RwIm3DVertexSetRGBA(&TraceVertices[0], 20, 20, 20, 255);
RwIm3DVertexSetRGBA(&TraceVertices[1], 20, 20, 20, 255);
RwIm3DVertexSetRGBA(&TraceVertices[2], 70, 70, 70, 255);
RwIm3DVertexSetRGBA(&TraceVertices[3], 70, 70, 70, 255);
RwIm3DVertexSetRGBA(&TraceVertices[4], 10, 10, 10, 255);
RwIm3DVertexSetRGBA(&TraceVertices[5], 10, 10, 10, 255);
RwIm3DVertexSetU(&TraceVertices[0], 0.0);
RwIm3DVertexSetV(&TraceVertices[0], 0.0);
RwIm3DVertexSetU(&TraceVertices[1], 1.0);
RwIm3DVertexSetV(&TraceVertices[1], 0.0);
RwIm3DVertexSetU(&TraceVertices[2], 0.0);
RwIm3DVertexSetV(&TraceVertices[2], 0.5);
RwIm3DVertexSetU(&TraceVertices[3], 1.0);
RwIm3DVertexSetV(&TraceVertices[3], 0.5);
RwIm3DVertexSetU(&TraceVertices[4], 0.0);
RwIm3DVertexSetV(&TraceVertices[4], 1.0);
RwIm3DVertexSetU(&TraceVertices[5], 1.0);
RwIm3DVertexSetV(&TraceVertices[5], 1.0);
TraceIndexList[0] = 0;
TraceIndexList[1] = 2;
TraceIndexList[2] = 1;
TraceIndexList[3] = 1;
TraceIndexList[4] = 2;
TraceIndexList[5] = 3;
TraceIndexList[6] = 2;
TraceIndexList[7] = 4;
TraceIndexList[8] = 3;
TraceIndexList[9] = 3;
TraceIndexList[10] = 4;
TraceIndexList[11] = 5;
CMotionBlurStreaks::Init();
CBrightLights::Init();
CShinyTexts::Init();
CMoneyMessages::Init();
C3dMarkers::Init();
CSpecialFX::bSnapShotActive = false;
CSpecialFX::bVideoCam = false;
CSpecialFX::SnapShotFrames = 0;
CSpecialFX::bLiftCam = false;
CTxdStore::PushCurrentTxd();
CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle"));
if(gpSmokeTrailTexture == nil)
gpSmokeTrailTexture = RwTextureRead("smoketrail", 0);
CTxdStore::PopCurrentTxd();
}
void
CSpecialFX::AddWeaponStreak(int type)
{
static CMatrix matrix;
CVector start;
CVector end;
if (FindPlayerPed() != nil && FindPlayerPed()->m_pWeaponModel != nil) {
switch (type) {
case WEAPONTYPE_BASEBALLBAT:
matrix = RwFrameGetLTM(RpAtomicGetFrame(FindPlayerPed()->m_pWeaponModel));
start = matrix * CVector(0.02f, 0.05f, 0.07f);
end = matrix * CVector(0.246f, 0.0325f, 0.796f);
break;
case WEAPONTYPE_GOLFCLUB:
matrix = RwFrameGetLTM(RpAtomicGetFrame(FindPlayerPed()->m_pWeaponModel));
start = matrix * CVector(0.02f, 0.05f, 0.07f);
end = matrix * CVector(-0.054f, 0.0325f, 0.796f);
break;
case WEAPONTYPE_KATANA:
matrix = RwFrameGetLTM(RpAtomicGetFrame(FindPlayerPed()->m_pWeaponModel));
start = matrix * CVector(0.02f, 0.05f, 0.07f);
end = matrix * CVector(0.096f, -0.0175f, 1.096f);
break;
default:
return;
}
CMotionBlurStreaks::RegisterStreak((uintptr)FindPlayerPed()->m_pWeaponModel, 100, 100, 100, start, end);
}
}
RwObject*
@ -119,23 +149,16 @@ CSpecialFX::Update(void)
{
CMotionBlurStreaks::Update();
CBulletTraces::Update();
if(FindPlayerPed() &&
FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT &&
FindPlayerPed()->GetWeapon()->m_eWeaponState == WEAPONSTATE_FIRING){
#ifdef PED_SKIN
if(IsClumpSkinned(FindPlayerPed()->GetClump())){
LookForBatCB((RwObject*)FindPlayerPed()->m_pWeaponModel, CModelInfo::GetModelInfo(MI_BASEBALL_BAT));
}else
#endif
RwFrameForAllObjects(FindPlayerPed()->m_pFrames[PED_HANDR]->frame, LookForBatCB, CModelInfo::GetModelInfo(MI_BASEBALL_BAT));
}
}
void
CSpecialFX::Shutdown(void)
{
C3dMarkers::Shutdown();
if (gpSmokeTrailTexture) {
RwTextureDestroy(gpSmokeTrailTexture);
gpSmokeTrailTexture = nil;
}
}
void
@ -149,6 +172,80 @@ CSpecialFX::Render(void)
C3dMarkers::Render();
}
void
CSpecialFX::Render2DFXs(void)
{
if (CSpecialFX::bVideoCam) {
CFont::SetScale(SCREEN_SCALE_X(1.5f), SCREEN_SCALE_Y(1.5f));
CFont::SetJustifyOff();
CFont::SetBackgroundOff();
CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(20.0f));
CFont::SetCentreOff();
CFont::SetPropOn();
CFont::SetColor(CRGBA(0, 255, 0, 200));
FONT_LOCALE(FONT_STANDARD);
sprintf(gString, "%d", CTimer::GetFrameCounter() & 0x3F); // mb % 63
AsciiToUnicode(gString, gUString);
CFont::PrintString(SCREEN_WIDTH * 8 / 10, SCREEN_HEIGHT * 8 / 10, gUString);
for (int32 i = 0; i < SCREEN_HEIGHT; i += 4) {
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE);
CSprite2d::Draw2DPolygon(0.0f, i, SCREEN_WIDTH, i, 0.0f, i+1, SCREEN_WIDTH, i+1, CRGBA(0, 100, 0, 100));
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
CSprite2d::Draw2DPolygon(0.0f, i+2, SCREEN_WIDTH, i+2, 0.0f, i+3, SCREEN_WIDTH, i+3, CRGBA(0, 0, 0, 150));
}
int32 tmp = (CTimer::GetTimeInMilliseconds() & 0x7ff) * (SCREEN_HEIGHT + 70.0f) / 2048 - 70.0f; //mb % 2048
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
CSprite2d::Draw2DPolygon(0.0, tmp, SCREEN_WIDTH, tmp, 0.0, tmp + 70.0f, SCREEN_WIDTH, tmp + 70.0f , CRGBA(0, 100, 0, 60));
}
if (CSpecialFX::bLiftCam) {
CFont::SetScale(SCREEN_SCALE_X(1.5f), SCREEN_SCALE_Y(1.5f));
CFont::SetJustifyOff();
CFont::SetBackgroundOff();
CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(20.0f));
CFont::SetCentreOff();
CFont::SetPropOn();
CFont::SetColor(CRGBA(100, 100, 100, 200));
FONT_LOCALE(FONT_STANDARD);
CFont::PrintString(SCREEN_WIDTH * 8 / 10, SCREEN_HEIGHT * 8 / 10, gUString);
for (int32 i = 0; i < SCREEN_HEIGHT; i += 4) {
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
CSprite2d::Draw2DPolygon(0.0f, i, SCREEN_WIDTH, i, 0.0f, i + 1, SCREEN_WIDTH, i + 1, CRGBA(100, 100, 100, 100));
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
CSprite2d::Draw2DPolygon(0.0f, i + 2, SCREEN_WIDTH, i + 2, 0.0f, i + 3, SCREEN_WIDTH, i + 3, CRGBA(0, 0, 0, 150));
}
int32 tmp = (CTimer::GetTimeInMilliseconds() & 0x7ff) * (SCREEN_HEIGHT + 70.0f) / 2048 - 70.0f; //mb % 2048
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
CSprite2d::Draw2DPolygon(0.0, tmp, SCREEN_WIDTH, tmp, 0.0, tmp + 70.0f, SCREEN_WIDTH, tmp + 70.0f, CRGBA(100, 100, 100, 60));
for (int32 i = 0; i < 200; i++) {
int32 posX = CGeneral::GetRandomNumber() % (int32)SCREEN_WIDTH;
int32 posY = CGeneral::GetRandomNumber() % (int32)SCREEN_HEIGHT;
CSprite2d::DrawRect(CRect(posX, posY + 2, posX+20, posY), CRGBA(255, 255, 255, 64));
}
}
if (CSpecialFX::bSnapShotActive) {
if (++CSpecialFX::SnapShotFrames > 20) {
CSpecialFX::bSnapShotActive = false;
CTimer::SetTimeScale(1.0f);
} else {
CTimer::SetTimeScale(0.0f); //in andro it's 0.00001
if (CSpecialFX::SnapShotFrames < 10) {
int32 tmp = (255 - 255 * CSpecialFX::SnapShotFrames / 10) * 0.65f;
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
CSprite2d::Draw2DPolygon(0.0f, 0.0f, SCREEN_WIDTH, 0.0f, 0.0f, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT, CRGBA(tmp, tmp, tmp, tmp));
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
}
}
}
}
CRegisteredMotionBlurStreak CMotionBlurStreaks::aStreaks[NUMMBLURSTREAKS];
void
@ -217,6 +314,7 @@ void
CMotionBlurStreaks::RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2)
{
int i;
for(i = 0; i < NUMMBLURSTREAKS; i++){
if(aStreaks[i].m_id == id){
// Found a streak from last frame, update
@ -229,10 +327,12 @@ CMotionBlurStreaks::RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVecto
return;
}
}
// Find free slot
for(i = 0; aStreaks[i].m_id != 0 ; i++)
if(i == NUMMBLURSTREAKS-1)
return;
// Create a new streak
aStreaks[i].m_id = id;
aStreaks[i].m_red = r;
@ -281,20 +381,103 @@ void CBulletTraces::Init(void)
aTraces[i].m_bInUse = false;
}
void CBulletTraces::AddTrace(CVector* vecStart, CVector* vecTarget)
void CBulletTraces::AddTrace(CVector* start, CVector* end, float thickness, uint32 lifeTime, uint8 visibility)
{
int index;
for (index = 0; index < NUMBULLETTRACES; index++) {
if (!aTraces[index].m_bInUse)
int32 enabledCount;
uint32 modifiedLifeTime;
int32 nextSlot;
enabledCount = 0;
for (int i = 0; i < NUMBULLETTRACES; i++)
if (aTraces[i].m_bInUse)
enabledCount++;
if (enabledCount >= 10)
modifiedLifeTime = lifeTime / 4;
else if (enabledCount >= 5)
modifiedLifeTime = lifeTime / 2;
else
modifiedLifeTime = lifeTime;
nextSlot = 0;
for (int i = 0; nextSlot < NUMBULLETTRACES && aTraces[i].m_bInUse; i++)
nextSlot++;
if (nextSlot < 16) {
aTraces[nextSlot].m_vecStartPos = *start;
aTraces[nextSlot].m_vecEndPos = *end;
aTraces[nextSlot].m_bInUse = true;
aTraces[nextSlot].m_nCreationTime = CTimer::GetTimeInMilliseconds();
aTraces[nextSlot].m_fVisibility = visibility;
aTraces[nextSlot].m_fThickness = thickness;
aTraces[nextSlot].m_nLifeTime = modifiedLifeTime;
}
float startProjFwd = DotProduct(TheCamera.GetForward(), *start - TheCamera.GetPosition());
float endProjFwd = DotProduct(TheCamera.GetForward(), *end - TheCamera.GetPosition());
if (startProjFwd * endProjFwd < 0.0f) { //if one of point behind us and second before us
float fStartDistFwd = Abs(startProjFwd) / (Abs(startProjFwd) + Abs(endProjFwd));
float startProjUp = DotProduct(TheCamera.GetUp(), *start - TheCamera.GetPosition());
float endProjUp = DotProduct(TheCamera.GetUp(), *end - TheCamera.GetPosition());
float distUp = (endProjUp - startProjUp) * fStartDistFwd + startProjUp;
float startProjRight = DotProduct(TheCamera.GetRight(), *start - TheCamera.GetPosition());
float endProjRight = DotProduct(TheCamera.GetRight(), *end - TheCamera.GetPosition());
float distRight = (endProjRight - startProjRight) * fStartDistFwd + startProjRight;
float dist = Sqrt(SQR(distUp) + SQR(distRight));
if (dist < 2.0f) {
if(distRight < 0.0f)
DMAudio.PlayFrontEndSound(SOUND_BULLETTRACE_2, 127 * (1.0f - dist * 0.5f));
else
DMAudio.PlayFrontEndSound(SOUND_BULLETTRACE_1, 127 * (1.0f - dist * 0.5f));
}
}
}
void CBulletTraces::AddTrace(CVector* start, CVector* end, int32 weaponType, class CEntity* shooter)
{
CPhysical* player;
float speed;
int16 camMode;
if (shooter == (CEntity*)FindPlayerPed() || (FindPlayerVehicle() != nil && FindPlayerVehicle() == (CVehicle*)shooter)) {
camMode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
if (camMode == CCam::MODE_M16_1STPERSON
|| camMode == CCam::MODE_CAMERA
|| camMode == CCam::MODE_SNIPER
|| camMode == CCam::MODE_M16_1STPERSON_RUNABOUT
|| camMode == CCam::MODE_ROCKETLAUNCHER
|| camMode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT
|| camMode == CCam::MODE_SNIPER_RUNABOUT
|| camMode == CCam::MODE_HELICANNON_1STPERSON) {
player = FindPlayerVehicle() ? (CPhysical*)FindPlayerVehicle() : (CPhysical*)FindPlayerPed();
speed = player->m_vecMoveSpeed.Magnitude();
if (speed < 0.05f)
return;
}
}
switch (weaponType) {
case WEAPONTYPE_PYTHON:
case WEAPONTYPE_SHOTGUN:
case WEAPONTYPE_SPAS12_SHOTGUN:
case WEAPONTYPE_STUBBY_SHOTGUN:
CBulletTraces::AddTrace(start, end, 0.7f, 1000, 200);
break;
case WEAPONTYPE_M4:
case WEAPONTYPE_RUGER:
case WEAPONTYPE_SNIPERRIFLE:
case WEAPONTYPE_LASERSCOPE:
case WEAPONTYPE_M60:
case WEAPONTYPE_MINIGUN:
case WEAPONTYPE_HELICANNON:
CBulletTraces::AddTrace(start, end, 1.0f, 2000, 220);
break;
default:
CBulletTraces::AddTrace(start, end, 0.4f, 750, 150);
break;
}
if (index == NUMBULLETTRACES)
return;
aTraces[index].m_vecCurrentPos = *vecStart;
aTraces[index].m_vecTargetPos = *vecTarget;
aTraces[index].m_bInUse = true;
aTraces[index].m_framesInUse = 0;
aTraces[index].m_lifeTime = 25 + CGeneral::GetRandomNumber() % 32;
}
void CBulletTraces::Render(void)
@ -303,31 +486,131 @@ void CBulletTraces::Render(void)
if (!aTraces[i].m_bInUse)
continue;
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
#ifdef FIX_BUGS
// Raster has no transparent pixels so it relies on the raster format having alpha
// to turn on blending. librw image conversion might get rid of it right now so let's
// just force it on.
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSmokeTrailTexture));
float timeAlive = CTimer::GetTimeInMilliseconds() - aTraces[i].m_nCreationTime;
float traceThickness = aTraces[i].m_fThickness * timeAlive / aTraces[i].m_nLifeTime;
CVector horizontalOffset = aTraces[i].m_vecEndPos - aTraces[i].m_vecStartPos;
horizontalOffset.Normalise();
horizontalOffset *= traceThickness;
//then closer trace to die then it more transparent
uint8 nAlphaValue = aTraces[i].m_fVisibility * (aTraces[i].m_nLifeTime - timeAlive) / aTraces[i].m_nLifeTime;
CVector start = aTraces[i].m_vecStartPos;
CVector end = aTraces[i].m_vecEndPos;
float startProj = DotProduct(start - TheCamera.GetPosition(), TheCamera.GetForward()) - 0.7f;
float endProj = DotProduct(end - TheCamera.GetPosition(), TheCamera.GetForward()) - 0.7f;
if (startProj < 0.0f && endProj < 0.0f) //we dont need render trace behind us
continue;
if (startProj < 0.0f) { //if strat behind us move it closer
float absStartProj = Abs(startProj);
float absEndProj = Abs(endProj);
start = (absEndProj * start + absStartProj * end) / (absStartProj + absEndProj);
} else if (endProj < 0.0f) {
float absStartProj = Abs(startProj);
float absEndProj = Abs(endProj);
end = (absEndProj * start + absStartProj * end) / (absStartProj + absEndProj);
}
//we divide trace at three parts
CVector start2 = (7.0f * start + end) / 8;
CVector end2 = (7.0f * end + start) / 8;
RwIm3DVertexSetV(&TraceVertices[5], 10.0f);
RwIm3DVertexSetV(&TraceVertices[6], 10.0f);
RwIm3DVertexSetV(&TraceVertices[7], 10.0f);
RwIm3DVertexSetV(&TraceVertices[8], 10.0f);
RwIm3DVertexSetV(&TraceVertices[9], 10.0f);
RwIm3DVertexSetRGBA(&TraceVertices[0], 255, 255, 255, nAlphaValue);
RwIm3DVertexSetRGBA(&TraceVertices[1], 255, 255, 255, nAlphaValue);
RwIm3DVertexSetRGBA(&TraceVertices[2], 255, 255, 255, nAlphaValue);
RwIm3DVertexSetRGBA(&TraceVertices[3], 255, 255, 255, nAlphaValue);
RwIm3DVertexSetRGBA(&TraceVertices[4], 255, 255, 255, nAlphaValue);
RwIm3DVertexSetRGBA(&TraceVertices[5], 255, 255, 255, nAlphaValue);
RwIm3DVertexSetRGBA(&TraceVertices[6], 255, 255, 255, nAlphaValue);
RwIm3DVertexSetRGBA(&TraceVertices[7], 255, 255, 255, nAlphaValue);
RwIm3DVertexSetRGBA(&TraceVertices[8], 255, 255, 255, nAlphaValue);
RwIm3DVertexSetRGBA(&TraceVertices[9], 255, 255, 255, nAlphaValue);
//two points in center
RwIm3DVertexSetPos(&TraceVertices[0], start2.x, start2.y, start2.z);
RwIm3DVertexSetPos(&TraceVertices[5], end2.x, end2.y, end2.z);
//vertical planes
RwIm3DVertexSetPos(&TraceVertices[1], start2.x, start2.y, start2.z + traceThickness);
RwIm3DVertexSetPos(&TraceVertices[3], start2.x, start2.y, start2.z - traceThickness);
RwIm3DVertexSetPos(&TraceVertices[6], end2.x, end2.y, end2.z + traceThickness);
RwIm3DVertexSetPos(&TraceVertices[8], end2.x, end2.y, end2.z - traceThickness);
//horizontal planes
RwIm3DVertexSetPos(&TraceVertices[2], start2.x + horizontalOffset.y, start2.y - horizontalOffset.x, start2.z);
RwIm3DVertexSetPos(&TraceVertices[7], end2.x + horizontalOffset.y, end2.y - horizontalOffset.x, end2.z);
#ifdef FIX_BUGS //this point calculated wrong for some reason
RwIm3DVertexSetPos(&TraceVertices[4], start2.x - horizontalOffset.y, start2.y + horizontalOffset.x, start2.z);
RwIm3DVertexSetPos(&TraceVertices[9], end2.x - horizontalOffset.y, end2.y + horizontalOffset.x, end2.z);
#else
RwIm3DVertexSetPos(&TraceVertices[4], start2.x - horizontalOffset.y, start2.y - horizontalOffset.y, start2.z);
RwIm3DVertexSetPos(&TraceVertices[9], end2.x - horizontalOffset.y, end2.y - horizontalOffset.y, end2.z);
#endif
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpShadowExplosionTex));
CVector inf = aTraces[i].m_vecCurrentPos;
CVector sup = aTraces[i].m_vecTargetPos;
CVector center = (inf + sup) / 2;
CVector width = CrossProduct(TheCamera.GetForward(), (sup - inf));
width.Normalise();
width /= 20;
uint8 intensity = aTraces[i].m_lifeTime;
for (int i = 0; i < ARRAY_SIZE(TraceVertices); i++)
RwIm3DVertexSetRGBA(&TraceVertices[i], intensity, intensity, intensity, 0xFF);
RwIm3DVertexSetPos(&TraceVertices[0], inf.x + width.x, inf.y + width.y, inf.z + width.z);
RwIm3DVertexSetPos(&TraceVertices[1], inf.x - width.x, inf.y - width.y, inf.z - width.z);
RwIm3DVertexSetPos(&TraceVertices[2], center.x + width.x, center.y + width.y, center.z + width.z);
RwIm3DVertexSetPos(&TraceVertices[3], center.x - width.x, center.y - width.y, center.z - width.z);
RwIm3DVertexSetPos(&TraceVertices[4], sup.x + width.x, sup.y + width.y, sup.z + width.z);
RwIm3DVertexSetPos(&TraceVertices[5], sup.x - width.x, sup.y - width.y, sup.z - width.z);
LittleTest();
if (RwIm3DTransform(TraceVertices, ARRAY_SIZE(TraceVertices), nil, 1)) {
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TraceIndexList, ARRAY_SIZE(TraceIndexList));
RwIm3DEnd();
}
RwIm3DVertexSetV(&TraceVertices[5], 2.0f);
RwIm3DVertexSetV(&TraceVertices[6], 2.0f);
RwIm3DVertexSetV(&TraceVertices[7], 2.0f);
RwIm3DVertexSetV(&TraceVertices[8], 2.0f);
RwIm3DVertexSetV(&TraceVertices[9], 2.0f);
RwIm3DVertexSetRGBA(&TraceVertices[0], 255, 255, 255, 0);
RwIm3DVertexSetRGBA(&TraceVertices[1], 255, 255, 255, 0);
RwIm3DVertexSetRGBA(&TraceVertices[2], 255, 255, 255, 0);
RwIm3DVertexSetRGBA(&TraceVertices[3], 255, 255, 255, 0);
RwIm3DVertexSetRGBA(&TraceVertices[4], 255, 255, 255, 0);
RwIm3DVertexSetPos(&TraceVertices[0], start.x, start.y, start.z);
RwIm3DVertexSetPos(&TraceVertices[1], start.x, start.y, start.z + traceThickness);
RwIm3DVertexSetPos(&TraceVertices[3], start.x, start.y, start.z - traceThickness);
RwIm3DVertexSetPos(&TraceVertices[2], start.x + horizontalOffset.y, start.y - horizontalOffset.x, start.z);
RwIm3DVertexSetPos(&TraceVertices[5], start2.x, start2.y, start2.z);
RwIm3DVertexSetPos(&TraceVertices[6], start2.x, start2.y, start2.z + traceThickness);
RwIm3DVertexSetPos(&TraceVertices[8], start2.x, start2.y, start2.z - traceThickness);
RwIm3DVertexSetPos(&TraceVertices[7], start2.x + horizontalOffset.y, start2.y - horizontalOffset.x, start2.z);
#ifdef FIX_BUGS
RwIm3DVertexSetPos(&TraceVertices[4], start.x - horizontalOffset.y, start.y + horizontalOffset.x, start.z);
RwIm3DVertexSetPos(&TraceVertices[9], start2.x - horizontalOffset.y, start2.y + horizontalOffset.x, start2.z);
#else
RwIm3DVertexSetPos(&TraceVertices[4], start.x - horizontalOffset.y, start.y - horizontalOffset.y, start.z);
RwIm3DVertexSetPos(&TraceVertices[9], start2.x - horizontalOffset.y, start2.y - horizontalOffset.y, start2.z);
#endif
if (RwIm3DTransform(TraceVertices, ARRAY_SIZE(TraceVertices), nil, rwIM3D_VERTEXUV)) {
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TraceIndexList, ARRAY_SIZE(TraceIndexList));
RwIm3DEnd();
}
RwIm3DVertexSetPos(&TraceVertices[1], end.x, end.y, end.z);
RwIm3DVertexSetPos(&TraceVertices[2], end.x, end.y, end.z + traceThickness);
RwIm3DVertexSetPos(&TraceVertices[4], end.x, end.y, end.z - traceThickness);
RwIm3DVertexSetPos(&TraceVertices[3], end.x + horizontalOffset.y, end.y - horizontalOffset.x, end.z);
RwIm3DVertexSetPos(&TraceVertices[5], end2.x, end2.y, end2.z);
RwIm3DVertexSetPos(&TraceVertices[6], end2.x, end2.y, end2.z + traceThickness);
RwIm3DVertexSetPos(&TraceVertices[8], end2.x, end2.y, end2.z - traceThickness);
RwIm3DVertexSetPos(&TraceVertices[7], end2.x + horizontalOffset.y, end2.y - horizontalOffset.x, end2.z);
#ifdef FIX_BUGS
RwIm3DVertexSetPos(&TraceVertices[5], end.x - horizontalOffset.y, end.y + horizontalOffset.x, end.z);
RwIm3DVertexSetPos(&TraceVertices[9], end2.x - horizontalOffset.y, end2.y + horizontalOffset.x, end2.z);
#else
RwIm3DVertexSetPos(&TraceVertices[5], end.x - horizontalOffset.y, end.y - horizontalOffset.y, end.z);
RwIm3DVertexSetPos(&TraceVertices[9], end2.x - horizontalOffset.y, end2.y - horizontalOffset.y, end2.z);
#endif
if (RwIm3DTransform(TraceVertices, ARRAY_SIZE(TraceVertices), nil, rwIM3D_VERTEXUV)) {
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TraceIndexList, ARRAY_SIZE(TraceIndexList));
RwIm3DEnd();
@ -348,23 +631,8 @@ void CBulletTraces::Update(void)
void CBulletTrace::Update(void)
{
if (m_framesInUse == 0) {
m_framesInUse++;
return;
}
if (m_framesInUse > 60) {
if (CTimer::GetTimeInMilliseconds() - m_nCreationTime >= m_nLifeTime)
m_bInUse = false;
return;
}
CVector diff = m_vecCurrentPos - m_vecTargetPos;
float remaining = diff.Magnitude();
if (remaining > 0.8f)
m_vecCurrentPos = m_vecTargetPos + (remaining - 0.8f) / remaining * diff;
else
m_bInUse = false;
if (--m_lifeTime == 0)
m_bInUse = false;
m_framesInUse++;
}
RpAtomic *
@ -578,7 +846,7 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size
} else {
pMarker->m_fStdSize = size;
}
} else if (type == MARKERTYPE_CYLINDER) {
} else {
if (dist < size + 12.0f) {
if (dist > size + 1.0f)
pMarker->m_Color.alpha = (1.0f - (size + 12.0f - dist) * 0.7f / 11.0f) * (float)a;
@ -591,15 +859,9 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size
float someSin = Sin(TWOPI * (float)((pMarker->m_nPulsePeriod - 1) & (CTimer::GetTimeInMilliseconds() - pMarker->m_nStartTime)) / (float)pMarker->m_nPulsePeriod);
pMarker->m_fSize = pMarker->m_fStdSize - pulseFraction * pMarker->m_fStdSize * someSin;
if (type == MARKERTYPE_ARROW) {
if (type == MARKERTYPE_ARROW)
pos.z += 0.25f * pMarker->m_fStdSize * someSin;
} else if (type == MARKERTYPE_0) {
if (someSin > 0.0f)
pMarker->m_Color.alpha = (float)a * 0.7f * someSin + a;
else
pMarker->m_Color.alpha = (float)a * 0.4f * someSin + a;
}
if (pMarker->m_nRotateRate) {
if (pMarker->m_nRotateRate != 0) {
RwV3d pos = pMarker->m_Matrix.m_matrix.pos;
pMarker->m_Matrix.RotateZ(DEGTORAD(pMarker->m_nRotateRate * CTimer::GetTimeStep()));
pMarker->m_Matrix.GetPosition() = pos;
@ -623,7 +885,7 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size
pMarker->DeleteMarkerObject();
pMarker->AddMarker(identifier, type, size, r, g, b, a, pulsePeriod, pulseFraction, rotateRate);
if (type == MARKERTYPE_CYLINDER || type == MARKERTYPE_0 || type == MARKERTYPE_2) {
if (type == MARKERTYPE_CYLINDER) {
if ((playerPos - pos).MagnitudeSqr() < sq(100.f) && CColStore::HasCollisionLoaded(CVector2D(pos))) {
float z = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z + 1.0f, nil);
if (z != 0.0f)
@ -634,10 +896,6 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size
}
}
pMarker->m_Matrix.SetTranslate(pos.x, pos.y, pos.z);
if (type == MARKERTYPE_2) {
pMarker->m_Matrix.RotateX(PI);
pMarker->m_Matrix.GetPosition() = pos;
}
pMarker->m_Matrix.UpdateRW();
if (type == MARKERTYPE_ARROW) {
if (dist < 25.0f) {
@ -648,7 +906,7 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size
} else {
pMarker->m_fStdSize = size;
}
} else if (type == MARKERTYPE_CYLINDER) {
} else {
if (dist < size + 12.0f) {
if (dist > size + 1.0f)
pMarker->m_Color.alpha = (1.0f - (size + 12.0f - dist) * 0.7f / 11.0f) * (float)a;
@ -752,6 +1010,9 @@ CBrightLights::Render(void)
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
TempBufferVerticesStored = 0;
TempBufferIndicesStored = 0;
for(i = 0; i < NumBrightLights; i++){
if(TempBufferIndicesStored > TEMPBUFFERINDEXSIZE-40 || TempBufferVerticesStored > TEMPBUFFERVERTSIZE-40)
RenderOutGeometryBuffer();
@ -788,6 +1049,10 @@ CBrightLights::Render(void)
g = aBrightLights[i].m_green;
b = aBrightLights[i].m_blue;
break;
#ifdef FIX_BUGS //just to make sure that color never will be undefined
default:
return;
#endif
}
if(aBrightLights[i].m_camDist < BRIGHTLIGHTS_FADE_DIST)
@ -1072,8 +1337,9 @@ CMoneyMessage::Render()
{
const float MAX_SCALE = 4.0f;
uint32 nLifeTime = CTimer::GetTimeInMilliseconds() - m_nTimeRegistered;
if (nLifeTime >= MONEY_MESSAGE_LIFETIME_MS) m_nTimeRegistered = 0;
else {
if (nLifeTime >= MONEY_MESSAGE_LIFETIME_MS) {
m_nTimeRegistered = 0;
} else {
float fLifeTime = (float)nLifeTime / MONEY_MESSAGE_LIFETIME_MS;
RwV3d vecOut;
float fDistX, fDistY;
@ -1082,17 +1348,15 @@ CMoneyMessage::Render()
fDistY *= (0.7 * fLifeTime + 2.0) * m_fSize;
CFont::SetPropOn();
CFont::SetBackgroundOff();
float fScaleY = Min(fDistY / 100.0f, MAX_SCALE);
float fScaleX = Min(fDistX / 100.0f, MAX_SCALE);
CFont::SetScale(fScaleX, fScaleY); // maybe use SCREEN_SCALE_X and SCREEN_SCALE_Y here?
CFont::SetCentreOn();
CFont::SetCentreSize(SCREEN_WIDTH);
CFont::SetJustifyOff();
CFont::SetColor(CRGBA(m_Colour.r, m_Colour.g, m_Colour.b, (255.0f - 255.0f * fLifeTime) * m_fOpacity));
CFont::SetBackGroundOnlyTextOff();
CFont::SetFontStyle(FONT_STANDARD);
FONT_LOCALE(FONT_STANDARD);
CFont::PrintString(vecOut.x, vecOut.y, m_aText);
}
}

View file

@ -1,8 +1,12 @@
#pragma once
//file done
class CSpecialFX
{
public:
static bool bVideoCam;
static bool bLiftCam;
static bool bSnapShotActive;
static int32 SnapShotFrames;
@ -10,8 +14,11 @@ public:
static void Update(void);
static void Init(void);
static void Shutdown(void);
static void AddWeaponStreak(int type);
static void Render2DFXs();
};
class CRegisteredMotionBlurStreak
{
public:
@ -27,6 +34,7 @@ public:
void Render(void);
};
class CMotionBlurStreaks
{
static CRegisteredMotionBlurStreak aStreaks[NUMMBLURSTREAKS];
@ -37,33 +45,31 @@ public:
static void Render(void);
};
struct CBulletTrace
{
CVector m_vecCurrentPos;
CVector m_vecTargetPos;
CVector m_vecStartPos;
CVector m_vecEndPos;
bool m_bInUse;
uint8 m_framesInUse;
uint8 m_lifeTime;
uint32 m_nCreationTime;
uint32 m_nLifeTime;
float m_fThickness;
uint8 m_fVisibility;
void Update(void);
};
class CBulletTraces
{
public:
static CBulletTrace aTraces[NUMBULLETTRACES];
static void Init(void);
static void AddTrace(CVector*, CVector*);
static void Render(void);
static void Update(void);
//TODO(MIAMI)
static void AddTrace(CVector *, CVector *, float, unsigned int, unsigned char) {}
static void AddTrace(CVector *a, CVector *b, int32 weapontype, class CEntity *shooter)
{
AddTrace(a, b); //TODO: temp
}
static void AddTrace(CVector* start, CVector* end, float thickness, uint32 lifeTime, uint8 visibility);
static void AddTrace(CVector* start, CVector* end, int32 weaponType, class CEntity* shooter);
};
enum
@ -104,6 +110,7 @@ public:
void Render();
};
class C3dMarkers
{
public:
@ -144,6 +151,7 @@ enum
BRIGHTLIGHT_REAR = BRIGHTLIGHT_REAR_LONG,
};
class CBrightLight
{
public:
@ -158,6 +166,7 @@ public:
uint8 m_blue;
};
class CBrightLights
{
static int NumBrightLights;
@ -177,6 +186,7 @@ enum
SHINYTEXT_FLAT
};
class CShinyText
{
public:
@ -189,6 +199,7 @@ public:
uint8 m_blue;
};
class CShinyTexts
{
static int NumShinyTexts;
@ -197,11 +208,12 @@ public:
static void Init(void);
static void RegisterOne(CVector p0, CVector p1, CVector p2, CVector p3,
float u0, float v0, float u1, float v1, float u2, float v2, float u3, float v3,
uint8 type, uint8 red, uint8 green, uint8 blue, float maxDist);
uint8 type, uint8 red, uint8 green, uint8 blue, float maxDist); //not used
static void Render(void);
static void RenderOutGeometryBuffer(void);
};
class CMoneyMessage
{
friend class CMoneyMessages;
@ -216,6 +228,7 @@ public:
void Render();
};
class CMoneyMessages
{
static CMoneyMessage aMoneyMessages[NUMMONEYMESSAGES];
@ -225,11 +238,12 @@ public:
static void RegisterOne(CVector vecPos, const char *pText, uint8 bRed, uint8 bGreen, uint8 bBlue, float fSize, float fOpacity);
};
class CSpecialParticleStuff
{
static uint32 BoatFromStart;
public:
static void CreateFoamAroundObject(CMatrix*, float, float, float, int32);
static void StartBoatFoamAnimation();
static void UpdateBoatFoamAnimation(CMatrix*);
static void CreateFoamAroundObject(CMatrix*, float, float, float, int32); //not used
static void StartBoatFoamAnimation(); //not used
static void UpdateBoatFoamAnimation(CMatrix*); //not used
};