added CCoronas

This commit is contained in:
aap 2019-06-01 01:58:19 +02:00
parent 7eee450a69
commit 0476a41883
11 changed files with 782 additions and 4 deletions

View File

@ -69,6 +69,17 @@ CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat)
return true;
}
int
CCamera::GetLookDirection(void)
{
if(Cams[ActiveCam].Mode == CCam::MODE_CAMONASTRING ||
Cams[ActiveCam].Mode == CCam::MODE_FIRSTPERSON ||
Cams[ActiveCam].Mode == CCam::MODE_BEHINDBOAT ||
Cams[ActiveCam].Mode == CCam::MODE_FOLLOWPED)
return Cams[ActiveCam].DirectionWasLooking;
return LOOKING_FORWARD;;
}
WRAPPER void CCamera::Fade(float timeout, int16 direction) { EAXJMP(0x46B3A0); }
WRAPPER void CCamera::ProcessFade(void) { EAXJMP(0x46F080); }
WRAPPER void CCamera::ProcessMusicFade(void) { EAXJMP(0x46F1E0); }

View File

@ -444,6 +444,7 @@ int m_iModeObbeCamIsInForCar;
bool IsPointVisible(const CVector &center, const CMatrix *mat);
bool IsSphereVisible(const CVector &center, float radius, const CMatrix *mat);
bool IsBoxVisible(RwV3d *box, const CMatrix *mat);
int GetLookDirection(void);
void Fade(float timeout, int16 direction);
int GetScreenFadeStatus(void);

View File

@ -104,6 +104,13 @@ public:
static int GetSkyBottomRed(void) { return m_nCurrentSkyBottomRed; }
static int GetSkyBottomGreen(void) { return m_nCurrentSkyBottomGreen; }
static int GetSkyBottomBlue(void) { return m_nCurrentSkyBottomBlue; }
static int GetSunCoreRed(void) { return m_nCurrentSunCoreRed; }
static int GetSunCoreGreen(void) { return m_nCurrentSunCoreGreen; }
static int GetSunCoreBlue(void) { return m_nCurrentSunCoreBlue; }
static int GetSunCoronaRed(void) { return m_nCurrentSunCoronaRed; }
static int GetSunCoronaGreen(void) { return m_nCurrentSunCoronaGreen; }
static int GetSunCoronaBlue(void) { return m_nCurrentSunCoronaBlue; }
static float GetSunSize(void) { return m_fCurrentSunSize; }
static float GetFarClip(void) { return m_fCurrentFarClip; }
static float GetFogStart(void) { return m_fCurrentFogStart; }
@ -119,4 +126,6 @@ public:
static int GetFogRed(void) { return m_nCurrentFogColourRed; }
static int GetFogGreen(void) { return m_nCurrentFogColourGreen; }
static int GetFogBlue(void) { return m_nCurrentFogColourBlue; }
static const CVector &GetSunPosition(void) { return m_VectorToSun[m_CurrentStoredValue]; }
};

View File

@ -401,6 +401,9 @@ CTheZones::GetZoneInfoForTimeOfDay(const CVector *pos, CZoneInfo *info)
info->pedGroup = night->pedGroup;
}
// BUG: there might be a bug somewhere in there that causes
// thresholds to become negative so CCarCtrl::ChooseModel will hang
void
CTheZones::SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity,
int16 gang0Num, int16 gang1Num, int16 gang2Num,
@ -432,6 +435,22 @@ CTheZones::SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity,
int16 oldGang7Num = info->gangThreshold[7] - info->gangThreshold[6];
int16 oldGang8Num = info->gangThreshold[8] - info->gangThreshold[7];
assert(oldCar1Num >= 0);
assert(oldCar2Num >= 0);
assert(oldCar3Num >= 0);
assert(oldCar4Num >= 0);
assert(oldCar5Num >= 0);
assert(oldCopNum >= 0);
assert(oldGang0Num >= 0);
assert(oldGang1Num >= 0);
assert(oldGang2Num >= 0);
assert(oldGang3Num >= 0);
assert(oldGang4Num >= 0);
assert(oldGang5Num >= 0);
assert(oldGang6Num >= 0);
assert(oldGang7Num >= 0);
assert(oldGang8Num >= 0);
if(car0Num != -1) info->carThreshold[0] = car0Num;
if(car1Num != -1) info->carThreshold[1] = info->carThreshold[0] + car1Num;
else info->carThreshold[1] = info->carThreshold[0] + oldCar1Num;
@ -463,6 +482,24 @@ CTheZones::SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity,
else info->gangThreshold[7] = info->gangThreshold[6] + oldGang7Num;
if(gang8Num != -1) info->gangThreshold[8] = info->gangThreshold[7] + gang8Num;
else info->gangThreshold[8] = info->gangThreshold[7] + oldGang8Num;
assert(info->carDensity >= 0);
assert(info->carThreshold[0] >= 0);
assert(info->carThreshold[1] >= 0);
assert(info->carThreshold[2] >= 0);
assert(info->carThreshold[3] >= 0);
assert(info->carThreshold[4] >= 0);
assert(info->carThreshold[5] >= 0);
assert(info->copThreshold >= 0);
assert(info->gangThreshold[0] >= 0);
assert(info->gangThreshold[1] >= 0);
assert(info->gangThreshold[2] >= 0);
assert(info->gangThreshold[3] >= 0);
assert(info->gangThreshold[4] >= 0);
assert(info->gangThreshold[5] >= 0);
assert(info->gangThreshold[6] >= 0);
assert(info->gangThreshold[7] >= 0);
assert(info->gangThreshold[8] >= 0);
}
void

