summaryrefslogtreecommitdiffstats
path: root/src/render
diff options
context:
space:
mode:
authorNikolay Korolev <nickvnuk@gmail.com>2020-04-08 13:26:07 +0200
committerNikolay Korolev <nickvnuk@gmail.com>2020-04-08 13:26:07 +0200
commitb075b0fccf3e40a375c229cee4dfa3021c618809 (patch)
tree1c45a3d3b54aa386c52825bddf0fec9ba993c51b /src/render
parentrain fix (diff)
parentfix bug (diff)
downloadre3-b075b0fccf3e40a375c229cee4dfa3021c618809.tar
re3-b075b0fccf3e40a375c229cee4dfa3021c618809.tar.gz
re3-b075b0fccf3e40a375c229cee4dfa3021c618809.tar.bz2
re3-b075b0fccf3e40a375c229cee4dfa3021c618809.tar.lz
re3-b075b0fccf3e40a375c229cee4dfa3021c618809.tar.xz
re3-b075b0fccf3e40a375c229cee4dfa3021c618809.tar.zst
re3-b075b0fccf3e40a375c229cee4dfa3021c618809.zip
Diffstat (limited to 'src/render')
-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/SpecialFX.cpp644
-rw-r--r--src/render/SpecialFX.h224
5 files changed, 1252 insertions, 88 deletions
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/SpecialFX.cpp b/src/render/SpecialFX.cpp
index 301ae265..0d856d9c 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); }
+RxObjSpace3DVertex StreakVertices[4];
+RwImVertexIndex StreakIndexList[12];
+
+RxObjSpace3DVertex 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];
-WRAPPER void CMotionBlurStreaks::RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2) { EAXJMP(0x519460); }
+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;
+}
+
+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)
{
@@ -81,8 +316,8 @@ void CBulletTraces::Render(void)
RwIm3DEnd();
}
}
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)1);
- RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)5);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)1);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)5);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)6);
}
@@ -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)
{
@@ -201,9 +434,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 +635,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 +1168,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..8519ae79 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 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
{
- static uint32 BoatFromStart;
public:
- static void CreateFoamAroundObject(CMatrix*, float, float, float, int32);
- static void StartBoatFoamAnimation();
- static void UpdateBoatFoamAnimation(CMatrix*);
-};
+ 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*);
+};