diff options
Diffstat (limited to '')
-rw-r--r-- | src/render/Clouds.cpp | 2 | ||||
-rw-r--r-- | src/render/Coronas.cpp | 242 | ||||
-rw-r--r-- | src/render/Fluff.cpp | 8 | ||||
-rw-r--r-- | src/render/Font.cpp | 201 | ||||
-rw-r--r-- | src/render/Font.h | 39 | ||||
-rw-r--r-- | src/render/Glass.cpp | 8 | ||||
-rw-r--r-- | src/render/Hud.cpp | 15 | ||||
-rw-r--r-- | src/render/MBlur.cpp | 365 | ||||
-rw-r--r-- | src/render/MBlur.h | 23 | ||||
-rw-r--r-- | src/render/Occlusion.cpp | 39 | ||||
-rw-r--r-- | src/render/Particle.cpp | 110 | ||||
-rw-r--r-- | src/render/Particle.h | 5 | ||||
-rw-r--r-- | src/render/PlayerSkin.cpp | 3 | ||||
-rw-r--r-- | src/render/PointLights.cpp | 4 | ||||
-rw-r--r-- | src/render/Renderer.cpp | 183 | ||||
-rw-r--r-- | src/render/Renderer.h | 21 | ||||
-rw-r--r-- | src/render/Shadows.cpp | 4 | ||||
-rw-r--r-- | src/render/SpecialFX.cpp | 32 | ||||
-rw-r--r-- | src/render/WaterLevel.cpp | 370 | ||||
-rw-r--r-- | src/render/WaterLevel.h | 41 | ||||
-rw-r--r-- | src/render/Weather.cpp | 2 |
21 files changed, 1513 insertions, 204 deletions
diff --git a/src/render/Clouds.cpp b/src/render/Clouds.cpp index 15bae90b..c7554356 100644 --- a/src/render/Clouds.cpp +++ b/src/render/Clouds.cpp @@ -129,7 +129,7 @@ CClouds::Render(void) CSprite::InitSpriteBuffer(); float minute = CClock::GetHours()*60 + CClock::GetMinutes() + CClock::GetSeconds()/60.0f; - RwV3d campos = *(RwV3d*)&TheCamera.GetPosition(); + RwV3d campos = TheCamera.GetPosition(); // Moon float moonfadeout = Abs(minute - 180.0f); // fully visible at 3AM diff --git a/src/render/Coronas.cpp b/src/render/Coronas.cpp index c40577d7..515e1000 100644 --- a/src/render/Coronas.cpp +++ b/src/render/Coronas.cpp @@ -2,6 +2,7 @@ #include "main.h" #include "General.h" +#include "Entity.h" #include "RenderBuffer.h" #include "TxdStore.h" #include "Camera.h" @@ -12,6 +13,10 @@ #include "Collision.h" #include "Timecycle.h" #include "Coronas.h" +#include "PointLights.h" +#include "Shadows.h" +#include "Clock.h" +#include "Bridge.h" //--MIAMI: file done @@ -271,7 +276,7 @@ CCoronas::Render(void) CVector spriteCoors; float spritew, spriteh; - if(!CSprite::CalcScreenCoors(aCoronas[i].coors, spriteCoors, &spritew, &spriteh, true)){ + if(!CSprite::CalcScreenCoors(aCoronas[i].coors, &spriteCoors, &spritew, &spriteh, true)){ aCoronas[i].offScreen = true; aCoronas[i].sightClear = false; }else{ @@ -478,7 +483,7 @@ CCoronas::RenderReflections(void) CVector spriteCoors; float spritew, spriteh; - if(CSprite::CalcScreenCoors(coors, spriteCoors, &spritew, &spriteh, true)){ + if(CSprite::CalcScreenCoors(coors, &spriteCoors, &spritew, &spriteh, true)) { float drawDist = 0.75f * aCoronas[i].drawDist; drawDist = Min(drawDist, 55.0f); if(spriteCoors.z < drawDist){ @@ -669,7 +674,7 @@ CCoronas::DoSunAndMoon(void) CVector spriteCoors; float spritew, spriteh; - if(CSprite::CalcScreenCoors(sunCoors, spriteCoors, &spritew, &spriteh, true)){ + if(CSprite::CalcScreenCoors(sunCoors, &spriteCoors, &spritew, &spriteh, true)) { SunScreenX = spriteCoors.x; SunScreenY = spriteCoors.y; }else{ @@ -715,3 +720,234 @@ CRegisteredCorona::Update(void) firstUpdate = false; registeredThisFrame = false; } + +void +CEntity::ProcessLightsForEntity(void) +{ + int i, n; + C2dEffect *effect; + CVector pos; + bool lightOn, lightFlickering; + uint32 flashTimer1, flashTimer2, flashTimer3; + + if(bRenderDamaged || !bIsVisible || GetUp().z < 0.96f) + return; + + flashTimer1 = 0; + flashTimer2 = 0; + flashTimer3 = 0; + + n = CModelInfo::GetModelInfo(GetModelIndex())->GetNum2dEffects(); + for(i = 0; i < n; i++, flashTimer1 += 0x80, flashTimer2 += 0x100, flashTimer3 += 0x200){ + effect = CModelInfo::GetModelInfo(GetModelIndex())->Get2dEffect(i); + + switch(effect->type){ + case EFFECT_LIGHT: + pos = GetMatrix() * effect->pos; + + lightOn = false; + lightFlickering = false; + switch(effect->light.lightType){ + case LIGHT_ON: + lightOn = true; + break; + case LIGHT_ON_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + lightOn = true; + break; + case LIGHT_FLICKER: + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed) & 3) + lightOn = true; + break; + case LIGHT_FLICKER_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7 || CWeather::WetRoads > 0.5f){ + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed) & 3) + lightOn = true; + } + break; + case LIGHT_FLASH1: + if((CTimer::GetTimeInMilliseconds() + flashTimer1) & 0x200) + lightOn = true; + break; + case LIGHT_FLASH1_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + if((CTimer::GetTimeInMilliseconds() + flashTimer1) & 0x200) + lightOn = true; + break; + case LIGHT_FLASH2: + if((CTimer::GetTimeInMilliseconds() + flashTimer2) & 0x400) + lightOn = true; + break; + case LIGHT_FLASH2_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + if((CTimer::GetTimeInMilliseconds() + flashTimer2) & 0x400) + lightOn = true; + break; + case LIGHT_FLASH3: + if((CTimer::GetTimeInMilliseconds() + flashTimer3) & 0x800) + lightOn = true; + break; + case LIGHT_FLASH3_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + if((CTimer::GetTimeInMilliseconds() + flashTimer3) & 0x800) + lightOn = true; + break; + case LIGHT_RANDOM_FLICKER: + if(m_randomSeed > 16) + lightOn = true; + else{ + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed*8) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed*8) & 3) + lightOn = true; + } + break; + case LIGHT_RANDOM_FLICKER_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7){ + if(m_randomSeed > 16) + lightOn = true; + else{ + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed*8) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed*8) & 3) + lightOn = true; + } + } + break; + case LIGHT_BRIDGE_FLASH1: + if(CBridge::ShouldLightsBeFlashing() && CTimer::GetTimeInMilliseconds() & 0x200) + lightOn = true; + break; + case LIGHT_BRIDGE_FLASH2: + if(CBridge::ShouldLightsBeFlashing() && (CTimer::GetTimeInMilliseconds() & 0x1FF) < 60) + lightOn = true; + break; + } + + if(effect->light.flags & LIGHTFLAG_HIDE_OBJECT){ + if(lightOn) + bDoNotRender = false; + else + bDoNotRender = true; + return; + } + + // Corona + if(lightOn) + CCoronas::RegisterCorona((uintptr)this + i, + effect->col.r, effect->col.g, effect->col.b, 255, + pos, effect->light.size, effect->light.dist, + effect->light.corona, effect->light.flareType, effect->light.roadReflection, + effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f, + !!(effect->light.flags&LIGHTFLAG_LONG_DIST)); + else if(lightFlickering) + CCoronas::RegisterCorona((uintptr)this + i, + 0, 0, 0, 255, + pos, effect->light.size, effect->light.dist, + effect->light.corona, effect->light.flareType, effect->light.roadReflection, + effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f, + !!(effect->light.flags&LIGHTFLAG_LONG_DIST)); + + // Pointlight + bool alreadyProcessedFog; + alreadyProcessedFog = false; + if(effect->light.range != 0.0f && lightOn){ + if(effect->col.r == 0 && effect->col.g == 0 && effect->col.b == 0){ + CPointLights::AddLight(CPointLights::LIGHT_POINT, + pos, CVector(0.0f, 0.0f, 0.0f), + effect->light.range, + 0.0f, 0.0f, 0.0f, + CPointLights::FOG_NONE, true); + }else{ + CPointLights::AddLight(CPointLights::LIGHT_POINT, + pos, CVector(0.0f, 0.0f, 0.0f), + effect->light.range, + effect->col.r*CTimeCycle::GetSpriteBrightness()/255.0f, + effect->col.g*CTimeCycle::GetSpriteBrightness()/255.0f, + effect->col.b*CTimeCycle::GetSpriteBrightness()/255.0f, + (effect->light.flags & LIGHTFLAG_FOG) >> 1, + true); + alreadyProcessedFog = true; + } + } + + if(!alreadyProcessedFog){ + if(effect->light.flags & LIGHTFLAG_FOG_ALWAYS){ + CPointLights::AddLight(CPointLights::LIGHT_FOGONLY_ALWAYS, + pos, CVector(0.0f, 0.0f, 0.0f), + 0.0f, + effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f, + CPointLights::FOG_ALWAYS, true); + }else if(effect->light.flags & LIGHTFLAG_FOG_NORMAL && lightOn && effect->light.range == 0.0f){ + CPointLights::AddLight(CPointLights::LIGHT_FOGONLY, + pos, CVector(0.0f, 0.0f, 0.0f), + 0.0f, + effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f, + CPointLights::FOG_NORMAL, true); + } + } + + // Light shadow + if(effect->light.shadowSize != 0.0f){ + if(lightOn){ + CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_ADDITIVE, + effect->light.shadow, &pos, + effect->light.shadowSize, 0.0f, + 0.0f, -effect->light.shadowSize, + 128, + effect->col.r*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f, + effect->col.g*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f, + effect->col.b*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f, + 15.0f, 1.0f, 40.0f, false, 0.0f); + }else if(lightFlickering){ + CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_ADDITIVE, + effect->light.shadow, &pos, + effect->light.shadowSize, 0.0f, + 0.0f, -effect->light.shadowSize, + 0, 0.0f, 0.0f, 0.0f, + 15.0f, 1.0f, 40.0f, false, 0.0f); + } + } + break; + + case EFFECT_SUNGLARE: + if(CWeather::SunGlare >= 0.0f){ + CVector pos = GetMatrix() * effect->pos; + CVector glareDir = pos - GetPosition(); + glareDir.Normalise(); + CVector camDir = TheCamera.GetPosition() - pos; + float dist = camDir.Magnitude(); + camDir *= 2.0f/dist; + glareDir += camDir; + glareDir.Normalise(); + float camAngle = -DotProduct(glareDir, CTimeCycle::GetSunDirection()); + if(camAngle > 0.0f){ + float intens = Sqrt(camAngle) * CWeather::SunGlare; + pos += camDir; + CCoronas::RegisterCorona((uintptr)this + 33 + i, + intens * (CTimeCycle::GetSunCoreRed() + 2*255)/3.0f, + intens * (CTimeCycle::GetSunCoreGreen() + 2*255)/3.0f, + intens * (CTimeCycle::GetSunCoreBlue() + 2*255)/3.0f, + 255, + pos, 0.5f*CWeather::SunGlare*Sqrt(dist), 120.0f, + CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, + CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, + CCoronas::STREAK_OFF, 0.0f); + } + } + break; + } + } +}
\ No newline at end of file diff --git a/src/render/Fluff.cpp b/src/render/Fluff.cpp index 3c0d3708..157be0c8 100644 --- a/src/render/Fluff.cpp +++ b/src/render/Fluff.cpp @@ -744,7 +744,7 @@ void CScrollBar::Render() RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); CVector coronaCoord, screenCoord; - float screenW, screenH; + float screenW, screenH; for (int i = 1; i < ARRAY_SIZE(m_MessageBar); ++i) { for (int j = 0; j < 5; ++j) @@ -756,7 +756,7 @@ void CScrollBar::Render() // Render main coronas if (m_MessageBar[i] & (1 << j)) { - if (CSprite::CalcScreenCoors(coronaCoord, screenCoord, &screenW, &screenH, true)) + if (CSprite::CalcScreenCoors(coronaCoord, &screenCoord, &screenW, &screenH, true)) { CSprite::RenderBufferedOneXLUSprite( screenCoord.x, screenCoord.y, screenCoord.z, @@ -768,7 +768,7 @@ void CScrollBar::Render() // Render smaller and faded coronas for a trailing effect else if (m_MessageBar[i - 1] & (1 << j)) { - if (CSprite::CalcScreenCoors(coronaCoord, screenCoord, &screenW, &screenH, true)) + if (CSprite::CalcScreenCoors(coronaCoord, &screenCoord, &screenW, &screenH, true)) { CSprite::RenderBufferedOneXLUSprite( screenCoord.x, screenCoord.y, screenCoord.z, @@ -1291,7 +1291,7 @@ INITSAVEBUF for (int32 j = 0; j < 6; j++) { if (pPath->m_pObjects[j] != nil) - pPath->m_pObjects[j] = (CObject*)(CPools::GetObjectPool()->GetJustIndex(pPath->m_pObjects[j]) + 1); + pPath->m_pObjects[j] = (CObject*)(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(pPath->m_pObjects[j]) + 1); } for (int32 j = 0; j < aArray[i].m_numNodes; j++) { diff --git a/src/render/Font.cpp b/src/render/Font.cpp index 78a8599e..d6a06db8 100644 --- a/src/render/Font.cpp +++ b/src/render/Font.cpp @@ -3,6 +3,9 @@ #include "Sprite2d.h" #include "TxdStore.h" #include "Font.h" +#ifdef BUTTON_ICONS +#include "FileMgr.h" +#endif #include "Timer.h" void @@ -224,6 +227,12 @@ union tFontRenderStatePointer tFontRenderStatePointer FontRenderStatePointer; uint8 FontRenderStateBuf[1024]; +#ifdef BUTTON_ICONS +CSprite2d CFont::ButtonSprite[MAX_BUTTON_ICONS]; +int CFont::PS2Symbol = BUTTON_NONE; +int CFont::ButtonsSlot = -1; +#endif // BUTTON_ICONS + void CFont::Initialise(void) { @@ -279,6 +288,34 @@ CFont::Initialise(void) SetAlphaFade(255.0f); SetDropShadowPosition(0); CTxdStore::PopCurrentTxd(); + +#ifdef BUTTON_ICONS + if (int file = CFileMgr::OpenFile("MODELS/X360BTNS.TXD")) { + CFileMgr::CloseFile(file); + ButtonsSlot = CTxdStore::AddTxdSlot("buttons"); + CTxdStore::LoadTxd(ButtonsSlot, "MODELS/X360BTNS.TXD"); + CTxdStore::AddRef(ButtonsSlot); + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(ButtonsSlot); +#if 0 // unused + ButtonSprite[BUTTON_UP].SetTexture("up"); + ButtonSprite[BUTTON_DOWN].SetTexture("down"); + ButtonSprite[BUTTON_LEFT].SetTexture("left"); + ButtonSprite[BUTTON_RIGHT].SetTexture("right"); +#endif + ButtonSprite[BUTTON_CROSS].SetTexture("cross"); + ButtonSprite[BUTTON_CIRCLE].SetTexture("circle"); + ButtonSprite[BUTTON_SQUARE].SetTexture("square"); + ButtonSprite[BUTTON_TRIANGLE].SetTexture("triangle"); + ButtonSprite[BUTTON_L1].SetTexture("l1"); + ButtonSprite[BUTTON_L2].SetTexture("l2"); + ButtonSprite[BUTTON_L3].SetTexture("l3"); + ButtonSprite[BUTTON_R1].SetTexture("r1"); + ButtonSprite[BUTTON_R2].SetTexture("r2"); + ButtonSprite[BUTTON_R3].SetTexture("r3"); + CTxdStore::PopCurrentTxd(); + } +#endif // BUTTON_ICONS } #ifdef MORE_LANGUAGES @@ -327,6 +364,13 @@ CFont::ReloadFonts(uint8 set) void CFont::Shutdown(void) { +#ifdef BUTTON_ICONS + if (ButtonsSlot != -1) { + for (int i = 0; i < MAX_BUTTON_ICONS; i++) + ButtonSprite[i].Delete(); + CTxdStore::RemoveTxdSlot(ButtonsSlot); + } +#endif Sprite[0].Delete(); Sprite[1].Delete(); #ifdef MORE_LANGUAGES @@ -347,7 +391,33 @@ CFont::InitPerFrame(void) FontRenderStatePointer.pRenderState = (CFontRenderState*)FontRenderStateBuf; SetDropShadowPosition(0); NewLine = 0; +#ifdef BUTTON_ICONS + PS2Symbol = BUTTON_NONE; +#endif +} + +#ifdef BUTTON_ICONS +void +CFont::DrawButton(float x, float y) +{ + if (x <= 0.0f || x > SCREEN_WIDTH || y <= 0.0f || y > SCREEN_HEIGHT) + return; + + if (PS2Symbol != BUTTON_NONE) { + CRect rect; + rect.left = x; + rect.top = Details.scaleY + Details.scaleY + y; + rect.right = Details.scaleY * 17.0f + x; + rect.bottom = Details.scaleY * 19.0f + y; + + int vertexAlphaState; + RwRenderStateGet(rwRENDERSTATEVERTEXALPHAENABLE, &vertexAlphaState); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE); + ButtonSprite[PS2Symbol].Draw(rect, CRGBA(255, 255, 255, Details.color.a)); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)vertexAlphaState); + } } +#endif void CFont::PrintChar(float x, float y, wchar c) @@ -374,7 +444,11 @@ CFont::PrintChar(float x, float y, wchar c) if(Details.style == FONT_BANK || Details.style == FONT_STANDARD){ if (bDontPrint) return; if (RenderState.slant == 0.0f) { +#ifdef FIX_BUGS + if (c < 192) { +#else if (c < 193) { +#endif CSprite2d::AddToBuffer( CRect(x, y, x + 32.0f * RenderState.scaleX * 1.0f, @@ -390,9 +464,9 @@ CFont::PrintChar(float x, float y, wchar c) x + 32.0f * RenderState.scaleX * 1.0f, y + 33.0f * RenderState.scaleY * 0.5f), RenderState.color, - xoff / 16.0f, yoff / 12.8f, - (xoff + 1.0f) / 16.0f - 0.001f, yoff / 12.8f - 0.017f, - xoff / 16.0f, (yoff + 1.0f) / 12.8f, + xoff / 16.0f, yoff / 12.8f + 0.0021f, + (xoff + 1.0f) / 16.0f - 0.001f, yoff / 12.8f + 0.0021f, + xoff / 16.0f, (yoff + 1.0f) / 12.8f - 0.017f, (xoff + 1.0f) / 16.0f - 0.001f, (yoff + 1.0f) / 12.8f - 0.017f); } } else @@ -851,6 +925,15 @@ CFont::PrintString(float x, float y, wchar *start, wchar *&end, float spwidth, f c = *s - ' '; if (Details.slant != 0.0f && !IsJapanese()) y = (Details.slantRefX - x) * Details.slant + Details.slantRefY; + +#ifdef BUTTON_ICONS + if (PS2Symbol != BUTTON_NONE) { + DrawButton(x, y); + x += Details.scaleY * 17.0f; + PS2Symbol = BUTTON_NONE; + } +#endif + PrintChar(x, y, c); x += GetCharacterSize(c); if (c == 0 && (!NewLine || !IsJapanese())) // space @@ -972,6 +1055,7 @@ CFont::GetCharacterWidth(wchar c) else return Size[LanguageSet][Details.style][192]; #else + if (Details.proportional) return Size[Details.style][c]; else @@ -1017,6 +1101,11 @@ CFont::GetCharacterSize(wchar c) else return Size[LanguageSet][Details.style][209] * Details.scaleX; #else + +#ifdef FIX_BUGS + // PS2 don't call FindNewCharacter in here at all, and also uses different chars for some symbols + if (!Details.bFontHalfTexture && c == 30) c = 61; // wanted star +#endif if (Details.bFontHalfTexture) c = FindNewCharacter(c); if (Details.proportional) @@ -1041,6 +1130,30 @@ CFont::GetStringWidth(wchar *s, bool spaces) do { while (*s == '~' || *s == JAP_TERMINATION) { s++; +#ifdef BUTTON_ICONS + switch (*s) { +#if 0 // unused + case 'U': + case 'D': + case '<': + case '>': +#endif + case 'X': + case 'O': + case 'Q': + case 'T': + case 'K': + case 'M': + case 'A': + case 'J': + case 'V': + case 'C': + w += 17.0f * Details.scaleY; + break; + default: + break; + } +#endif while (!(*s == '~' || *s == JAP_TERMINATION)) s++; s++; } @@ -1055,6 +1168,30 @@ CFont::GetStringWidth(wchar *s, bool spaces) for (wchar c = *s; (c != ' ' || spaces) && c != '\0'; c = *(++s)) { if (c == '~') { s++; +#ifdef BUTTON_ICONS + switch (*s) { +#if 0 // unused + case 'U': + case 'D': + case '<': + case '>': +#endif + case 'X': + case 'O': + case 'Q': + case 'T': + case 'K': + case 'M': + case 'A': + case 'J': + case 'V': + case 'C': + w += 17.0f * Details.scaleY; + break; + default: + break; + } +#endif while (*s != '~') { s++; } @@ -1142,6 +1279,24 @@ CFont::ParseToken(wchar *s, bool japShit) case 'r': SetColor(CRGBA(113, 43, 73, 255)); break; case 'w': SetColor(CRGBA(175, 175, 175, 255)); break; case 'y': SetColor(CRGBA(210, 196, 106, 255)); break; +#ifdef BUTTON_ICONS +#if 0 // unused + case 'U': PS2Symbol = BUTTON_UP; break; + case 'D': PS2Symbol = BUTTON_DOWN; break; + case '<': PS2Symbol = BUTTON_LEFT; break; + case '>': PS2Symbol = BUTTON_RIGHT; break; +#endif + case 'X': PS2Symbol = BUTTON_CROSS; break; + case 'O': PS2Symbol = BUTTON_CIRCLE; break; + case 'Q': PS2Symbol = BUTTON_SQUARE; break; + case 'T': PS2Symbol = BUTTON_TRIANGLE; break; + case 'K': PS2Symbol = BUTTON_L1; break; + case 'M': PS2Symbol = BUTTON_L2; break; + case 'A': PS2Symbol = BUTTON_L3; break; + case 'J': PS2Symbol = BUTTON_R1; break; + case 'V': PS2Symbol = BUTTON_R2; break; + case 'C': PS2Symbol = BUTTON_R3; break; +#endif } } else if (IsJapanese()) { if ((*s & 0x7FFF) == 'N' || (*s & 0x7FFF) == 'n') @@ -1186,6 +1341,24 @@ CFont::ParseToken(wchar *s) case 'x': SetColor(CRGBA(132, 146, 197, 255)); Details.anonymous_23 = true; break; #endif case 'y': SetColor(CRGBA(255, 227, 79, 255)); Details.anonymous_23 = true; break; +#ifdef BUTTON_ICONS +#if 0 // unused + case 'U': PS2Symbol = BUTTON_UP; break; + case 'D': PS2Symbol = BUTTON_DOWN; break; + case '<': PS2Symbol = BUTTON_LEFT; break; + case '>': PS2Symbol = BUTTON_RIGHT; break; +#endif + case 'X': PS2Symbol = BUTTON_CROSS; break; + case 'O': PS2Symbol = BUTTON_CIRCLE; break; + case 'Q': PS2Symbol = BUTTON_SQUARE; break; + case 'T': PS2Symbol = BUTTON_TRIANGLE; break; + case 'K': PS2Symbol = BUTTON_L1; break; + case 'M': PS2Symbol = BUTTON_L2; break; + case 'A': PS2Symbol = BUTTON_L3; break; + case 'J': PS2Symbol = BUTTON_R1; break; + case 'V': PS2Symbol = BUTTON_R2; break; + case 'C': PS2Symbol = BUTTON_R3; break; +#endif } while(*s != '~') s++; if (*(++s) == '~') @@ -1356,6 +1529,10 @@ CFont::RenderFontBuffer() PrintChar(textPosX + 2.0f, textPosY, c); textPosX += 2.0f; } +#ifdef FIX_BUGS + // PS2 uses different chars for some symbols + if (!RenderState.bFontHalfTexture && c == 30) c = 61; // wanted star +#endif textPosX += RenderState.scaleX * (RenderState.proportional ? Size[RenderState.style][c] : Size[RenderState.style][209]); if (c == '\0') textPosX += RenderState.fExtraSpace; @@ -1437,3 +1614,21 @@ CFont::SetDropColor(CRGBA col) if (Details.alphaFade < 255.0f) Details.dropColor.a *= Details.alphaFade / 255.0f; } + +void +CFont::FilterOutTokensFromString(wchar *str) +{ + int newIdx = 0; + wchar copy[256], *c; + UnicodeStrcpy(copy, str); + + for (c = copy; *c != '\0'; c++) { + if (*c == '~') { + c++; + while (*c != '~') c++; + } else { + str[newIdx++] = *c; + } + } + str[newIdx] = '\0'; +} diff --git a/src/render/Font.h b/src/render/Font.h index 47a39f73..d61ca6e7 100644 --- a/src/render/Font.h +++ b/src/render/Font.h @@ -91,6 +91,31 @@ enum #define FONT_LOCALE(style) (style) #endif +#ifdef BUTTON_ICONS +enum +{ + BUTTON_NONE = -1, +#if 0 // unused + BUTTON_UP, + BUTTON_DOWN, + BUTTON_LEFT, + BUTTON_RIGHT, +#endif + BUTTON_CROSS, + BUTTON_CIRCLE, + BUTTON_SQUARE, + BUTTON_TRIANGLE, + BUTTON_L1, + BUTTON_L2, + BUTTON_L3, + BUTTON_R1, + BUTTON_R2, + BUTTON_R3, + MAX_BUTTON_ICONS +}; +#endif // BUTTON_ICONS + + class CFont { #ifdef MORE_LANGUAGES @@ -106,11 +131,24 @@ public: static CFontDetails Details; static CFontRenderState RenderState; +#ifdef BUTTON_ICONS + static int32 ButtonsSlot; + static CSprite2d ButtonSprite[MAX_BUTTON_ICONS]; + static int PS2Symbol; + + static void DrawButton(float x, float y); +#endif // BUTTON_ICONS + + static void Initialise(void); static void Shutdown(void); static void InitPerFrame(void); static void PrintChar(float x, float y, wchar c); static void PrintString(float x, float y, wchar *s); +#ifdef XBOX_SUBTITLES + static void PrintStringFromBottom(float x, float y, wchar *str); + static void PrintOutlinedString(float x, float y, wchar *str, float outlineStrength, bool fromBottom, CRGBA outlineColor); +#endif static int GetNumberLines(float xstart, float ystart, wchar *s); static void GetTextRect(CRect *rect, float xstart, float ystart, wchar *s); #ifdef MORE_LANGUAGES @@ -200,6 +238,7 @@ public: static void SetColor(CRGBA col); static void SetDropColor(CRGBA col); static wchar FindNewCharacter(wchar c); + static void FilterOutTokensFromString(wchar*); #ifdef MORE_LANGUAGES static void ReloadFonts(uint8 set); diff --git a/src/render/Glass.cpp b/src/render/Glass.cpp index 536d94e0..a11495a9 100644 --- a/src/render/Glass.cpp +++ b/src/render/Glass.cpp @@ -1,4 +1,4 @@ -#include "common.h" +#include "common.h" #include "Glass.h" #include "Timer.h" @@ -150,7 +150,11 @@ CFallingGlassPane::Render(void) fwdNorm.Normalise(); uint8 alpha = CGlass::CalcAlphaWithNormal(&fwdNorm); - int32 time = clamp(CTimer::GetTimeInMilliseconds() - m_nTimer, 0, 500); +#ifdef FIX_BUGS + uint16 time = clamp(CTimer::GetTimeInMilliseconds() > m_nTimer ? CTimer::GetTimeInMilliseconds() - m_nTimer : 0u, 0u, 500u); +#else + uint16 time = clamp(CTimer::GetTimeInMilliseconds() - m_nTimer, 0, 500); +#endif uint8 color = int32( float(alpha) * (float(time) / 500) ); diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 239d0de4..c4e78a91 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -1172,6 +1172,10 @@ void CHud::Draw() onceItWasWidescreen = true; if (FrontEndMenuManager.m_PrefsShowSubtitles || !CCutsceneMgr::IsRunning()) { +#ifdef CUTSCENE_BORDERS_SWITCH + if (!FrontEndMenuManager.m_PrefsCutsceneBorders) + CFont::SetDropShadowPosition(2); +#endif CFont::SetCentreSize(SCREEN_WIDTH - SCREEN_SCALE_X(60.0f)); CFont::SetScale(SCREEN_SCALE_X(0.58f), SCREEN_SCALE_Y(1.2f)); CFont::PrintString(SCREEN_WIDTH / 2.f, SCREEN_SCALE_FROM_BOTTOM(80.0f), m_Message); @@ -1558,15 +1562,8 @@ void CHud::DrawAfterFade() CFont::SetFontStyle(FONT_LOCALE(FONT_STANDARD)); CFont::SetDropShadowPosition(2); CFont::SetDropColor(CRGBA(0, 0, 0, 255)); -#ifdef BETA_SLIDING_TEXT - - CFont::SetColor(ODDJOB2_COLOR); - CFont::PrintString(SCREEN_WIDTH / 2 - SCREEN_SCALE_X(OddJob2XOffset), SCREEN_SCALE_Y(217.0f), m_BigMessage[5]); -#else - CFont::SetColor(ODDJOB2_COLOR); CFont::PrintString(SCREEN_WIDTH / 2, SCREEN_SCALE_Y(217.0f), m_BigMessage[5]); -#endif } } @@ -1615,11 +1612,7 @@ void CHud::DrawAfterFade() CFont::SetDropShadowPosition(2); CFont::SetDropColor(CRGBA(0, 0, 0, BigMessageAlpha[1])); CFont::SetColor(CRGBA(MISSIONTITLE_COLOR.r, MISSIONTITLE_COLOR.g, MISSIONTITLE_COLOR.b, BigMessageAlpha[1])); -#ifdef BETA_SLIDING_TEXT - CFont::PrintString(BigMessageX[1], SCREEN_SCALE_FROM_BOTTOM(140.0f), m_BigMessage[1]); -#else CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(140.0f), m_BigMessage[1]); -#endif } else { m_ZoneFadeTimer = 0; BigMessageX[1] = SCREEN_SCALE_FROM_RIGHT(DEFAULT_SCREEN_WIDTH + 60.0f); diff --git a/src/render/MBlur.cpp b/src/render/MBlur.cpp index 08298a1f..44d4f1d4 100644 --- a/src/render/MBlur.cpp +++ b/src/render/MBlur.cpp @@ -7,10 +7,15 @@ #include <d3d8caps.h> #endif +#include "General.h" #include "RwHelper.h" #include "Camera.h" -#include "MBlur.h" +#include "Timecycle.h" +#include "Particle.h" #include "Timer.h" +#include "Hud.h" +#include "Frontend.h" +#include "MBlur.h" #include "postfx.h" // Originally taken from RW example 'mblur' @@ -21,6 +26,8 @@ bool CMBlur::ms_bScaledBlur; bool CMBlur::BlurOn; float CMBlur::Drunkness; +int32 CMBlur::pBufVertCount; + static RwIm2DVertex Vertex[4]; static RwIm2DVertex Vertex2[4]; static RwImVertexIndex Index[6] = { 0, 1, 2, 0, 2, 3 }; @@ -244,6 +251,84 @@ CMBlur::CreateImmediateModeData(RwCamera *cam, RwRect *rect) } void +CMBlur::CreateImmediateModeData(RwCamera *cam, RwRect *rect, RwIm2DVertex *verts, RwRGBA color, float u1Off, float v1Off, float u2Off, float v2Off, float z, int fullTexture) +{ + float x1 = rect->x; + float y1 = rect->y; + float x2 = rect->w; + float y2 = rect->h; + + float u1, v1, u2, v2; + if(fullTexture){ + u1 = 0.0f; + v1 = 0.0f; + u2 = 1.0f; + v2 = 1.0f; + }else{ + if(RwRasterGetDepth(RwCameraGetRaster(cam)) == 16){ + x1 += HALFPX; + y1 += HALFPX; + x2 += HALFPX; + y2 += HALFPX; + }else{ + x1 -= HALFPX; + y1 -= HALFPX; + x2 -= HALFPX; + y2 -= HALFPX; + } + + int32 width = Pow(2.0f, int32(log2(RwRasterGetWidth (RwCameraGetRaster(cam))))+1); + int32 height = Pow(2.0f, int32(log2(RwRasterGetHeight(RwCameraGetRaster(cam))))+1); + u1 = x1/width + u1Off; + v1 = y1/height + v1Off; + u2 = x2/width + u2Off; + v2 = y2/height + v2Off; + u1 = clamp(u1, 0.0f, 1.0f); + v1 = clamp(v1, 0.0f, 1.0f); + u2 = clamp(u2, 0.0f, 1.0f); + v2 = clamp(v2, 0.0f, 1.0f); + } + + float recipz = 1.0f/z; + // TODO: CameraZ is wrong, what should we do? + RwIm2DVertexSetScreenX(&verts[0], x1); + RwIm2DVertexSetScreenY(&verts[0], y1); + RwIm2DVertexSetScreenZ(&verts[0], z); + RwIm2DVertexSetCameraZ(&verts[0], RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetRecipCameraZ(&verts[0], recipz); + RwIm2DVertexSetU(&verts[0], u1, recipz); + RwIm2DVertexSetV(&verts[0], v1, recipz); + RwIm2DVertexSetIntRGBA(&verts[0], color.red, color.green, color.blue, color.alpha); + + RwIm2DVertexSetScreenX(&verts[1], x1); + RwIm2DVertexSetScreenY(&verts[1], y2); + RwIm2DVertexSetScreenZ(&verts[1], z); + RwIm2DVertexSetCameraZ(&verts[1], RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetRecipCameraZ(&verts[1], recipz); + RwIm2DVertexSetU(&verts[1], u1, recipz); + RwIm2DVertexSetV(&verts[1], v2, recipz); + RwIm2DVertexSetIntRGBA(&verts[1], color.red, color.green, color.blue, color.alpha); + + RwIm2DVertexSetScreenX(&verts[2], x2); + RwIm2DVertexSetScreenY(&verts[2], y2); + RwIm2DVertexSetScreenZ(&verts[2], z); + RwIm2DVertexSetCameraZ(&verts[2], RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetRecipCameraZ(&verts[2], recipz); + RwIm2DVertexSetU(&verts[2], u2, recipz); + RwIm2DVertexSetV(&verts[2], v2, recipz); + RwIm2DVertexSetIntRGBA(&verts[2], color.red, color.green, color.blue, color.alpha); + + RwIm2DVertexSetScreenX(&verts[3], x2); + RwIm2DVertexSetScreenY(&verts[3], y1); + RwIm2DVertexSetScreenZ(&verts[3], z); + RwIm2DVertexSetCameraZ(&verts[3], RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetRecipCameraZ(&verts[3], recipz); + RwIm2DVertexSetU(&verts[3], u2, recipz); + RwIm2DVertexSetV(&verts[3], v1, recipz); + RwIm2DVertexSetIntRGBA(&verts[3], color.red, color.green, color.blue, color.alpha); +} + +void CMBlur::MotionBlurRender(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blur, int32 type, uint32 bluralpha) { #ifdef EXTENDED_COLOURFILTER @@ -415,7 +500,8 @@ CMBlur::OverlayRender(RwCamera *cam, RwRaster *raster, RwRGBA color, int32 type, RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6); } - // TODO(MIAMI): OverlayRenderFx + if(type != MOTION_BLUR_SNIPER) + OverlayRenderFx(cam, pFrontBuffer); RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); @@ -437,4 +523,277 @@ CMBlur::ClearDrunkBlur() { Drunkness = 0.0f; CTimer::SetTimeScale(1.0f); -}
\ No newline at end of file +} + +#define NUM_RENDER_FX 64 + +static RwRect fxRect[NUM_RENDER_FX]; +static FxType fxType[NUM_RENDER_FX]; +static float fxZ[NUM_RENDER_FX]; + +bool +CMBlur::PosInside(RwRect *rect, float x1, float y1, float x2, float y2) +{ + if((rect->x < x1 - 10.0f || rect->x > x2 + 10.0f || rect->y < y1 - 10.0f || rect->y > y2 + 10.0f) && + (rect->w < x1 - 10.0f || rect->w > x2 + 10.0f || rect->h < y1 - 10.0f || rect->h > y2 + 10.0f) && + (rect->x < x1 - 10.0f || rect->x > x2 + 10.0f || rect->h < y1 - 10.0f || rect->h > y2 + 10.0f) && + (rect->w < x1 - 10.0f || rect->w > x2 + 10.0f || rect->y < y1 - 10.0f || rect->y > y2 + 10.0f)) + return false; + return true; +} + +bool +CMBlur::AddRenderFx(RwCamera *cam, RwRect *rect, float z, FxType type) +{ + if(pBufVertCount >= NUM_RENDER_FX) + return false; + + rect->x = Max(rect->x, 0); + rect->y = Max(rect->y, 0); + rect->w = Min(rect->w, SCREEN_WIDTH); + rect->h = Min(rect->h, SCREEN_HEIGHT); + if(rect->x >= rect->w || rect->y >= rect->h) + return false; + + switch(type){ + case FXTYPE_WATER1: + case FXTYPE_WATER2: + case FXTYPE_BLOOD1: + case FXTYPE_BLOOD2: + case FXTYPE_HEATHAZE: // code seems to be duplicated for this case + for(int i = 0; i < pBufVertCount; i++) + if(fxType[i] == type && PosInside(rect, fxRect[i].x-10.0f, fxRect[i].y-10.0f, fxRect[i].w+10.0f, fxRect[i].h+10.0f)) + return false; + // TODO: fix aspect ratio scaling + // radar + if(PosInside(rect, 40.0f, SCREEN_SCALE_FROM_BOTTOM(116.0f), 40.0f + SCREEN_SCALE_X(94.0f), SCREEN_SCALE_FROM_BOTTOM(116.0f - 76.0f))) + return false; + // HUD + if(PosInside(rect, 400.0f, 0.0f, SCREEN_WIDTH, 90.0f)) + return false; + // vehicle name + if(CHud::m_VehicleState != 0 && PosInside(rect, SCREEN_WIDTH/2, 350.0f, SCREEN_WIDTH, SCREEN_HEIGHT)) + return false; + // zone name + if(CHud::m_ZoneState != 0 && PosInside(rect, SCREEN_WIDTH/2, 350.0f, SCREEN_WIDTH, SCREEN_HEIGHT)) + return false; + break; + } + + fxRect[pBufVertCount] = *rect; + fxZ[pBufVertCount] = z; + fxType[pBufVertCount] = type; + pBufVertCount++; + + return true; +} + +void +CMBlur::OverlayRenderFx(RwCamera *cam, RwRaster *frontBuf) +{ + bool drawWaterDrops = false; + RwIm2DVertex verts[4]; + int red = (0.75f*CTimeCycle::GetDirectionalRed() + CTimeCycle::GetAmbientRed())*0.55f * 255; + int green = (0.75f*CTimeCycle::GetDirectionalGreen() + CTimeCycle::GetAmbientGreen())*0.55f * 255; + int blue = (0.75f*CTimeCycle::GetDirectionalBlue() + CTimeCycle::GetAmbientBlue())*0.55f * 255; + red = clamp(red, 0, 255); + green = clamp(green, 0, 255); + blue = clamp(blue, 0, 255); + + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + +#ifdef LIBRW + rw::SetRenderState(rw::STENCILENABLE, TRUE); +#else + RwD3D8SetRenderState(D3DRS_STENCILENABLE, TRUE); +#endif + + for(int i = 0; i < pBufVertCount; i++) + switch(fxType[i]){ + case FXTYPE_WATER1: + case FXTYPE_WATER2: + case FXTYPE_BLOOD1: + case FXTYPE_BLOOD2: { + drawWaterDrops = true; + int32 width = Pow(2.0f, int32(log2(RwRasterGetWidth (RwCameraGetRaster(cam))))+1); + int32 height = Pow(2.0f, int32(log2(RwRasterGetHeight(RwCameraGetRaster(cam))))+1); + + float u1Off = (fxRect[i].w - fxRect[i].x)/width; + float u2Off = u1Off - (fxRect[i].w - fxRect[i].x + 0.5f)*0.66f/width; + float halfHeight = (fxRect[i].h - fxRect[i].y + 0.5f)*0.25f/height; + + if(RwRasterGetDepth(RwCameraGetRaster(cam)) == 16){ + if(fxType[i] == FXTYPE_BLOOD1 || fxType[i] == FXTYPE_BLOOD2) + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(255, 0, 0, 128), 0.0f, 0.0f, 0.0f, 0.0f, fxZ[i], true); + else + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(32, 32, 32, 225), 0.0f, 0.0f, 0.0f, 0.0f, fxZ[i], true); + }else{ + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(32, 32, 32, 225), 0.0f, 0.0f, 0.0f, 0.0f, fxZ[i], true); + } + + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpDotRaster); +#ifdef LIBRW + rw::SetRenderState(rw::STENCILFUNCTION, rw::STENCILALWAYS); + rw::SetRenderState(rw::STENCILFUNCTIONREF, 1); + rw::SetRenderState(rw::STENCILFUNCTIONMASK, 0xFFFFFFFF); + rw::SetRenderState(rw::STENCILFUNCTIONWRITEMASK, 0xFFFFFFFF); + rw::SetRenderState(rw::STENCILZFAIL, rw::STENCILKEEP); + rw::SetRenderState(rw::STENCILFAIL, rw::STENCILKEEP); + rw::SetRenderState(rw::STENCILPASS, rw::STENCILREPLACE); +#else + RwD3D8SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + RwD3D8SetRenderState(D3DRS_STENCILREF, 1); + RwD3D8SetRenderState(D3DRS_STENCILMASK, 0xFFFFFFFF); + RwD3D8SetRenderState(D3DRS_STENCILWRITEMASK, 0xFFFFFFFF); + RwD3D8SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); + RwD3D8SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + RwD3D8SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); +#endif + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, verts, 4, Index, 6); + + if(RwRasterGetDepth(RwCameraGetRaster(cam)) != 16){ + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, frontBuf); +#ifdef LIBRW + rw::SetRenderState(rw::STENCILFUNCTION, rw::STENCILEQUAL); + rw::SetRenderState(rw::STENCILPASS, rw::STENCILKEEP); +#else + RwD3D8SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + RwD3D8SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); +#endif + if(BlurOn){ + if(fxType[i] == FXTYPE_BLOOD1 || fxType[i] == FXTYPE_BLOOD2) + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(255, 0, 0, 255), u1Off, 0.0f+halfHeight, u2Off, 0.0f-halfHeight, fxZ[i], false); + else + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(225, 225, 225, 160), u1Off, 0.0f+halfHeight, u2Off, 0.0f-halfHeight, fxZ[i], false); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDDESTALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVDESTALPHA); + }else{ + if(fxType[i] == FXTYPE_BLOOD1 || fxType[i] == FXTYPE_BLOOD2) + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(255, 0, 0, 128), u1Off, 0.0f+halfHeight, u2Off, 0.0f-halfHeight, fxZ[i], false); + else + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(128, 128, 128, 32), u1Off, 0.0f+halfHeight, u2Off, 0.0f-halfHeight, fxZ[i], false); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + } + RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, verts, 4, Index, 6); + } + break; + } + case FXTYPE_SPLASH1: + case FXTYPE_SPLASH2: + case FXTYPE_SPLASH3: + drawWaterDrops = true; + break; + + case FXTYPE_HEATHAZE: + if(TheCamera.GetScreenFadeStatus() == FADE_0 && frontBuf){ + int alpha = FrontEndMenuManager.m_PrefsBrightness > 255 ? + FrontEndMenuManager.m_PrefsBrightness - 90 : + FrontEndMenuManager.m_PrefsBrightness - 130; + alpha = clamp(alpha, 16, 200)/2; + + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(0, 0, 0, alpha), 0.0f, 0.0f, 0.0f, 0.0f, fxZ[i], true); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpHeatHazeRaster); +#ifdef LIBRW + rw::SetRenderState(rw::STENCILFUNCTION, rw::STENCILALWAYS); + rw::SetRenderState(rw::STENCILFUNCTIONREF, 1); + rw::SetRenderState(rw::STENCILFUNCTIONMASK, 0xFFFFFFFF); + rw::SetRenderState(rw::STENCILFUNCTIONWRITEMASK, 0xFFFFFFFF); + rw::SetRenderState(rw::STENCILZFAIL, rw::STENCILKEEP); + rw::SetRenderState(rw::STENCILFAIL, rw::STENCILKEEP); + rw::SetRenderState(rw::STENCILPASS, rw::STENCILREPLACE); +#else + RwD3D8SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + RwD3D8SetRenderState(D3DRS_STENCILREF, 1); + RwD3D8SetRenderState(D3DRS_STENCILMASK, 0xFFFFFFFF); + RwD3D8SetRenderState(D3DRS_STENCILWRITEMASK, 0xFFFFFFFF); + RwD3D8SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); + RwD3D8SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + RwD3D8SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); +#endif + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, verts, 4, Index, 6); + + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(255, 255, 255, alpha), + CGeneral::GetRandomNumberInRange(-0.002f, 0.002f), + CGeneral::GetRandomNumberInRange(-0.002f, 0.002f), + CGeneral::GetRandomNumberInRange(-0.002f, 0.002f), + CGeneral::GetRandomNumberInRange(-0.002f, 0.002f), + fxZ[i], false); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, frontBuf); +#ifdef LIBRW + rw::SetRenderState(rw::STENCILFUNCTION, rw::STENCILEQUAL); + rw::SetRenderState(rw::STENCILPASS, rw::STENCILKEEP); +#else + RwD3D8SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + RwD3D8SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); +#endif + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, verts, 4, Index, 6); + } + break; + } +#ifdef LIBRW + rw::SetRenderState(rw::STENCILENABLE, FALSE); +#else + RwD3D8SetRenderState(D3DRS_STENCILENABLE, FALSE); +#endif + + if(drawWaterDrops){ + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + + // Draw drops + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpRainDripRaster[0]); + for(int i = 0; i < pBufVertCount; i++) + if(fxType[i] == FXTYPE_WATER1 || fxType[i] == FXTYPE_BLOOD1){ + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(red, green, blue, fxType[i] == FXTYPE_BLOOD1 ? 255 : 192), + 0.0f, 0.0f, 0.0f, 0.0f, fxZ[i], true); + RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, verts, 4, Index, 6); + } + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpRainDripRaster[1]); + for(int i = 0; i < pBufVertCount; i++) + if(fxType[i] == FXTYPE_WATER2 || fxType[i] == FXTYPE_BLOOD2){ + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(red, green, blue, fxType[i] == FXTYPE_BLOOD2 ? 255 : 192), + 0.0f, 0.0f, 0.0f, 0.0f, fxZ[i], true); + RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, verts, 4, Index, 6); + } + + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCarSplashRaster[0]); + for(int i = 0; i < pBufVertCount; i++) + if(fxType[i] == FXTYPE_SPLASH1 || fxType[i] == FXTYPE_SPLASH2 || fxType[i] == FXTYPE_SPLASH3){ + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(200, 200, 200, 255), + 0.0f, 0.0f, 0.0f, 0.0f, fxZ[i], true); + RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, verts, 4, Index, 6); + } + + // Darken the water drops + int alpha = 192*0.5f; + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpRainDripDarkRaster[0]); + for(int i = 0; i < pBufVertCount; i++) + if(fxType[i] == FXTYPE_WATER1){ + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(red, green, blue, alpha), + 0.0f, 0.0f, 0.0f, 0.0f, fxZ[i], true); + RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, verts, 4, Index, 6); + } + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpRainDripDarkRaster[1]); + for(int i = 0; i < pBufVertCount; i++) + if(fxType[i] == FXTYPE_WATER2){ + CreateImmediateModeData(cam, &fxRect[i], verts, CRGBA(red, green, blue, alpha), + 0.0f, 0.0f, 0.0f, 0.0f, fxZ[i], true); + RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, verts, 4, Index, 6); + } + } + + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + pBufVertCount = 0; +} diff --git a/src/render/MBlur.h b/src/render/MBlur.h index c2572256..3dc53082 100644 --- a/src/render/MBlur.h +++ b/src/render/MBlur.h @@ -2,12 +2,14 @@ enum FxType { - FXTYPE_0 = 0, - FXTYPE_1, - FXTYPE_2, - FXTYPE_3, - FXTYPE_4, - FXTYPE_5, + FXTYPE_WATER1, + FXTYPE_WATER2, + FXTYPE_BLOOD1, + FXTYPE_BLOOD2, + FXTYPE_HEATHAZE, + FXTYPE_SPLASH1, + FXTYPE_SPLASH2, + FXTYPE_SPLASH3 }; class CMBlur @@ -19,16 +21,19 @@ public: static bool BlurOn; static float Drunkness; + static int32 pBufVertCount; + public: static RwBool MotionBlurOpen(RwCamera *cam); static RwBool MotionBlurClose(void); static void CreateImmediateModeData(RwCamera *cam, RwRect *rect); + static void CreateImmediateModeData(RwCamera *cam, RwRect *rect, RwIm2DVertex *verts, RwRGBA color, float u1Off, float v1Off, float u2Off, float v2Off, float z, int fullTexture); static void MotionBlurRender(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blur, int32 type, uint32 bluralpha); static void OverlayRender(RwCamera *cam, RwRaster *raster, RwRGBA color, int32 type, int32 bluralpha); static void SetDrunkBlur(float drunkness); static void ClearDrunkBlur(); - //TODO - static void AddRenderFx(RwCamera *,RwRect *,float,FxType) - {} + static bool PosInside(RwRect *rect, float x1, float y1, float x2, float y2); + static bool AddRenderFx(RwCamera *cam, RwRect *rect, float z, FxType type); + static void OverlayRenderFx(RwCamera *cam, RwRaster *frontBuf); }; diff --git a/src/render/Occlusion.cpp b/src/render/Occlusion.cpp index 79ce0461..2b15e75b 100644 --- a/src/render/Occlusion.cpp +++ b/src/render/Occlusion.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "main.h" +#include "Entity.h" #include "Occlusion.h" #include "Game.h" #include "Camera.h" @@ -292,6 +293,11 @@ COcclusion::ProcessBeforeRendering(void) { NumActiveOccluders = 0; +#ifndef MASTER + if (gbModelViewer) + return; +#endif + if (CGame::currArea != AREA_MAIN_MAP) return; @@ -488,3 +494,36 @@ void COcclusion::Render() { DefinedState(); } #endif + +bool CEntity::IsEntityOccluded(void) { + + CVector coors; + float width, height; + + if (COcclusion::NumActiveOccluders == 0 || !CalcScreenCoors(GetBoundCentre(), &coors, &width, &height)) + return false; + + float area = Max(width, height) * GetBoundRadius() * 0.9f; + + for (int i = 0; i < COcclusion::NumActiveOccluders; i++) { + if (coors.z - (GetBoundRadius() * 0.85f) > COcclusion::aActiveOccluders[i].radius) { + if (COcclusion::aActiveOccluders[i].IsPointWithinOcclusionArea(coors.x, coors.y, area)) { + return true; + } + + if (COcclusion::aActiveOccluders[i].IsPointWithinOcclusionArea(coors.x, coors.y, 0.0f)) { + CVector min = m_matrix * CModelInfo::GetModelInfo(GetModelIndex())->GetColModel()->boundingBox.min; + CVector max = m_matrix * CModelInfo::GetModelInfo(GetModelIndex())->GetColModel()->boundingBox.max; + + if (CalcScreenCoors(min, &coors) && !COcclusion::aActiveOccluders[i].IsPointWithinOcclusionArea(coors.x, coors.y, 0.0f)) continue; + if (CalcScreenCoors(CVector(max.x, max.y, min.z), &coors) && !COcclusion::aActiveOccluders[i].IsPointWithinOcclusionArea(coors.x, coors.y, 0.0f)) continue; + if (CalcScreenCoors(CVector(max.x, min.y, max.z), &coors) && !COcclusion::aActiveOccluders[i].IsPointWithinOcclusionArea(coors.x, coors.y, 0.0f)) continue; + if (CalcScreenCoors(CVector(min.x, max.y, max.z), &coors) && !COcclusion::aActiveOccluders[i].IsPointWithinOcclusionArea(coors.x, coors.y, 0.0f)) continue; + + return true; + } + } + } + + return false; +}
\ No newline at end of file diff --git a/src/render/Particle.cpp b/src/render/Particle.cpp index 6a42bc4d..0ad4681d 100644 --- a/src/render/Particle.cpp +++ b/src/render/Particle.cpp @@ -213,19 +213,19 @@ RwTexture *gpSparkTex; RwTexture *gpNewspaperTex; RwTexture *gpGunSmokeTex; RwTexture *gpDotTex; -RwTexture *gpHeathazeTex; +RwTexture *gpHeatHazeTex; RwTexture *gpBeastieTex; -RwTexture *gpRaindripTex1[MAX_RAINDRIP_FILES]; -RwTexture *gpRaindripTex2[MAX_RAINDRIP_FILES]; +RwTexture *gpRainDripTex[MAX_RAINDRIP_FILES]; +RwTexture *gpRainDripDarkTex[MAX_RAINDRIP_FILES]; RwRaster *gpSparkRaster; RwRaster *gpNewspaperRaster; RwRaster *gpGunSmokeRaster; RwRaster *gpDotRaster; -RwRaster *gpHeathazeRaster; +RwRaster *gpHeatHazeRaster; RwRaster *gpBeastieRaster; -RwRaster *gpRaindripRaster1[MAX_RAINDRIP_FILES]; -RwRaster *gpRaindripRaster2[MAX_RAINDRIP_FILES]; +RwRaster *gpRainDripRaster[MAX_RAINDRIP_FILES]; +RwRaster *gpRainDripDarkRaster[MAX_RAINDRIP_FILES]; float CParticle::ms_afRandTable[CParticle::RAND_TABLE_SIZE]; CParticle *CParticle::m_pUnusedListHead; @@ -411,9 +411,11 @@ void CParticle::Initialise() gpFlame5Tex = RwTextureRead("flame5", nil); -#ifdef FIX_BUGS +//#ifdef FIX_BUGS +#if 0 gpFlame5Raster = RwTextureGetRaster(gpFlame5Tex); #else + // this seems to have become more of a design choice gpFlame5Raster = RwTextureGetRaster(gpFlame1Tex); // copy-paste bug ? #endif @@ -465,23 +467,23 @@ void CParticle::Initialise() gpDotTex = RwTextureRead("dot", nil); gpDotRaster = RwTextureGetRaster(gpDotTex); - gpHeathazeTex = RwTextureRead("heathaze", nil); - gpHeathazeRaster = RwTextureGetRaster(gpHeathazeTex); + gpHeatHazeTex = RwTextureRead("heathaze", nil); + gpHeatHazeRaster = RwTextureGetRaster(gpHeatHazeTex); gpBeastieTex = RwTextureRead("beastie", nil); gpBeastieRaster = RwTextureGetRaster(gpBeastieTex); - gpRaindripTex1[0] = RwTextureRead("raindrip64", nil); - gpRaindripRaster1[0] = RwTextureGetRaster(gpRaindripTex1[0]); + gpRainDripTex[0] = RwTextureRead("raindrip64", nil); + gpRainDripRaster[0] = RwTextureGetRaster(gpRainDripTex[0]); - gpRaindripTex1[1] = RwTextureRead("raindripb64", nil); - gpRaindripRaster1[1] = RwTextureGetRaster(gpRaindripTex1[1]); + gpRainDripTex[1] = RwTextureRead("raindripb64", nil); + gpRainDripRaster[1] = RwTextureGetRaster(gpRainDripTex[1]); - gpRaindripTex2[0] = RwTextureRead("raindrip64_d", nil); - gpRaindripRaster2[0] = RwTextureGetRaster(gpRaindripTex2[0]); + gpRainDripDarkTex[0] = RwTextureRead("raindrip64_d", nil); + gpRainDripDarkRaster[0] = RwTextureGetRaster(gpRainDripDarkTex[0]); - gpRaindripTex2[1] = RwTextureRead("raindripb64_d", nil); - gpRaindripRaster2[1] = RwTextureGetRaster(gpRaindripTex2[1]); + gpRainDripDarkTex[1] = RwTextureRead("raindripb64_d", nil); + gpRainDripDarkRaster[1] = RwTextureGetRaster(gpRainDripDarkTex[1]); CTxdStore::PopCurrentTxd(); @@ -586,7 +588,7 @@ void CParticle::Initialise() break; case PARTICLE_TEARGAS: - entry->m_ppRaster = &gpHeathazeRaster; + entry->m_ppRaster = &gpHeatHazeRaster; break; case PARTICLE_SHARD: @@ -749,11 +751,11 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_RAINDRIP_FILES; i++ ) { - RwTextureDestroy(gpRaindripTex1[i]); - gpRaindripTex1[i] = nil; + RwTextureDestroy(gpRainDripTex[i]); + gpRainDripTex[i] = nil; - RwTextureDestroy(gpRaindripTex2[i]); - gpRaindripTex2[i] = nil; + RwTextureDestroy(gpRainDripDarkTex[i]); + gpRainDripDarkTex[i] = nil; } RwTextureDestroy(gpBoatWakeTex); @@ -812,8 +814,8 @@ void CParticle::Shutdown() RwTextureDestroy(gpDotTex); gpDotTex = nil; - RwTextureDestroy(gpHeathazeTex); - gpHeathazeTex = nil; + RwTextureDestroy(gpHeatHazeTex); + gpHeatHazeTex = nil; RwTextureDestroy(gpBeastieTex); gpBeastieTex = nil; @@ -941,7 +943,7 @@ CParticle *CParticle::AddParticle(tParticleType type, CVector const &vecPos, CVe CVector screen; float w, h; - if ( !CSprite::CalcScreenCoors(vecPos, screen, &w, &h, true) ) + if ( !CSprite::CalcScreenCoors(vecPos, &screen, &w, &h, true) ) return nil; pParticle->m_vecPosition = screen; @@ -1913,9 +1915,9 @@ void CParticle::Render() FxType fxtype; if ( particle->m_nCurrentFrame != 0 ) - fxtype = FXTYPE_1; + fxtype = FXTYPE_WATER2; else - fxtype = FXTYPE_0; + fxtype = FXTYPE_WATER1; CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, fxtype); @@ -1939,9 +1941,9 @@ void CParticle::Render() FxType fxtype; if ( particle->m_nCurrentFrame ) - fxtype = FXTYPE_3; + fxtype = FXTYPE_BLOOD2; else - fxtype = FXTYPE_2; + fxtype = FXTYPE_BLOOD1; CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, fxtype); @@ -1957,7 +1959,7 @@ void CParticle::Render() rect.w = int32(particle->m_vecPosition.x + SCREEN_STRETCH_X(particle->m_fSize * stretchTexW)); rect.h = int32(particle->m_vecPosition.y + SCREEN_STRETCH_Y(particle->m_fSize * stretchTexH * 0.15f)); - CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, FXTYPE_4); + CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, FXTYPE_HEATHAZE); canDraw = false; } @@ -1993,7 +1995,7 @@ void CParticle::Render() break; } - CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, FXTYPE_4); + CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, FXTYPE_HEATHAZE); canDraw = false; } @@ -2034,7 +2036,7 @@ void CParticle::Render() float w; float h; - if ( CSprite::CalcScreenCoors(particle->m_vecPosition, coors, &w, &h, true) ) + if ( CSprite::CalcScreenCoors(particle->m_vecPosition, &coors, &w, &h, true) ) { if ( i == PARTICLE_ENGINE_STEAM @@ -2115,7 +2117,7 @@ void CParticle::Render() * (CSprite::GetFarScreenZ() - CSprite::GetNearScreenZ()) * CDraw::GetFarClipZ() / ( (CDraw::GetFarClipZ() - CDraw::GetNearClipZ()) * coors.z ) + CSprite::GetNearScreenZ(); - CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, FXTYPE_5); + CMBlur::AddRenderFx(Scene.camera, &rect, screenZ, FXTYPE_SPLASH1); } else { @@ -2189,7 +2191,7 @@ void CParticle::Render() float fTrailLength; CVector vecScreenPosition; - if ( CSprite::CalcScreenCoors(vecPrevPos, vecScreenPosition, &fTrailLength, &fRotation, true) ) + if ( CSprite::CalcScreenCoors(vecPrevPos, &vecScreenPosition, &fTrailLength, &fRotation, true) ) { CVector2D vecDist ( @@ -2470,3 +2472,43 @@ void CParticle::HandleShootableBirdsStuff(CEntity *entity, CVector const&camPos) } } + +void +CEntity::AddSteamsFromGround(CVector *unused) +{ + int i, n; + C2dEffect *effect; + CVector pos; + + n = CModelInfo::GetModelInfo(GetModelIndex())->GetNum2dEffects(); + for(i = 0; i < n; i++){ + effect = CModelInfo::GetModelInfo(GetModelIndex())->Get2dEffect(i); + if(effect->type != EFFECT_PARTICLE) + continue; + + pos = GetMatrix() * effect->pos; + switch(effect->particle.particleType){ + case 0: + CParticleObject::AddObject(POBJECT_PAVEMENT_STEAM, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 1: + CParticleObject::AddObject(POBJECT_WALL_STEAM, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 2: + CParticleObject::AddObject(POBJECT_DRY_ICE, pos, effect->particle.scale, false); + break; + case 3: + CParticleObject::AddObject(POBJECT_SMALL_FIRE, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 4: + CParticleObject::AddObject(POBJECT_DARK_SMOKE, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 5: + CParticleObject::AddObject(POBJECT_WATER_FOUNTAIN_VERT, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 6: + CParticleObject::AddObject(POBJECT_WATER_FOUNTAIN_HORIZ, pos, effect->particle.dir, effect->particle.scale, false); + break; + } + } +} diff --git a/src/render/Particle.h b/src/render/Particle.h index 9c496fe1..5542dc02 100644 --- a/src/render/Particle.h +++ b/src/render/Particle.h @@ -99,5 +99,10 @@ public: extern bool clearWaterDrop; extern int32 numWaterDropOnScreen; +extern RwRaster *gpCarSplashRaster[]; +extern RwRaster *gpHeatHazeRaster; +extern RwRaster *gpDotRaster; +extern RwRaster *gpRainDripRaster[]; +extern RwRaster *gpRainDripDarkRaster[]; VALIDATE_SIZE(CParticle, 0x58); diff --git a/src/render/PlayerSkin.cpp b/src/render/PlayerSkin.cpp index 261bbec0..1626716f 100644 --- a/src/render/PlayerSkin.cpp +++ b/src/render/PlayerSkin.cpp @@ -14,6 +14,7 @@ #include "RwHelper.h" #include "Timer.h" #include "Lights.h" +#include "MemoryMgr.h" //--MIAMI: file done @@ -75,6 +76,7 @@ LoadPlayerDff(void) void CPlayerSkin::Initialise(void) { + // empty on PS2 m_txdSlot = CTxdStore::AddTxdSlot("skin"); CTxdStore::Create(m_txdSlot); CTxdStore::AddRef(m_txdSlot); @@ -83,6 +85,7 @@ CPlayerSkin::Initialise(void) void CPlayerSkin::Shutdown(void) { + // empty on PS2 CTxdStore::RemoveTxdSlot(m_txdSlot); } diff --git a/src/render/PointLights.cpp b/src/render/PointLights.cpp index b09b07bd..c8f21d21 100644 --- a/src/render/PointLights.cpp +++ b/src/render/PointLights.cpp @@ -239,7 +239,7 @@ CPointLights::RenderFogEffect(void) // more intensity the closer to line intensity *= 1.0f - sq(Sqrt(linedistsq) / FOG_AREA_WIDTH); - if(CSprite::CalcScreenCoors(fogcoors, spriteCoors, &spritew, &spriteh, true)){ + if(CSprite::CalcScreenCoors(fogcoors, &spriteCoors, &spritew, &spriteh, true)) { float rotation = (CTimer::GetTimeInMilliseconds()&0x1FFF) * 2*3.14f / 0x2000; float size = FogSizes[r>>1]; CSprite::RenderBufferedOneXLUSprite_Rotate_Aspect(spriteCoors.x, spriteCoors.y, spriteCoors.z, @@ -287,7 +287,7 @@ CPointLights::RenderFogEffect(void) intensity *= 1.0f - sq(lightdist / FOG_AREA_RADIUS); CVector fogcoors(xi, yi, groundZ + 1.6f); - if(CSprite::CalcScreenCoors(fogcoors, spriteCoors, &spritew, &spriteh, true)){ + if(CSprite::CalcScreenCoors(fogcoors, &spriteCoors, &spritew, &spriteh, true)) { float rotation = (CTimer::GetTimeInMilliseconds()&0x3FFF) * 2*3.14f / 0x4000; float size = FogSizes[r>>1]; CSprite::RenderBufferedOneXLUSprite_Rotate_Aspect(spriteCoors.x, spriteCoors.y, spriteCoors.z, diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index c2982d6d..660b05fe 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -24,9 +24,12 @@ #include "Occlusion.h" #include "Renderer.h" #include "custompipes.h" +#include "Frontend.h" //--MIAMI: file done +bool gbShowPedRoadGroups; +bool gbShowCarRoadGroups; bool gbShowCollisionPolys; bool gbShowCollisionLines; bool gbBigWhiteDebugLightSwitchedOn; @@ -37,6 +40,10 @@ bool gbDontRenderPeds; bool gbDontRenderObjects; bool gbDontRenderVehicles; +// unused +int16 TestCloseThings; +int16 TestBigThings; + struct EntityInfo { CEntity *ent; @@ -61,14 +68,10 @@ CVehicle *CRenderer::m_pFirstPersonVehicle; bool CRenderer::m_loadingPriority; float CRenderer::ms_lodDistScale = 1.2f; -#ifdef FIX_BUGS -#define LOD_DISTANCE (300.0f*TheCamera.LODDistMultiplier) -#else -#define LOD_DISTANCE 300.0f -#endif -#define FADE_DISTANCE 20.0f -#define STREAM_DISTANCE 30.0f - +// unused +BlockedRange CRenderer::aBlockedRanges[16]; +BlockedRange* CRenderer::pFullBlockedRanges; +BlockedRange* CRenderer::pEmptyBlockedRanges; void CRenderer::Init(void) @@ -346,45 +349,45 @@ enum { static RwRGBAReal black; -#ifdef RW_D3D9 -struct BuildingInst -{ - rw::RawMatrix combinedMat; - rw::d3d9::InstanceDataHeader *instHeader; - uint8 fadeAlpha; - bool lighting; -}; -static BuildingInst blendInsts[3][2000]; -static int numBlendInsts[3]; - static void SetStencilState(int state) { switch(state){ // disable stencil case 0: - rw::d3d::setRenderState(D3DRS_STENCILENABLE, FALSE); + rw::SetRenderState(rw::STENCILENABLE, FALSE); break; // test against stencil case 1: - rw::d3d::setRenderState(D3DRS_STENCILENABLE, TRUE); - rw::d3d::setRenderState(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL); - rw::d3d::setRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); - rw::d3d::setRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); - rw::d3d::setRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); - rw::d3d::setRenderState(D3DRS_STENCILMASK, 0xFF); - rw::d3d::setRenderState(D3DRS_STENCILREF, 0xFF); + rw::SetRenderState(rw::STENCILENABLE, TRUE); + rw::SetRenderState(rw::STENCILFUNCTION, rw::STENCILNOTEQUAL); + rw::SetRenderState(rw::STENCILPASS, rw::STENCILKEEP); + rw::SetRenderState(rw::STENCILFAIL, rw::STENCILKEEP); + rw::SetRenderState(rw::STENCILZFAIL, rw::STENCILKEEP); + rw::SetRenderState(rw::STENCILFUNCTIONMASK, 0xFF); + rw::SetRenderState(rw::STENCILFUNCTIONREF, 0xFF); break; // write to stencil case 2: - rw::d3d::setRenderState(D3DRS_STENCILENABLE, TRUE); - rw::d3d::setRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - rw::d3d::setRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - rw::d3d::setRenderState(D3DRS_STENCILREF, 0xFF); + rw::SetRenderState(rw::STENCILENABLE, TRUE); + rw::SetRenderState(rw::STENCILFUNCTION, rw::STENCILALWAYS); + rw::SetRenderState(rw::STENCILPASS, rw::STENCILREPLACE); + rw::SetRenderState(rw::STENCILFUNCTIONREF, 0xFF); break; } } +#ifdef RW_D3D9 +struct BuildingInst +{ + rw::RawMatrix combinedMat; + rw::d3d9::InstanceDataHeader *instHeader; + uint8 fadeAlpha; + bool lighting; +}; +static BuildingInst blendInsts[3][2000]; +static int numBlendInsts[3]; + static void SetMatrix(BuildingInst *building, rw::Matrix *worldMat) { @@ -537,30 +540,6 @@ struct BuildingInst static BuildingInst blendInsts[3][2000]; static int numBlendInsts[3]; -static void -SetStencilState(int state) -{ - switch(state){ - // disable stencil - case 0: - glDisable(GL_STENCIL_TEST); - break; - // test against stencil - case 1: - glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_NOTEQUAL, 0xFF, 0xFF); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilMask(0xFF); - break; - // write to stencil - case 2: - glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 0xFF, 0xFF); - glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - break; - } -} - static bool IsTextureTransparent(RwTexture *tex) { @@ -711,12 +690,13 @@ CRenderer::RenderOneBuilding(CEntity *ent, float camdist) { if(ent->m_rwObject == nil) return; + + ent->bImBeingRendered = true; // TODO: this seems wrong, but do we even need it? + assert(RwObjectGetType(ent->m_rwObject) == rpATOMIC); RpAtomic *atomic = (RpAtomic*)ent->m_rwObject; CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(ent->GetModelIndex()); - ent->bImBeingRendered = true; // TODO: this seems wrong, but do we even need it? - int pass = PASS_BLEND; if(mi->m_additive) // very questionable pass = PASS_ADD; @@ -1188,7 +1168,7 @@ CRenderer::SetupBigBuildingVisibility(CEntity *ent) if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj)) RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?) mi->IncreaseAlpha(); - if(!ent->IsVisibleComplex() || ent->IsEntityOccluded()){ + if(!ent->IsVisible() || !ent->GetIsOnScreenComplex() || ent->IsEntityOccluded()){ mi->m_alpha = 255; return VIS_INVISIBLE; } @@ -1232,7 +1212,7 @@ CRenderer::SetupBigBuildingVisibility(CEntity *ent) if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj)) RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?) mi->IncreaseAlpha(); - if(!ent->IsVisibleComplex() || ent->IsEntityOccluded()){ + if(!ent->IsVisible() || !ent->GetIsOnScreenComplex() || ent->IsEntityOccluded()){ mi->m_alpha = 255; return VIS_INVISIBLE; } @@ -1253,7 +1233,21 @@ CRenderer::ConstructRenderList(void) ms_nNoOfInVisibleEntities = 0; } ms_vecCameraPosition = TheCamera.GetPosition(); - // TODO: blocked ranges, but unused + + // unused + pFullBlockedRanges = nil; + pEmptyBlockedRanges = aBlockedRanges; + for(int i = 0; i < 16; i++){ + aBlockedRanges[i].prev = &aBlockedRanges[i-1]; + aBlockedRanges[i].next = &aBlockedRanges[i+1]; + } + aBlockedRanges[0].prev = nil; + aBlockedRanges[15].next = nil; + + // unused + TestCloseThings = 0; + TestBigThings = 0; + ScanWorld(); } @@ -1333,7 +1327,7 @@ CRenderer::ScanWorld(void) vectors[CORNER_PRIO_RIGHT].x = vectors[CORNER_LOD_RIGHT].x * 0.2f; vectors[CORNER_PRIO_RIGHT].y = vectors[CORNER_LOD_RIGHT].y * 0.2f; vectors[CORNER_PRIO_RIGHT].z = vectors[CORNER_LOD_RIGHT].z; - RwV3dTransformPoints((RwV3d*)vectors, (RwV3d*)vectors, 9, cammatrix); + RwV3dTransformPoints(vectors, vectors, 9, cammatrix); m_loadingPriority = false; if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || @@ -1403,8 +1397,19 @@ CRenderer::ScanWorld(void) poly[2].y = CWorld::GetSectorY(vectors[CORNER_FAR_TOPRIGHT].y); ScanSectorPoly(poly, 3, ScanSectorList); } - - ScanBigBuildingList(CWorld::GetBigBuildingList(CGame::currLevel)); + +#ifdef NO_ISLAND_LOADING + if (FrontEndMenuManager.m_PrefsIslandLoading == CMenuManager::ISLAND_LOADING_HIGH) { + ScanBigBuildingList(CWorld::GetBigBuildingList(LEVEL_BEACH)); + ScanBigBuildingList(CWorld::GetBigBuildingList(LEVEL_MAINLAND)); + } else +#endif + { +#ifdef FIX_BUGS + if(CCollision::ms_collisionInMemory != LEVEL_GENERIC) +#endif + ScanBigBuildingList(CWorld::GetBigBuildingList(CGame::currLevel)); + } ScanBigBuildingList(CWorld::GetBigBuildingList(LEVEL_GENERIC)); } } @@ -1453,7 +1458,7 @@ CRenderer::RequestObjectsInFrustum(void) vectors[CORNER_PRIO_RIGHT].x = vectors[CORNER_LOD_RIGHT].x * 0.2f; vectors[CORNER_PRIO_RIGHT].y = vectors[CORNER_LOD_RIGHT].y * 0.2f; vectors[CORNER_PRIO_RIGHT].z = vectors[CORNER_LOD_RIGHT].z; - RwV3dTransformPoints((RwV3d*)vectors, (RwV3d*)vectors, 9, cammatrix); + RwV3dTransformPoints(vectors, vectors, 9, cammatrix); if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || #ifdef FIX_BUGS @@ -1492,6 +1497,56 @@ CRenderer::RequestObjectsInFrustum(void) } } +bool +CEntity::SetupLighting(void) +{ + return false; +} + +void +CEntity::RemoveLighting(bool) +{ +} + +// --MIAMI: Done +bool +CPed::SetupLighting(void) +{ + ActivateDirectional(); + SetAmbientColoursForPedsCarsAndObjects(); + +#ifndef MASTER + // Originally this was being called through iteration of Sectors, but putting it here is better. + if (GetDebugDisplay() != 0 && !IsPlayer()) + DebugRenderOnePedText(); +#endif + + if (bRenderScorched) { + WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); + } else { + // Note that this lightMult is only affected by LIGHT_DARKEN. If there's no LIGHT_DARKEN, it will be 1.0. + float lightMult = CPointLights::GenerateLightsAffectingObject(&GetPosition()); + if (lightMult != 1.0f) { + SetAmbientAndDirectionalColours(lightMult); + return true; + } + } + return false; +} + +// --MIAMI: Done +void +CPed::RemoveLighting(bool reset) +{ + if (!bRenderScorched) { + CRenderer::RemoveVehiclePedLights(this, reset); + if (reset) + ReSetAmbientAndDirectionalColours(); + } + SetAmbientColours(); + DeActivateDirectional(); +} + float CalcNewDelta(RwV2d *a, RwV2d *b) { diff --git a/src/render/Renderer.h b/src/render/Renderer.h index b579bb4c..9b202098 100644 --- a/src/render/Renderer.h +++ b/src/render/Renderer.h @@ -2,6 +2,16 @@ class CEntity; +#ifdef FIX_BUGS +#define LOD_DISTANCE (300.0f*TheCamera.LODDistMultiplier) +#else +#define LOD_DISTANCE 300.0f +#endif +#define FADE_DISTANCE 20.0f +#define STREAM_DISTANCE 30.0f + +extern bool gbShowPedRoadGroups; +extern bool gbShowCarRoadGroups; extern bool gbShowCollisionPolys; extern bool gbShowCollisionLines; extern bool gbBigWhiteDebugLightSwitchedOn; @@ -15,6 +25,13 @@ extern bool gbDontRenderVehicles; class CVehicle; class CPtrList; +// unused +struct BlockedRange +{ + float a, b; // unknown + BlockedRange *prev, *next; +}; + class CRenderer { static int32 ms_nNoOfVisibleEntities; @@ -32,6 +49,10 @@ class CRenderer static CVector ms_vecCameraPosition; static CVehicle *m_pFirstPersonVehicle; + // unused + static BlockedRange aBlockedRanges[16]; + static BlockedRange *pFullBlockedRanges; + static BlockedRange *pEmptyBlockedRanges; public: static float ms_lodDistScale; static bool m_loadingPriority; diff --git a/src/render/Shadows.cpp b/src/render/Shadows.cpp index a964ceb6..e8be23bd 100644 --- a/src/render/Shadows.cpp +++ b/src/render/Shadows.cpp @@ -2229,7 +2229,7 @@ CShadows::CastShadowEntityXYZ(CEntity *pEntity, CVector *pPosn, sphere.Set(2.0f, center); RwV3d point; - RwV3dTransformPoints(&point, center, 1, &invMatrix); + RwV3dTransformPoints(&point, ¢er, 1, &invMatrix); CColSphere colSphere; colSphere.Set(2.0f, CVector(point), 0, 0); @@ -2252,7 +2252,7 @@ CShadows::CastShadowEntityXYZ(CEntity *pEntity, CVector *pPosn, p[1] += offset; p[2] += offset; - if ( !ShadowRenderTriangleCB((RwV3d *)p, n, &proj) ) + if ( !ShadowRenderTriangleCB(p, &n, &proj) ) break; } i++; diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp index 665a41ab..e17caa97 100644 --- a/src/render/SpecialFX.cpp +++ b/src/render/SpecialFX.cpp @@ -1384,21 +1384,25 @@ CMoneyMessages::Render() void CMoneyMessages::RegisterOne(CVector vecPos, const char *pText, uint8 bRed, uint8 bGreen, uint8 bBlue, float fSize, float fOpacity) { - uint32 nIndex = 0; - while (aMoneyMessages[nIndex].m_nTimeRegistered != 0) { - if (++nIndex >= NUMMONEYMESSAGES) return; - } - - // Add data of this money message to the array - AsciiToUnicode(pText, aMoneyMessages[nIndex].m_aText); + uint32 i; +#ifdef FIX_BUGS + for(i = 0; i < NUMMONEYMESSAGES && aMoneyMessages[i].m_nTimeRegistered != 0; i++); +#else + for(i = 0; aMoneyMessages[i].m_nTimeRegistered != 0 && i < NUMMONEYMESSAGES; i++); +#endif - aMoneyMessages[nIndex].m_nTimeRegistered = CTimer::GetTimeInMilliseconds(); - aMoneyMessages[nIndex].m_vecPosition = vecPos; - aMoneyMessages[nIndex].m_Colour.red = bRed; - aMoneyMessages[nIndex].m_Colour.green = bGreen; - aMoneyMessages[nIndex].m_Colour.blue = bBlue; - aMoneyMessages[nIndex].m_fSize = fSize; - aMoneyMessages[nIndex].m_fOpacity = fOpacity; + if(i < NUMMONEYMESSAGES) { + // Add data of this money message to the array + AsciiToUnicode(pText, aMoneyMessages[i].m_aText); + + aMoneyMessages[i].m_nTimeRegistered = CTimer::GetTimeInMilliseconds(); + aMoneyMessages[i].m_vecPosition = vecPos; + aMoneyMessages[i].m_Colour.red = bRed; + aMoneyMessages[i].m_Colour.green = bGreen; + aMoneyMessages[i].m_Colour.blue = bBlue; + aMoneyMessages[i].m_fSize = fSize; + aMoneyMessages[i].m_fOpacity = fOpacity; + } } CRGBA FoamColour(255, 255, 255, 255); diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp index 88c45c79..b698a5b2 100644 --- a/src/render/WaterLevel.cpp +++ b/src/render/WaterLevel.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "main.h" #include "FileMgr.h" +#include "FileLoader.h" #include "TxdStore.h" #include "Timer.h" #include "Weather.h" @@ -17,6 +18,7 @@ #include "ParticleMgr.h" #include "RwHelper.h" #include "Streaming.h" +#include "ColStore.h" #include "CdStream.h" #include "Pad.h" #include "RenderBuffer.h" @@ -43,8 +45,8 @@ float _TEXTURE_WAKE_ADDV; int32 CWaterLevel::ms_nNoOfWaterLevels; float CWaterLevel::ms_aWaterZs[48]; CRect CWaterLevel::ms_aWaterRects[48]; -uint8 CWaterLevel::aWaterBlockList[WATER_BLOCK_SECTORS][WATER_BLOCK_SECTORS]; -uint8 CWaterLevel::aWaterFineBlockList[WATER_FINEBLOCK_SECTORS][WATER_FINEBLOCK_SECTORS]; +int8 CWaterLevel::aWaterBlockList[MAX_LARGE_SECTORS][MAX_LARGE_SECTORS]; +int8 CWaterLevel::aWaterFineBlockList[MAX_SMALL_SECTORS][MAX_SMALL_SECTORS]; bool CWaterLevel::WavesCalculatedThisFrame; @@ -115,15 +117,19 @@ WaterLevelInitialise(Const char *pWaterDat) { CWaterLevel::ms_nNoOfWaterLevels = 0; - int32 hFile; - +#ifdef MASTER + int32 hFile = -1; + do { hFile = CFileMgr::OpenFile("DATA\\waterpro.dat", "rb"); } while ( hFile < 0 ); +#else + int32 hFile = CFileMgr::OpenFile("DATA\\waterpro.dat", "rb"); +#endif - if ( hFile > 0 ) + if (hFile > 0) { CFileMgr::Read(hFile, (char *)&CWaterLevel::ms_nNoOfWaterLevels, sizeof(CWaterLevel::ms_nNoOfWaterLevels)); CFileMgr::Read(hFile, (char *)CWaterLevel::ms_aWaterZs, sizeof(CWaterLevel::ms_aWaterZs)); @@ -132,6 +138,142 @@ WaterLevelInitialise(Const char *pWaterDat) CFileMgr::Read(hFile, (char *)CWaterLevel::aWaterFineBlockList, sizeof(CWaterLevel::aWaterFineBlockList)); CFileMgr::CloseFile(hFile); } +#ifndef MASTER + else + { + printf("Init waterlevels\n"); + + // collision is streamed in VC + CColStore::LoadAllCollision(); + + CFileMgr::SetDir(""); + hFile = CFileMgr::OpenFile(pWaterDat, "r"); + + char *line; + + while ((line = CFileLoader::LoadLine(hFile))) + { + if (*line && *line != ';' && !strstr(line, "* ;end of file")) + { + float z, l, b, r, t; + sscanf(line, "%f %f %f %f %f", &z, &l, &b, &r, &t); + CWaterLevel::AddWaterLevel(l, b, r, t, z); + } + } + + CFileMgr::CloseFile(hFile); + + for (int32 x = 0; x < MAX_SMALL_SECTORS; x++) + { + for (int32 y = 0; y < MAX_SMALL_SECTORS; y++) + { + CWaterLevel::aWaterFineBlockList[x][y] = NO_WATER; + } + } + + // rasterize water rects read from file + for (int32 i = 0; i < CWaterLevel::ms_nNoOfWaterLevels; i++) + { + int32 l = WATER_HUGE_X(CWaterLevel::ms_aWaterRects[i].left + WATER_X_OFFSET); + int32 r = WATER_HUGE_X(CWaterLevel::ms_aWaterRects[i].right + WATER_X_OFFSET) + 1.0f; + int32 t = WATER_HUGE_Y(CWaterLevel::ms_aWaterRects[i].top); + int32 b = WATER_HUGE_Y(CWaterLevel::ms_aWaterRects[i].bottom) + 1.0f; + + l = clamp(l, 0, MAX_SMALL_SECTORS - 1); + r = clamp(r, 0, MAX_SMALL_SECTORS - 1); + t = clamp(t, 0, MAX_SMALL_SECTORS - 1); + b = clamp(b, 0, MAX_SMALL_SECTORS - 1); + + for (int32 x = l; x <= r; x++) + { + for (int32 y = t; y <= b; y++) + { + CWaterLevel::aWaterFineBlockList[x][y] = i; + } + } + } + + // remove tiles that are obscured by land + for (int32 x = 0; x < MAX_SMALL_SECTORS; x++) + { + float worldX = WATER_START_X + x * SMALL_SECTOR_SIZE - WATER_X_OFFSET; + + for (int32 y = 0; y < MAX_SMALL_SECTORS; y++) + { + if (CWaterLevel::aWaterFineBlockList[x][y] >= 0) + { + float worldY = WATER_START_Y + y * SMALL_SECTOR_SIZE; + + int32 i; + for (i = 0; i <= 8; i++) + { + for (int32 j = 0; j <= 8; j++) + { + CVector worldPos = CVector(worldX + i * (SMALL_SECTOR_SIZE / 8), worldY + j * (SMALL_SECTOR_SIZE / 8), CWaterLevel::ms_aWaterZs[CWaterLevel::aWaterFineBlockList[x][y]]); + + if ((worldPos.x > WORLD_MIN_X && worldPos.x < WORLD_MAX_X) && (worldPos.y > WORLD_MIN_Y && worldPos.y < WORLD_MAX_Y) && + (!CWaterLevel::WaterLevelAccordingToRectangles(worldPos.x, worldPos.y) || CWaterLevel::TestVisibilityForFineWaterBlocks(worldPos))) + continue; + + // at least one point in the tile wasn't blocked, so don't remove water + i = 1000; + break; + } + } + + if (i < 1000) + CWaterLevel::aWaterFineBlockList[x][y] = NO_WATER; + } + } + } + + CWaterLevel::RemoveIsolatedWater(); + + // calculate coarse tiles from fine tiles + for (int32 x = 0; x < MAX_LARGE_SECTORS; x++) + { + for (int32 y = 0; y < MAX_LARGE_SECTORS; y++) + { + if (CWaterLevel::aWaterFineBlockList[x * 2][y * 2] >= 0) + { + CWaterLevel::aWaterBlockList[x][y] = CWaterLevel::aWaterFineBlockList[x * 2][y * 2]; + } + else if (CWaterLevel::aWaterFineBlockList[x * 2 + 1][y * 2] >= 0) + { + CWaterLevel::aWaterBlockList[x][y] = CWaterLevel::aWaterFineBlockList[x * 2 + 1][y * 2]; + } + else if (CWaterLevel::aWaterFineBlockList[x * 2][y * 2 + 1] >= 0) + { + CWaterLevel::aWaterBlockList[x][y] = CWaterLevel::aWaterFineBlockList[x * 2][y * 2 + 1]; + } + else if (CWaterLevel::aWaterFineBlockList[x * 2 + 1][y * 2 + 1] >= 0) + { + CWaterLevel::aWaterBlockList[x][y] = CWaterLevel::aWaterFineBlockList[x * 2 + 1][y * 2 + 1]; + } + else + { + CWaterLevel::aWaterBlockList[x][y] = NO_WATER; + } + } + } + + hFile = CFileMgr::OpenFileForWriting("data\\waterpro.dat"); + + if (hFile > 0) + { + CFileMgr::Write(hFile, (char *)&CWaterLevel::ms_nNoOfWaterLevels, sizeof(CWaterLevel::ms_nNoOfWaterLevels)); + CFileMgr::Write(hFile, (char *)CWaterLevel::ms_aWaterZs, sizeof(CWaterLevel::ms_aWaterZs)); + CFileMgr::Write(hFile, (char *)CWaterLevel::ms_aWaterRects, sizeof(CWaterLevel::ms_aWaterRects)); + CFileMgr::Write(hFile, (char *)CWaterLevel::aWaterBlockList, sizeof(CWaterLevel::aWaterBlockList)); + CFileMgr::Write(hFile, (char *)CWaterLevel::aWaterFineBlockList, sizeof(CWaterLevel::aWaterFineBlockList)); + + CFileMgr::CloseFile(hFile); + } + + // collision is streamed in VC + CColStore::RemoveAllCollision(); + } +#endif CTxdStore::PushCurrentTxd(); @@ -397,6 +539,170 @@ CWaterLevel::DestroyWavyAtomic() #undef _DELETE_ATOMIC } +#ifndef MASTER +void +CWaterLevel::AddWaterLevel(float fXLeft, float fYBottom, float fXRight, float fYTop, float fLevel) +{ + ms_aWaterRects[ms_nNoOfWaterLevels] = CRect(fXLeft, fYBottom, fXRight, fYTop); + ms_aWaterZs[ms_nNoOfWaterLevels] = fLevel; + ms_nNoOfWaterLevels++; +} + +bool +CWaterLevel::WaterLevelAccordingToRectangles(float fX, float fY, float *pfOutLevel) +{ + if (ms_nNoOfWaterLevels <= 0) return false; + + for (int32 i = 0; i < ms_nNoOfWaterLevels; i++) + { + if (fX >= ms_aWaterRects[i].left && fX <= ms_aWaterRects[i].right + && fY >= ms_aWaterRects[i].top && fY <= ms_aWaterRects[i].bottom) + { + if (pfOutLevel) *pfOutLevel = ms_aWaterZs[i]; + + return true; + } + } + + return false; +} + +bool +CWaterLevel::TestVisibilityForFineWaterBlocks(const CVector &worldPos) +{ + static CVector2D tab[] = + { + { 50.0f, 50.0f }, + { -50.0f, 50.0f }, + { -50.0f, -50.0f }, + { 50.0f, -50.0f }, + { 50.0f, 0.0f }, + { -50.0f, 0.0f }, + { 0.0f, -50.0f }, + { 0.0f, 50.0f }, + }; + + CEntity *entity; + CColPoint col; + CVector lineStart, lineEnd; + + lineStart = worldPos; + + if (!CWorld::ProcessVerticalLine(lineStart, lineStart.z + 100.0f, col, entity, true, false, false, false, true, false, nil)) + { + lineStart.x += 0.4f; + lineStart.y += 0.4f; + + if (!CWorld::ProcessVerticalLine(lineStart, lineStart.z + 100.0f, col, entity, true, false, false, false, true, false, nil)) + { + return false; + } + } + + for (int32 i = 0; i < ARRAY_SIZE(tab); i++) + { + lineStart = worldPos; + lineEnd = worldPos; + + lineEnd.x += tab[i].x; + lineEnd.y += tab[i].y; + lineEnd.z += 100.0f; + + if ((lineEnd.x > WORLD_MIN_X && lineEnd.x < WORLD_MAX_X) && (lineEnd.y > WORLD_MIN_Y && lineEnd.y < WORLD_MAX_Y)) + { + if (!CWorld::ProcessLineOfSight(lineStart, lineEnd, col, entity, true, false, false, false, true, false, nil)) + { + lineStart.x += 0.4f; + lineStart.y += 0.4f; + lineEnd.x += 0.4f; + lineEnd.y += 0.4f; + + if (!CWorld::ProcessLineOfSight(lineStart, lineEnd, col, entity, true, false, false, false, true, false, nil)) + { + return false; + } + } + } + } + + return true; +} + +void +CWaterLevel::RemoveIsolatedWater() +{ + bool (*isConnected)[MAX_SMALL_SECTORS] = new bool[MAX_SMALL_SECTORS][MAX_SMALL_SECTORS]; + + for (int32 x = 0; x < MAX_SMALL_SECTORS; x++) + { + for (int32 y = 0; y < MAX_SMALL_SECTORS; y++) + { + isConnected[x][y] = false; + } + } + + isConnected[0][0] = true; + bool keepGoing; + + do + { + keepGoing = false; + + for (int32 x = 0; x < MAX_SMALL_SECTORS; x++) + { + for (int32 y = 0; y < MAX_SMALL_SECTORS; y++) + { + if (aWaterFineBlockList[x][y] < 0 || isConnected[x][y]) + continue; + + if (x > 0 && isConnected[x - 1][y]) + { + isConnected[x][y] = true; + keepGoing = true; + } + + if (y > 0 && isConnected[x][y - 1]) + { + isConnected[x][y] = true; + keepGoing = true; + } + + if (x + 1 < MAX_SMALL_SECTORS && isConnected[x + 1][y]) + { + isConnected[x][y] = true; + keepGoing = true; + } + + if (y + 1 < MAX_SMALL_SECTORS && isConnected[x][y + 1]) + { + isConnected[x][y] = true; + keepGoing = true; + } + } + } + } + while (keepGoing); + + int32 numRemoved = 0; + + for (int32 x = 0; x < MAX_SMALL_SECTORS; x++) + { + for (int32 y = 0; y < MAX_SMALL_SECTORS; y++) + { + if (aWaterFineBlockList[x][y] >= 0 && !isConnected[x][y] && ms_aWaterZs[aWaterFineBlockList[x][y]] == 6.0f) + { + numRemoved++; + aWaterFineBlockList[x][y] = NO_WATER; + } + } + } + + printf("Removed %d isolated patches of water\n", numRemoved); + + delete[] isConnected; +} +#endif + bool CWaterLevel::GetWaterLevel(float fX, float fY, float fZ, float *pfOutLevel, bool bDontCheckZ) { @@ -542,38 +848,38 @@ inline bool _IsColideWithBlock(int32 x, int32 y, int32 &block) { block = CWaterLevel::aWaterFineBlockList[x + 0][y + 0]; - if (!(block & 0x80)) + if (block >= 0) return true; block = CWaterLevel::aWaterFineBlockList[x + 0][y + 1]; - if (!(block & 0x80)) + if (block >= 0) { block = CWaterLevel::aWaterFineBlockList[x + 0][y + 2]; - if (!(block & 0x80)) + if (block >= 0) return true; } block = CWaterLevel::aWaterFineBlockList[x + 1][y + 0]; - if (!(block & 0x80)) + if (block >= 0) return true; block = CWaterLevel::aWaterFineBlockList[x + 1][y + 1]; - if (!(block & 0x80)) + if (block >= 0) { block = CWaterLevel::aWaterFineBlockList[x + 1][y + 2]; - if (!(block & 0x80)) + if (block >= 0) return true; } block = CWaterLevel::aWaterFineBlockList[x + 2][y + 0]; - if (!(block & 0x80)) + if (block >= 0) return true; block = CWaterLevel::aWaterFineBlockList[x + 2][y + 1]; - if (!(block & 0x80)) + if (block >= 0) { block = CWaterLevel::aWaterFineBlockList[x + 2][y + 2]; - if (!(block & 0x80)) + if (block >= 0) return true; } @@ -693,10 +999,10 @@ CWaterLevel::RenderWater() { for ( int32 y = nStartY; y <= nEndY; y++ ) { - if ( !(aWaterBlockList[2*x+0][2*y+0] & 0x80) - || !(aWaterBlockList[2*x+1][2*y+0] & 0x80) - || !(aWaterBlockList[2*x+0][2*y+1] & 0x80) - || !(aWaterBlockList[2*x+1][2*y+1] & 0x80) ) + if ( aWaterBlockList[2*x+0][2*y+0] >= 0 + || aWaterBlockList[2*x+1][2*y+0] >= 0 + || aWaterBlockList[2*x+0][2*y+1] >= 0 + || aWaterBlockList[2*x+1][2*y+1] >= 0 ) { float fX = WATER_FROM_HUGE_SECTOR_X(x) - WATER_X_OFFSET; float fY = WATER_FROM_HUGE_SECTOR_Y(y); @@ -716,16 +1022,16 @@ CWaterLevel::RenderWater() float fZ; - if ( !(aWaterBlockList[2*x+0][2*y+0] & 0x80) ) + if ( aWaterBlockList[2*x+0][2*y+0] >= 0 ) fZ = ms_aWaterZs[ aWaterBlockList[2*x+0][2*y+0] ]; - if ( !(aWaterBlockList[2*x+1][2*y+0] & 0x80) ) + if ( aWaterBlockList[2*x+1][2*y+0] >= 0 ) fZ = ms_aWaterZs[ aWaterBlockList[2*x+1][2*y+0] ]; - if ( !(aWaterBlockList[2*x+0][2*y+1] & 0x80) ) + if ( aWaterBlockList[2*x+0][2*y+1] >= 0 ) fZ = ms_aWaterZs[ aWaterBlockList[2*x+0][2*y+1] ]; - if ( !(aWaterBlockList[2*x+1][2*y+1] & 0x80) ) + if ( aWaterBlockList[2*x+1][2*y+1] >= 0 ) fZ = ms_aWaterZs[ aWaterBlockList[2*x+1][2*y+1] ]; if ( fHugeSectorDistToCamSqr >= SQR(500.0f) ) @@ -960,10 +1266,10 @@ CWaterLevel::RenderTransparentWater(void) { for ( int32 y = nStartY; y <= nEndY; y++ ) { - if ( !(aWaterBlockList[2*x+0][2*y+0] & 0x80) - || !(aWaterBlockList[2*x+1][2*y+0] & 0x80) - || !(aWaterBlockList[2*x+0][2*y+1] & 0x80) - || !(aWaterBlockList[2*x+1][2*y+1] & 0x80) ) + if ( aWaterBlockList[2*x+0][2*y+0] >= 0 + || aWaterBlockList[2*x+1][2*y+0] >= 0 + || aWaterBlockList[2*x+0][2*y+1] >= 0 + || aWaterBlockList[2*x+1][2*y+1] >= 0 ) { float fX = WATER_FROM_HUGE_SECTOR_X(x) - WATER_X_OFFSET; float fY = WATER_FROM_HUGE_SECTOR_Y(y); @@ -991,7 +1297,7 @@ CWaterLevel::RenderTransparentWater(void) { for ( int32 y2 = 2*y; y2 <= 2*y+1; y2++ ) { - if ( !(aWaterBlockList[x2][y2] & 0x80) ) + if ( aWaterBlockList[x2][y2] >= 0 ) { float fLargeX = WATER_FROM_LARGE_SECTOR_X(x2) - WATER_X_OFFSET; float fLargeY = WATER_FROM_LARGE_SECTOR_Y(y2); @@ -1025,7 +1331,7 @@ CWaterLevel::RenderTransparentWater(void) float fZ; // WS - if ( !(aWaterFineBlockList[2*x2+0][2*y2+0] & 0x80) ) + if ( aWaterFineBlockList[2*x2+0][2*y2+0] >= 0 ) { float fSmallX = fLargeX; float fSmallY = fLargeY; @@ -1042,7 +1348,7 @@ CWaterLevel::RenderTransparentWater(void) } // SE - if ( !(aWaterFineBlockList[2*x2+1][2*y2+0] & 0x80) ) + if ( aWaterFineBlockList[2*x2+1][2*y2+0] >= 0 ) { float fSmallX = fLargeX + (LARGE_SECTOR_SIZE/2); float fSmallY = fLargeY; @@ -1059,7 +1365,7 @@ CWaterLevel::RenderTransparentWater(void) } // WN - if ( !(aWaterFineBlockList[2*x2+0][2*y2+1] & 0x80) ) + if ( aWaterFineBlockList[2*x2+0][2*y2+1] >= 0 ) { float fSmallX = fLargeX; float fSmallY = fLargeY + (LARGE_SECTOR_SIZE/2); @@ -1076,7 +1382,7 @@ CWaterLevel::RenderTransparentWater(void) } //NE - if ( !(aWaterFineBlockList[2*x2+1][2*y2+1] & 0x80) ) + if ( aWaterFineBlockList[2*x2+1][2*y2+1] >= 0 ) { float fSmallX = fLargeX + (LARGE_SECTOR_SIZE/2); float fSmallY = fLargeY + (LARGE_SECTOR_SIZE/2); @@ -2588,7 +2894,7 @@ CWaterLevel::CalcDistanceToWater(float fX, float fY) { for ( int32 y = nStartY; y <= nEndY; y++ ) { - if ( !(aWaterFineBlockList[x][y] & 0x80) ) + if ( aWaterFineBlockList[x][y] >= 0 ) { float fSectorX = WATER_FROM_SMALL_SECTOR_X(x) - WATER_X_OFFSET; float fSectorY = WATER_FROM_SMALL_SECTOR_Y(y); diff --git a/src/render/WaterLevel.h b/src/render/WaterLevel.h index 0e682305..5a497ddf 100644 --- a/src/render/WaterLevel.h +++ b/src/render/WaterLevel.h @@ -2,10 +2,10 @@ #define WATER_X_OFFSET (400.0f) -#define WATER_BLOCK_SECTORS MAX_LARGE_SECTORS -#define WATER_FINEBLOCK_SECTORS MAX_SMALL_SECTORS #define WATER_Z_OFFSET (0.5f) +#define NO_WATER -128 + #define MAX_SMALL_SECTORS 128 #define MAX_LARGE_SECTORS 64 #define MAX_HUGE_SECTORS 32 @@ -25,7 +25,6 @@ #define WATER_WIDTH ((WATER_END_X - WATER_START_X)) #define WATER_HEIGHT ((WATER_END_Y - WATER_START_Y)) - #define WATER_UNSIGN_X(x) ( (x) + (WATER_WIDTH /2) ) #define WATER_UNSIGN_Y(y) ( (y) + (WATER_HEIGHT/2) ) #define WATER_SIGN_X(x) ( (x) - (WATER_WIDTH /2) ) @@ -38,7 +37,7 @@ // 128x128 Small blocks 32x32 each #define WATER_TO_FINEBLOCK_X(x) ( WATER_UNSIGN_X(x) / WATER_FINEBLOCK_SECTORS ) #define WATER_TO_FINEBLOCK_Y(x) ( WATER_UNSIGN_Y(x) / WATER_FINEBLOCK_SECTORS ) - + // 32 #define WATER_SMALL_X(x) ( WATER_UNSIGN_X(x) / MAX_SMALL_SECTORS ) #define WATER_SMALL_Y(y) ( WATER_UNSIGN_Y(y) / MAX_SMALL_SECTORS ) @@ -104,31 +103,35 @@ public: static int32 ms_nNoOfWaterLevels; static float ms_aWaterZs[48]; static CRect ms_aWaterRects[48]; - static uint8 aWaterBlockList[WATER_BLOCK_SECTORS][WATER_BLOCK_SECTORS]; // 64x64 Large blocks 64x64 each - static uint8 aWaterFineBlockList[WATER_FINEBLOCK_SECTORS][WATER_FINEBLOCK_SECTORS]; // 128x128 Small blocks 32x32 each + static int8 aWaterBlockList[MAX_LARGE_SECTORS][MAX_LARGE_SECTORS]; // 64x64 Large blocks 64x64 each + static int8 aWaterFineBlockList[MAX_SMALL_SECTORS][MAX_SMALL_SECTORS]; // 128x128 Small blocks 32x32 each static bool WavesCalculatedThisFrame; - + static bool RequireWavySector; static bool MaskCalculatedThisFrame; static CVector PreCalculatedMaskPosn; static bool m_bRenderSeaBed; static int32 m_nRenderWaterLayers; - + static RpAtomic *ms_pWavyAtomic; static RpAtomic *ms_pMaskAtomic; static void Shutdown(); - + static void CreateWavyAtomic(); static void DestroyWavyAtomic(); - - + + static void AddWaterLevel(float fXLeft, float fYBottom, float fXRight, float fYTop, float fLevel); + static bool WaterLevelAccordingToRectangles(float fX, float fY, float *pfOutLevel = nil); + static bool TestVisibilityForFineWaterBlocks(const CVector &worldPos); + static void RemoveIsolatedWater(); + static bool GetWaterLevel(float fX, float fY, float fZ, float *pfOutLevel, bool bDontCheckZ); static bool GetWaterLevel(CVector coors, float *pfOutLevel, bool bDontCheckZ) { return GetWaterLevel(coors.x, coors.y, coors.z, pfOutLevel, bDontCheckZ); } static bool GetWaterLevelNoWaves(float fX, float fY, float fZ, float *pfOutLevel); static float GetWaterWavesOnly(short x, short y); // unused static CVector GetWaterNormal(float fX, float fY); - + static void RenderWater(); static void RenderTransparentWater(void); // unused @@ -151,11 +154,11 @@ public: static bool PreCalcWavySector(RwRGBA const &color); //fucked up static bool PreCalcWavyMask(float fX, float fY, float fZ, float fSectorX, float fSectorY, float fCamPosX, float fCamPosY, float fCamDirX, float fCamDirY, RwRGBA const&color); #endif - - + + static void RenderBoatWakes(void); static void RenderWakeSegment(CVector2D &vecA, CVector2D &vecB, CVector2D &vecC, CVector2D &vecD, float &fSizeA, float &fSizeB, float &fAlphaA, float &fAlphaB, float &fWakeZ); - + // unused static void RenderOneSlopedUnderWaterPoly(float fX, float fY, float fZ, RwRGBA const&color); // UNUSED static void RenderOneFlatSmallWaterPolyBlended(float fX, float fY, float fZ, float fCamX, float fCamY, RwRGBA const &color, RwRGBA const &colorTrans, float fDrawDist); @@ -163,18 +166,18 @@ public: static void RenderAndEmptyRenderBuffer(); static bool GetGroundLevel(CVector const &vecPosn, float *pfOutLevel, ColData *pData, float fDistance); - + // unused static bool IsLocationOutOfWorldBounds_WS(CVector const &vecPosn, int nOffset); // unused static bool GetGroundLevel_WS(CVector const & vecPosn, float *pfOutLevel, ColData *pData, float fDistance); static bool GetWaterDepth(CVector const &vecPosn, float *pfDepth, float *pfLevelNoWaves, float *pfGroundLevel); - + static void RenderSeaBirds(); static void RenderShipsOnHorizon(); - + static void HandleSeaLifeForms(); - + static void HandleBeachToysStuff(void); static CEntity *CreateBeachToy(CVector const &vec, eBeachToy beachtoy); }; diff --git a/src/render/Weather.cpp b/src/render/Weather.cpp index 3f242362..52e93951 100644 --- a/src/render/Weather.cpp +++ b/src/render/Weather.cpp @@ -139,7 +139,7 @@ void CWeather::Init(void) ForcedWeatherType = WEATHER_RANDOM; SoundHandle = DMAudio.CreateEntity(AUDIOTYPE_WEATHER, (void*)1); if (SoundHandle >= 0) - DMAudio.SetEntityStatus(SoundHandle, 1); + DMAudio.SetEntityStatus(SoundHandle, true); } void CWeather::Update(void) |