View File

@ -52,6 +52,7 @@ enum Config {
NUMHOURS = 24,
NUMANTENNAS = 8,
NUMCORONAS = 56
};
#define GTA3_1_1_PATCH FALSE

View File

@ -25,6 +25,7 @@ public:
float Magnitude(void) const { return sqrt(x*x + y*y + z*z); }
float MagnitudeSqr(void) const { return x*x + y*y + z*z; }
float Magnitude2D(void) const { return sqrt(x*x + y*y); }
float MagnitudeSqr2D(void) const { return x*x + y*y; }
void Normalise(void) {
float sq = MagnitudeSqr();
if(sq > 0.0f){

View File

@ -104,8 +104,6 @@ delayedPatches10(int a, int b)
DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil);
DebugMenuAddVar("Debug", "Dbg Surface", &gDbgSurf, nil, 1, 0, 34, nil);
DebugMenuAddVar("Debug", "blur type", &TheCamera.m_BlurType, nil, 1, 0, 10, nil);
DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start);
DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop);
}
@ -113,6 +111,7 @@ delayedPatches10(int a, int b)
return RsEventHandler_orig(a, b);
}
void
patch()
{

View File

@ -1,7 +1,52 @@
#include "common.h"
#include "patcher.h"
#include "General.h"
#include "TxdStore.h"
#include "Camera.h"
#include "Sprite.h"
#include "Timer.h"
#include "World.h"
#include "Weather.h"
#include "Collision.h"
#include "TimeCycle.h"
#include "Coronas.h"
struct FlareDef
{
float position;
float size;
int16 red;
int16 green;
int16 blue;
int16 alpha;
int16 texture;
};
FlareDef SunFlareDef[] = {
{ -0.5f, 15.0f, 50, 50, 0, 200, 1 },
{ -1.0f, 10.0f, 50, 20, 0, 200, 2 },
{ -1.5f, 15.0f, 50, 0, 0, 200, 3 },
{ -2.5f, 25.0f, 50, 0, 0, 200, 1 },
{ 0.5f, 12.5f, 40, 40, 25, 200, 1 },
{ 0.05f, 20.0f, 30, 22, 9, 200, 2 },
{ 1.3f, 7.5f, 50, 30, 9, 200, 3 },
{ 0.0f, 0.0f, 255, 255, 255, 255, 0 }
};
FlareDef HeadLightsFlareDef[] = {
{ -0.5f, 15.5, 70, 70, 70, 200, 1 },
{ -1.0f, 10.0, 70, 70, 70, 200, 2 },
{ -1.5f, 5.5f, 50, 50, 50, 200, 3 },
{ 0.5f, 12.0f, 50, 50, 50, 200, 1 },
{ 0.05f, 20.0f, 40, 40, 40, 200, 2 },
{ 1.3f, 8.0f, 60, 60, 60, 200, 3 },
{ -2.0f, 12.0f, 50, 50, 50, 200, 1 },
{ -2.3f, 15.0f, 40, 40, 40, 200, 2 },
{ -3.0f, 16.0f, 40, 40, 40, 200, 3 },
{ 0.0f, 0.0f, 255, 255, 255, 255, 0 }
};
RwTexture **gpCoronaTexture = (RwTexture**)0x5FAF44; //[9]
float &CCoronas::LightsMult = *(float*)0x5FB088; // 1.0
@ -9,6 +54,535 @@ float &CCoronas::SunScreenX = *(float*)0x8F4358;
float &CCoronas::SunScreenY = *(float*)0x8F4354;
bool &CCoronas::bSmallMoon = *(bool*)0x95CD49;
bool &CCoronas::SunBlockedByClouds = *(bool*)0x95CD73;
int &CCoronas::bChangeBrightnessImmediately = *(int*)0x8E2C30;
WRAPPER void CCoronas::Render(void) { EAXJMP(0x4F8FB0); }
WRAPPER void CCoronas::RenderReflections(void) { EAXJMP(0x4F9B40); }
CRegisteredCorona *CCoronas::aCoronas = (CRegisteredCorona*)0x72E518;
//WRAPPER void CCoronas::Render(void) { EAXJMP(0x4F8FB0); }
//WRAPPER void CCoronas::RenderReflections(void) { EAXJMP(0x4F9B40); }
const char aCoronaSpriteNames[][32] = {
"coronastar",
"corona",
"coronamoon",
"coronareflect",
"coronaheadlightline",
"coronahex",
"coronacircle",
"coronaringa",
"streek"
};
void
CCoronas::Init(void)
{
int i;
CTxdStore::PushCurrentTxd();
CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle"));
for(i = 0; i < 9; i++)
if(gpCoronaTexture[i] == nil)
gpCoronaTexture[i] = RwTextureRead(aCoronaSpriteNames[i], nil);
CTxdStore::PopCurrentTxd();
for(i = 0; i < NUMCORONAS; i++)
aCoronas[i].id = 0;
}
void
CCoronas::Shutdown(void)
{
int i;
for(i = 0; i < 9; i++)
if(gpCoronaTexture[i]){
RwTextureDestroy(gpCoronaTexture[i]);
gpCoronaTexture[i] = nil;
}
}
void
CCoronas::Update(void)
{
int i;
static int LastCamLook = 0;
LightsMult = min(LightsMult + 0.03f * CTimer::GetTimeStep(), 1.0f);
int CamLook = 0;
if(TheCamera.Cams[TheCamera.ActiveCam].LookingLeft) CamLook |= 1;
if(TheCamera.Cams[TheCamera.ActiveCam].LookingRight) CamLook |= 2;
if(TheCamera.Cams[TheCamera.ActiveCam].LookingBehind) CamLook |= 4;
// BUG?
if(TheCamera.GetLookDirection() == LOOKING_BEHIND) CamLook |= 8;
if(LastCamLook != CamLook)
bChangeBrightnessImmediately = 3;
else
bChangeBrightnessImmediately = max(bChangeBrightnessImmediately-1, 0);
LastCamLook = CamLook;
for(i = 0; i < NUMCORONAS; i++)
if(aCoronas[i].id != 0)
aCoronas[i].Update();
}
void
CCoronas::RegisterCorona(uint32 id, uint8 red, uint8 green, uint8 blue, uint8 alpha,
const CVector &coors, float size, float drawDist, RwTexture *tex,
int8 flareType, uint8 reflection, uint8 LOScheck, uint8 drawStreak, float someAngle)
{
int i;
if(sq(drawDist) < (TheCamera.GetPosition() - coors).MagnitudeSqr2D())
return;
for(i = 0; i < NUMCORONAS; i++)
if(aCoronas[i].id == id)
break;
if(i == NUMCORONAS){
// add a new one
// find empty slot
for(i = 0; i < NUMCORONAS; i++)
if(aCoronas[i].id == 0)
break;
if(i == NUMCORONAS)
return; // no space
aCoronas[i].fadeAlpha = 0;
aCoronas[i].offScreen = true;
aCoronas[i].firstUpdate = true;
aCoronas[i].renderReflection = false;
aCoronas[i].lastLOScheck = 0;
aCoronas[i].sightClear = false;
aCoronas[i].hasValue[0] = false;
aCoronas[i].hasValue[1] = false;
aCoronas[i].hasValue[2] = false;
aCoronas[i].hasValue[3] = false;
aCoronas[i].hasValue[4] = false;
aCoronas[i].hasValue[5] = false;
}else{
// use existing one
if(aCoronas[i].fadeAlpha == 0 && alpha == 0){
// unregister
aCoronas[i].id = 0;
return;
}
}
aCoronas[i].id = id;
aCoronas[i].red = red;
aCoronas[i].green = green;
aCoronas[i].blue = blue;
aCoronas[i].alpha = alpha;
aCoronas[i].coors = coors;
aCoronas[i].size = size;
aCoronas[i].someAngle = someAngle;
aCoronas[i].registeredThisFrame = true;
aCoronas[i].drawDist = drawDist;
aCoronas[i].texture = tex;
aCoronas[i].flareType = flareType;
aCoronas[i].reflection = reflection;
aCoronas[i].LOScheck = LOScheck;
aCoronas[i].drawStreak = drawStreak;
}
void
CCoronas::RegisterCorona(uint32 id, uint8 red, uint8 green, uint8 blue, uint8 alpha,
const CVector &coors, float size, float drawDist, uint8 type,
int8 flareType, uint8 reflection, uint8 LOScheck, uint8 drawStreak, float someAngle)
{
RegisterCorona(id, red, green, blue, alpha, coors, size, drawDist,
gpCoronaTexture[type], flareType, reflection, LOScheck, drawStreak, someAngle);
}
void
CCoronas::UpdateCoronaCoors(int id, const CVector &coors, float drawDist, float someAngle)
{
int i;
if(sq(drawDist) < (TheCamera.GetPosition() - coors).MagnitudeSqr2D())
return;
for(i = 0; i < NUMCORONAS; i++)
if(aCoronas[i].id == id)
break;
if(i == NUMCORONAS)
return;
if(aCoronas[i].fadeAlpha == 0)
aCoronas[i].id = 0; // faded out, remove
else{
aCoronas[i].coors = coors;
aCoronas[i].someAngle = someAngle;
}
}
static RwIm2DVertex vertexbufferX[2];
// TODO? not sure streaks look quite right...
void
CCoronas::Render(void)
{
int i, j;
int screenw, screenh;
screenw = RwRasterGetWidth(RwCameraGetRaster(Scene.camera));
screenh = RwRasterGetHeight(RwCameraGetRaster(Scene.camera));
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
for(i = 0; i < NUMCORONAS; i++){
for(j = 5; j > 0; j--){
aCoronas[i].prevX[j] = aCoronas[i].prevX[j-1];
aCoronas[i].prevY[j] = aCoronas[i].prevY[j-1];
aCoronas[i].prevRed[j] = aCoronas[i].prevRed[j-1];
aCoronas[i].prevGreen[j] = aCoronas[i].prevGreen[j-1];
aCoronas[i].prevBlue[j] = aCoronas[i].prevBlue[j-1];
aCoronas[i].hasValue[j] = aCoronas[i].hasValue[j-1];
}
aCoronas[i].hasValue[0] = false;
if(aCoronas[i].id == 0 ||
aCoronas[i].fadeAlpha == 0 && aCoronas[i].alpha == 0)
continue;
CVector spriteCoors;
float spritew, spriteh;
if(CSprite::CalcScreenCoors(aCoronas[i].coors, spriteCoors, &spritew, &spriteh, true)){
aCoronas[i].offScreen = false;
if(spriteCoors.x < 0.0f || spriteCoors.y < 0.0f ||
spriteCoors.x > screenw || spriteCoors.y > screenh){
aCoronas[i].offScreen = true;
aCoronas[i].sightClear = false;
}else{
if(CTimer::GetTimeInMilliseconds() > aCoronas[i].lastLOScheck + 2000){
aCoronas[i].lastLOScheck = CTimer::GetTimeInMilliseconds();
aCoronas[i].sightClear = CWorld::GetIsLineOfSightClear(
aCoronas[i].coors, TheCamera.Cams[TheCamera.ActiveCam].Source,
true, true, false, false, false, true, false);
}
// add new streak point
if(aCoronas[i].sightClear){
aCoronas[i].prevX[0] = spriteCoors.x;
aCoronas[i].prevY[0] = spriteCoors.y;
aCoronas[i].prevRed[0] = aCoronas[i].red;
aCoronas[i].prevGreen[0] = aCoronas[i].green;
aCoronas[i].prevBlue[0] = aCoronas[i].blue;
aCoronas[i].hasValue[0] = true;
}
// if distance too big, break streak
if(aCoronas[i].hasValue[1]){
if(fabs(aCoronas[i].prevX[0] - aCoronas[i].prevX[1]) > 50.0f ||
fabs(aCoronas[i].prevY[0] - aCoronas[i].prevY[1]) > 50.0f)
aCoronas[i].hasValue[0] = false;
}
}
if(aCoronas[i].fadeAlpha == 0)
continue;
if(spriteCoors.z < aCoronas[i].drawDist){
float recipz = 1.0f/spriteCoors.z;
float fadeDistance = aCoronas[i].drawDist / 2.0f;
float distanceFade = spriteCoors.z < fadeDistance ? 1.0f : 1.0f - (spriteCoors.z - fadeDistance)/fadeDistance;
int totalFade = aCoronas[i].fadeAlpha * distanceFade;
if(aCoronas[i].LOScheck)
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
else
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
// render corona itself
if(aCoronas[i].texture){
float fogscale = CWeather::Foggyness*min(spriteCoors.z, 40.0f)/40.0f + 1.0f;
if(CCoronas::aCoronas[i].id == SUN_CORE)
spriteCoors.z = 0.95f * RwCameraGetFarClipPlane(Scene.camera);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(aCoronas[i].texture));
spriteCoors.z -= 1.5f;
if(aCoronas[i].texture == gpCoronaTexture[8]){
// what's this?
float f = 1.0f - aCoronas[i].someAngle*2.0f/PI;
float wscale = 6.0f*sq(sq(sq(f))) + 0.5f;
float hscale = 0.35f - (wscale - 0.5f) * 0.06f;
hscale = max(hscale, 0.15f);
CSprite::RenderOneXLUSprite(spriteCoors.x, spriteCoors.y, spriteCoors.z,
spritew * aCoronas[i].size * wscale,
spriteh * aCoronas[i].size * fogscale * hscale,
CCoronas::aCoronas[i].red / fogscale,
CCoronas::aCoronas[i].green / fogscale,
CCoronas::aCoronas[i].blue / fogscale,
totalFade,
recipz,
255);
}else{
CSprite::RenderOneXLUSprite_Rotate_Aspect(
spriteCoors.x, spriteCoors.y, spriteCoors.z,
spritew * aCoronas[i].size * fogscale,
spriteh * aCoronas[i].size * fogscale,
CCoronas::aCoronas[i].red / fogscale,
CCoronas::aCoronas[i].green / fogscale,
CCoronas::aCoronas[i].blue / fogscale,
totalFade,
recipz,
20.0f * recipz,
255);
}
}
// render flares
if(aCoronas[i].flareType != FLARE_NONE){
FlareDef *flare;
switch(aCoronas[i].flareType){
case FLARE_SUN: flare = SunFlareDef; break;
case FLARE_HEADLIGHTS: flare = HeadLightsFlareDef; break;
default: assert(0);
}
for(; flare->texture; flare++){
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[flare->texture + 4]));
CSprite::RenderOneXLUSprite(
(spriteCoors.x - (screenw/2)) * flare->position + (screenw/2),
(spriteCoors.y - (screenh/2)) * flare->position + (screenh/2),
spriteCoors.z,
4.0f*flare->size * spritew/spriteh,
4.0f*flare->size,
(flare->red * aCoronas[i].red)>>8,
(flare->green * aCoronas[i].green)>>8,
(flare->blue * aCoronas[i].blue)>>8,
(totalFade * flare->alpha)>>8,
recipz, 255);
}
}
}else{
aCoronas[i].offScreen = true;
aCoronas[i].sightClear = false;
}
}
}
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
// streaks
for(i = 0; i < NUMCORONAS; i++){
if(aCoronas[i].id == 0 || !aCoronas[i].drawStreak)
break;
for(j = 0; j < 5; j++){
if(!aCoronas[i].hasValue[j] || !aCoronas[i].hasValue[j+1])
continue;
RwIm2DVertexSetScreenX(&vertexbufferX[0], aCoronas[i].prevX[j]);
RwIm2DVertexSetScreenY(&vertexbufferX[0], aCoronas[i].prevY[j]);
RwIm2DVertexSetIntRGBA(&vertexbufferX[0], aCoronas[i].prevRed[j], aCoronas[i].prevGreen[j], aCoronas[i].prevBlue[j], 255);
RwIm2DVertexSetScreenX(&vertexbufferX[1], aCoronas[i].prevX[j+1]);
RwIm2DVertexSetScreenY(&vertexbufferX[1], aCoronas[i].prevY[j+1]);
RwIm2DVertexSetIntRGBA(&vertexbufferX[1], aCoronas[i].prevRed[j+1], aCoronas[i].prevGreen[j+1], aCoronas[i].prevBlue[j+1], 255);
// BUG: game doesn't do this
RwIm2DVertexSetScreenZ(&vertexbufferX[0], RwIm2DGetNearScreenZ());
RwIm2DVertexSetCameraZ(&vertexbufferX[0], RwCameraGetNearClipPlane(Scene.camera));
RwIm2DVertexSetRecipCameraZ(&vertexbufferX[0], 1.0f/RwCameraGetNearClipPlane(Scene.camera));
RwIm2DVertexSetScreenZ(&vertexbufferX[1], RwIm2DGetNearScreenZ());
RwIm2DVertexSetCameraZ(&vertexbufferX[1], RwCameraGetNearClipPlane(Scene.camera));
RwIm2DVertexSetRecipCameraZ(&vertexbufferX[1], 1.0f/RwCameraGetNearClipPlane(Scene.camera));
RwIm2DRenderLine(vertexbufferX, 2, 0, 1);
}
}
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
}
void
CCoronas::RenderReflections(void)
{
int i;
CColPoint point;
CEntity *entity;
if(CWeather::WetRoads > 0.0f){
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[3]));
for(i = 0; i < NUMCORONAS; i++){
if(aCoronas[i].id == 0 ||
aCoronas[i].fadeAlpha == 0 && aCoronas[i].alpha == 0)
continue;
// check if we want a reflection on this corona
if(aCoronas[i].renderReflection){
if(((CTimer::GetFrameCounter() + i) & 0xF) == 0 &&
CWorld::ProcessVerticalLine(aCoronas[i].coors, -1000.0f, point, entity, true, false, false, false, true, false, nil))
aCoronas[i].heightAboveRoad = aCoronas[i].coors.z - point.point.z;
}else{
if(CWorld::ProcessVerticalLine(aCoronas[i].coors, -1000.0f, point, entity, true, false, false, false, true, false, nil)){
aCoronas[i].heightAboveRoad = aCoronas[i].coors.z - point.point.z;
aCoronas[i].renderReflection = true;
}
}
if(!aCoronas[i].renderReflection)
continue;
// Don't draw if reflection is too high
if(aCoronas[i].heightAboveRoad < 20.0){
// don't draw if camera is below road
if(CCoronas::aCoronas[i].coors.z - aCoronas[i].heightAboveRoad > TheCamera.GetPosition().z)
continue;
CVector coors = aCoronas[i].coors;
coors.z -= 2.0f*aCoronas[i].heightAboveRoad;
CVector spriteCoors;
float spritew, spriteh;
if(CSprite::CalcScreenCoors(coors, spriteCoors, &spritew, &spriteh, true)){
float drawDist = 0.75f * aCoronas[i].drawDist;
drawDist = min(drawDist, 50.0f);
if(spriteCoors.z < drawDist){
float fadeDistance = drawDist / 2.0f;
float distanceFade = spriteCoors.z < fadeDistance ? 1.0f : 1.0f - (spriteCoors.z - fadeDistance)/fadeDistance;
distanceFade = clamp(distanceFade, 0.0f, 1.0f);
float recipz = 1.0f/RwCameraGetNearClipPlane(Scene.camera);
int intensity = (20.0f - aCoronas[i].heightAboveRoad) * 230.0 * distanceFade*CWeather::WetRoads * 0.05f;
CSprite::RenderBufferedOneXLUSprite(
spriteCoors.x, spriteCoors.y, RwIm2DGetNearScreenZ(),
spritew * aCoronas[i].size * 0.75f,
spriteh * aCoronas[i].size * 2.0f,
(intensity * CCoronas::aCoronas[i].red)>>8,
(intensity * CCoronas::aCoronas[i].green)>>8,
(intensity * CCoronas::aCoronas[i].blue)>>8,
255,
recipz,
255);
}
}
}
}
CSprite::FlushSpriteBuffer();
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
}else{
for(i = 0; i < NUMCORONAS; i++)
aCoronas[i].renderReflection = false;
}
}
void
CCoronas::DoSunAndMoon(void)
{
// yeah, moon is done somewhere else....
CVector sunCoors = CTimeCycle::GetSunPosition();
sunCoors *= 150.0f;
sunCoors += TheCamera.GetPosition();
if(CTimeCycle::GetSunPosition().z > -0.2f){
float size = ((CGeneral::GetRandomNumber()&0xFF) * 0.005f + 10.0f) * CTimeCycle::GetSunSize();
RegisterCorona(SUN_CORE,
CTimeCycle::GetSunCoreRed(), CTimeCycle::GetSunCoreGreen(), CTimeCycle::GetSunCoreBlue(),
255, sunCoors, size,
999999.88f, TYPE_STAR, FLARE_NONE, REFLECTION_OFF, LOSCHECK_OFF, STREAK_OFF, 0.0f);
if(CTimeCycle::GetSunPosition().z > 0.0f)
RegisterCorona(SUN_CORONA,
CTimeCycle::GetSunCoronaRed(), CTimeCycle::GetSunCoronaGreen(), CTimeCycle::GetSunCoronaBlue(),
255, sunCoors, 25.0f * CTimeCycle::GetSunSize(),
999999.88f, TYPE_STAR, FLARE_SUN, REFLECTION_OFF, LOSCHECK_ON, STREAK_OFF, 0.0f);
}
CVector spriteCoors;
float spritew, spriteh;
if(CSprite::CalcScreenCoors(sunCoors, spriteCoors, &spritew, &spriteh, true)){
SunScreenX = spriteCoors.x;
SunScreenY = spriteCoors.y;
}else{
SunScreenX = 1000000.0f;
SunScreenY = 1000000.0f;
}
}
void
CRegisteredCorona::Update(void)
{
if(!registeredThisFrame)
alpha = 0;
if(LOScheck &&
(CCoronas::SunBlockedByClouds && id == CCoronas::SUN_CORONA ||
!CWorld::GetIsLineOfSightClear(coors, TheCamera.GetPosition(), true, false, false, false, false, false))){
// Corona is blocked, fade out
fadeAlpha = max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), 0.0f);
}else if(offScreen){
// Same when off screen
fadeAlpha = max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), 0.0f);
}else{
// Visible
if(alpha > fadeAlpha){
// fade in
fadeAlpha = min(fadeAlpha + 15.0f*CTimer::GetTimeStep(), alpha);
if(CCoronas::bChangeBrightnessImmediately)
fadeAlpha = alpha;
}else if(alpha < fadeAlpha){
// too visible, decrease alpha but not below alpha
fadeAlpha = max(fadeAlpha - 15.0f*CTimer::GetTimeStep(), alpha);
}
// darken scene when the sun is visible
if(id == CCoronas::SUN_CORONA)
CCoronas::LightsMult = max(CCoronas::LightsMult - CTimer::GetTimeStep()*0.06f, 0.6f);
}
// remove if invisible
if(fadeAlpha == 0 && !firstUpdate)
id = 0;
firstUpdate = false;
registeredThisFrame = false;
}
STARTPATCHES
InjectHook(0x4F9F90, CCoronas::Init, PATCH_JUMP);
InjectHook(0x4FA050, CCoronas::Shutdown, PATCH_JUMP);
InjectHook(0x4F8EC0, CCoronas::Update, PATCH_JUMP);
InjectHook(0x4FA0E0, (void (*)(uint32, uint8, uint8, uint8, uint8, const CVector&, float, float, RwTexture*, int8, uint8, uint8, uint8, float))CCoronas::RegisterCorona, PATCH_JUMP);
InjectHook(0x4FA080, (void (*)(uint32, uint8, uint8, uint8, uint8, const CVector&, float, float, uint8, int8, uint8, uint8, uint8, float))CCoronas::RegisterCorona, PATCH_JUMP);
InjectHook(0x4FA2D0, CCoronas::UpdateCoronaCoors, PATCH_JUMP);
InjectHook(0x4F8FB0, CCoronas::Render, PATCH_JUMP);
InjectHook(0x4F9B40, CCoronas::RenderReflections, PATCH_JUMP);
InjectHook(0x4FA380, CCoronas::DoSunAndMoon, PATCH_JUMP);
InjectHook(0x4F8C40, &CRegisteredCorona::Update, PATCH_JUMP);
ENDPATCHES

