summaryrefslogtreecommitdiffstats
path: root/src/render
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/render/Clouds.cpp14
-rw-r--r--src/render/Coronas.cpp4
-rw-r--r--src/render/Fluff.cpp4
-rw-r--r--src/render/Hud.cpp275
-rw-r--r--src/render/Hud.h69
-rw-r--r--src/render/MBlur.cpp3
-rw-r--r--src/render/PlayerSkin.cpp (renamed from src/core/PlayerSkin.cpp)345
-rw-r--r--src/render/PlayerSkin.h (renamed from src/core/PlayerSkin.h)6
-rw-r--r--src/render/Renderer.h2
-rw-r--r--src/render/Rubbish.cpp422
-rw-r--r--src/render/Rubbish.h39
-rw-r--r--src/render/Shadows.h11
-rw-r--r--src/render/Skidmarks.cpp247
-rw-r--r--src/render/Skidmarks.h26
-rw-r--r--src/render/SpecialFX.cpp657
-rw-r--r--src/render/SpecialFX.h228
-rw-r--r--src/render/Sprite.cpp12
-rw-r--r--src/render/Sprite2d.cpp30
-rw-r--r--src/render/TexList.cpp41
-rw-r--r--src/render/TexList.h14
-rw-r--r--src/render/Timecycle.h3
-rw-r--r--src/render/Weather.cpp470
-rw-r--r--src/render/Weather.h22
-rw-r--r--src/rw/Lights.cpp (renamed from src/render/Lights.cpp)0
-rw-r--r--src/rw/Lights.h (renamed from src/render/Lights.h)0
-rw-r--r--src/rw/VisibilityPlugins.cpp (renamed from src/render/VisibilityPlugins.cpp)2
-rw-r--r--src/rw/VisibilityPlugins.h (renamed from src/render/VisibilityPlugins.h)0
27 files changed, 2469 insertions, 477 deletions
diff --git a/src/render/Clouds.cpp b/src/render/Clouds.cpp
index 2884894c..39866294 100644
--- a/src/render/Clouds.cpp
+++ b/src/render/Clouds.cpp
@@ -87,7 +87,7 @@ CClouds::Render(void)
RwV3d pos = { 0.0f, -100.0f, 15.0f };
RwV3dAdd(&worldpos, &campos, &pos);
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[2]->raster);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[2]));
if(CCoronas::bSmallMoon){
szx *= 4.0f;
szy *= 4.0f;
@@ -116,7 +116,7 @@ CClouds::Render(void)
static float StarCoorsY[9] = { 0.0f, 0.45f, 0.9f, 1.0f, 0.85f, 0.52f, 0.48f, 0.35f, 0.2f };
static float StarSizes[9] = { 1.0f, 1.4f, 0.9f, 1.0f, 0.6f, 1.5f, 1.3f, 1.0f, 0.8f };
int brightness = (1.0f - coverage) * starintens;
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[0]->raster);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
for(i = 0; i < 11; i++){
RwV3d pos = { 100.0f, 0.0f, 10.0f };
if(i >= 9) pos.x = -pos.x;
@@ -132,7 +132,7 @@ CClouds::Render(void)
CSprite::FlushSpriteBuffer();
// *
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[0]->raster);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
RwV3d pos = { 100.0f, 0.0f, 10.0f };
RwV3dAdd(&worldpos, &campos, &pos);
worldpos.y -= 90.0f;
@@ -156,7 +156,7 @@ CClouds::Render(void)
int b = CTimeCycle::GetLowCloudsBlue() * lowcloudintensity;
for(int cloudtype = 0; cloudtype < 3; cloudtype++){
for(i = cloudtype; i < 12; i += 3){
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCloudTex[cloudtype]->raster);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCloudTex[cloudtype]));
RwV3d pos = { 800.0f*LowCloudsX[i], 800.0f*LowCloudsY[i], 60.0f*LowCloudsZ[i] };
worldpos.x = campos.x + pos.x;
worldpos.y = campos.y + pos.y;
@@ -202,7 +202,7 @@ CClouds::Render(void)
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCloudTex[4]->raster);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCloudTex[4]));
for(i = 0; i < 37; i++){
RwV3d pos = { 2.0f*CoorsOffsetX[i], 2.0f*CoorsOffsetY[i], 40.0f*CoorsOffsetZ[i] + 40.0f };
worldpos.x = pos.x*rot_cos + pos.y*rot_sin + campos.x;
@@ -244,7 +244,7 @@ CClouds::Render(void)
// Highlights
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCloudTex[3]->raster);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCloudTex[3]));
for(i = 0; i < 37; i++){
RwV3d pos = { 2.0f*CoorsOffsetX[i], 2.0f*CoorsOffsetY[i], 40.0f*CoorsOffsetZ[i] + 40.0f };
@@ -269,7 +269,7 @@ CClouds::Render(void)
static uint8 BowRed[6] = { 30, 30, 30, 10, 0, 15 };
static uint8 BowGreen[6] = { 0, 15, 30, 30, 0, 0 };
static uint8 BowBlue[6] = { 0, 0, 0, 10, 30, 30 };
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[0]->raster);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
for(i = 0; i < 6; i++){
RwV3d pos = { i*1.5f, 100.0f, 5.0f };
RwV3dAdd(&worldpos, &campos, &pos);
diff --git a/src/render/Coronas.cpp b/src/render/Coronas.cpp
index c934540b..68994b0b 100644
--- a/src/render/Coronas.cpp
+++ b/src/render/Coronas.cpp
@@ -320,7 +320,7 @@ CCoronas::Render(void)
CSprite::RenderOneXLUSprite(spriteCoors.x, spriteCoors.y, spriteCoors.z,
spritew * aCoronas[i].size * wscale,
- spriteh * SCREEN_SCALE_AR2(aCoronas[i].size * fogscale * hscale),
+ spriteh * aCoronas[i].size * fogscale * hscale,
CCoronas::aCoronas[i].red / fogscale,
CCoronas::aCoronas[i].green / fogscale,
CCoronas::aCoronas[i].blue / fogscale,
@@ -331,7 +331,7 @@ CCoronas::Render(void)
CSprite::RenderOneXLUSprite_Rotate_Aspect(
spriteCoors.x, spriteCoors.y, spriteCoors.z,
spritew * aCoronas[i].size * fogscale,
- spriteh * SCREEN_SCALE_AR2(aCoronas[i].size * fogscale),
+ spriteh * aCoronas[i].size * fogscale,
CCoronas::aCoronas[i].red / fogscale,
CCoronas::aCoronas[i].green / fogscale,
CCoronas::aCoronas[i].blue / fogscale,
diff --git a/src/render/Fluff.cpp b/src/render/Fluff.cpp
index 8d7fad92..e2899532 100644
--- a/src/render/Fluff.cpp
+++ b/src/render/Fluff.cpp
@@ -755,14 +755,14 @@ void CTowerClock::Render()
&TempV[1],
m_Position.x + Sin(angleMinute) * m_fScale * m_Size.x,
m_Position.y + Sin(angleMinute) * m_fScale * m_Size.y,
- m_Position.z + Cos(angleMinute) * m_fScale;
+ m_Position.z + Cos(angleMinute) * m_fScale
);
RwIm3DVertexSetPos(&TempV[2], m_Position.x, m_Position.y, m_Position.z);
RwIm3DVertexSetPos(
&TempV[3],
m_Position.x + Sin(angleHour) * 0.75f * m_fScale * m_Size.x,
m_Position.y + Sin(angleHour) * 0.75f * m_fScale * m_Size.y,
- m_Position.z + Cos(angleHour) * 0.75f * m_fScale;
+ m_Position.z + Cos(angleHour) * 0.75f * m_fScale
);
LittleTest();
diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp
index 3c07039c..56a024a7 100644
--- a/src/render/Hud.cpp
+++ b/src/render/Hud.cpp
@@ -23,55 +23,47 @@
//wchar *CHud::m_HelpMessage = (wchar*)0x86B888;
//wchar *CHud::m_LastHelpMessage = (wchar*)0x6E8F28;
-wchar CHud::m_HelpMessage[256];
-wchar CHud::m_LastHelpMessage[256];
-
-int32 &CHud::m_HelpMessageState = *(int32*)0x880E1C;
-int32 &CHud::m_HelpMessageTimer = *(int32*)0x880FA4;
-int32 &CHud::m_HelpMessageFadeTimer = *(int32*)0x8F6258;
-wchar *CHud::m_HelpMessageToPrint = (wchar*)0x664480;
-float &CHud::m_HelpMessageDisplayTime = *(float*)0x8E2C28;
-float &CHud::m_fTextBoxNumLines = *(float*)0x8E2C28;
-float &CHud::m_fHelpMessageTime = *(float *)0x8E2C28;
-bool &CHud::m_HelpMessageQuick = *(bool *)0x95CCF7;
-int32 CHud::m_ZoneState = *(int32*)0x8F29AC;
+wchar CHud::m_HelpMessageToPrint[256]; // = (wchar*)0x664480;
+float CHud::m_fHelpMessageTime; // *(float *)0x8E2C28;
+bool CHud::m_HelpMessageQuick; // = *(bool*)0x95CCF7;
+uint32 CHud::m_ZoneState; // = *(int32*)0x8F29AC;
int32 CHud::m_ZoneFadeTimer;
-int32 CHud::m_ZoneNameTimer = *(int32*)0x8F1A50;
-wchar *&CHud::m_pZoneName = *(wchar **)0x8E2C2C;
-wchar *CHud::m_pLastZoneName = (wchar*)0x8F432C;
+uint32 CHud::m_ZoneNameTimer; // = *(int32*)0x8F1A50;
+wchar *CHud::m_pZoneName; // = *(wchar**)0x8E2C2C;
+wchar *CHud::m_pLastZoneName; // = (wchar*)0x8F432C;
wchar *CHud::m_ZoneToPrint;
-int32 CHud::m_VehicleState = *(int32*)0x940560;
+uint32 CHud::m_VehicleState; // = *(int32*)0x940560;
int32 CHud::m_VehicleFadeTimer;
-int32 CHud::m_VehicleNameTimer = *(int32*)0x8F2A14;
-wchar *&CHud::m_VehicleName = *(wchar **)0x942FB4;
-wchar *CHud::m_pLastVehicleName = *(wchar **)0x8E2DD8;
+uint32 CHud::m_VehicleNameTimer; // = *(int32*)0x8F2A14;
+wchar *CHud::m_VehicleName; // = *(wchar**)0x942FB4;
+wchar *CHud::m_pLastVehicleName; // = *(wchar**)0x8E2DD8;
wchar *CHud::m_pVehicleNameToPrint;
-wchar *CHud::m_Message = (wchar*)0x72E318;
-wchar *CHud::m_PagerMessage = (wchar*)0x878840;
-bool &CHud::m_Wants_To_Draw_Hud = *(bool*)0x95CD89;
-bool &CHud::m_Wants_To_Draw_3dMarkers = *(bool*)0x95CD62;
-wchar(&CHud::m_BigMessage)[6][128] = *(wchar(*)[6][128])*(uintptr*)0x664CE0;
-int16 &CHud::m_ItemToFlash = *(int16*)0x95CC82;
+wchar CHud::m_Message[256];// = (wchar*)0x72E318;
+wchar CHud::m_PagerMessage[256]; // = (wchar*)0x878840;
+bool CHud::m_Wants_To_Draw_Hud; // (bool*)0x95CD89;
+bool CHud::m_Wants_To_Draw_3dMarkers; // = *(bool*)0x95CD62;
+wchar CHud::m_BigMessage[6][128]; // = *(wchar(*)[6][128]) * (uintptr*)0x664CE0;
+int16 CHud::m_ItemToFlash; // = *(int16*)0x95CC82;
// These aren't really in CHud
float CHud::BigMessageInUse[6];
float CHud::BigMessageAlpha[6];
float CHud::BigMessageX[6];
-float &CHud::OddJob2OffTimer = *(float*)0x942FA0;
-int8 &CHud::CounterOnLastFrame = *(int8*)0x95CD67;
-float &CHud::OddJob2XOffset = *(float*)0x8F1B5C;
-int16 &CHud::CounterFlashTimer = *(int16*)0x95CC20;
-int16 &CHud::OddJob2Timer = *(int16*)0x95CC52;
-int8 &CHud::TimerOnLastFrame = *(int8*)0x95CDA7;
-int16 &CHud::OddJob2On = *(int16*)0x95CC78;
-int16 &CHud::TimerFlashTimer = *(int16*)0x95CC6C;
-int16 &CHud::PagerSoundPlayed = *(int16*)0x95CC4A;
-int32 &CHud::SpriteBrightness = *(int32*)0x95CC54;
-float &CHud::PagerXOffset = *(float*)0x941590;
-int16 &CHud::PagerTimer = *(int16*)0x95CC3A;
-int16 &CHud::PagerOn = *(int16*)0x95CCA0;
-
-CSprite2d *CHud::Sprites = (CSprite2d*)0x95CB9C;
+float CHud::OddJob2OffTimer; // = *(float*)0x942FA0;
+bool CHud::CounterOnLastFrame; // = *(int8*)0x95CD67;
+float CHud::OddJob2XOffset; // = *(float*)0x8F1B5C;
+uint16 CHud::CounterFlashTimer; // = *(int16*)0x95CC20;
+uint16 CHud::OddJob2Timer; // = *(int16*)0x95CC52;
+bool CHud::TimerOnLastFrame; //= *(int8*)0x95CDA7;
+int16 CHud::OddJob2On; //= *(int16*)0x95CC78;
+uint16 CHud::TimerFlashTimer; //= *(int16*)0x95CC6C;
+int16 CHud::PagerSoundPlayed; //= *(int16*)0x95CC4A;
+int32 CHud::SpriteBrightness; //= *(int32*)0x95CC54;
+float CHud::PagerXOffset; //= *(float*)0x941590;
+int16 CHud::PagerTimer; //= *(int16*)0x95CC3A;
+int16 CHud::PagerOn; //= *(int16*)0x95CCA0;
+
+CSprite2d CHud::Sprites[NUM_HUD_SPRITES]; // = (CSprite2d*)0x95CB9C;
struct
{
@@ -93,14 +85,14 @@ struct
{"detonator", "detonator_mask"},
{"", ""},
{"", ""},
- {"radardisc", "radardiscm"},
+ {"radardisc", "radardisc"},
{"pager", "pagerm"},
{"", ""},
{"", ""},
{"bleeder", ""},
{"sitesniper", "sitesniperm"},
{"siteM16", "siteM16m"},
- {"siterocket", "siterocketm"}
+ {"siterocket", "siterocket"}
};
RwTexture *&gpSniperSightTex = *(RwTexture**)0x8F5834;
@@ -418,7 +410,7 @@ void CHud::Draw()
DrawZoneName
*/
if (m_pZoneName) {
- float fZoneAlpha = 0.0f;
+ float fZoneAlpha = 255.0f;
if (m_pZoneName != m_pLastZoneName) {
switch (m_ZoneState) {
@@ -432,7 +424,7 @@ void CHud::Draw()
case 2:
case 3:
case 4:
- m_ZoneNameTimer = 0;
+ m_ZoneNameTimer = 5;
m_ZoneState = 4;
break;
default:
@@ -444,6 +436,7 @@ void CHud::Draw()
if (m_ZoneState) {
switch (m_ZoneState) {
case 1:
+ m_ZoneFadeTimer = 1000;
if (m_ZoneNameTimer > 10000) {
m_ZoneFadeTimer = 1000;
m_ZoneState = 3;
@@ -471,7 +464,6 @@ void CHud::Draw()
if (m_ZoneFadeTimer < 0) {
m_ZoneFadeTimer = 0;
m_ZoneToPrint = m_pLastZoneName;
- m_ZoneNameTimer = 0;
m_ZoneState = 2;
}
fZoneAlpha = m_ZoneFadeTimer * 0.001f * 255.0f;
@@ -503,12 +495,6 @@ void CHud::Draw()
}
}
}
- /*else {
- m_pLastZoneName = nil;
- m_ZoneState = 0;
- m_ZoneFadeTimer = 0;
- m_ZoneNameTimer = 0;
- }*/
/*
DrawVehicleName
@@ -636,9 +622,9 @@ void CHud::Draw()
wchar sTimer[16];
if (!CUserDisplay::OnscnTimer.m_sEntries[0].m_bTimerProcessed)
- TimerOnLastFrame = 0;
+ TimerOnLastFrame = false;
if (!CUserDisplay::OnscnTimer.m_sEntries[0].m_bCounterProcessed)
- CounterOnLastFrame = 0;
+ CounterOnLastFrame = false;
#ifdef FIX_BUGS
#define TIMER_RIGHT_OFFSET 34.0f // Taken from VC frenzy timer
@@ -650,7 +636,7 @@ void CHud::Draw()
if (!TimerOnLastFrame)
TimerFlashTimer = 1;
- TimerOnLastFrame = 1;
+ TimerOnLastFrame = true;
if (TimerFlashTimer) {
if (++TimerFlashTimer > 50)
@@ -688,7 +674,7 @@ void CHud::Draw()
if (!CounterOnLastFrame)
CounterFlashTimer = 1;
- CounterOnLastFrame = 1;
+ CounterOnLastFrame = true;
if (CounterFlashTimer) {
if (++CounterFlashTimer > 50)
@@ -742,11 +728,9 @@ void CHud::Draw()
/*
DrawPager
*/
- if (!m_PagerMessage[0]) {
- if (PagerOn == 1) {
- PagerSoundPlayed = false;
- PagerOn = 2;
- }
+ if (!m_PagerMessage[0] && PagerOn == 1) {
+ PagerSoundPlayed = false;
+ PagerOn = 2;
}
if (m_PagerMessage[0] || PagerOn == 2) {
if (!PagerOn) {
@@ -755,7 +739,7 @@ void CHud::Draw()
}
if (PagerOn == 1) {
if (PagerXOffset > 0.0f) {
- float fStep = PagerXOffset * 0.05f;
+ float fStep = PagerXOffset * 0.1f;
if (fStep > 10.0f)
fStep = 10.0f;
PagerXOffset -= fStep * CTimer::GetTimeStep();
@@ -766,10 +750,10 @@ void CHud::Draw()
}
}
else if (PagerOn == 2) {
- float fStep = PagerXOffset * 0.05f;
+ float fStep = PagerXOffset * 0.1f;
if (fStep < 2.0f)
fStep = 2.0f;
- PagerXOffset += fStep * CTimer::GetTimeStep();
+ PagerXOffset += fStep;
if (PagerXOffset > 150.0f) {
PagerXOffset = 150.0f;
PagerOn = 0;
@@ -818,9 +802,7 @@ void CHud::Draw()
DrawScriptText
*/
if (!CTimer::GetIsUserPaused()) {
- CTextLine* IntroText = CTheScripts::IntroTextLines;
-
- for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++) {
+ for (int i = 0; i < ARRAY_SIZE(CTheScripts::IntroTextLines); i++) {
if (CTheScripts::IntroTextLines[i].m_Text[0] && CTheScripts::IntroTextLines[i].m_bTextBeforeFade) {
CFont::SetScale(SCREEN_SCALE_X(CTheScripts::IntroTextLines[i].m_fScaleX), SCREEN_SCALE_Y(CTheScripts::IntroTextLines[i].m_fScaleY * 0.5f));
CFont::SetColor(CTheScripts::IntroTextLines[i].m_sColor);
@@ -861,31 +843,31 @@ void CHud::Draw()
CFont::SetPropOff();
CFont::SetFontStyle(FONTJAP(CTheScripts::IntroTextLines[i].m_nFont));
- CFont::PrintString(SCREEN_SCALE_X(640.0f - CTheScripts::IntroTextLines[i].m_fAtX), SCREEN_SCALE_Y(448.0f - CTheScripts::IntroTextLines[i].m_fAtY), IntroText->m_Text);
+ CFont::PrintString(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - CTheScripts::IntroTextLines[i].m_fAtX), SCREEN_SCALE_Y(DEFAULT_SCREEN_HEIGHT - CTheScripts::IntroTextLines[i].m_fAtY), CTheScripts::IntroTextLines[i].m_Text);
}
}
+ for (int i = 0; i < ARRAY_SIZE(CTheScripts::IntroRectangles); i++) {
+ intro_script_rectangle &IntroRect = CTheScripts::IntroRectangles[i];
- CScriptRectangle* IntroRect = CTheScripts::IntroRectangles;
-
- for (int i = 0; i < 16; i++) {
- if (CTheScripts::IntroRectangles[i].m_bIsUsed && CTheScripts::IntroRectangles[i].m_bBeforeFade) {
- if (CTheScripts::IntroRectangles[i].m_nTextureId >= 0) {
+ // Yeah, top and bottom changed place. R* vision
+ if (IntroRect.m_bIsUsed && IntroRect.m_bBeforeFade) {
+ if (IntroRect.m_nTextureId >= 0) {
CRect rect = {
- CTheScripts::IntroRectangles[i].m_sRect.left,
- CTheScripts::IntroRectangles[i].m_sRect.bottom,
- CTheScripts::IntroRectangles[i].m_sRect.right,
- CTheScripts::IntroRectangles[i].m_sRect.bottom };
+ IntroRect.m_sRect.left,
+ IntroRect.m_sRect.top,
+ IntroRect.m_sRect.right,
+ IntroRect.m_sRect.bottom };
- CTheScripts::ScriptSprites[CTheScripts::IntroRectangles[i].m_nTextureId].Draw(rect, IntroRect->m_sColor);
+ CTheScripts::ScriptSprites[IntroRect.m_nTextureId].Draw(rect, IntroRect.m_sColor);
}
else {
CRect rect = {
- CTheScripts::IntroRectangles[i].m_sRect.left,
- CTheScripts::IntroRectangles[i].m_sRect.bottom,
- CTheScripts::IntroRectangles[i].m_sRect.right,
- CTheScripts::IntroRectangles[i].m_sRect.bottom };
+ IntroRect.m_sRect.left,
+ IntroRect.m_sRect.top,
+ IntroRect.m_sRect.right,
+ IntroRect.m_sRect.bottom };
- CSprite2d::DrawRect(rect, IntroRect->m_sColor);
+ CSprite2d::DrawRect(rect, IntroRect.m_sColor);
}
}
}
@@ -931,7 +913,7 @@ void CHud::Draw()
CFont::SetCentreSize(SCREEN_SCALE_X(615.0f));
CFont::SetFontStyle(FONT_HEADING);
- if (BigMessageX[0] >= (SCREEN_WIDTH - 20)) {
+ if (BigMessageX[0] >= SCREEN_SCALE_FROM_RIGHT(20.0f)) {
BigMessageInUse[0] += CTimer::GetTimeStep();
if (BigMessageInUse[0] >= 120.0f) {
@@ -948,7 +930,7 @@ void CHud::Draw()
BigMessageX[0] += (CTimer::GetTimeStepInMilliseconds() * 0.3f);
BigMessageAlpha[0] += (CTimer::GetTimeStepInMilliseconds() * 0.3f);
- if (BigMessageAlpha[0] >= 255.0f)
+ if (BigMessageAlpha[0] > 255.0f)
BigMessageAlpha[0] = 255.0f;
}
@@ -992,7 +974,7 @@ void CHud::Draw()
CFont::SetFontStyle(FONT_HEADING);
CFont::SetColor(CRGBA(0, 0, 0, BigMessageAlpha[2]));
- CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f + 4.0f), SCREEN_SCALE_FROM_BOTTOM(78.0f), m_BigMessage[2]);
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f - 4.0f), SCREEN_SCALE_FROM_BOTTOM(78.0f), m_BigMessage[2]);
CFont::SetColor(CRGBA(170, 123, 87, BigMessageAlpha[2]));
CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(82.0f), m_BigMessage[2]);
@@ -1021,7 +1003,7 @@ void CHud::DrawAfterFade()
m_HelpMessageState = 2;
m_HelpMessageTimer = 0;
CMessages::WideStringCopy(m_HelpMessageToPrint, m_HelpMessage, 256);
- m_HelpMessageDisplayTime = CMessages::GetWideStringLength(m_HelpMessage) * 0.05f + 3.0f;
+ m_fHelpMessageTime = CMessages::GetWideStringLength(m_HelpMessage) * 0.05f + 3.0f;
if (TheCamera.m_ScreenReductionPercentage == 0.0f)
DMAudio.PlayFrontEndSound(SOUND_A0, 0);
@@ -1039,14 +1021,14 @@ void CHud::DrawAfterFade()
CMessages::WideStringCopy(m_LastHelpMessage, m_HelpMessage, 256);
}
- float fAlpha = 255.0f;
+ float fAlpha = 225.0f;
- if (m_HelpMessageState) {
+ if (m_HelpMessageState != 0) {
switch (m_HelpMessageState) {
case 1:
- fAlpha = 255.0f;
+ fAlpha = 225.0f;
m_HelpMessageFadeTimer = 600;
- if (m_HelpMessageTimer > m_fHelpMessageTime * 1000 || m_HelpMessageQuick && m_HelpMessageTimer > 1500) {
+ if (m_HelpMessageTimer > m_fHelpMessageTime * 1000.0f || m_HelpMessageQuick && m_HelpMessageTimer > 1500.0f) {
m_HelpMessageFadeTimer = 600;
m_HelpMessageState = 3;
}
@@ -1057,24 +1039,24 @@ void CHud::DrawAfterFade()
m_HelpMessageState = 1;
m_HelpMessageFadeTimer = 0;
}
- fAlpha = m_HelpMessageFadeTimer * 0.001f * 255.0f;
+ fAlpha = m_HelpMessageFadeTimer * 0.001f * 225.0f;
break;
case 3:
m_HelpMessageFadeTimer -= 2 * CTimer::GetTimeStepInMilliseconds();
- if (m_HelpMessageFadeTimer >= 0) {
+ if (m_HelpMessageFadeTimer < 0) {
m_HelpMessageState = 0;
m_HelpMessageFadeTimer = 0;
}
- fAlpha = m_HelpMessageFadeTimer * 0.001f * 255.0f;
+ fAlpha = m_HelpMessageFadeTimer * 0.001f * 225.0f;
break;
case 4:
m_HelpMessageFadeTimer -= 2 * CTimer::GetTimeStepInMilliseconds();
- if (m_HelpMessageFadeTimer >= 0) {
+ if (m_HelpMessageFadeTimer < 0) {
m_HelpMessageState = 2;
m_HelpMessageFadeTimer = 0;
- CMessages::WideStringCopy(m_HelpMessageToPrint, m_LastHelpMessage, 400);
+ CMessages::WideStringCopy(m_HelpMessageToPrint, m_LastHelpMessage, 256);
}
- fAlpha = m_HelpMessageFadeTimer * 0.001f * 255.0f;
+ fAlpha = m_HelpMessageFadeTimer * 0.001f * 225.0f;
break;
default:
break;
@@ -1093,6 +1075,7 @@ void CHud::DrawAfterFade()
else
CFont::SetScale(SCREEN_SCALE_X(0.52f), SCREEN_SCALE_Y(1.1f));
+ CFont::SetColor(CRGBA(175, 175, 175, 255));
CFont::SetJustifyOff();
if (CFont::LanguageSet == FONT_LANGSET_JAPANESE)
CFont::SetWrapx(SCREEN_SCALE_X(229.0f + 26.0f - 4.0f));
@@ -1101,14 +1084,69 @@ void CHud::DrawAfterFade()
CFont::SetFontStyle(FONTJAP(FONT_BANK));
CFont::SetBackgroundOn();
CFont::SetBackGroundOnlyTextOff();
- CFont::SetBackgroundColor(CRGBA(0, 0, 0, fAlpha * 0.8f));
- CFont::SetColor(CRGBA(175, 175, 175, 255));
+ CFont::SetBackgroundColor(CRGBA(0, 0, 0, fAlpha * 0.9f));
CFont::PrintString(SCREEN_SCALE_X(26.0f), SCREEN_SCALE_Y(28.0f + (150.0f - PagerXOffset) * 0.6f), CHud::m_HelpMessageToPrint);
CFont::SetAlphaFade(255.0f);
}
}
- else
- m_HelpMessageState = 0;
+
+ for (int i = 0; i < ARRAY_SIZE(CTheScripts::IntroTextLines); i++) {
+ intro_text_line &line = CTheScripts::IntroTextLines[i];
+ if (line.m_Text[0] != '\0' && !line.m_bTextBeforeFade) {
+ CFont::SetScale(SCREEN_SCALE_X(line.m_fScaleX), SCREEN_SCALE_Y(line.m_fScaleY) / 2);
+
+ CFont::SetColor(line.m_sColor);
+ if (line.m_bJustify)
+ CFont::SetJustifyOn();
+ else
+ CFont::SetJustifyOff();
+
+ if (line.m_bRightJustify)
+ CFont::SetRightJustifyOn();
+ else
+ CFont::SetRightJustifyOff();
+
+ if (line.m_bCentered)
+ CFont::SetCentreOn();
+ else
+ CFont::SetCentreOff();
+
+ CFont::SetWrapx(SCREEN_SCALE_X(line.m_fWrapX));
+ CFont::SetCentreSize(SCREEN_SCALE_X(line.m_fCenterSize));
+ if (line.m_bBackground)
+ CFont::SetBackgroundOn();
+ else
+ CFont::SetBackgroundOff();
+
+ CFont::SetBackgroundColor(line.m_sBackgroundColor);
+ if (line.m_bBackgroundOnly)
+ CFont::SetBackGroundOnlyTextOn();
+ else
+ CFont::SetBackGroundOnlyTextOff();
+
+ if (line.m_bTextProportional)
+ CFont::SetPropOn();
+ else
+ CFont::SetPropOff();
+
+ CFont::SetFontStyle(line.m_nFont);
+ CFont::PrintString(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - line.m_fAtX), SCREEN_SCALE_Y(DEFAULT_SCREEN_HEIGHT - line.m_fAtY), line.m_Text);
+ }
+ }
+ for (int i = 0; i < ARRAY_SIZE(CTheScripts::IntroRectangles); i++) {
+ intro_script_rectangle &rectangle = CTheScripts::IntroRectangles[i];
+ if (rectangle.m_bIsUsed && !rectangle.m_bBeforeFade) {
+
+ // Yeah, top and bottom changed place. R* vision
+ if (rectangle.m_nTextureId >= 0) {
+ CTheScripts::ScriptSprites[rectangle.m_nTextureId].Draw(CRect(rectangle.m_sRect.left, rectangle.m_sRect.bottom,
+ rectangle.m_sRect.right, rectangle.m_sRect.top), rectangle.m_sColor);
+ } else {
+ CSprite2d::DrawRect(CRect(rectangle.m_sRect.left, rectangle.m_sRect.bottom,
+ rectangle.m_sRect.right, rectangle.m_sRect.top), rectangle.m_sColor);
+ }
+ }
+ }
/*
DrawBigMessage2
@@ -1150,10 +1188,9 @@ void CHud::DrawAfterFade()
if (OddJob2OffTimer > 0)
OddJob2OffTimer -= CTimer::GetTimeStepInMilliseconds();
- static float fStep;
+ float fStep;
if (m_BigMessage[5][0] && OddJob2OffTimer <= 0.0f) {
- if (OddJob2On <= 3) {
- switch (OddJob2On) {
+ switch (OddJob2On) {
case 0:
OddJob2On = 1;
OddJob2XOffset = 380.0f;
@@ -1164,9 +1201,7 @@ void CHud::DrawAfterFade()
OddJob2On = 2;
}
else {
- fStep = 40.0f;
- if ((OddJob2XOffset / 6.0f) <= 40.0f)
- fStep = OddJob2XOffset / 6.0f;
+ fStep = min(40.0f, OddJob2XOffset / 6.0f);
OddJob2XOffset = OddJob2XOffset - fStep;
}
break;
@@ -1177,9 +1212,7 @@ void CHud::DrawAfterFade()
}
break;
case 3:
- fStep = 30.0f;
- if ((OddJob2XOffset / 5.0f) >= 30.0f)
- fStep = OddJob2XOffset / 5.0f;
+ fStep = max(30.0f, OddJob2XOffset / 5.0f);
OddJob2XOffset = OddJob2XOffset - fStep;
@@ -1190,7 +1223,6 @@ void CHud::DrawAfterFade()
break;
default:
break;
- }
}
if (!m_BigMessage[1][0]) {
@@ -1224,10 +1256,10 @@ void CHud::DrawAfterFade()
CFont::SetScale(SCREEN_SCALE_X(1.04f), SCREEN_SCALE_Y(1.6f));
CFont::SetPropOn();
- CFont::SetRightJustifyWrap(-500.0f);
+ CFont::SetRightJustifyWrap(SCREEN_SCALE_X(-500.0f));
CFont::SetRightJustifyOn();
CFont::SetFontStyle(FONT_HEADING);
- if (BigMessageX[1] >= (SCREEN_WIDTH - 20)) {
+ if (BigMessageX[1] >= SCREEN_SCALE_FROM_RIGHT(20.0f)) {
BigMessageInUse[1] += CTimer::GetTimeStep();
if (BigMessageInUse[1] >= 120.0f) {
@@ -1238,12 +1270,11 @@ void CHud::DrawAfterFade()
m_BigMessage[1][0] = 0;
BigMessageAlpha[1] = 0.0f;
}
- }
- else {
+ } else {
BigMessageX[1] += (CTimer::GetTimeStepInMilliseconds() * 0.3f);
BigMessageAlpha[1] += (CTimer::GetTimeStepInMilliseconds() * 0.3f);
- if (BigMessageAlpha[1] >= 255.0f)
+ if (BigMessageAlpha[1] > 255.0f)
BigMessageAlpha[1] = 255.0f;
}
@@ -1281,7 +1312,7 @@ void CHud::GetRidOfAllHudMessages()
m_HelpMessageFadeTimer = 0;
m_HelpMessageState = 0;
m_HelpMessageQuick = 0;
- m_HelpMessageDisplayTime = 1.0f;
+ m_fHelpMessageTime = 1.0f;
m_VehicleName = nil;
m_pLastVehicleName = nil;
m_pVehicleNameToPrint = nil;
@@ -1311,7 +1342,7 @@ void CHud::Initialise()
CTxdStore::PopCurrentTxd();
CTxdStore::SetCurrentTxd(HudTXD);
- for (int i = 0; i < ARRAY_SIZE(WeaponFilenames); i++) {
+ for (int i = 0; i < NUM_HUD_SPRITES; i++) {
Sprites[i].SetTexture(WeaponFilenames[i].name, WeaponFilenames[i].mask);
}
@@ -1322,14 +1353,14 @@ void CHud::Initialise()
if (gpRocketSightTex == nil)
gpRocketSightTex = RwTextureRead("siterocket", nil);
- CounterOnLastFrame = 0;
+ CounterOnLastFrame = false;
m_ItemToFlash = ITEM_NONE;
OddJob2Timer = 0;
OddJob2OffTimer = 0.0f;
OddJob2On = 0;
OddJob2XOffset = 0.0f;
CounterFlashTimer = 0;
- TimerOnLastFrame = 0;
+ TimerOnLastFrame = false;
TimerFlashTimer = 0;
SpriteBrightness = 0;
PagerOn = 0;
@@ -1346,14 +1377,14 @@ void CHud::ReInitialise() {
GetRidOfAllHudMessages();
- CounterOnLastFrame = 0;
+ CounterOnLastFrame = false;
m_ItemToFlash = ITEM_NONE;
OddJob2Timer = 0;
OddJob2OffTimer = 0.0f;
OddJob2On = 0;
OddJob2XOffset = 0.0f;
CounterFlashTimer = 0;
- TimerOnLastFrame = 0;
+ TimerOnLastFrame = false;
TimerFlashTimer = 0;
SpriteBrightness = 0;
PagerOn = 0;
@@ -1443,7 +1474,7 @@ void CHud::SetZoneName(wchar *name)
void CHud::Shutdown()
{
- for (int i = 0; i < ARRAY_SIZE(WeaponFilenames); ++i) {
+ for (int i = 0; i < NUM_HUD_SPRITES; ++i) {
Sprites[i].Delete();
}
diff --git a/src/render/Hud.h b/src/render/Hud.h
index dad3a58d..701e47e2 100644
--- a/src/render/Hud.h
+++ b/src/render/Hud.h
@@ -27,59 +27,60 @@ enum eSprites
HUD_RADARDISC = 15,
HUD_PAGER = 16,
HUD_SITESNIPER = 20,
- HUD_SITEM16 = 21
+ HUD_SITEM16,
+ HUD_SITEROCKET,
+ NUM_HUD_SPRITES,
};
class CHud
{
public:
- static CSprite2d *Sprites;
- static int32 &SpriteBrightness;
+ static CSprite2d Sprites[NUM_HUD_SPRITES];
static wchar m_HelpMessage[256];
static wchar m_LastHelpMessage[256];
- static int32 &m_HelpMessageState;
- static int32 &m_HelpMessageTimer;
- static int32 &m_HelpMessageFadeTimer;
- static wchar *m_HelpMessageToPrint;
+ static uint32 m_HelpMessageState;
+ static uint32 m_HelpMessageTimer;
+ static int32 m_HelpMessageFadeTimer;
+ static wchar m_HelpMessageToPrint[256];
static float &m_HelpMessageDisplayTime;
- static float &m_fTextBoxNumLines;
- static float &m_fHelpMessageTime;
- static bool &m_HelpMessageQuick;
- static int32 m_ZoneState;
+ static float m_fHelpMessageTime;
+ static bool m_HelpMessageQuick;
+ static uint32 m_ZoneState;
static int32 m_ZoneFadeTimer;
- static int32 m_ZoneNameTimer;
- static wchar *&m_pZoneName;
+ static uint32 m_ZoneNameTimer;
+ static wchar *m_pZoneName;
static wchar *m_pLastZoneName;
static wchar *m_ZoneToPrint;
- static wchar *&m_VehicleName;
+ static wchar *m_VehicleName;
static wchar *m_pLastVehicleName;
static wchar *m_pVehicleNameToPrint;
- static int32 m_VehicleState;
+ static uint32 m_VehicleState;
static int32 m_VehicleFadeTimer;
- static int32 m_VehicleNameTimer;
- static wchar *m_Message;
- static wchar *m_PagerMessage;
- static bool &m_Wants_To_Draw_Hud;
- static bool &m_Wants_To_Draw_3dMarkers;
- static wchar(&m_BigMessage)[6][128];
- static int16 &m_ItemToFlash;
+ static uint32 m_VehicleNameTimer;
+ static wchar m_Message[256];
+ static wchar m_PagerMessage[256];
+ static bool m_Wants_To_Draw_Hud;
+ static bool m_Wants_To_Draw_3dMarkers;
+ static wchar m_BigMessage[6][128];
+ static int16 m_ItemToFlash;
// These aren't really in CHud
static float BigMessageInUse[6];
static float BigMessageAlpha[6];
static float BigMessageX[6];
- static float &OddJob2OffTimer;
- static int8 &CounterOnLastFrame;
- static float &OddJob2XOffset;
- static int16 &CounterFlashTimer;
- static int16 &OddJob2Timer;
- static int8 &TimerOnLastFrame;
- static int16 &OddJob2On;
- static int16 &TimerFlashTimer;
- static int16 &PagerSoundPlayed;
- static float &PagerXOffset;
- static int16 &PagerTimer;
- static int16 &PagerOn;
+ static float OddJob2OffTimer;
+ static bool CounterOnLastFrame;
+ static float OddJob2XOffset;
+ static uint16 CounterFlashTimer;
+ static uint16 OddJob2Timer;
+ static bool TimerOnLastFrame;
+ static int16 OddJob2On;
+ static uint16 TimerFlashTimer;
+ static int16 PagerSoundPlayed;
+ static int32 SpriteBrightness;
+ static float PagerXOffset;
+ static int16 PagerTimer;
+ static int16 PagerOn;
public:
static void Draw();
diff --git a/src/render/MBlur.cpp b/src/render/MBlur.cpp
index 1cf27ee0..d28671fa 100644
--- a/src/render/MBlur.cpp
+++ b/src/render/MBlur.cpp
@@ -4,12 +4,13 @@
#include "Camera.h"
#include "MBlur.h"
+// Originally taken from RW example 'mblur'
+
RwRaster *&CMBlur::pFrontBuffer = *(RwRaster**)0x8E2C48;
bool &CMBlur::ms_bJustInitialised = *(bool*)0x95CDAB;
bool &CMBlur::BlurOn = *(bool*)0x95CDAD;
static RwIm2DVertex Vertex[4];
-//static RwIm2DVertex *Vertex = (RwIm2DVertex*)0x62F780;
static RwImVertexIndex Index[6] = { 0, 1, 2, 0, 2, 3 };
void
diff --git a/src/core/PlayerSkin.cpp b/src/render/PlayerSkin.cpp
index 4f730b90..2cba45fe 100644
--- a/src/core/PlayerSkin.cpp
+++ b/src/render/PlayerSkin.cpp
@@ -1,173 +1,174 @@
-#include "common.h"
-#include "patcher.h"
-#include "main.h"
-#include "PlayerSkin.h"
-#include "TxdStore.h"
-#include "rtbmp.h"
-#include "ClumpModelInfo.h"
-#include "VisibilityPlugins.h"
-#include "World.h"
-#include "PlayerInfo.h"
-#include "CdStream.h"
-#include "FileMgr.h"
-#include "Directory.h"
-#include "RwHelper.h"
-#include "Timer.h"
-#include "Lights.h"
-
-int CPlayerSkin::m_txdSlot;
-
-void
-FindPlayerDff(uint32 &offset, uint32 &size)
-{
- int file;
- CDirectory::DirectoryInfo info;
-
- file = CFileMgr::OpenFile("models\\gta3.dir", "rb");
-
- do {
- if (!CFileMgr::Read(file, (char*)&info, sizeof(CDirectory::DirectoryInfo)))
- return;
- } while (strcasecmp("player.dff", info.name) != 0);
-
- offset = info.offset;
- size = info.size;
-}
-
-void
-LoadPlayerDff(void)
-{
- RwStream *stream;
- RwMemory mem;
- uint32 offset, size;
- uint8 *buffer;
- bool streamWasAdded = false;
-
- if (CdStreamGetNumImages() == 0) {
- CdStreamAddImage("models\\gta3.img");
- streamWasAdded = true;
- }
-
- FindPlayerDff(offset, size);
- buffer = (uint8*)RwMallocAlign(size << 11, 2048);
- CdStreamRead(0, buffer, offset, size);
- CdStreamSync(0);
-
- mem.start = buffer;
- mem.length = size << 11;
- stream = RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem);
-
- if (RwStreamFindChunk(stream, rwID_CLUMP, nil, nil))
- gpPlayerClump = RpClumpStreamRead(stream);
-
- RwStreamClose(stream, &mem);
- RwFreeAlign(buffer);
-
- if (streamWasAdded)
- CdStreamRemoveImages();
-}
-
-void
-CPlayerSkin::Initialise(void)
-{
- m_txdSlot = CTxdStore::AddTxdSlot("skin");
- CTxdStore::Create(m_txdSlot);
- CTxdStore::AddRef(m_txdSlot);
-}
-
-void
-CPlayerSkin::Shutdown(void)
-{
- CTxdStore::RemoveTxdSlot(m_txdSlot);
-}
-
-RwTexture *
-CPlayerSkin::GetSkinTexture(const char *texName)
-{
- RwTexture *tex;
- RwRaster *raster;
- int32 width, height, depth, format;
-
- CTxdStore::PushCurrentTxd();
- CTxdStore::SetCurrentTxd(m_txdSlot);
- tex = RwTextureRead(texName, NULL);
- CTxdStore::PopCurrentTxd();
- if (tex) return tex;
-
- if (strcmp(DEFAULT_SKIN_NAME, texName) == 0)
- sprintf(gString, "models\\generic\\player.bmp");
- else
- sprintf(gString, "skins\\%s.bmp", texName);
-
- if (RwImage *image = RtBMPImageRead(gString)) {
- RwImageFindRasterFormat(image, rwRASTERTYPETEXTURE, &width, &height, &depth, &format);
- raster = RwRasterCreate(width, height, depth, format);
- RwRasterSetFromImage(raster, image);
-
- tex = RwTextureCreate(raster);
- RwTextureSetName(tex, texName);
- RwTextureSetFilterMode(tex, rwFILTERLINEAR); // filtering bugfix from VC
- RwTexDictionaryAddTexture(CTxdStore::GetSlot(m_txdSlot)->texDict, tex);
-
- RwImageDestroy(image);
- }
- return tex;
-}
-
-void
-CPlayerSkin::BeginFrontendSkinEdit(void)
-{
- LoadPlayerDff();
- RpClumpForAllAtomics(gpPlayerClump, CClumpModelInfo::SetAtomicRendererCB, CVisibilityPlugins::RenderPlayerCB);
- CWorld::Players[0].LoadPlayerSkin();
- gOldFov = CDraw::GetFOV();
- CDraw::SetFOV(30.0f);
-}
-
-void
-CPlayerSkin::EndFrontendSkinEdit(void)
-{
- RpClumpDestroy(gpPlayerClump);
- gpPlayerClump = NULL;
- CDraw::SetFOV(gOldFov);
-}
-
-void
-CPlayerSkin::RenderFrontendSkinEdit(void)
-{
- static float rotation = 0.0f;
- RwRGBAReal AmbientColor = { 0.65f, 0.65f, 0.65f, 1.0f };
- RwV3d pos = { 1.35f, 0.35f, 7.725f };
- const RwV3d axis1 = { 1.0f, 0.0f, 0.0f };
- const RwV3d axis2 = { 0.0f, 0.0f, 1.0f };
- static uint32 LastFlash = 0;
-
-#ifdef ASPECT_RATIO_SCALE
- pos.x = 1.35f * (SCREEN_ASPECT_RATIO / DEFAULT_ASPECT_RATIO);
-#endif
-
- RwFrame *frame = RpClumpGetFrame(gpPlayerClump);
-
- if (CTimer::GetTimeInMillisecondsPauseMode() - LastFlash > 7) {
- rotation += 2.0f;
- if (rotation > 360.0f)
- rotation -= 360.0f;
- LastFlash = CTimer::GetTimeInMillisecondsPauseMode();
- }
- RwFrameTransform(frame, RwFrameGetMatrix(RwCameraGetFrame(Scene.camera)), rwCOMBINEREPLACE);
- RwFrameTranslate(frame, &pos, rwCOMBINEPRECONCAT);
- RwFrameRotate(frame, &axis1, -90.0f, rwCOMBINEPRECONCAT);
- RwFrameRotate(frame, &axis2, rotation, rwCOMBINEPRECONCAT);
- RwFrameUpdateObjects(frame);
- SetAmbientColours(&AmbientColor);
- RpClumpRender(gpPlayerClump);
-}
-
-STARTPATCHES
-InjectHook(0x59B9B0, &CPlayerSkin::Initialise, PATCH_JUMP);
-InjectHook(0x59B9E0, &CPlayerSkin::Shutdown, PATCH_JUMP);
-InjectHook(0x59B9F0, &CPlayerSkin::GetSkinTexture, PATCH_JUMP);
-InjectHook(0x59BC70, &CPlayerSkin::BeginFrontendSkinEdit, PATCH_JUMP);
-InjectHook(0x59BCB0, &CPlayerSkin::EndFrontendSkinEdit, PATCH_JUMP);
-InjectHook(0x59BCE0, &CPlayerSkin::RenderFrontendSkinEdit, PATCH_JUMP);
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+#include "PlayerSkin.h"
+#include "TxdStore.h"
+#include "rtbmp.h"
+#include "ClumpModelInfo.h"
+#include "VisibilityPlugins.h"
+#include "World.h"
+#include "PlayerInfo.h"
+#include "CdStream.h"
+#include "FileMgr.h"
+#include "Directory.h"
+#include "RwHelper.h"
+#include "Timer.h"
+#include "Lights.h"
+
+RpClump *gpPlayerClump;
+float gOldFov;
+
+int CPlayerSkin::m_txdSlot;
+
+void
+FindPlayerDff(uint32 &offset, uint32 &size)
+{
+ int file;
+ CDirectory::DirectoryInfo info;
+
+ file = CFileMgr::OpenFile("models\\gta3.dir", "rb");
+
+ do {
+ if (!CFileMgr::Read(file, (char*)&info, sizeof(CDirectory::DirectoryInfo)))
+ return;
+ } while (strcasecmp("player.dff", info.name) != 0);
+
+ offset = info.offset;
+ size = info.size;
+}
+
+void
+LoadPlayerDff(void)
+{
+ RwStream *stream;
+ RwMemory mem;
+ uint32 offset, size;
+ uint8 *buffer;
+ bool streamWasAdded = false;
+
+ if (CdStreamGetNumImages() == 0) {
+ CdStreamAddImage("models\\gta3.img");
+ streamWasAdded = true;
+ }
+
+ FindPlayerDff(offset, size);
+ buffer = (uint8*)RwMallocAlign(size << 11, 2048);
+ CdStreamRead(0, buffer, offset, size);
+ CdStreamSync(0);
+
+ mem.start = buffer;
+ mem.length = size << 11;
+ stream = RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem);
+
+ if (RwStreamFindChunk(stream, rwID_CLUMP, nil, nil))
+ gpPlayerClump = RpClumpStreamRead(stream);
+
+ RwStreamClose(stream, &mem);
+ RwFreeAlign(buffer);
+
+ if (streamWasAdded)
+ CdStreamRemoveImages();
+}
+
+void
+CPlayerSkin::Initialise(void)
+{
+ m_txdSlot = CTxdStore::AddTxdSlot("skin");
+ CTxdStore::Create(m_txdSlot);
+ CTxdStore::AddRef(m_txdSlot);
+}
+
+void
+CPlayerSkin::Shutdown(void)
+{
+ CTxdStore::RemoveTxdSlot(m_txdSlot);
+}
+
+RwTexture *
+CPlayerSkin::GetSkinTexture(const char *texName)
+{
+ RwTexture *tex;
+ RwRaster *raster;
+ int32 width, height, depth, format;
+
+ CTxdStore::PushCurrentTxd();
+ CTxdStore::SetCurrentTxd(m_txdSlot);
+ tex = RwTextureRead(texName, NULL);
+ CTxdStore::PopCurrentTxd();
+ if (tex != nil) return tex;
+
+ if (strcmp(DEFAULT_SKIN_NAME, texName) == 0)
+ sprintf(gString, "models\\generic\\player.bmp");
+ else
+ sprintf(gString, "skins\\%s.bmp", texName);
+
+ if (RwImage *image = RtBMPImageRead(gString)) {
+ RwImageFindRasterFormat(image, rwRASTERTYPETEXTURE, &width, &height, &depth, &format);
+ raster = RwRasterCreate(width, height, depth, format);
+ RwRasterSetFromImage(raster, image);
+
+ tex = RwTextureCreate(raster);
+ RwTextureSetName(tex, texName);
+#ifdef FIX_BUGS
+ RwTextureSetFilterMode(tex, rwFILTERLINEAR); // filtering bugfix from VC
+#endif
+ RwTexDictionaryAddTexture(CTxdStore::GetSlot(m_txdSlot)->texDict, tex);
+
+ RwImageDestroy(image);
+ }
+ return tex;
+}
+
+void
+CPlayerSkin::BeginFrontendSkinEdit(void)
+{
+ LoadPlayerDff();
+ RpClumpForAllAtomics(gpPlayerClump, CClumpModelInfo::SetAtomicRendererCB, CVisibilityPlugins::RenderPlayerCB);
+ CWorld::Players[0].LoadPlayerSkin();
+ gOldFov = CDraw::GetFOV();
+ CDraw::SetFOV(30.0f);
+}
+
+void
+CPlayerSkin::EndFrontendSkinEdit(void)
+{
+ RpClumpDestroy(gpPlayerClump);
+ gpPlayerClump = NULL;
+ CDraw::SetFOV(gOldFov);
+}
+
+void
+CPlayerSkin::RenderFrontendSkinEdit(void)
+{
+ static float rotation = 0.0f;
+ RwRGBAReal AmbientColor = { 0.65f, 0.65f, 0.65f, 1.0f };
+ const RwV3d pos = { 1.35f, 0.35f, 7.725f };
+ const RwV3d axis1 = { 1.0f, 0.0f, 0.0f };
+ const RwV3d axis2 = { 0.0f, 0.0f, 1.0f };
+ static uint32 LastFlash = 0;
+
+ RwFrame *frame = RpClumpGetFrame(gpPlayerClump);
+
+ if (CTimer::GetTimeInMillisecondsPauseMode() - LastFlash > 7) {
+ rotation += 2.0f;
+ if (rotation > 360.0f)
+ rotation -= 360.0f;
+ LastFlash = CTimer::GetTimeInMillisecondsPauseMode();
+ }
+ RwFrameTransform(frame, RwFrameGetMatrix(RwCameraGetFrame(Scene.camera)), rwCOMBINEREPLACE);
+ RwFrameTranslate(frame, &pos, rwCOMBINEPRECONCAT);
+ RwFrameRotate(frame, &axis1, -90.0f, rwCOMBINEPRECONCAT);
+ RwFrameRotate(frame, &axis2, rotation, rwCOMBINEPRECONCAT);
+ RwFrameUpdateObjects(frame);
+ SetAmbientColours(&AmbientColor);
+ RpClumpRender(gpPlayerClump);
+}
+
+STARTPATCHES
+InjectHook(0x59B9B0, &CPlayerSkin::Initialise, PATCH_JUMP);
+InjectHook(0x59B9E0, &CPlayerSkin::Shutdown, PATCH_JUMP);
+InjectHook(0x59B9F0, &CPlayerSkin::GetSkinTexture, PATCH_JUMP);
+InjectHook(0x59BC70, &CPlayerSkin::BeginFrontendSkinEdit, PATCH_JUMP);
+InjectHook(0x59BCB0, &CPlayerSkin::EndFrontendSkinEdit, PATCH_JUMP);
+InjectHook(0x59BCE0, &CPlayerSkin::RenderFrontendSkinEdit, PATCH_JUMP);
ENDPATCHES \ No newline at end of file
diff --git a/src/core/PlayerSkin.h b/src/render/PlayerSkin.h
index 2d82ec12..e0214ce0 100644
--- a/src/core/PlayerSkin.h
+++ b/src/render/PlayerSkin.h
@@ -2,12 +2,6 @@
#define DEFAULT_SKIN_NAME "$$\"\""
-static RpClump *gpPlayerClump;// = *(RpClump**)0x660FF8;
-static float gOldFov;// = *(float*)0x660FFC;
-
-void LoadPlayerDff(void);
-void FindPlayerDff(uint32 &offset, uint32 &size);
-
class CPlayerSkin
{
static int m_txdSlot;
diff --git a/src/render/Renderer.h b/src/render/Renderer.h
index 89fc23cb..42c154ec 100644
--- a/src/render/Renderer.h
+++ b/src/render/Renderer.h
@@ -29,7 +29,7 @@ class CRenderer
static CVehicle *&m_pFirstPersonVehicle;
public:
- static float &ms_lodDistScale; // defined in Frontend.cpp
+ static float ms_lodDistScale; // defined in Frontend.cpp
static bool &m_loadingPriority;
static void Init(void);
diff --git a/src/render/Rubbish.cpp b/src/render/Rubbish.cpp
index a52e59a0..65d8b2dd 100644
--- a/src/render/Rubbish.cpp
+++ b/src/render/Rubbish.cpp
@@ -1,10 +1,420 @@
#include "common.h"
+#include "main.h"
#include "patcher.h"
+#include "General.h"
+#include "Timer.h"
+#include "Weather.h"
+#include "Camera.h"
+#include "World.h"
+#include "Vehicle.h"
+#include "ZoneCull.h"
+#include "TxdStore.h"
+#include "RenderBuffer.h"
#include "Rubbish.h"
-WRAPPER void CRubbish::Render(void) { EAXJMP(0x512190); }
-WRAPPER void CRubbish::StirUp(CVehicle *veh) { EAXJMP(0x512690); }
-WRAPPER void CRubbish::Update(void) { EAXJMP(0x511B90); }
-WRAPPER void CRubbish::SetVisibility(bool) { EAXJMP(0x512AA0); }
-WRAPPER void CRubbish::Init(void) { EAXJMP(0x511940); }
-WRAPPER void CRubbish::Shutdown(void) { EAXJMP(0x511B50); }
+#define RUBBISH_MAX_DIST (18.0f)
+#define RUBBISH_FADE_DIST (16.5f)
+
+RwTexture *gpRubbishTexture[4];
+RwImVertexIndex RubbishIndexList[6];
+RwImVertexIndex RubbishIndexList2[6]; // unused
+RwIm3DVertex RubbishVertices[4];
+bool CRubbish::bRubbishInvisible;
+int CRubbish::RubbishVisibility;
+COneSheet CRubbish::aSheets[NUM_RUBBISH_SHEETS];
+COneSheet CRubbish::StartEmptyList;
+COneSheet CRubbish::EndEmptyList;
+COneSheet CRubbish::StartStaticsList;
+COneSheet CRubbish::EndStaticsList;
+COneSheet CRubbish::StartMoversList;
+COneSheet CRubbish::EndMoversList;
+
+
+void
+COneSheet::AddToList(COneSheet *list)
+{
+ this->m_next = list->m_next;
+ this->m_prev = list;
+ list->m_next = this;
+ this->m_next->m_prev = this;
+}
+
+void
+COneSheet::RemoveFromList(void)
+{
+ m_next->m_prev = m_prev;
+ m_prev->m_next = m_next;
+}
+
+
+void
+CRubbish::Render(void)
+{
+ int type;
+
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
+
+ for(type = 0; type < 4; type++){
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRubbishTexture[type]));
+
+ TempBufferIndicesStored = 0;
+ TempBufferVerticesStored = 0;
+
+ COneSheet *sheet;
+ for(sheet = &aSheets[type*NUM_RUBBISH_SHEETS / 4];
+ sheet < &aSheets[(type+1)*NUM_RUBBISH_SHEETS / 4];
+ sheet++){
+ if(sheet->m_state == 0)
+ continue;
+
+ uint32 alpha = 128;
+ CVector pos;
+ if(sheet->m_state == 1){
+ pos = sheet->m_basePos;
+ if(!sheet->m_isVisible)
+ alpha = 0;
+ }else{
+ pos = sheet->m_animatedPos;
+ // Not fully visible during animation, calculate current alpha
+ if(!sheet->m_isVisible || !sheet->m_targetIsVisible){
+ float t = (float)(CTimer::GetTimeInMilliseconds() - sheet->m_moveStart)/sheet->m_moveDuration;
+ float f1 = sheet->m_isVisible ? 1.0f-t : 0.0f;
+ float f2 = sheet->m_targetIsVisible ? t : 0.0f;
+ alpha = 128 * (f1+f2);
+ }
+ }
+
+ float camDist = (pos - TheCamera.GetPosition()).Magnitude2D();
+ if(camDist < RUBBISH_MAX_DIST){
+ if(camDist >= RUBBISH_FADE_DIST)
+ alpha -= alpha*(camDist-RUBBISH_FADE_DIST)/(RUBBISH_MAX_DIST-RUBBISH_FADE_DIST);
+ alpha = (RubbishVisibility*alpha)/256;
+
+ float vx = Sin(sheet->m_angle) * 0.4f;
+ float vy = Cos(sheet->m_angle) * 0.4f;
+
+ int v = TempBufferVerticesStored;
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[v+0], pos.x + vx, pos.y + vy, pos.z);
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+0], 255, 255, 255, alpha);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[v+1], pos.x - vy, pos.y + vx, pos.z);
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+1], 255, 255, 255, alpha);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[v+2], pos.x + vy, pos.y - vx, pos.z);
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+2], 255, 255, 255, alpha);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[v+3], pos.x - vx, pos.y - vy, pos.z);
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+3], 255, 255, 255, alpha);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[v+0], 0.0f);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[v+0], 0.0f);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[v+1], 1.0f);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[v+1], 0.0f);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[v+2], 0.0f);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[v+2], 1.0f);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[v+3], 1.0f);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[v+3], 1.0f);
+
+ int i = TempBufferIndicesStored;
+ TempBufferRenderIndexList[i+0] = RubbishIndexList[0] + TempBufferVerticesStored;
+ TempBufferRenderIndexList[i+1] = RubbishIndexList[1] + TempBufferVerticesStored;
+ TempBufferRenderIndexList[i+2] = RubbishIndexList[2] + TempBufferVerticesStored;
+ TempBufferRenderIndexList[i+3] = RubbishIndexList[3] + TempBufferVerticesStored;
+ TempBufferRenderIndexList[i+4] = RubbishIndexList[4] + TempBufferVerticesStored;
+ TempBufferRenderIndexList[i+5] = RubbishIndexList[5] + TempBufferVerticesStored;
+ TempBufferVerticesStored += 4;
+ TempBufferIndicesStored += 6;
+ }
+ }
+
+ if(TempBufferIndicesStored != 0){
+ LittleTest();
+ if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
+ RwIm3DEnd();
+ }
+ }
+ }
+
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+}
+
+void
+CRubbish::StirUp(CVehicle *veh)
+{
+ if((CTimer::GetFrameCounter() ^ (veh->m_randomSeed&3)) == 0)
+ return;
+
+ if(Abs(veh->GetPosition().x - TheCamera.GetPosition().x) < 20.0f &&
+ Abs(veh->GetPosition().y - TheCamera.GetPosition().y) < 20.0f)
+ if(Abs(veh->GetMoveSpeed().x) > 0.05f || Abs(veh->GetMoveSpeed().y) > 0.05f){
+ float speed = veh->GetMoveSpeed().Magnitude2D();
+ if(speed > 0.05f){
+ bool movingForward = DotProduct2D(veh->GetMoveSpeed(), veh->GetForward()) > 0.0f;
+ COneSheet *sheet = StartStaticsList.m_next;
+ CVector2D size = veh->GetColModel()->boundingBox.max;
+
+ // Check all static sheets
+ while(sheet != &EndStaticsList){
+ COneSheet *next = sheet->m_next;
+ CVector2D carToSheet = sheet->m_basePos - veh->GetPosition();
+ float distFwd = DotProduct2D(carToSheet, veh->GetForward());
+
+ // sheet has to be a bit behind car
+ if(movingForward && distFwd < -0.5f*size.y && distFwd > -1.5f*size.y ||
+ !movingForward && distFwd > 0.5f*size.y && distFwd < 1.5f*size.y){
+ float distSide = Abs(DotProduct2D(carToSheet, veh->GetRight()));
+ if(distSide < 1.5*size.x){
+ // Check with higher speed for sheet directly behind car
+ float speedToCheck = distSide < size.x ? speed : speed*0.5f;
+ if(speedToCheck > 0.05f){
+ sheet->m_state = 2;
+ if(speedToCheck > 0.15f)
+ sheet->m_animationType = 2;
+ else
+ sheet->m_animationType = 1;
+ sheet->m_moveDuration = 2000;
+ sheet->m_xDist = veh->GetMoveSpeed().x;
+ sheet->m_yDist = veh->GetMoveSpeed().y;
+ float dist = Sqrt(SQR(sheet->m_xDist)+SQR(sheet->m_yDist));
+ sheet->m_xDist *= 25.0f*speed/dist;
+ sheet->m_yDist *= 25.0f*speed/dist;
+ sheet->m_animHeight = 3.0f*speed;
+ sheet->m_moveStart = CTimer::GetTimeInMilliseconds();
+ float tx = sheet->m_basePos.x + sheet->m_xDist;
+ float ty = sheet->m_basePos.y + sheet->m_yDist;
+ float tz = sheet->m_basePos.z + 3.0f;
+ sheet->m_targetZ = CWorld::FindGroundZFor3DCoord(tx, ty, tz, nil) + 0.1f;
+ sheet->RemoveFromList();
+ sheet->AddToList(&StartMoversList);
+ }
+ }
+ }
+
+ sheet = next;
+ }
+ }
+ }
+}
+
+static float aAnimations[3][34] = {
+ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
+
+ // Normal move
+ { 0.0f, 0.05f, 0.12f, 0.25f, 0.42f, 0.57f, 0.68f, 0.8f, 0.86f, 0.9f, 0.93f, 0.95f, 0.96f, 0.97f, 0.98f, 0.99f, 1.0f, // XY movemnt
+ 0.15f, 0.35f, 0.6f, 0.9f, 1.2f, 1.25f, 1.3f, 1.2f, 1.1f, 0.95f, 0.8f, 0.6f, 0.45f, 0.3f, 0.2f, 0.1f, 0 }, // Z movement
+
+ // Stirred up by fast vehicle
+ { 0.0f, 0.05f, 0.12f, 0.25f, 0.42f, 0.57f, 0.68f, 0.8f, 0.95f, 1.1f, 1.15f, 1.18f, 1.15f, 1.1f, 1.05f, 1.03f, 1.0f,
+ 0.15f, 0.35f, 0.6f, 0.9f, 1.2f, 1.25f, 1.3f, 1.2f, 1.1f, 0.95f, 0.8f, 0.6f, 0.45f, 0.3f, 0.2f, 0.1f, 0 }
+};
+
+void
+CRubbish::Update(void)
+{
+ bool foundGround;
+
+ // FRAMETIME
+ if(bRubbishInvisible)
+ RubbishVisibility = max(RubbishVisibility-5, 0);
+ else
+ RubbishVisibility = min(RubbishVisibility+5, 255);
+
+ // Spawn a new sheet
+ COneSheet *sheet = StartEmptyList.m_next;
+ if(sheet != &EndEmptyList){
+ float spawnDist;
+ float spawnAngle;
+
+ spawnDist = (CGeneral::GetRandomNumber()&0xFF)/256.0f + RUBBISH_MAX_DIST;
+ uint8 r = CGeneral::GetRandomNumber();
+ if(r&1)
+ spawnAngle = (CGeneral::GetRandomNumber()&0xFF)/256.0f * 6.28f;
+ else
+ spawnAngle = (r-128)/160.0f + TheCamera.Orientation;
+ sheet->m_basePos.x = TheCamera.GetPosition().x + spawnDist*Sin(spawnAngle);
+ sheet->m_basePos.y = TheCamera.GetPosition().y + spawnDist*Cos(spawnAngle);
+ sheet->m_basePos.z = CWorld::FindGroundZFor3DCoord(sheet->m_basePos.x, sheet->m_basePos.y, TheCamera.GetPosition().z, &foundGround) + 0.1f;
+ if(foundGround){
+ // Found ground, so add to statics list
+ sheet->m_angle = (CGeneral::GetRandomNumber()&0xFF)/256.0f * 6.28f;
+ sheet->m_state = 1;
+ if(CCullZones::FindAttributesForCoors(sheet->m_basePos, nil) & ATTRZONE_NORAIN)
+ sheet->m_isVisible = false;
+ else
+ sheet->m_isVisible = true;
+ sheet->RemoveFromList();
+ sheet->AddToList(&StartStaticsList);
+ }
+ }
+
+ // Process animation
+ sheet = StartMoversList.m_next;
+ while(sheet != &EndMoversList){
+ uint32 currentTime = CTimer::GetTimeInMilliseconds() - sheet->m_moveStart;
+ if(currentTime < sheet->m_moveDuration){
+ // Animation
+ int step = 16 * currentTime / sheet->m_moveDuration; // 16 steps in animation
+ int stepTime = sheet->m_moveDuration/16; // time in each step
+ float s = (float)(currentTime - stepTime*step) / stepTime; // position on step
+ float t = (float)currentTime / sheet->m_moveDuration; // position on total animation
+ // factors for xy and z-movment
+ float fxy = aAnimations[sheet->m_animationType][step]*(1.0f-s) + aAnimations[sheet->m_animationType][step+1]*s;
+ float fz = aAnimations[sheet->m_animationType][step+17]*(1.0f-s) + aAnimations[sheet->m_animationType][step+1+17]*s;
+ sheet->m_animatedPos.x = sheet->m_basePos.x + fxy*sheet->m_xDist;
+ sheet->m_animatedPos.y = sheet->m_basePos.y + fxy*sheet->m_yDist;
+ sheet->m_animatedPos.z = (1.0f-t)*sheet->m_basePos.z + t*sheet->m_targetZ + fz*sheet->m_animHeight;
+ sheet->m_angle += CTimer::GetTimeStep()*0.04f;
+ if(sheet->m_angle > 6.28f)
+ sheet->m_angle -= 6.28f;
+ sheet = sheet->m_next;
+ }else{
+ // End of animation, back into statics list
+ sheet->m_basePos.x += sheet->m_xDist;
+ sheet->m_basePos.y += sheet->m_yDist;
+ sheet->m_basePos.z = sheet->m_targetZ;
+ sheet->m_state = 1;
+ sheet->m_isVisible = sheet->m_targetIsVisible;
+
+ COneSheet *next = sheet->m_next;
+ sheet->RemoveFromList();
+ sheet->AddToList(&StartStaticsList);
+ sheet = next;
+ }
+ }
+
+ // Stir up a sheet by wind
+ // FRAMETIME
+ int freq;
+ if(CWeather::Wind < 0.1f)
+ freq = 31;
+ else if(CWeather::Wind < 0.4f)
+ freq = 7;
+ else if(CWeather::Wind < 0.7f)
+ freq = 1;
+ else
+ freq = 0;
+ if((CTimer::GetFrameCounter() & freq) == 0){
+ // Pick a random sheet and set animation state if static
+ int i = CGeneral::GetRandomNumber() % NUM_RUBBISH_SHEETS;
+ if(aSheets[i].m_state == 1){
+ aSheets[i].m_moveStart = CTimer::GetTimeInMilliseconds();
+ aSheets[i].m_moveDuration = CWeather::Wind*1500.0f + 1000.0f;
+ aSheets[i].m_animHeight = 0.2f;
+ aSheets[i].m_xDist = 3.0f*CWeather::Wind;
+ aSheets[i].m_yDist = 3.0f*CWeather::Wind;
+ // Check if target position is ok
+ float tx = aSheets[i].m_basePos.x + aSheets[i].m_xDist;
+ float ty = aSheets[i].m_basePos.y + aSheets[i].m_yDist;
+ float tz = aSheets[i].m_basePos.z + 3.0f;
+ aSheets[i].m_targetZ = CWorld::FindGroundZFor3DCoord(tx, ty, tz, &foundGround) + 0.1f;
+ if(CCullZones::FindAttributesForCoors(CVector(tx, ty, aSheets[i].m_targetZ), nil) & ATTRZONE_NORAIN)
+ aSheets[i].m_targetIsVisible = false;
+ else
+ aSheets[i].m_targetIsVisible = true;
+ if(foundGround){
+ // start animation
+ aSheets[i].m_state = 2;
+ aSheets[i].m_animationType = 1;
+ aSheets[i].RemoveFromList();
+ aSheets[i].AddToList(&StartMoversList);
+ }
+ }
+ }
+
+ // Remove sheets that are too far away
+ int i = (CTimer::GetFrameCounter()%(NUM_RUBBISH_SHEETS/4))*4;
+ int last = ((CTimer::GetFrameCounter()%(NUM_RUBBISH_SHEETS/4)) + 1)*4;
+ for(; i < last; i++){
+ if(aSheets[i].m_state == 1 &&
+ (aSheets[i].m_basePos - TheCamera.GetPosition()).MagnitudeSqr2D() > SQR(RUBBISH_MAX_DIST+1.0f)){
+ aSheets[i].m_state = 0;
+ aSheets[i].RemoveFromList();
+ aSheets[i].AddToList(&StartEmptyList);
+ }
+ }
+}
+
+void
+CRubbish::SetVisibility(bool visible)
+{
+ bRubbishInvisible = !visible;
+}
+
+void
+CRubbish::Init(void)
+{
+ int i;
+ for(i = 0; i < NUM_RUBBISH_SHEETS; i++){
+ aSheets[i].m_state = 0;
+ if(i < NUM_RUBBISH_SHEETS-1)
+ aSheets[i].m_next = &aSheets[i+1];
+ else
+ aSheets[i].m_next = &EndEmptyList;
+ if(i > 0)
+ aSheets[i].m_prev = &aSheets[i-1];
+ else
+ aSheets[i].m_prev = &StartEmptyList;
+ }
+
+ StartEmptyList.m_next = &aSheets[0];
+ StartEmptyList.m_prev = nil;
+ EndEmptyList.m_next = nil;
+ EndEmptyList.m_prev = &aSheets[NUM_RUBBISH_SHEETS-1];
+
+ StartStaticsList.m_next = &EndStaticsList;
+ StartStaticsList.m_prev = nil;
+ EndStaticsList.m_next = nil;
+ EndStaticsList.m_prev = &StartStaticsList;
+
+ StartMoversList.m_next = &EndMoversList;
+ StartMoversList.m_prev = nil;
+ EndMoversList.m_next = nil;
+ EndMoversList.m_prev = &StartMoversList;
+
+ // unused
+ RwIm3DVertexSetU(&RubbishVertices[0], 0.0f);
+ RwIm3DVertexSetV(&RubbishVertices[0], 0.0f);
+ RwIm3DVertexSetU(&RubbishVertices[1], 1.0f);
+ RwIm3DVertexSetV(&RubbishVertices[1], 0.0f);
+ RwIm3DVertexSetU(&RubbishVertices[2], 0.0f);
+ RwIm3DVertexSetV(&RubbishVertices[2], 1.0f);
+ RwIm3DVertexSetU(&RubbishVertices[3], 1.0f);
+ RwIm3DVertexSetV(&RubbishVertices[3], 1.0f);
+
+ // unused
+ RubbishIndexList2[0] = 0;
+ RubbishIndexList2[1] = 2;
+ RubbishIndexList2[2] = 1;
+ RubbishIndexList2[3] = 1;
+ RubbishIndexList2[4] = 2;
+ RubbishIndexList2[5] = 3;
+
+ RubbishIndexList[0] = 0;
+ RubbishIndexList[1] = 1;
+ RubbishIndexList[2] = 2;
+ RubbishIndexList[3] = 1;
+ RubbishIndexList[4] = 3;
+ RubbishIndexList[5] = 2;
+
+ CTxdStore::PushCurrentTxd();
+ int slot = CTxdStore::FindTxdSlot("particle");
+ CTxdStore::SetCurrentTxd(slot);
+ gpRubbishTexture[0] = RwTextureRead("gameleaf01_64", nil);
+ gpRubbishTexture[1] = RwTextureRead("gameleaf02_64", nil);
+ gpRubbishTexture[2] = RwTextureRead("newspaper01_64", nil);
+ gpRubbishTexture[3] = RwTextureRead("newspaper02_64", nil);
+ CTxdStore::PopCurrentTxd();
+ RubbishVisibility = 255;
+ bRubbishInvisible = false;
+}
+
+void
+CRubbish::Shutdown(void)
+{
+ RwTextureDestroy(gpRubbishTexture[0]);
+ RwTextureDestroy(gpRubbishTexture[1]);
+ RwTextureDestroy(gpRubbishTexture[2]);
+ RwTextureDestroy(gpRubbishTexture[3]);
+}
diff --git a/src/render/Rubbish.h b/src/render/Rubbish.h
index 17323694..2be592fe 100644
--- a/src/render/Rubbish.h
+++ b/src/render/Rubbish.h
@@ -2,13 +2,50 @@
class CVehicle;
+enum {
+ // NB: not all values are allowed, check the code
+ NUM_RUBBISH_SHEETS = 64
+};
+
+class COneSheet
+{
+public:
+ CVector m_basePos;
+ CVector m_animatedPos;
+ float m_targetZ;
+ int8 m_state;
+ int8 m_animationType;
+ uint32 m_moveStart;
+ uint32 m_moveDuration;
+ float m_animHeight;
+ float m_xDist;
+ float m_yDist;
+ float m_angle;
+ bool m_isVisible;
+ bool m_targetIsVisible;
+ COneSheet *m_next;
+ COneSheet *m_prev;
+
+ void AddToList(COneSheet *list);
+ void RemoveFromList(void);
+};
+
class CRubbish
{
+ static bool bRubbishInvisible;
+ static int RubbishVisibility;
+ static COneSheet aSheets[NUM_RUBBISH_SHEETS];
+ static COneSheet StartEmptyList;
+ static COneSheet EndEmptyList;
+ static COneSheet StartStaticsList;
+ static COneSheet EndStaticsList;
+ static COneSheet StartMoversList;
+ static COneSheet EndMoversList;
public:
static void Render(void);
static void StirUp(CVehicle *veh); // CAutomobile on PS2
static void Update(void);
- static void SetVisibility(bool);
+ static void SetVisibility(bool visible);
static void Init(void);
static void Shutdown(void);
};
diff --git a/src/render/Shadows.h b/src/render/Shadows.h
index 982cc463..fb41ebbc 100644
--- a/src/render/Shadows.h
+++ b/src/render/Shadows.h
@@ -175,11 +175,18 @@ public:
static void RenderIndicatorShadow (uint32 nID, uint8 ShadowType, RwTexture *pTexture, CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity);
};
-extern RwTexture *&gpBloodPoolTex;
+extern RwTexture *&gpShadowCarTex;
+extern RwTexture *&gpShadowPedTex;
+extern RwTexture *&gpShadowHeliTex;
extern RwTexture *&gpShadowExplosionTex;
extern RwTexture *&gpShadowHeadLightsTex;
-extern RwTexture *&gpGoalTex;
extern RwTexture *&gpOutline1Tex;
extern RwTexture *&gpOutline2Tex;
extern RwTexture *&gpOutline3Tex;
+extern RwTexture *&gpBloodPoolTex;
+extern RwTexture *&gpReflectionTex;
+extern RwTexture *&gpGoalMarkerTex;
+extern RwTexture *&gpWalkDontTex;
extern RwTexture *&gpCrackedGlassTex;
+extern RwTexture *&gpPostShadowTex;
+extern RwTexture *&gpGoalTex;
diff --git a/src/render/Skidmarks.cpp b/src/render/Skidmarks.cpp
index c2725ed6..41ee5d1d 100644
--- a/src/render/Skidmarks.cpp
+++ b/src/render/Skidmarks.cpp
@@ -1,12 +1,247 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
+#include "TxdStore.h"
+#include "Timer.h"
+#include "Replay.h"
#include "Skidmarks.h"
-WRAPPER void CSkidmarks::Clear(void) { EAXJMP(0x518130); }
-WRAPPER void CSkidmarks::Update() { EAXJMP(0x518200); }
+CSkidmark CSkidmarks::aSkidmarks[NUMSKIDMARKS];
-WRAPPER void CSkidmarks::Render(void) { EAXJMP(0x5182E0); }
-WRAPPER void CSkidmarks::RegisterOne(uint32 id, CVector pos, float fwdx, float fwdY, bool *isMuddy, bool *isBloddy) { EAXJMP(0x5185C0); }
+RwImVertexIndex SkidmarkIndexList[SKIDMARK_LENGTH * 6];
+RwIm3DVertex SkidmarkVertices[SKIDMARK_LENGTH * 2];
+RwTexture *gpSkidTex;
+RwTexture *gpSkidBloodTex;
+RwTexture *gpSkidMudTex;
-WRAPPER void CSkidmarks::Init(void) { EAXJMP(0x517D70); }
-WRAPPER void CSkidmarks::Shutdown(void) { EAXJMP(0x518100); }
+void
+CSkidmarks::Init(void)
+{
+ int i, ix, slot;
+ CTxdStore::PushCurrentTxd();
+ slot = CTxdStore::FindTxdSlot("particle");
+ CTxdStore::SetCurrentTxd(slot);
+ gpSkidTex = RwTextureRead("particleskid", nil);
+ gpSkidBloodTex = RwTextureRead("particleskidblood", nil);
+ gpSkidMudTex = RwTextureRead("particleskidmud", nil);
+ CTxdStore::PopCurrentTxd();
+
+ for(i = 0; i < NUMSKIDMARKS; i++){
+ aSkidmarks[i].m_state = 0;
+ aSkidmarks[i].m_wasUpdated = false;
+ }
+
+ ix = 0;
+ for(i = 0; i < SKIDMARK_LENGTH; i++){
+ SkidmarkIndexList[i*6+0] = ix+0;
+ SkidmarkIndexList[i*6+1] = ix+2;
+ SkidmarkIndexList[i*6+2] = ix+1;
+ SkidmarkIndexList[i*6+3] = ix+1;
+ SkidmarkIndexList[i*6+4] = ix+2;
+ SkidmarkIndexList[i*6+5] = ix+3;
+ ix += 2;
+ }
+
+ for(i = 0; i < SKIDMARK_LENGTH; i++){
+ RwIm3DVertexSetU(&SkidmarkVertices[i*2 + 0], 0.0f);
+ RwIm3DVertexSetV(&SkidmarkVertices[i*2 + 0], i*5.01f);
+ RwIm3DVertexSetU(&SkidmarkVertices[i*2 + 1], 1.0f);
+ RwIm3DVertexSetV(&SkidmarkVertices[i*2 + 1], i*5.01f);
+ }
+}
+
+void
+CSkidmarks::Shutdown(void)
+{
+ RwTextureDestroy(gpSkidTex);
+ RwTextureDestroy(gpSkidBloodTex);
+ RwTextureDestroy(gpSkidMudTex);
+}
+
+void
+CSkidmarks::Clear(void)
+{
+ int i;
+ for(i = 0; i < NUMSKIDMARKS; i++){
+ aSkidmarks[i].m_state = 0;
+ aSkidmarks[i].m_wasUpdated = false;
+ }
+}
+
+void
+CSkidmarks::Update(void)
+{
+ int i;
+ uint32 t1 = CTimer::GetTimeInMilliseconds() + 2500;
+ uint32 t2 = CTimer::GetTimeInMilliseconds() + 5000;
+ uint32 t3 = CTimer::GetTimeInMilliseconds() + 10000;
+ uint32 t4 = CTimer::GetTimeInMilliseconds() + 20000;
+ for(i = 0; i < NUMSKIDMARKS; i++){
+ switch(aSkidmarks[i].m_state){
+ case 1:
+ if(!aSkidmarks[i].m_wasUpdated){
+ // Didn't continue this one last time, so finish it and set fade times
+ aSkidmarks[i].m_state = 2;
+ if(aSkidmarks[i].m_last < 4){
+ aSkidmarks[i].m_fadeStart = t1;
+ aSkidmarks[i].m_fadeEnd = t2;
+ }else if(aSkidmarks[i].m_last < 9){
+ aSkidmarks[i].m_fadeStart = t2;
+ aSkidmarks[i].m_fadeEnd = t3;
+ }else{
+ aSkidmarks[i].m_fadeStart = t3;
+ aSkidmarks[i].m_fadeEnd = t4;
+ }
+ }
+ break;
+ case 2:
+ if(CTimer::GetTimeInMilliseconds() > aSkidmarks[i].m_fadeEnd)
+ aSkidmarks[i].m_state = 0;
+ break;
+ }
+ aSkidmarks[i].m_wasUpdated = false;
+ }
+}
+
+void
+CSkidmarks::Render(void)
+{
+ int i, j;
+ RwTexture *lastTex = nil;
+
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+
+ for(i = 0; i < NUMSKIDMARKS; i++){
+ if(aSkidmarks[i].m_state == 0 || aSkidmarks[i].m_last < 1)
+ continue;
+
+ if(aSkidmarks[i].m_isBloody){
+ if(lastTex != gpSkidBloodTex){
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidBloodTex));
+ lastTex = gpSkidBloodTex;
+ }
+ }else if(aSkidmarks[i].m_isMuddy){
+ if(lastTex != gpSkidMudTex){
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidMudTex));
+ lastTex = gpSkidMudTex;
+ }
+ }else{
+ if(lastTex != gpSkidTex){
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidTex));
+ lastTex = gpSkidTex;
+ }
+ }
+
+ uint32 fade, alpha;
+ if(aSkidmarks[i].m_state == 1 || CTimer::GetTimeInMilliseconds() < aSkidmarks[i].m_fadeStart)
+ fade = 255;
+ else
+ fade = 255*(aSkidmarks[i].m_fadeEnd - CTimer::GetTimeInMilliseconds()) / (aSkidmarks[i].m_fadeEnd - aSkidmarks[i].m_fadeStart);
+
+ for(j = 0; j <= aSkidmarks[i].m_last; j++){
+ alpha = 128;
+ if(j == 0 || j == aSkidmarks[i].m_last && aSkidmarks[i].m_state == 2)
+ alpha = 0;
+ alpha = alpha*fade/256;
+
+ CVector p1 = aSkidmarks[i].m_pos[j] + aSkidmarks[i].m_side[j];
+ CVector p2 = aSkidmarks[i].m_pos[j] - aSkidmarks[i].m_side[j];
+ RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+0], 255, 255, 255, alpha);
+ RwIm3DVertexSetPos(&SkidmarkVertices[j*2+0], p1.x, p1.y, p1.z+0.1f);
+ RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+1], 255, 255, 255, alpha);
+ RwIm3DVertexSetPos(&SkidmarkVertices[j*2+1], p2.x, p2.y, p2.z+0.1f);
+ }
+
+ LittleTest();
+ if(RwIm3DTransform(SkidmarkVertices, 2*(aSkidmarks[i].m_last+1), nil, rwIM3D_VERTEXUV)){
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, SkidmarkIndexList, 6*aSkidmarks[i].m_last);
+ RwIm3DEnd();
+ }
+ }
+
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+}
+
+void
+CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody)
+{
+ int i;
+ CVector2D fwd(fwdX, fwdY);
+
+ if(CReplay::IsPlayingBack())
+ return;
+
+ // Find a skidmark to continue
+ for(i = 0; i < NUMSKIDMARKS; i++)
+ if(aSkidmarks[i].m_state == 1 && aSkidmarks[i].m_id == id)
+ break;
+
+ if(i < NUMSKIDMARKS){
+ // Continue this one
+
+ if(aSkidmarks[i].m_isBloody != *isBloody){
+ // Blood-status changed, end this one
+ aSkidmarks[i].m_state = 2;
+ aSkidmarks[i].m_fadeStart = CTimer::GetTimeInMilliseconds() + 10000;
+ aSkidmarks[i].m_fadeEnd = CTimer::GetTimeInMilliseconds() + 20000;
+ return;
+ }
+
+ aSkidmarks[i].m_wasUpdated = true;
+
+ if(CTimer::GetTimeInMilliseconds() - aSkidmarks[i].m_lastUpdate <= 100){
+ // Last update was recently, just change last coords
+ aSkidmarks[i].m_pos[aSkidmarks[i].m_last] = pos;
+ return;
+ }
+ aSkidmarks[i].m_lastUpdate = CTimer::GetTimeInMilliseconds();
+
+ if(aSkidmarks[i].m_last >= SKIDMARK_LENGTH-1){
+ // No space to continue, end it
+ aSkidmarks[i].m_state = 2;
+ aSkidmarks[i].m_fadeStart = CTimer::GetTimeInMilliseconds() + 10000;
+ aSkidmarks[i].m_fadeEnd = CTimer::GetTimeInMilliseconds() + 20000;
+ *isBloody = false; // stpo blood marks at end
+ return;
+ }
+ aSkidmarks[i].m_last++;
+
+ aSkidmarks[i].m_pos[aSkidmarks[i].m_last] = pos;
+
+ CVector2D dist = aSkidmarks[i].m_pos[aSkidmarks[i].m_last] - aSkidmarks[i].m_pos[aSkidmarks[i].m_last-1];
+ dist.Normalise();
+ CVector2D right(dist.y, -dist.x);
+ float turn = DotProduct2D(fwd, right);
+ turn = Abs(turn) + 1.0f;
+ aSkidmarks[i].m_side[aSkidmarks[i].m_last] = CVector(right.x, right.y, 0.0f) * turn * 0.125f;
+ if(aSkidmarks[i].m_last == 1)
+ aSkidmarks[i].m_side[0] = aSkidmarks[i].m_side[1];
+
+ if(aSkidmarks[i].m_last > 8)
+ *isBloody = false; // stop blood marks after 8
+ return;
+ }
+
+ // Start a new one
+ for(i = 0; i < NUMSKIDMARKS; i++)
+ if(aSkidmarks[i].m_state == 0)
+ break;
+ if(i < NUMSKIDMARKS){
+ // Found a free slot
+ aSkidmarks[i].m_state = 1;
+ aSkidmarks[i].m_id = id;
+ aSkidmarks[i].m_pos[0] = pos;
+ aSkidmarks[i].m_side[0] = CVector(0.0f, 0.0f, 0.0f);
+ aSkidmarks[i].m_wasUpdated = true;
+ aSkidmarks[i].m_last = 0;
+ aSkidmarks[i].m_lastUpdate = CTimer::GetTimeInMilliseconds() - 1000;
+ aSkidmarks[i].m_isBloody = *isBloody;
+ aSkidmarks[i].m_isMuddy = *isMuddy;
+ }else
+ *isBloody = false; // stop blood marks if no space
+}
diff --git a/src/render/Skidmarks.h b/src/render/Skidmarks.h
index bf2da7e4..085b4c6d 100644
--- a/src/render/Skidmarks.h
+++ b/src/render/Skidmarks.h
@@ -1,12 +1,32 @@
#pragma once
+enum { SKIDMARK_LENGTH = 16 };
+
+class CSkidmark
+{
+public:
+ uint8 m_state;
+ bool m_wasUpdated;
+ bool m_isBloody;
+ bool m_isMuddy;
+ uintptr m_id;
+ int16 m_last;
+ uint32 m_lastUpdate;;
+ uint32 m_fadeStart;
+ uint32 m_fadeEnd;
+ CVector m_pos[SKIDMARK_LENGTH];
+ CVector m_side[SKIDMARK_LENGTH];
+};
+
class CSkidmarks
{
+ static CSkidmark aSkidmarks[NUMSKIDMARKS];
public:
+
+ static void Init(void);
+ static void Shutdown(void);
static void Clear(void);
static void Update(void);
static void Render(void);
- static void RegisterOne(uint32 id, CVector pos, float fwdx, float fwdY, bool *isMuddy, bool *isBloddy);
- static void Init(void);
- static void Shutdown(void);
+ static void RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody);
};
diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp
index 301ae265..9189a7c2 100644
--- a/src/render/SpecialFX.cpp
+++ b/src/render/SpecialFX.cpp
@@ -1,6 +1,7 @@
#include "common.h"
#include "patcher.h"
#include "SpecialFX.h"
+#include "RenderBuffer.h"
#include "Timer.h"
#include "Sprite.h"
#include "Font.h"
@@ -8,26 +9,260 @@
#include "TxdStore.h"
#include "FileMgr.h"
#include "FileLoader.h"
+#include "Timecycle.h"
#include "Lights.h"
+#include "ModelIndices.h"
#include "VisibilityPlugins.h"
#include "World.h"
+#include "PlayerPed.h"
#include "Particle.h"
+#include "Shadows.h"
#include "General.h"
#include "Camera.h"
#include "Shadows.h"
#include "main.h"
-WRAPPER void CSpecialFX::Render(void) { EAXJMP(0x518DC0); }
-WRAPPER void CSpecialFX::Update(void) { EAXJMP(0x518D40); }
-WRAPPER void CSpecialFX::Init(void) { EAXJMP(0x5189E0); }
-WRAPPER void CSpecialFX::Shutdown(void) { EAXJMP(0x518BE0); }
+RwIm3DVertex StreakVertices[4];
+RwImVertexIndex StreakIndexList[12];
+
+RwIm3DVertex TraceVertices[6];
+RwImVertexIndex TraceIndexList[12];
+
+
+void
+CSpecialFX::Init(void)
+{
+ CBulletTraces::Init();
+
+ RwIm3DVertexSetU(&StreakVertices[0], 0.0f);
+ RwIm3DVertexSetV(&StreakVertices[0], 0.0f);
+ RwIm3DVertexSetU(&StreakVertices[1], 1.0f);
+ RwIm3DVertexSetV(&StreakVertices[1], 0.0f);
+ RwIm3DVertexSetU(&StreakVertices[2], 0.0f);
+ RwIm3DVertexSetV(&StreakVertices[2], 0.0f);
+ RwIm3DVertexSetU(&StreakVertices[3], 1.0f);
+ RwIm3DVertexSetV(&StreakVertices[3], 0.0f);
+
+ StreakIndexList[0] = 0;
+ StreakIndexList[1] = 1;
+ StreakIndexList[2] = 2;
+ StreakIndexList[3] = 1;
+ StreakIndexList[4] = 3;
+ StreakIndexList[5] = 2;
+ StreakIndexList[6] = 0;
+ StreakIndexList[7] = 2;
+ StreakIndexList[8] = 1;
+ StreakIndexList[9] = 1;
+ 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();
+}
+
+RwObject*
+LookForBatCB(RwObject *object, void *data)
+{
+ static CMatrix MatLTM;
+
+ if(CVisibilityPlugins::GetAtomicModelInfo((RpAtomic*)object) == (CSimpleModelInfo*)data){
+ MatLTM = CMatrix(RwFrameGetLTM(RpAtomicGetFrame((RpAtomic*)object)));
+ CVector p1 = MatLTM * CVector(0.02f, 0.05f, 0.07f);
+ CVector p2 = MatLTM * CVector(0.246f, 0.0325f, 0.796f);
+ CMotionBlurStreaks::RegisterStreak((uintptr)object, 100, 100, 100, p1, p2);
+ }
+ return nil;
+}
+
+void
+CSpecialFX::Update(void)
+{
+ CMotionBlurStreaks::Update();
+ CBulletTraces::Update();
+
+ if(FindPlayerPed() &&
+ FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT &&
+ FindPlayerPed()->GetWeapon()->m_eWeaponState == WEAPONSTATE_FIRING)
+ RwFrameForAllObjects(FindPlayerPed()->GetNodeFrame(PED_HANDR), LookForBatCB, CModelInfo::GetModelInfo(MI_BASEBALL_BAT));
+}
+
+void
+CSpecialFX::Shutdown(void)
+{
+ C3dMarkers::Shutdown();
+}
+
+void
+CSpecialFX::Render(void)
+{
+ CMotionBlurStreaks::Render();
+ CBulletTraces::Render();
+ CBrightLights::Render();
+ CShinyTexts::Render();
+ CMoneyMessages::Render();
+ C3dMarkers::Render();
+}
+
+CRegisteredMotionBlurStreak CMotionBlurStreaks::aStreaks[NUMMBLURSTREAKS];
+
+void
+CRegisteredMotionBlurStreak::Update(void)
+{
+ int i;
+ bool wasUpdated;
+ bool lastWasUpdated = false;
+ for(i = 2; i > 0; i--){
+ m_pos1[i] = m_pos1[i-1];
+ m_pos2[i] = m_pos2[i-1];
+ m_isValid[i] = m_isValid[i-1];
+ wasUpdated = true;
+ if(!lastWasUpdated && !m_isValid[i])
+ wasUpdated = false;
+ lastWasUpdated = wasUpdated;
+ }
+ m_isValid[0] = false;
+ if(!wasUpdated)
+ m_id = 0;
+}
+
+void
+CRegisteredMotionBlurStreak::Render(void)
+{
+ int i;
+ int a1, a2;
+ for(i = 0; i < 2; i++)
+ if(m_isValid[i] && m_isValid[i+1]){
+ a1 = (255/3)*(3-i)/3;
+ RwIm3DVertexSetRGBA(&StreakVertices[0], m_red, m_green, m_blue, a1);
+ RwIm3DVertexSetRGBA(&StreakVertices[1], m_red, m_green, m_blue, a1);
+ a2 = (255/3)*(3-(i+1))/3;
+ RwIm3DVertexSetRGBA(&StreakVertices[2], m_red, m_green, m_blue, a2);
+ RwIm3DVertexSetRGBA(&StreakVertices[3], m_red, m_green, m_blue, a2);
+ RwIm3DVertexSetPos(&StreakVertices[0], m_pos1[i].x, m_pos1[i].y, m_pos1[i].z);
+ RwIm3DVertexSetPos(&StreakVertices[1], m_pos2[i].x, m_pos2[i].y, m_pos2[i].z);
+ RwIm3DVertexSetPos(&StreakVertices[2], m_pos1[i+1].x, m_pos1[i+1].y, m_pos1[i+1].z);
+ RwIm3DVertexSetPos(&StreakVertices[3], m_pos2[i+1].x, m_pos2[i+1].y, m_pos2[i+1].z);
+ LittleTest();
+ if(RwIm3DTransform(StreakVertices, 4, nil, rwIM3D_VERTEXUV)){
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, StreakIndexList, 12);
+ RwIm3DEnd();
+ }
+ }
+}
+
+void
+CMotionBlurStreaks::Init(void)
+{
+ int i;
+ for(i = 0; i < NUMMBLURSTREAKS; i++)
+ aStreaks[i].m_id = 0;
+}
+
+void
+CMotionBlurStreaks::Update(void)
+{
+ int i;
+ for(i = 0; i < NUMMBLURSTREAKS; i++)
+ if(aStreaks[i].m_id)
+ aStreaks[i].Update();
+}
+
+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
+ aStreaks[i].m_red = r;
+ aStreaks[i].m_green = g;
+ aStreaks[i].m_blue = b;
+ aStreaks[i].m_pos1[0] = p1;
+ aStreaks[i].m_pos2[0] = p2;
+ aStreaks[i].m_isValid[0] = true;
+ return;
+ }
+ }
+ // Find free slot
+ for(i = 0; aStreaks[i].m_id; i++)
+ if(i == NUMMBLURSTREAKS-1)
+ return;
+ // Create a new streak
+ aStreaks[i].m_id = id;
+ aStreaks[i].m_red = r;
+ aStreaks[i].m_green = g;
+ aStreaks[i].m_blue = b;
+ aStreaks[i].m_pos1[0] = p1;
+ aStreaks[i].m_pos2[0] = p2;
+ aStreaks[i].m_isValid[0] = true;
+ aStreaks[i].m_isValid[1] = false;
+ aStreaks[i].m_isValid[2] = false;
+}
-WRAPPER void CMotionBlurStreaks::RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2) { EAXJMP(0x519460); }
+void
+CMotionBlurStreaks::Render(void)
+{
+ bool setRenderStates = false;
+ int i;
+ for(i = 0; i < NUMMBLURSTREAKS; i++)
+ if(aStreaks[i].m_id){
+ if(!setRenderStates){
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE);
+ RwRenderStateSet(rwRENDERSTATEFOGCOLOR,
+ (void*)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255));
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE);
+ setRenderStates = true;
+ }
+ aStreaks[i].Render();
+ }
+ if(setRenderStates){
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE);
+ }
+}
-CBulletTrace (&CBulletTraces::aTraces)[NUMBULLETTRACES] = *(CBulletTrace(*)[NUMBULLETTRACES])*(uintptr*)0x72B1B8;
-RxObjSpace3DVertex (&TraceVertices)[6] = *(RxObjSpace3DVertex(*)[6])*(uintptr*)0x649884;
-RwImVertexIndex (&TraceIndexList)[12] = *(RwImVertexIndex(*)[12])*(uintptr*)0x64986C;
+CBulletTrace CBulletTraces::aTraces[NUMBULLETTRACES];
void CBulletTraces::Init(void)
{
@@ -56,10 +291,10 @@ void CBulletTraces::Render(void)
for (int i = 0; i < NUMBULLETTRACES; i++) {
if (!aTraces[i].m_bInUse)
continue;
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)0);
- RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)2);
- RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)2);
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpShadowExplosionTex->raster);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ 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;
@@ -81,9 +316,9 @@ void CBulletTraces::Render(void)
RwIm3DEnd();
}
}
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)1);
- RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)5);
- RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)6);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
}
void CBulletTraces::Update(void)
@@ -115,8 +350,6 @@ void CBulletTrace::Update(void)
m_framesInUse++;
}
-WRAPPER void CBrightLights::RegisterOne(CVector pos, CVector up, CVector right, CVector fwd, uint8 type, uint8 unk1, uint8 unk2, uint8 unk3) { EAXJMP(0x51A410); }
-
RpAtomic *
MarkerAtomicCB(RpAtomic *atomic, void *data)
{
@@ -181,8 +414,7 @@ C3dMarker::Render()
{
if (m_pAtomic == nil) return;
- RwRGBA *color = RpMaterialGetColor(m_pMaterial);
- *color = m_Color;
+ RpMaterialSetColor(m_pMaterial, &m_Color);
m_Matrix.UpdateRW();
@@ -201,9 +433,9 @@ C3dMarker::Render()
ReSetAmbientAndDirectionalColours();
}
-C3dMarker(&C3dMarkers::m_aMarkerArray)[NUM3DMARKERS] = *(C3dMarker(*)[NUM3DMARKERS])*(uintptr*)0x72D408;
-int32 &C3dMarkers::NumActiveMarkers = *(int32*)0x8F2A08;
-RpClump* (&C3dMarkers::m_pRpClumpArray)[NUMMARKERTYPES] = *(RpClump*(*)[NUMMARKERTYPES])*(uintptr*)0x8E2888;
+C3dMarker C3dMarkers::m_aMarkerArray[NUM3DMARKERS];
+int32 C3dMarkers::NumActiveMarkers;
+RpClump* C3dMarkers::m_pRpClumpArray[NUMMARKERTYPES];
void
C3dMarkers::Init()
@@ -402,6 +634,377 @@ C3dMarkers::Update()
{
}
+
+#define BRIGHTLIGHTS_MAX_DIST (60.0f) // invisible beyond this
+#define BRIGHTLIGHTS_FADE_DIST (45.0f) // strongest between these two
+#define CARLIGHTS_MAX_DIST (30.0f)
+#define CARLIGHTS_FADE_DIST (15.0f) // 31 for close lights
+
+int CBrightLights::NumBrightLights;
+CBrightLight CBrightLights::aBrightLights[NUMBRIGHTLIGHTS];
+
+void
+CBrightLights::Init(void)
+{
+ NumBrightLights = 0;
+}
+
+void
+CBrightLights::RegisterOne(CVector pos, CVector up, CVector side, CVector front,
+ uint8 type, uint8 red, uint8 green, uint8 blue)
+{
+ if(NumBrightLights >= NUMBRIGHTLIGHTS)
+ return;
+
+ aBrightLights[NumBrightLights].m_camDist = (pos - TheCamera.GetPosition()).Magnitude();
+ if(aBrightLights[NumBrightLights].m_camDist > BRIGHTLIGHTS_MAX_DIST)
+ return;
+
+ aBrightLights[NumBrightLights].m_pos = pos;
+ aBrightLights[NumBrightLights].m_up = up;
+ aBrightLights[NumBrightLights].m_side = side;
+ aBrightLights[NumBrightLights].m_front = front;
+ aBrightLights[NumBrightLights].m_type = type;
+ aBrightLights[NumBrightLights].m_red = red;
+ aBrightLights[NumBrightLights].m_green = green;
+ aBrightLights[NumBrightLights].m_blue = blue;
+
+ NumBrightLights++;
+}
+
+static float TrafficLightsSide[6] = { -0.09f, 0.09f, 0.162f, 0.09f, -0.09f, -0.162f };
+static float TrafficLightsUp[6] = { 0.162f, 0.162f, 0.0f, -0.162f, -0.162f, 0.0f };
+static float LongCarHeadLightsSide[8] = { -0.2f, 0.2f, -0.2f, 0.2f, -0.2f, 0.2f, -0.2f, 0.2f };
+static float LongCarHeadLightsFront[8] = { 0.1f, 0.1f, -0.1f, -0.1f, 0.1f, 0.1f, -0.1f, -0.1f };
+static float LongCarHeadLightsUp[8] = { 0.1f, 0.1f, 0.1f, 0.1f, -0.1f, -0.1f, -0.1f, -0.1f };
+static float SmallCarHeadLightsSide[8] = { -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f };
+static float SmallCarHeadLightsFront[8] = { 0.08f, 0.08f, -0.08f, -0.08f, 0.08f, 0.08f, -0.08f, -0.08f };
+static float SmallCarHeadLightsUp[8] = { 0.08f, 0.08f, 0.08f, 0.08f, -0.08f, -0.08f, -0.08f, -0.08f };
+static float BigCarHeadLightsSide[8] = { -0.15f, 0.15f, -0.15f, 0.15f, -0.15f, 0.15f, -0.15f, 0.15f };
+static float BigCarHeadLightsFront[8] = { 0.15f, 0.15f, -0.15f, -0.15f, 0.15f, 0.15f, -0.15f, -0.15f };
+static float BigCarHeadLightsUp[8] = { 0.15f, 0.15f, 0.15f, 0.15f, -0.15f, -0.15f, -0.15f, -0.15f };
+static float TallCarHeadLightsSide[8] = { -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f };
+static float TallCarHeadLightsFront[8] = { 0.08f, 0.08f, -0.08f, -0.08f, 0.08f, 0.08f, -0.08f, -0.08f };
+static float TallCarHeadLightsUp[8] = { 0.2f, 0.2f, 0.2f, 0.2f, -0.2f, -0.2f, -0.2f, -0.2f };
+static float SirenLightsSide[6] = { -0.04f, 0.04f, 0.06f, 0.04f, -0.04f, -0.06f };
+static float SirenLightsUp[6] = { 0.06f, 0.06f, 0.0f, -0.06f, -0.06f, 0.0f };
+static RwImVertexIndex TrafficLightIndices[4*3] = { 0, 1, 5, 1, 2, 3, 1, 3, 4, 1, 4, 5 };
+static RwImVertexIndex CubeIndices[12*3] = {
+ 0, 2, 1, 1, 2, 3, 3, 5, 1, 3, 7, 5,
+ 2, 7, 3, 2, 6, 7, 4, 0, 1, 4, 1, 5,
+ 6, 0, 4, 6, 2, 0, 6, 5, 7, 6, 4, 5
+};
+
+void
+CBrightLights::Render(void)
+{
+ int i, j;
+ CVector pos;
+
+ if(NumBrightLights == 0)
+ return;
+
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+
+ for(i = 0; i < NumBrightLights; i++){
+ if(TempBufferIndicesStored > TEMPBUFFERINDEXSIZE-40 || TempBufferVerticesStored > TEMPBUFFERVERTSIZE-40)
+ RenderOutGeometryBuffer();
+
+ int r, g, b, a;
+ float flicker = (CGeneral::GetRandomNumber()&0xFF) * 0.2f;
+ switch(aBrightLights[i].m_type){
+ case BRIGHTLIGHT_TRAFFIC_GREEN:
+ r = flicker; g = 255; b = flicker;
+ break;
+ case BRIGHTLIGHT_TRAFFIC_YELLOW:
+ r = 255; g = 128; b = flicker;
+ break;
+ case BRIGHTLIGHT_TRAFFIC_RED:
+ r = 255; g = flicker; b = flicker;
+ break;
+
+ case BRIGHTLIGHT_FRONT_LONG:
+ case BRIGHTLIGHT_FRONT_SMALL:
+ case BRIGHTLIGHT_FRONT_BIG:
+ case BRIGHTLIGHT_FRONT_TALL:
+ r = 255; g = 255; b = 255;
+ break;
+
+ case BRIGHTLIGHT_REAR_LONG:
+ case BRIGHTLIGHT_REAR_SMALL:
+ case BRIGHTLIGHT_REAR_BIG:
+ case BRIGHTLIGHT_REAR_TALL:
+ r = 255; g = flicker; b = flicker;
+ break;
+
+ case BRIGHTLIGHT_SIREN:
+ r = aBrightLights[i].m_red;
+ g = aBrightLights[i].m_green;
+ b = aBrightLights[i].m_blue;
+ break;
+ }
+
+ if(aBrightLights[i].m_camDist < BRIGHTLIGHTS_FADE_DIST)
+ a = 255;
+ else
+ a = 255*(1.0f - (aBrightLights[i].m_camDist-BRIGHTLIGHTS_FADE_DIST)/(BRIGHTLIGHTS_MAX_DIST-BRIGHTLIGHTS_FADE_DIST));
+ // fade car lights down to 31 as they come near
+ if(aBrightLights[i].m_type >= BRIGHTLIGHT_FRONT_LONG && aBrightLights[i].m_type <= BRIGHTLIGHT_REAR_TALL){
+ if(aBrightLights[i].m_camDist < CARLIGHTS_FADE_DIST)
+ a = 31;
+ else if(aBrightLights[i].m_camDist < CARLIGHTS_MAX_DIST)
+ a = 31 + (255-31)*((aBrightLights[i].m_camDist-CARLIGHTS_FADE_DIST)/(CARLIGHTS_MAX_DIST-CARLIGHTS_FADE_DIST));
+ }
+
+ switch(aBrightLights[i].m_type){
+ case BRIGHTLIGHT_TRAFFIC_GREEN:
+ case BRIGHTLIGHT_TRAFFIC_YELLOW:
+ case BRIGHTLIGHT_TRAFFIC_RED:
+ for(j = 0; j < 6; j++){
+ pos = TrafficLightsSide[j]*aBrightLights[i].m_side +
+ TrafficLightsUp[j]*aBrightLights[i].m_up +
+ aBrightLights[i].m_pos;
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+ }
+ for(j = 0; j < 4*3; j++)
+ TempBufferRenderIndexList[TempBufferIndicesStored+j] = TrafficLightIndices[j] + TempBufferVerticesStored;
+ TempBufferVerticesStored += 6;
+ TempBufferIndicesStored += 4*3;
+ break;
+
+ case BRIGHTLIGHT_FRONT_LONG:
+ case BRIGHTLIGHT_REAR_LONG:
+ for(j = 0; j < 8; j++){
+ pos = LongCarHeadLightsSide[j]*aBrightLights[i].m_side +
+ LongCarHeadLightsUp[j]*aBrightLights[i].m_up +
+ LongCarHeadLightsFront[j]*aBrightLights[i].m_front +
+ aBrightLights[i].m_pos;
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+ }
+ for(j = 0; j < 12*3; j++)
+ TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
+ TempBufferVerticesStored += 8;
+ TempBufferIndicesStored += 12*3;
+ break;
+
+ case BRIGHTLIGHT_FRONT_SMALL:
+ case BRIGHTLIGHT_REAR_SMALL:
+ for(j = 0; j < 8; j++){
+ pos = SmallCarHeadLightsSide[j]*aBrightLights[i].m_side +
+ SmallCarHeadLightsUp[j]*aBrightLights[i].m_up +
+ SmallCarHeadLightsFront[j]*aBrightLights[i].m_front +
+ aBrightLights[i].m_pos;
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+ }
+ for(j = 0; j < 12*3; j++)
+ TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
+ TempBufferVerticesStored += 8;
+ TempBufferIndicesStored += 12*3;
+ break;
+
+ case BRIGHTLIGHT_FRONT_TALL:
+ case BRIGHTLIGHT_REAR_TALL:
+ for(j = 0; j < 8; j++){
+ pos = TallCarHeadLightsSide[j]*aBrightLights[i].m_side +
+ TallCarHeadLightsUp[j]*aBrightLights[i].m_up +
+ TallCarHeadLightsFront[j]*aBrightLights[i].m_front +
+ aBrightLights[i].m_pos;
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+ }
+ for(j = 0; j < 12*3; j++)
+ TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
+ TempBufferVerticesStored += 8;
+ TempBufferIndicesStored += 12*3;
+ break;
+
+ case BRIGHTLIGHT_SIREN:
+ for(j = 0; j < 6; j++){
+ pos = SirenLightsSide[j]*aBrightLights[i].m_side +
+ SirenLightsUp[j]*aBrightLights[i].m_up +
+ aBrightLights[i].m_pos;
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+ }
+ for(j = 0; j < 4*3; j++)
+ TempBufferRenderIndexList[TempBufferIndicesStored+j] = TrafficLightIndices[j] + TempBufferVerticesStored;
+ TempBufferVerticesStored += 6;
+ TempBufferIndicesStored += 4*3;
+ break;
+
+ }
+ }
+
+ RenderOutGeometryBuffer();
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+ NumBrightLights = 0;
+}
+
+void
+CBrightLights::RenderOutGeometryBuffer(void)
+{
+ if(TempBufferIndicesStored != 0){
+ LittleTest();
+ if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
+ RwIm3DEnd();
+ }
+ TempBufferVerticesStored = 0;
+ TempBufferIndicesStored = 0;
+ }
+}
+
+int CShinyTexts::NumShinyTexts;
+CShinyText CShinyTexts::aShinyTexts[NUMSHINYTEXTS];
+
+void
+CShinyTexts::Init(void)
+{
+ NumShinyTexts = 0;
+}
+
+void
+CShinyTexts::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)
+{
+ if(NumShinyTexts >= NUMSHINYTEXTS)
+ return;
+
+ aShinyTexts[NumShinyTexts].m_camDist = (p0 - TheCamera.GetPosition()).Magnitude();
+ if(aShinyTexts[NumShinyTexts].m_camDist > maxDist)
+ return;
+ aShinyTexts[NumShinyTexts].m_verts[0] = p0;
+ aShinyTexts[NumShinyTexts].m_verts[1] = p1;
+ aShinyTexts[NumShinyTexts].m_verts[2] = p2;
+ aShinyTexts[NumShinyTexts].m_verts[3] = p3;
+ aShinyTexts[NumShinyTexts].m_texCoords[0].x = u0;
+ aShinyTexts[NumShinyTexts].m_texCoords[0].y = v0;
+ aShinyTexts[NumShinyTexts].m_texCoords[1].x = u1;
+ aShinyTexts[NumShinyTexts].m_texCoords[1].y = v1;
+ aShinyTexts[NumShinyTexts].m_texCoords[2].x = u2;
+ aShinyTexts[NumShinyTexts].m_texCoords[2].y = v2;
+ aShinyTexts[NumShinyTexts].m_texCoords[3].x = u3;
+ aShinyTexts[NumShinyTexts].m_texCoords[3].y = v3;
+ aShinyTexts[NumShinyTexts].m_type = type;
+ aShinyTexts[NumShinyTexts].m_red = red;
+ aShinyTexts[NumShinyTexts].m_green = green;
+ aShinyTexts[NumShinyTexts].m_blue = blue;
+ // Fade out at half the max dist
+ float halfDist = maxDist*0.5f;
+ if(aShinyTexts[NumShinyTexts].m_camDist > halfDist){
+ float f = 1.0f - (aShinyTexts[NumShinyTexts].m_camDist - halfDist)/halfDist;
+ aShinyTexts[NumShinyTexts].m_red *= f;
+ aShinyTexts[NumShinyTexts].m_green *= f;
+ aShinyTexts[NumShinyTexts].m_blue *= f;
+ }
+
+ NumShinyTexts++;
+}
+
+void
+CShinyTexts::Render(void)
+{
+ int i, ix, v;
+ RwTexture *lastTex = nil;
+
+ if(NumShinyTexts == 0)
+ return;
+
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+
+ TempBufferVerticesStored = 0;
+ TempBufferIndicesStored = 0;
+
+ for(i = 0; i < NumShinyTexts; i++){
+ if(TempBufferIndicesStored > TEMPBUFFERINDEXSIZE-64 || TempBufferVerticesStored > TEMPBUFFERVERTSIZE-62)
+ RenderOutGeometryBuffer();
+
+ uint8 r = aShinyTexts[i].m_red;
+ uint8 g = aShinyTexts[i].m_green;
+ uint8 b = aShinyTexts[i].m_blue;
+
+ switch(aShinyTexts[i].m_type){
+ case SHINYTEXT_WALK:
+ if(lastTex != gpWalkDontTex){
+ RenderOutGeometryBuffer();
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpWalkDontTex));
+ lastTex = gpWalkDontTex;
+ }
+ quad:
+ v = TempBufferVerticesStored;
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+0], r, g, b, 255);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_verts[0].x, aShinyTexts[i].m_verts[0].y, aShinyTexts[i].m_verts[0].z);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_texCoords[0].x);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_texCoords[0].y);
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+1], r, g, b, 255);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_verts[1].x, aShinyTexts[i].m_verts[1].y, aShinyTexts[i].m_verts[1].z);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_texCoords[1].x);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_texCoords[1].y);
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+2], r, g, b, 255);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_verts[2].x, aShinyTexts[i].m_verts[2].y, aShinyTexts[i].m_verts[2].z);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_texCoords[2].x);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_texCoords[2].y);
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+3], r, g, b, 255);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_verts[3].x, aShinyTexts[i].m_verts[3].y, aShinyTexts[i].m_verts[3].z);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_texCoords[3].x);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_texCoords[3].y);
+ ix = TempBufferIndicesStored;
+ TempBufferRenderIndexList[ix+0] = 0 + TempBufferVerticesStored;
+ TempBufferRenderIndexList[ix+1] = 1 + TempBufferVerticesStored;
+ TempBufferRenderIndexList[ix+2] = 2 + TempBufferVerticesStored;
+ TempBufferRenderIndexList[ix+3] = 2 + TempBufferVerticesStored;
+ TempBufferRenderIndexList[ix+4] = 1 + TempBufferVerticesStored;
+ TempBufferRenderIndexList[ix+5] = 3 + TempBufferVerticesStored;
+ TempBufferVerticesStored += 4;
+ TempBufferIndicesStored += 6;
+ break;
+
+ case SHINYTEXT_FLAT:
+ if(lastTex != nil){
+ RenderOutGeometryBuffer();
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+ lastTex = nil;
+ }
+ goto quad;
+ }
+ }
+
+ RenderOutGeometryBuffer();
+ NumShinyTexts = 0;
+
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+}
+
+void
+CShinyTexts::RenderOutGeometryBuffer(void)
+{
+ if(TempBufferIndicesStored != 0){
+ LittleTest();
+ if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
+ RwIm3DEnd();
+ }
+ TempBufferVerticesStored = 0;
+ TempBufferIndicesStored = 0;
+ }
+}
+
+
+
#define MONEY_MESSAGE_LIFETIME_MS 2000
CMoneyMessage CMoneyMessages::aMoneyMessages[NUMMONEYMESSAGES];
@@ -564,6 +1167,16 @@ STARTPATCHES
InjectHook(0x51B400, C3dMarkers::Render, PATCH_JUMP);
InjectHook(0x51B3B0, C3dMarkers::Shutdown, PATCH_JUMP);
+ InjectHook(0x5197A0, CBrightLights::Init, PATCH_JUMP);
+ InjectHook(0x51A410, CBrightLights::RegisterOne, PATCH_JUMP);
+ InjectHook(0x5197B0, CBrightLights::Render, PATCH_JUMP);
+ InjectHook(0x51A3B0, CBrightLights::RenderOutGeometryBuffer, PATCH_JUMP);
+
+ InjectHook(0x51A5A0, CShinyTexts::Init, PATCH_JUMP);
+ InjectHook(0x51AAB0, CShinyTexts::RegisterOne, PATCH_JUMP);
+ InjectHook(0x51A5B0, CShinyTexts::Render, PATCH_JUMP);
+ InjectHook(0x51AA50, CShinyTexts::RenderOutGeometryBuffer, PATCH_JUMP);
+
InjectHook(0x51AF70, CMoneyMessages::Init, PATCH_JUMP);
InjectHook(0x51B030, CMoneyMessages::Render, PATCH_JUMP);
ENDPATCHES
diff --git a/src/render/SpecialFX.h b/src/render/SpecialFX.h
index fc155a53..2d9f18b1 100644
--- a/src/render/SpecialFX.h
+++ b/src/render/SpecialFX.h
@@ -9,10 +9,29 @@ public:
static void Shutdown(void);
};
+class CRegisteredMotionBlurStreak
+{
+public:
+ uintptr m_id;
+ uint8 m_red;
+ uint8 m_green;
+ uint8 m_blue;
+ CVector m_pos1[3];
+ CVector m_pos2[3];
+ bool m_isValid[3];
+
+ void Update(void);
+ void Render(void);
+};
+
class CMotionBlurStreaks
{
+ static CRegisteredMotionBlurStreak aStreaks[NUMMBLURSTREAKS];
public:
- static void RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2);
+ static void Init(void);
+ static void Update(void);
+ static void RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2);
+ static void Render(void);
};
struct CBulletTrace
@@ -29,7 +48,7 @@ struct CBulletTrace
class CBulletTraces
{
public:
- static CBulletTrace (&aTraces)[NUMBULLETTRACES];
+ static CBulletTrace aTraces[NUMBULLETTRACES];
static void Init(void);
static void AddTrace(CVector*, CVector*);
@@ -37,12 +56,6 @@ public:
static void Update(void);
};
-class CBrightLights
-{
-public:
- static void RegisterOne(CVector pos, CVector up, CVector right, CVector fwd, uint8 type, uint8 unk1 = 0, uint8 unk2 = 0, uint8 unk3 = 0);
-};
-
enum
{
MARKERTYPE_0 = 0,
@@ -57,27 +70,27 @@ enum
class C3dMarker
-{
-public:
- CMatrix m_Matrix;
- RpAtomic *m_pAtomic;
- RpMaterial *m_pMaterial;
- uint16 m_nType;
- bool m_bIsUsed;
- uint32 m_nIdentifier;
- RwRGBA m_Color;
- uint16 m_nPulsePeriod;
- int16 m_nRotateRate;
- uint32 m_nStartTime;
- float m_fPulseFraction;
- float m_fStdSize;
- float m_fSize;
- float m_fBrightness;
- float m_fCameraRange;
-
- bool AddMarker(uint32 identifier, uint16 type, float fSize, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
- void DeleteMarkerObject();
- void Render();
+{
+public:
+ CMatrix m_Matrix;
+ RpAtomic *m_pAtomic;
+ RpMaterial *m_pMaterial;
+ uint16 m_nType;
+ bool m_bIsUsed;
+ uint32 m_nIdentifier;
+ RwRGBA m_Color;
+ uint16 m_nPulsePeriod;
+ int16 m_nRotateRate;
+ uint32 m_nStartTime;
+ float m_fPulseFraction;
+ float m_fStdSize;
+ float m_fSize;
+ float m_fBrightness;
+ float m_fCameraRange;
+
+ bool AddMarker(uint32 identifier, uint16 type, float fSize, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
+ void DeleteMarkerObject();
+ void Render();
};
class C3dMarkers
@@ -87,42 +100,125 @@ public:
static void Shutdown();
static C3dMarker *PlaceMarker(uint32 id, uint16 type, CVector &pos, float size, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
static void PlaceMarkerSet(uint32 id, uint16 type, CVector &pos, float size, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
- static void Render();
+ static void Render();
static void Update();
- static C3dMarker(&m_aMarkerArray)[NUM3DMARKERS];
- static int32 &NumActiveMarkers;
- static RpClump* (&m_pRpClumpArray)[NUMMARKERTYPES];
-};
-
-class CMoneyMessage
-{
- friend class CMoneyMessages;
-
- uint32 m_nTimeRegistered;
- CVector m_vecPosition;
- wchar m_aText[16];
- CRGBA m_Colour;
- float m_fSize;
- float m_fOpacity;
-public:
- void Render();
-};
-
-class CMoneyMessages
-{
- static CMoneyMessage aMoneyMessages[NUMMONEYMESSAGES];
-public:
- static void Init();
- static void Render();
- 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 C3dMarker m_aMarkerArray[NUM3DMARKERS];
+ static int32 NumActiveMarkers;
+ static RpClump* m_pRpClumpArray[NUMMARKERTYPES];
+};
+
+enum
+{
+ BRIGHTLIGHT_INVALID,
+ BRIGHTLIGHT_TRAFFIC_GREEN,
+ BRIGHTLIGHT_TRAFFIC_YELLOW,
+ BRIGHTLIGHT_TRAFFIC_RED,
+
+ // white
+ BRIGHTLIGHT_FRONT_LONG,
+ BRIGHTLIGHT_FRONT_SMALL,
+ BRIGHTLIGHT_FRONT_BIG,
+ BRIGHTLIGHT_FRONT_TALL,
+
+ // red
+ BRIGHTLIGHT_REAR_LONG,
+ BRIGHTLIGHT_REAR_SMALL,
+ BRIGHTLIGHT_REAR_BIG,
+ BRIGHTLIGHT_REAR_TALL,
+
+ BRIGHTLIGHT_SIREN, // unused
+
+ BRIGHTLIGHT_FRONT = BRIGHTLIGHT_FRONT_LONG,
+ BRIGHTLIGHT_REAR = BRIGHTLIGHT_REAR_LONG,
+};
+
+class CBrightLight
+{
+public:
+ CVector m_pos;
+ CVector m_up;
+ CVector m_side;
+ CVector m_front;
+ float m_camDist;
+ uint8 m_type;
+ uint8 m_red;
+ uint8 m_green;
+ uint8 m_blue;
+};
+
+class CBrightLights
+{
+ static int NumBrightLights;
+ static CBrightLight aBrightLights[NUMBRIGHTLIGHTS];
+public:
+ static void Init(void);
+ static void RegisterOne(CVector pos, CVector up, CVector side, CVector front,
+ uint8 type, uint8 red = 0, uint8 green = 0, uint8 blue = 0);
+ static void Render(void);
+ static void RenderOutGeometryBuffer(void);
+};
+
+
+enum
+{
+ SHINYTEXT_WALK = 1,
+ SHINYTEXT_FLAT
+};
+
+class CShinyText
+{
+public:
+ CVector m_verts[4];
+ CVector2D m_texCoords[4];
+ float m_camDist;
+ uint8 m_type;
+ uint8 m_red;
+ uint8 m_green;
+ uint8 m_blue;
+};
+
+class CShinyTexts
+{
+ static int NumShinyTexts;
+ static CShinyText aShinyTexts[NUMSHINYTEXTS];
+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);
+ static void Render(void);
+ static void RenderOutGeometryBuffer(void);
+};
+
+class CMoneyMessage
+{
+ friend class CMoneyMessages;
+
+ uint32 m_nTimeRegistered;
+ CVector m_vecPosition;
+ wchar m_aText[16];
+ CRGBA m_Colour;
+ float m_fSize;
+ float m_fOpacity;
+public:
+ void Render();
+};
+
+class CMoneyMessages
+{
+ static CMoneyMessage aMoneyMessages[NUMMONEYMESSAGES];
+public:
+ static void Init();
+ static void Render();
+ 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*);
+};
diff --git a/src/render/Sprite.cpp b/src/render/Sprite.cpp
index 24577f41..8ac2315f 100644
--- a/src/render/Sprite.cpp
+++ b/src/render/Sprite.cpp
@@ -30,10 +30,12 @@ CSprite::CalcScreenCoors(const RwV3d &in, RwV3d *out, float *outw, float *outh,
out->x *= SCREEN_WIDTH * recip;
out->y *= SCREEN_HEIGHT * recip;
// What is this? size?
- *outw = 70.0f/CDraw::GetFOV();
- *outh = 70.0f/CDraw::GetFOV();
- *outw *= SCREEN_WIDTH * recip;
- *outh *= SCREEN_HEIGHT * recip;
+ *outw = 70.0f/CDraw::GetFOV() * SCREEN_WIDTH * recip;
+#ifdef ASPECT_RATIO_SCALE
+ *outh = 70.0f/CDraw::GetFOV() / (DEFAULT_ASPECT_RATIO / SCREEN_ASPECT_RATIO) * SCREEN_HEIGHT * recip;
+#else
+ *outh = 70.0f/CDraw::GetFOV() * SCREEN_HEIGHT * recip;
+#endif
return true;
}
@@ -432,6 +434,7 @@ void
CSprite::Set6Vertices2D(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
{
float screenz, recipz;
+ float z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
screenz = m_f2DNearScreenZ;
recipz = m_fRecipNearClipPlane;
@@ -496,6 +499,7 @@ CSprite::Set6Vertices2D(RwIm2DVertex *verts, float x1, float y1, float x2, float
const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
{
float screenz, recipz;
+ float z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
screenz = m_f2DNearScreenZ;
recipz = m_fRecipNearClipPlane;
diff --git a/src/render/Sprite2d.cpp b/src/render/Sprite2d.cpp
index c4dbcdaa..3f21516a 100644
--- a/src/render/Sprite2d.cpp
+++ b/src/render/Sprite2d.cpp
@@ -267,6 +267,7 @@ CSprite2d::SetVertices(float x1, float y1, float x2, float y2, float x3, float y
const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
{
float screenz, recipz;
+ float z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
screenz = RwIm2DGetNearScreenZ();
recipz = RecipNearClip;
@@ -312,10 +313,11 @@ void
CSprite2d::SetVertices(int n, float *positions, float *uvs, const CRGBA &col)
{
int i;
- float screenz, recipz;
+ float screenz, recipz, z;
screenz = RwIm2DGetNearScreenZ();
recipz = RecipNearClip;
+ z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
for(i = 0; i < n; i++){
@@ -334,10 +336,11 @@ void
CSprite2d::SetMaskVertices(int n, float *positions)
{
int i;
- float screenz, recipz;
+ float screenz, recipz, z;
screenz = RwIm2DGetNearScreenZ();
recipz = RecipNearClip;
+ z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
for(i = 0; i < n; i++){
RwIm2DVertexSetScreenX(&maVertices[i], positions[i*2 + 0]);
@@ -345,7 +348,7 @@ CSprite2d::SetMaskVertices(int n, float *positions)
RwIm2DVertexSetScreenZ(&maVertices[i], screenz);
RwIm2DVertexSetCameraZ(&maVertices[i], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[i], recipz);
- RwIm2DVertexSetIntRGBA(&maVertices[i], 0, 0, 0, 0);
+ RwIm2DVertexSetIntRGBA(&maVertices[i], 255, 255, 255, 255); // 0, 0, 0, 0 on PC
}
}
@@ -353,10 +356,11 @@ void
CSprite2d::SetVertices(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2)
{
- float screenz, recipz;
+ float screenz, recipz, z;
screenz = RwIm2DGetNearScreenZ();
recipz = RecipNearClip;
+ z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
RwIm2DVertexSetScreenX(&verts[0], r.left);
RwIm2DVertexSetScreenY(&verts[0], r.top);
@@ -459,15 +463,15 @@ CSprite2d::DrawRectXLU(const CRect &r, const CRGBA &c0, const CRGBA &c1, const C
void CSprite2d::Draw2DPolygon(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, const CRGBA &color)
{
- SetVertices(x1, y1, x2, y2, x3, y3, x4, y4, color, color, color, color);
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, 0);
- RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
- RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(color.a != 255));
- RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
- RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ SetVertices(x1, y1, x2, y2, x3, y3, x4, y4, color, color, color, color);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, 0);
+ RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(color.a != 255));
+ RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD);
}
diff --git a/src/render/TexList.cpp b/src/render/TexList.cpp
new file mode 100644
index 00000000..1689837f
--- /dev/null
+++ b/src/render/TexList.cpp
@@ -0,0 +1,41 @@
+#include "common.h"
+#include "TexList.h"
+#include "rtbmp.h"
+#include "FileMgr.h"
+
+bool CTexList::ms_nTexUsed[MAX_TEXUSED];
+
+void
+CTexList::Initialise()
+{}
+
+void
+CTexList::Shutdown()
+{}
+
+RwTexture *
+CTexList::SetTexture(int32 slot, char *name)
+{
+ return nil;
+}
+
+int32
+CTexList::GetFirstFreeTexture()
+{
+ for (int32 i = 0; i < MAX_TEXUSED; i++)
+ if (!ms_nTexUsed[i])
+ return i;
+ return -1;
+}
+
+RwTexture *
+CTexList::LoadFileNameTexture(char *name)
+{
+ return SetTexture(GetFirstFreeTexture(), name);
+}
+
+void
+CTexList::LoadGlobalTextureList()
+{
+ CFileMgr::SetDir("TEXTURES");
+} \ No newline at end of file
diff --git a/src/render/TexList.h b/src/render/TexList.h
new file mode 100644
index 00000000..7e042211
--- /dev/null
+++ b/src/render/TexList.h
@@ -0,0 +1,14 @@
+#pragma once
+
+class CTexList
+{
+ enum { MAX_TEXUSED = 400, };
+ static bool ms_nTexUsed[MAX_TEXUSED];
+public:
+ static void Initialise();
+ static void Shutdown();
+ static RwTexture *SetTexture(int32 slot, char *name);
+ static int32 GetFirstFreeTexture();
+ static RwTexture *LoadFileNameTexture(char *name);
+ static void LoadGlobalTextureList();
+}; \ No newline at end of file
diff --git a/src/render/Timecycle.h b/src/render/Timecycle.h
index 235d559c..ed4a026b 100644
--- a/src/render/Timecycle.h
+++ b/src/render/Timecycle.h
@@ -119,8 +119,10 @@ public:
static int GetSunCoronaBlue(void) { return m_nCurrentSunCoronaBlue; }
static float GetSunSize(void) { return m_fCurrentSunSize; }
static float GetSpriteBrightness(void) { return m_fCurrentSpriteBrightness; }
+ static float GetSpriteSize(void) { return m_fCurrentSpriteSize; }
static int GetShadowStrength(void) { return m_nCurrentShadowStrength; }
static int GetLightShadowStrength(void) { return m_nCurrentLightShadowStrength; }
+ static int GetLightOnGroundBrightness(void) { return m_fCurrentLightsOnGroundBrightness; }
static float GetFarClip(void) { return m_fCurrentFarClip; }
static float GetFogStart(void) { return m_fCurrentFogStart; }
@@ -136,6 +138,7 @@ public:
static int GetFogRed(void) { return m_nCurrentFogColourRed; }
static int GetFogGreen(void) { return m_nCurrentFogColourGreen; }
static int GetFogBlue(void) { return m_nCurrentFogColourBlue; }
+ static int GetFogReduction(void) { return m_FogReduction; }
static void Initialise(void);
static void Update(void);
diff --git a/src/render/Weather.cpp b/src/render/Weather.cpp
index c1988ab4..b440e77c 100644
--- a/src/render/Weather.cpp
+++ b/src/render/Weather.cpp
@@ -2,6 +2,22 @@
#include "patcher.h"
#include "Weather.h"
+#include "Camera.h"
+#include "Clock.h"
+#include "CutsceneMgr.h"
+#include "DMAudio.h"
+#include "General.h"
+#include "Pad.h"
+#include "Particle.h"
+#include "RenderBuffer.h"
+#include "Stats.h"
+#include "Shadows.h"
+#include "Timecycle.h"
+#include "Timer.h"
+#include "Vehicle.h"
+#include "World.h"
+#include "ZoneCull.h"
+
int32 &CWeather::SoundHandle = *(int32*)0x5FFBC4;
int32 &CWeather::WeatherTypeInList = *(int32*)0x8F626C;
@@ -32,13 +48,203 @@ int16 &CWeather::Stored_OldWeatherType = *(int16*)0x95CC68;
int16 &CWeather::Stored_NewWeatherType = *(int16*)0x95CCAE;
float &CWeather::Stored_Rain = *(float*)0x885B4C;
-WRAPPER void CWeather::RenderRainStreaks(void) { EAXJMP(0x524550); }
-WRAPPER void CWeather::Update(void) { EAXJMP(0x522C10); }
-WRAPPER void CWeather::Init(void) { EAXJMP(0x522BA0); }
+tRainStreak Streaks[NUM_RAIN_STREAKS];
-void CWeather::ReleaseWeather()
+const int16 WeatherTypesList[] = {
+ WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+ WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+ WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+ WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+ WEATHER_CLOUDY, WEATHER_CLOUDY, WEATHER_RAINY, WEATHER_RAINY,
+ WEATHER_CLOUDY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+ WEATHER_CLOUDY, WEATHER_FOGGY, WEATHER_FOGGY, WEATHER_CLOUDY,
+ WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_CLOUDY, WEATHER_CLOUDY,
+ WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+ WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+ WEATHER_CLOUDY, WEATHER_CLOUDY, WEATHER_RAINY, WEATHER_RAINY,
+ WEATHER_CLOUDY, WEATHER_RAINY, WEATHER_CLOUDY, WEATHER_SUNNY,
+ WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+ WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+ WEATHER_SUNNY, WEATHER_FOGGY, WEATHER_FOGGY, WEATHER_SUNNY,
+ WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_RAINY, WEATHER_CLOUDY,
+};
+
+const float Windiness[] = {
+ 0.0f, // WEATHER_SUNNY
+ 0.7f, // WEATHER_CLOUDY
+ 1.0f, // WEATHER_RAINY
+ 0.5f // WEATHER_FOGGY
+};
+
+#define MIN_TIME_BETWEEN_LIGHTNING_FLASH_CHANGES (50)
+
+#define RAIN_CHANGE_SPEED (0.003f)
+
+#define DROPLETS_LEFT_OFFSET (10.0f)
+#define DROPLETS_RIGHT_OFFSET (10.0f)
+#define DROPLETS_TOP_OFFSET (10.0f)
+#define DROPLETS_BOTTOM_OFFSET (10.0f)
+
+#define STREAK_U (10.0f)
+#define STREAK_V (18.0f)
+#define LARGE_STREAK_COEFFICIENT (1.23f)
+#define STREAK_MIN_DISTANCE (8.0f)
+#define STREAK_MAX_DISTANCE (16.0f)
+
+#define SPLASH_CHECK_RADIUS (7.0f)
+#define SPLASH_OFFSET_RADIUS (2.0f)
+
+#define STREAK_LIFETIME (4.0f)
+#define STREAK_INTEROLATION_TIME (0.3f)
+
+#define RAIN_COLOUR_R (200)
+#define RAIN_COLOUR_G (200)
+#define RAIN_COLOUR_B (256)
+#define RAIN_ALPHA (255)
+
+void CWeather::Init(void)
{
- ForcedWeatherType = -1;
+ NewWeatherType = WEATHER_SUNNY;
+ bScriptsForceRain = false;
+ OldWeatherType = WEATHER_CLOUDY;
+ Stored_StateStored = false;
+ InterpolationValue = 0.0f;
+ WhenToPlayLightningSound = 0;
+ WeatherTypeInList = 0;
+ ForcedWeatherType = WEATHER_RANDOM;
+ SoundHandle = DMAudio.CreateEntity(AUDIOTYPE_WEATHER, (void*)1);
+ if (SoundHandle >= 0)
+ DMAudio.SetEntityStatus(SoundHandle, 1);
+}
+
+void CWeather::Update(void)
+{
+ float fNewInterpolation = CClock::GetMinutes() * 1.0f / 60;
+ if (fNewInterpolation < InterpolationValue) {
+ // new hour
+ OldWeatherType = NewWeatherType;
+ if (ForcedWeatherType >= 0)
+ NewWeatherType = ForcedWeatherType;
+ else {
+ WeatherTypeInList = (WeatherTypeInList + 1) % ARRAYSIZE(WeatherTypesList);
+ NewWeatherType = WeatherTypesList[WeatherTypeInList];
+#ifdef FIX_BUGS
+ }
+ if (NewWeatherType == WEATHER_RAINY)
+ CStats::mmRain += CGeneral::GetRandomNumber() & 7;
+#else
+ if (NewWeatherType == WEATHER_RAINY)
+ CStats::mmRain += CGeneral::GetRandomNumber() & 7;
+ }
+#endif
+ }
+ InterpolationValue = fNewInterpolation;
+ if (CPad::GetPad(1)->GetRightShockJustDown()) {
+ NewWeatherType = (NewWeatherType + 1) % WEATHER_TOTAL;
+ OldWeatherType = NewWeatherType;
+ }
+
+ // Lightning
+ if (NewWeatherType != WEATHER_RAINY || OldWeatherType != WEATHER_RAINY) {
+ LightningFlash = false;
+ LightningBurst = false;
+ }
+ else{
+ if (LightningBurst) {
+ if ((CGeneral::GetRandomNumber() & 255) >= 32) {
+ // 0.875 probability
+ if (CTimer::GetTimeInMilliseconds() - LightningFlashLastChange > MIN_TIME_BETWEEN_LIGHTNING_FLASH_CHANGES) {
+ bool bOldLightningFlash = LightningFlash;
+ LightningFlash = CGeneral::GetRandomTrueFalse();
+ if (LightningFlash != bOldLightningFlash)
+ LightningFlashLastChange = CTimer::GetTimeInMilliseconds();
+ }
+ }
+ else {
+ // 0.125 probability
+ LightningBurst = false;
+ LightningDuration = min(CTimer::GetFrameCounter() - LightningStart, 20);
+ LightningFlash = false;
+ WhenToPlayLightningSound = CTimer::GetTimeInMilliseconds() + 150 * (20 - LightningDuration);
+ }
+ }
+ else {
+ if (CGeneral::GetRandomNumber() >= 200) {
+ // lower probability on PC due to randomness bug
+ LightningFlash = false;
+ }
+ else {
+ LightningBurst = true;
+ LightningStart = CTimer::GetFrameCounter();
+ LightningFlashLastChange = CTimer::GetTimeInMilliseconds();
+ LightningFlash = true;
+ }
+ }
+ }
+ if (WhenToPlayLightningSound && CTimer::GetTimeInMilliseconds() > WhenToPlayLightningSound) {
+ DMAudio.PlayOneShot(SoundHandle, SOUND_LIGHTNING, LightningDuration);
+ CPad::GetPad(0)->StartShake(40 * LightningDuration + 100, 2 * LightningDuration + 80);
+ WhenToPlayLightningSound = 0;
+ }
+
+ // Wet roads
+ if (OldWeatherType == WEATHER_RAINY) {
+ if (NewWeatherType == WEATHER_RAINY)
+ WetRoads = 1.0f;
+ else
+ WetRoads = 1.0f - InterpolationValue;
+ }
+ else {
+ if (NewWeatherType == WEATHER_RAINY)
+ WetRoads = InterpolationValue;
+ else
+ WetRoads = 0.0f;
+ }
+
+ // Rain
+ float fNewRain;
+ if (NewWeatherType == WEATHER_RAINY) {
+ // if raining for >1 hour, values: 0, 0.33, 0.66, 0.99, switching every ~16.5s
+ fNewRain = ((uint16)CTimer::GetTimeInMilliseconds() >> 14) * 0.33f;
+ if (OldWeatherType != WEATHER_RAINY) {
+ if (InterpolationValue < 0.4f)
+ // if rain has just started (<24 minutes), always 0.5
+ fNewRain = 0.5f;
+ else
+ // if rain is ongoing for >24 minutes, values: 0.25, 0.5, 0.75, 1.0, switching every ~16.5s
+ fNewRain = 0.25f + ((uint16)CTimer::GetTimeInMilliseconds() >> 14) * 0.25f;
+ }
+ }
+ else
+ fNewRain = 0.0f;
+ if (Rain != fNewRain) { // ok to use comparasion
+ if (Rain < fNewRain)
+ Rain = min(fNewRain, Rain + RAIN_CHANGE_SPEED * CTimer::GetTimeStep());
+ else
+ Rain = max(fNewRain, Rain - RAIN_CHANGE_SPEED * CTimer::GetTimeStep());
+ }
+
+ // Clouds
+ if (OldWeatherType != WEATHER_SUNNY)
+ CloudCoverage = 1.0f - InterpolationValue;
+ else
+ CloudCoverage = 0.0f;
+ if (NewWeatherType != WEATHER_SUNNY)
+ CloudCoverage += InterpolationValue;
+
+ // Fog
+ if (OldWeatherType == WEATHER_FOGGY)
+ Foggyness = 1.0f - InterpolationValue;
+ else
+ Foggyness = 0.0f;
+ if (NewWeatherType == WEATHER_FOGGY)
+ Foggyness += InterpolationValue;
+ if (OldWeatherType == WEATHER_RAINY && NewWeatherType == WEATHER_SUNNY && InterpolationValue < 0.5f && CClock::GetHours() > 6 && CClock::GetHours() < 21)
+ Rainbow = 1.0f - 4.0f * Abs(InterpolationValue - 0.25f) / 4.0f;
+ else
+ Rainbow = 0.0f;
+ Wind = InterpolationValue * Windiness[NewWeatherType] + (1.0f - InterpolationValue) * Windiness[OldWeatherType];
+ AddRain();
}
void CWeather::ForceWeather(int16 weather)
@@ -53,6 +259,258 @@ void CWeather::ForceWeatherNow(int16 weather)
ForcedWeatherType = weather;
}
+void CWeather::ReleaseWeather()
+{
+ ForcedWeatherType = -1;
+}
+
+void CWeather::AddRain()
+{
+ if (CCullZones::CamNoRain() || CCullZones::PlayerNoRain())
+ return;
+ if (TheCamera.GetLookingLRBFirstPerson()) {
+ CVehicle* pVehicle = FindPlayerVehicle();
+ if (pVehicle && pVehicle->CarHasRoof()) {
+ CParticle::RemovePSystem(PARTICLE_RAINDROP_2D);
+ return;
+ }
+ }
+ if (Rain <= 0.1f)
+ return;
+ static RwRGBA colour;
+ float screen_width = RsGlobal.width;
+ float screen_height = RsGlobal.height;
+ int cur_frame = (int)(3 * Rain) & 3;
+ int num_drops = (int)(2 * Rain) + 2;
+ static int STATIC_RAIN_ANGLE = -45;
+ static int count = 1500;
+ static int add_angle = 1;
+ if (--count == 0) {
+ count = 1;
+ if (add_angle) {
+ STATIC_RAIN_ANGLE += 12;
+ if (STATIC_RAIN_ANGLE > 45) {
+ count = 1500;
+ add_angle = !add_angle;
+ }
+ }
+ else {
+ STATIC_RAIN_ANGLE -= 12;
+ if (STATIC_RAIN_ANGLE < -45) {
+ count = 1500;
+ add_angle = !add_angle;
+ }
+ }
+ }
+ float rain_angle = DEGTORAD(STATIC_RAIN_ANGLE + ((STATIC_RAIN_ANGLE < 0) ? 360 : 0));
+ float sin_angle = Sin(rain_angle);
+ float cos_angle = Cos(rain_angle);
+ float base_x = 0.0f * cos_angle - 1.0f * sin_angle;
+ float base_y = 1.0f * cos_angle + 0.0f * sin_angle;
+ CVector xpos(0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < 2 * num_drops; i++) {
+ CVector dir;
+ dir.x = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_x) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+ dir.y = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_y) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+ dir.z = 0;
+ CParticle::AddParticle(PARTICLE_RAINDROP_2D, xpos, dir, nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
+ colour, 0, rain_angle + CGeneral::GetRandomNumberInRange(-10, 10), cur_frame);
+ xpos.x += screen_width / (2 * num_drops);
+ xpos.x += CGeneral::GetRandomNumberInRange(-25.0f, 25.0f);
+ }
+ CVector ypos(0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < num_drops; i++) {
+ CVector dir;
+ dir.x = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_x) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+ dir.y = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_y) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+ dir.z = 0;
+ CParticle::AddParticle(PARTICLE_RAINDROP_2D, ypos, dir, nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
+ colour, 0, rain_angle + CGeneral::GetRandomNumberInRange(-10, 10), cur_frame);
+ ypos.y += screen_width / num_drops;
+ ypos.y += CGeneral::GetRandomNumberInRange(-25.0f, 25.0f);
+ }
+ CVector ypos2(0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < num_drops; i++) {
+ CVector dir;
+ dir.x = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_x) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+ dir.y = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_y) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+ dir.z = 0;
+ CParticle::AddParticle(PARTICLE_RAINDROP_2D, ypos2, dir, nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
+ colour, 0, rain_angle + CGeneral::GetRandomNumberInRange(-10, 10), cur_frame);
+ ypos2.y += screen_width / num_drops;
+ ypos2.y += CGeneral::GetRandomNumberInRange(-25.0f, 25.0f);
+ }
+ for (int i = 0; i < num_drops; i++) {
+ CVector pos;
+ pos.x = CGeneral::GetRandomNumberInRange(DROPLETS_LEFT_OFFSET, screen_width - DROPLETS_RIGHT_OFFSET);
+ pos.y = CGeneral::GetRandomNumberInRange(DROPLETS_TOP_OFFSET, screen_height - DROPLETS_TOP_OFFSET);
+ pos.z = 0.0f;
+ CParticle::AddParticle(PARTICLE_RAINDROP_2D, pos, CVector(0.0f, 0.0f, 0.0f), nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
+ colour, CGeneral::GetRandomNumberInRange(-10, 10), 360 - rain_angle + CGeneral::GetRandomNumberInRange(-30, 30), cur_frame, 0);
+ }
+ int num_splash_attempts = (int)(3 * Rain) + 1;
+ int num_splashes = (int)(3 * Rain) + 4;
+ CVector splash_points[4];
+ splash_points[0] = CVector(-RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
+ RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
+ splash_points[1] = CVector(RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
+ RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
+ splash_points[2] = 4.0f * CVector(-RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
+ RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
+ splash_points[3] = 4.0f * CVector(RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
+ RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
+ RwV3dTransformPoints((RwV3d*)splash_points, (RwV3d*)splash_points, 4, RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera)));
+ CVector fp = (splash_points[0] + splash_points[1] + splash_points[2] + splash_points[3]) / 4;
+ for (int i = 0; i < num_splash_attempts; i++) {
+ CColPoint point;
+ CEntity* entity;
+ CVector np = fp + CVector(CGeneral::GetRandomNumberInRange(-SPLASH_CHECK_RADIUS, SPLASH_CHECK_RADIUS), CGeneral::GetRandomNumberInRange(-SPLASH_CHECK_RADIUS, SPLASH_CHECK_RADIUS), 0.0f);
+ if (CWorld::ProcessVerticalLine(np + CVector(0.0f, 0.0f, 40.0f), -40.0f, point, entity, true, false, false, false, true, false, nil)) {
+ for (int j = 0; j < num_splashes; j++)
+ CParticle::AddParticle((CGeneral::GetRandomTrueFalse() ? PARTICLE_RAIN_SPLASH : PARTICLE_RAIN_SPLASHUP),
+ CVector(
+ np.x + CGeneral::GetRandomNumberInRange(-SPLASH_OFFSET_RADIUS, SPLASH_OFFSET_RADIUS),
+ np.y + CGeneral::GetRandomNumberInRange(-SPLASH_OFFSET_RADIUS, SPLASH_OFFSET_RADIUS),
+ point.point.z + 0.1f),
+ CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, colour);
+ }
+ }
+}
+
+void RenderOneRainStreak(CVector pos, CVector unused, int intensity, bool scale, float distance)
+{
+ static float RandomTex;
+ static float RandomTexX;
+ static float RandomTexY;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 0] = TempBufferVerticesStored + 0;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 1] = TempBufferVerticesStored + 2;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 2] = TempBufferVerticesStored + 1;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 3] = TempBufferVerticesStored + 0;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 4] = TempBufferVerticesStored + 3;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 5] = TempBufferVerticesStored + 2;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 6] = TempBufferVerticesStored + 1;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 7] = TempBufferVerticesStored + 2;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 8] = TempBufferVerticesStored + 4;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 9] = TempBufferVerticesStored + 2;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 10] = TempBufferVerticesStored + 3;
+ TempBufferRenderIndexList[TempBufferIndicesStored + 11] = TempBufferVerticesStored + 4;
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 0], 0, 0, 0, 0);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 0], pos.x + 11.0f * TheCamera.GetUp().x, pos.y + 11.0f * TheCamera.GetUp().y, pos.z + 11.0f * TheCamera.GetUp().z);
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 1], 0, 0, 0, 0);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 1], pos.x - 9.0f * TheCamera.GetRight().x, pos.y - 9.0f * TheCamera.GetRight().y, pos.z - 9.0f * TheCamera.GetUp().z);
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 2], RAIN_COLOUR_R * intensity / 256, RAIN_COLOUR_G * intensity / 256, RAIN_COLOUR_B * intensity / 256, RAIN_ALPHA);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 2], pos.x, pos.y, pos.z);
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 3], 0, 0, 0, 0);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 3], pos.x + 9.0f * TheCamera.GetRight().x, pos.y + 9.0f * TheCamera.GetRight().y, pos.z + 9.0f * TheCamera.GetUp().z);
+ RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 4], 0, 0, 0, 0);
+ RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 4], pos.x - 11.0f * TheCamera.GetUp().x, pos.y - 11.0f * TheCamera.GetUp().y, pos.z - 11.0f * TheCamera.GetUp().z);
+ float u = STREAK_U;
+ float v = STREAK_V;
+ if (scale) {
+ u *= LARGE_STREAK_COEFFICIENT;
+ v *= LARGE_STREAK_COEFFICIENT;
+ }
+ float distance_coefficient;
+ if (distance < STREAK_MIN_DISTANCE)
+ distance_coefficient = 1.0f;
+ else if (distance > STREAK_MAX_DISTANCE)
+ distance_coefficient = 0.5f;
+ else
+ distance_coefficient = 1.0f - 0.5f * (distance - STREAK_MIN_DISTANCE) / (STREAK_MAX_DISTANCE - STREAK_MIN_DISTANCE);
+ u *= distance_coefficient;
+ v *= distance_coefficient;
+ if (!CTimer::GetIsPaused()) {
+ RandomTex = ((CGeneral::GetRandomNumber() & 255) - 128) * 0.01f;
+ RandomTexX = (CGeneral::GetRandomNumber() & 127) * 0.01f;
+ RandomTexY = (CGeneral::GetRandomNumber() & 127) * 0.01f;
+ }
+ RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 0], 0.5f * u - RandomTex + RandomTexX);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 0], -v * 0.5f + RandomTexY);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 1], RandomTexX);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 1], RandomTexY);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 2], 0.5f * u + RandomTexX);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 2], RandomTexY);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 3], u + RandomTexX);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 3], RandomTexY);
+ RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 4], 0.5f * u + RandomTex + RandomTexX);
+ RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 5], 0.5f * v + RandomTexY);
+ TempBufferIndicesStored += 12;
+ TempBufferVerticesStored += 5;
+}
+
+void CWeather::RenderRainStreaks(void)
+{
+ if (CTimer::GetIsCodePaused())
+ return;
+ int base_intensity = (64.0f - CTimeCycle::GetFogReduction()) / 64.0f * int(255 * Rain);
+ if (base_intensity == 0)
+ return;
+ TempBufferIndicesStored = 0;
+ TempBufferVerticesStored = 0;
+ for (int i = 0; i < NUM_RAIN_STREAKS; i++) {
+ if (Streaks[i].timer) {
+ float secondsElapsed = (CTimer::GetTimeInMilliseconds() - Streaks[i].timer) / 1024.0f;
+ if (secondsElapsed > STREAK_LIFETIME)
+ Streaks[i].timer = 0;
+ else{
+ int intensity;
+ if (secondsElapsed < STREAK_INTEROLATION_TIME)
+ intensity = base_intensity * 0.5f * secondsElapsed / STREAK_INTEROLATION_TIME;
+ else if (secondsElapsed > (STREAK_LIFETIME - STREAK_INTEROLATION_TIME))
+ intensity = (STREAK_LIFETIME - secondsElapsed) * 0.5f * base_intensity / STREAK_INTEROLATION_TIME;
+ else
+ intensity = base_intensity * 0.5f;
+ CVector dir = Streaks[i].direction;
+ dir.Normalise();
+ CVector pos = Streaks[i].position + secondsElapsed * Streaks[i].direction;
+ RenderOneRainStreak(pos, dir, intensity, false, (pos - TheCamera.GetPosition()).Magnitude());
+#ifndef FIX_BUGS // remove useless code
+ if (secondsElapsed > 1.0f && secondsElapsed < STREAK_LIFETIME - 1.0f) {
+ CGeneral::GetRandomNumber(), CGeneral::GetRandomNumber();
+ }
+#endif
+ }
+ }
+ else if ((CGeneral::GetRandomNumber() & 0xF00) == 0){
+ // 1/16 probability
+ Streaks[i].direction = CVector(4.0f, 4.0f, -4.0f);
+ Streaks[i].position = 6.0f * TheCamera.GetForward() + TheCamera.GetPosition() + CVector(-1.8f * Streaks[i].direction.x, -1.8f * Streaks[i].direction.y, 8.0f);
+ if (!CCutsceneMgr::IsRunning()) {
+ Streaks[i].position.x += 2.0f * FindPlayerSpeed().x * 60.0f;
+ Streaks[i].position.y += 2.0f * FindPlayerSpeed().y * 60.0f;
+ }
+ else
+ Streaks[i].position += (TheCamera.GetPosition() - TheCamera.m_RealPreviousCameraPosition) * 20.0f;
+ Streaks[i].position.x += ((CGeneral::GetRandomNumber() & 255) - 128) * 0.08f;
+ Streaks[i].position.y += ((CGeneral::GetRandomNumber() & 255) - 128) * 0.08f;
+ Streaks[i].timer = CTimer::GetTimeInMilliseconds();
+ }
+ }
+ if (TempBufferIndicesStored){
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEFOGTYPE, (void*)rwFOGTYPELINEAR);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRainDropTex[3]));
+ if (RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, 1))
+ {
+ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
+ RwIm3DEnd();
+ }
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+ }
+ TempBufferVerticesStored = 0;
+ TempBufferIndicesStored = 0;
+}
+
void CWeather::StoreWeatherState()
{
Stored_StateStored = true;
@@ -71,4 +529,4 @@ void CWeather::RestoreWeatherState()
Rain = Stored_Rain;
NewWeatherType = Stored_NewWeatherType;
OldWeatherType = Stored_OldWeatherType;
-} \ No newline at end of file
+}
diff --git a/src/render/Weather.h b/src/render/Weather.h
index 63def9b9..9e4ea378 100644
--- a/src/render/Weather.h
+++ b/src/render/Weather.h
@@ -8,6 +8,14 @@ enum {
class CWeather
{
public:
+ enum {
+ WEATHER_RANDOM = -1,
+ WEATHER_SUNNY = 0,
+ WEATHER_CLOUDY = 1,
+ WEATHER_RAINY = 2,
+ WEATHER_FOGGY = 3,
+ WEATHER_TOTAL = 4
+ };
static int32 &SoundHandle;
static int32 &WeatherTypeInList;
@@ -46,4 +54,18 @@ public:
static void ForceWeatherNow(int16);
static void StoreWeatherState();
static void RestoreWeatherState();
+ static void AddRain();
};
+
+enum {
+ NUM_RAIN_STREAKS = 35
+};
+
+struct tRainStreak
+{
+ CVector position;
+ CVector direction;
+ uint32 timer;
+};
+
+extern RwTexture* (&gpRainDropTex)[4]; \ No newline at end of file
diff --git a/src/render/Lights.cpp b/src/rw/Lights.cpp
index cd83a898..cd83a898 100644
--- a/src/render/Lights.cpp
+++ b/src/rw/Lights.cpp
diff --git a/src/render/Lights.h b/src/rw/Lights.h
index 6fdd51de..6fdd51de 100644
--- a/src/render/Lights.h
+++ b/src/rw/Lights.h
diff --git a/src/render/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp
index 74cd2590..f8b1f6b2 100644
--- a/src/render/VisibilityPlugins.cpp
+++ b/src/rw/VisibilityPlugins.cpp
@@ -117,7 +117,7 @@ CVisibilityPlugins::SetRenderWareCamera(RwCamera *camera)
RpMaterial*
SetAlphaCB(RpMaterial *material, void *data)
{
- material->color.alpha = (uint8)(uint32)data;
+ ((RwRGBA*)RpMaterialGetColor(material))->alpha = (uint8)(uint32)data;
return material;
}
diff --git a/src/render/VisibilityPlugins.h b/src/rw/VisibilityPlugins.h
index 65d2675a..65d2675a 100644
--- a/src/render/VisibilityPlugins.h
+++ b/src/rw/VisibilityPlugins.h