View File

@ -2,15 +2,99 @@
extern RwTexture **gpCoronaTexture; //[9]
struct CRegisteredCorona
{
uint32 id;
uint32 lastLOScheck;
RwTexture *texture;
uint8 red;
uint8 green;
uint8 blue;
uint8 alpha; // alpha when fully visible
uint8 fadeAlpha; // actual value used for rendering, faded
CVector coors;
float size;
float someAngle;
bool registeredThisFrame;
float drawDist;
int8 flareType;
int8 reflection;
uint8 LOScheck : 1;
uint8 offScreen : 1;
uint8 firstUpdate : 1;
uint8 drawStreak : 1;
uint8 sightClear : 1;
bool renderReflection;
float heightAboveRoad;
float prevX[6];
float prevY[6];
uint8 prevRed[6];
uint8 prevGreen[6];
uint8 prevBlue[6];
bool hasValue[6];
void Update(void);
};
static_assert(sizeof(CRegisteredCorona) == 0x80, "CRegisteredCorona: error");
class CCoronas
{
static CRegisteredCorona *aCoronas; //[NUMCORONAS];
public:
enum {
SUN_CORE = 1,
SUN_CORONA
};
enum {
TYPE_STAR,
TYPE_NORMAL,
TYPE_MOON,
TYPE_REFLECT,
TYPE_HEADLIGHT,
TYPE_HEX,
TYPE_CIRCLE,
TYPE_RING,
TYPE_STREAK,
};
enum {
FLARE_NONE,
FLARE_SUN,
FLARE_HEADLIGHTS
};
enum {
REFLECTION_OFF,
REFLECTION_ON,
};
enum {
LOSCHECK_OFF,
LOSCHECK_ON,
};
enum {
STREAK_OFF,
STREAK_ON,
};
static float &LightsMult;
static float &SunScreenY;
static float &SunScreenX;
static bool &bSmallMoon;
static bool &SunBlockedByClouds;
static int &bChangeBrightnessImmediately;
static void Init(void);
static void Shutdown(void);
static void Update(void);
static void RegisterCorona(uint32 id, uint8 red, uint8 green, uint8 blue, uint8 alpha,
const CVector &coors, float size, float drawDist, RwTexture *tex,
int8 flareType, uint8 reflection, uint8 LOScheck, uint8 drawStreak, float someAngle);
static void RegisterCorona(uint32 id, uint8 red, uint8 green, uint8 blue, uint8 alpha,
const CVector &coors, float size, float drawDist, uint8 type,
int8 flareType, uint8 reflection, uint8 LOScheck, uint8 drawStreak, float someAngle);
static void UpdateCoronaCoors(int id, const CVector &coors, float drawDist, float someAngle);
static void Render(void);
static void RenderReflections(void);
static void DoSunAndMoon(void);
};

View File

@ -131,6 +131,65 @@ CSprite::RenderOneXLUSprite(float x, float y, float z, float w, float h, uint8 r
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, verts, 4);
}
void
CSprite::RenderOneXLUSprite_Rotate_Aspect(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, float rotation, uint8 a)
{
float c = cos(DEGTORAD(rotation));
float s = sin(DEGTORAD(rotation));
float xs[4];
float ys[4];
float us[4];
float vs[4];
int i;
// Fade out when too near
// why not in buffered version?
if(z < 3.0f){
if(z < 1.5f)
return;
int f = (z - 1.5f)/1.5f * 255;
r = f*r >> 8;
g = f*g >> 8;
b = f*b >> 8;
intens = f*intens >> 8;
}
xs[0] = x + w*(-c-s); us[0] = 0.0f;
xs[1] = x + w*(-c+s); us[1] = 0.0f;
xs[2] = x + w*(+c+s); us[2] = 1.0f;
xs[3] = x + w*(+c-s); us[3] = 1.0f;
ys[0] = y + h*(-c+s); vs[0] = 0.0f;
ys[1] = y + h*(+c+s); vs[1] = 1.0f;
ys[2] = y + h*(+c-s); vs[2] = 1.0f;
ys[3] = y + h*(-c-s); vs[3] = 0.0f;
// No clipping, just culling
if(xs[0] < 0.0f && xs[1] < 0.0f && xs[2] < 0.0f && xs[3] < 0.0f) return;
if(ys[0] < 0.0f && ys[1] < 0.0f && ys[2] < 0.0f && ys[3] < 0.0f) return;
if(xs[0] > RsGlobal.maximumWidth && xs[1] > RsGlobal.maximumWidth &&
xs[2] > RsGlobal.maximumWidth && xs[3] > RsGlobal.maximumWidth) return;
if(ys[0] > RsGlobal.maximumHeight && ys[1] > RsGlobal.maximumHeight &&
ys[2] > RsGlobal.maximumHeight && ys[3] > RsGlobal.maximumHeight) return;
float screenz = m_f2DNearScreenZ +
(z-CDraw::GetNearClipZ())*(m_f2DFarScreenZ-m_f2DNearScreenZ)*CDraw::GetFarClipZ() /
((CDraw::GetFarClipZ()-CDraw::GetNearClipZ())*z);
for(i = 0; i < 4; i++){
RwIm2DVertexSetScreenX(&verts[i], xs[i]);
RwIm2DVertexSetScreenY(&verts[i], ys[i]);
RwIm2DVertexSetScreenZ(&verts[i], screenz);
RwIm2DVertexSetCameraZ(&verts[i], z);
RwIm2DVertexSetRecipCameraZ(&verts[i], recipz);
RwIm2DVertexSetIntRGBA(&verts[i], r*intens>>8, g*intens>>8, b*intens>>8, a);
RwIm2DVertexSetU(&verts[i], us[i], recipz);
RwIm2DVertexSetV(&verts[i], vs[i], recipz);
}
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, verts, 4);
}
void
CSprite::RenderBufferedOneXLUSprite(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, uint8 a)
{
@ -537,6 +596,7 @@ STARTPATCHES
InjectHook(0x51C5B0, CSprite::InitSpriteBuffer2D, PATCH_JUMP);
InjectHook(0x51C520, CSprite::FlushSpriteBuffer, PATCH_JUMP);
InjectHook(0x51C960, CSprite::RenderOneXLUSprite, PATCH_JUMP);
InjectHook(0x51D110, CSprite::RenderOneXLUSprite_Rotate_Aspect, PATCH_JUMP);
InjectHook(0x51C5D0, CSprite::RenderBufferedOneXLUSprite, PATCH_JUMP);
InjectHook(0x51D5B0, CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension, PATCH_JUMP);
InjectHook(0x51CCD0, CSprite::RenderBufferedOneXLUSprite_Rotate_Aspect, PATCH_JUMP);

View File

@ -13,6 +13,7 @@ public:
static void InitSpriteBuffer2D(void);
static void FlushSpriteBuffer(void);
static void RenderOneXLUSprite(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, uint8 a);
static void RenderOneXLUSprite_Rotate_Aspect(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, float roll, uint8 a);
static void RenderBufferedOneXLUSprite(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, uint8 a);
static void RenderBufferedOneXLUSprite_Rotate_Dimension(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, float roll, uint8 a);
static void RenderBufferedOneXLUSprite_Rotate_Aspect(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, float roll, uint8 a);