Merge branch 'master' into master

This commit is contained in:
Fire_Head 2019-06-02 06:15:00 +03:00 committed by GitHub
commit 809c81ea9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1505 additions and 46 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

@ -5,7 +5,7 @@
#include "Messages.h"
#include "Text.h"
static wchar_t WideErrorString[25];
static wchar WideErrorString[25];
CText &TheText = *(CText*)0x941520;
@ -90,7 +90,7 @@ CText::Unload(void)
keyArray.Unload();
}
wchar_t*
wchar*
CText::Get(const char *key)
{
return keyArray.Search(key);
@ -119,11 +119,11 @@ CKeyArray::Unload(void)
}
void
CKeyArray::Update(wchar_t *chars)
CKeyArray::Update(wchar *chars)
{
int i;
for(i = 0; i < numEntries; i++)
entries[i].value = (wchar_t*)((uint8*)chars + (uintptr)entries[i].value);
entries[i].value = (wchar*)((uint8*)chars + (uintptr)entries[i].value);
}
CKeyEntry*
@ -146,7 +146,7 @@ CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 hi
return nil;
}
wchar_t*
wchar*
CKeyArray::Search(const char *key)
{
CKeyEntry *found;
@ -169,8 +169,8 @@ CData::Load(uint32 length, uint8 *data, int *offset)
uint32 i;
uint8 *rawbytes;
numChars = length / sizeof(wchar_t);
chars = new wchar_t[numChars];
numChars = length / sizeof(wchar);
chars = new wchar[numChars];
rawbytes = (uint8*)chars;
for(i = 0; i < length; i++)
@ -185,6 +185,12 @@ CData::Unload(void)
numChars = 0;
}
void
AsciiToUnicode(const char *cs, uint16 *ws)
{
while((*ws++ = *cs++) != '\0');
}
STARTPATCHES
InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP);
InjectHook(0x52C580, &CText::Unload, PATCH_JUMP);

View File

@ -1,8 +1,10 @@
#pragma once
void AsciiToUnicode(const char *cs, wchar *ws);
struct CKeyEntry
{
wchar_t *value;
wchar *value;
char key[8];
};
// If this fails, CKeyArray::Load will have to be fixed
@ -16,15 +18,15 @@ public:
void Load(uint32 length, uint8 *data, int *offset);
void Unload(void);
void Update(wchar_t *chars);
void Update(wchar *chars);
CKeyEntry *BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high);
wchar_t *Search(const char *key);
wchar *Search(const char *key);
};
class CData
{
public:
wchar_t *chars;
wchar *chars;
int numChars;
void Load(uint32 length, uint8 *data, int *offset);
@ -41,7 +43,7 @@ public:
~CText(void);
void Load(void);
void Unload(void);
wchar_t *Get(const char *key);
wchar *Get(const char *key);
};
extern CText &TheText;

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

@ -19,6 +19,26 @@ CZoneInfo *CTheZones::ZoneInfoArray = (CZoneInfo*)0x714400;
#define SWAPF(a, b) { float t; t = a; a = b; b = t; }
static void
CheckZoneInfo(CZoneInfo *info)
{
assert(info->carThreshold[0] >= 0);
assert(info->carThreshold[0] <= info->carThreshold[1]);
assert(info->carThreshold[1] <= info->carThreshold[2]);
assert(info->carThreshold[2] <= info->carThreshold[3]);
assert(info->carThreshold[3] <= info->carThreshold[4]);
assert(info->carThreshold[4] <= info->carThreshold[5]);
assert(info->carThreshold[5] <= info->copThreshold);
assert(info->copThreshold <= info->gangThreshold[0]);
assert(info->gangThreshold[0] <= info->gangThreshold[1]);
assert(info->gangThreshold[1] <= info->gangThreshold[2]);
assert(info->gangThreshold[2] <= info->gangThreshold[3]);
assert(info->gangThreshold[3] <= info->gangThreshold[4]);
assert(info->gangThreshold[4] <= info->gangThreshold[5]);
assert(info->gangThreshold[5] <= info->gangThreshold[6]);
assert(info->gangThreshold[6] <= info->gangThreshold[7]);
assert(info->gangThreshold[7] <= info->gangThreshold[8]);
}
void
CTheZones::Init(void)
@ -49,6 +69,7 @@ CTheZones::Init(void)
zonei->gangThreshold[6] = zonei->gangThreshold[5];
zonei->gangThreshold[7] = zonei->gangThreshold[6];
zonei->gangThreshold[8] = zonei->gangThreshold[7];
CheckZoneInfo(zonei);
}
TotalNumberOfZoneInfos = 1; // why 1?
@ -360,10 +381,12 @@ CTheZones::GetZoneInfoForTimeOfDay(const CVector *pos, CZoneInfo *info)
else{
if(CClock::GetIsTimeInRange(19, 22)){
n = (CClock::GetHours() - 19) / 3.0f;
d = n - 1.0f;
assert(n >= 0.0f && n <= 1.0f);
d = 1.0f - n;
}else{
d = (CClock::GetHours() - 5) / 3.0f;
n = d - 1.0f;
assert(d >= 0.0f && d <= 1.0f);
n = 1.0f - d;
}
info->carDensity = day->carDensity * d + night->carDensity * n;
info->carThreshold[0] = day->carThreshold[0] * d + night->carThreshold[0] * n;
@ -399,6 +422,8 @@ CTheZones::GetZoneInfoForTimeOfDay(const CVector *pos, CZoneInfo *info)
info->pedGroup = day->pedGroup;
else
info->pedGroup = night->pedGroup;
CheckZoneInfo(info);
}
void
@ -415,6 +440,8 @@ CTheZones::SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity,
zone = GetZone(zoneid);
info = &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight];
CheckZoneInfo(info);
if(carDensity != -1) info->carDensity = carDensity;
int16 oldCar1Num = info->carThreshold[1] - info->carThreshold[0];
int16 oldCar2Num = info->carThreshold[2] - info->carThreshold[1];
@ -463,6 +490,8 @@ 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;
CheckZoneInfo(info);
}
void
@ -477,15 +506,15 @@ CTheZones::SetZonePedInfo(uint16 zoneid, uint8 day, int16 pedDensity,
info = &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight];
if(pedDensity != -1) info->pedDensity = pedDensity;
if(copDensity != -1) info->copDensity = copDensity;
if(gang0Density != -1) info->gangThreshold[0] = gang0Density;
if(gang1Density != -1) info->gangThreshold[1] = gang1Density;
if(gang2Density != -1) info->gangThreshold[2] = gang2Density;
if(gang3Density != -1) info->gangThreshold[3] = gang3Density;
if(gang4Density != -1) info->gangThreshold[4] = gang4Density;
if(gang5Density != -1) info->gangThreshold[5] = gang5Density;
if(gang6Density != -1) info->gangThreshold[6] = gang6Density;
if(gang7Density != -1) info->gangThreshold[7] = gang7Density;
if(gang8Density != -1) info->gangThreshold[8] = gang8Density;
if(gang0Density != -1) info->gangDensity[0] = gang0Density;
if(gang1Density != -1) info->gangDensity[1] = gang1Density;
if(gang2Density != -1) info->gangDensity[2] = gang2Density;
if(gang3Density != -1) info->gangDensity[3] = gang3Density;
if(gang4Density != -1) info->gangDensity[4] = gang4Density;
if(gang5Density != -1) info->gangDensity[5] = gang5Density;
if(gang6Density != -1) info->gangDensity[6] = gang6Density;
if(gang7Density != -1) info->gangDensity[7] = gang7Density;
if(gang8Density != -1) info->gangDensity[8] = gang8Density;
}
void

View File

@ -33,10 +33,10 @@ class CZoneInfo
{
public:
// Car data
uint16 carDensity;
uint16 carThreshold[6];
uint16 copThreshold;
uint16 gangThreshold[9];
int16 carDensity;
int16 carThreshold[6];
int16 copThreshold;
int16 gangThreshold[9];
// Ped data
uint16 pedDensity;

View File

@ -40,12 +40,13 @@ typedef int32_t int32, Int32;
typedef uintptr_t uintptr;
typedef uint64_t uint64, UInt64;
typedef int64_t int64, Int64;
// hardcode ucs-2
typedef uint16_t wchar, WChar;
typedef float Float;
typedef double Double;
typedef bool Bool;
typedef char Char;
typedef wchar_t WChar;
#define nil NULL

View File

@ -51,8 +51,13 @@ enum Config {
NUMWEATHERS = 4,
NUMHOURS = 24,
NUMEXTRADIRECTIONALS = 4,
NUMANTENNAS = 8,
NUMCORONAS = 56,
NUMPOINTLIGHTS = 32
};
#define GTA3_1_1_PATCH FALSE
#define USE_PS2_RAND FALSE
#define USE_PS2_RAND FALSE
#define RANDOMSPLASH
#define CHATTYSPLASH

View File

@ -39,6 +39,9 @@
#include "Credits.h"
#include "CullZones.h"
#include "TimeCycle.h"
#include "TxdStore.h"
#include "FileMgr.h"
#include "Text.h"
#include "Frontend.h"
#define DEFAULT_VIEWWINDOW (tan(CDraw::GetFOV() * (360.0f / PI)))
@ -69,6 +72,10 @@ void RenderMenus(void);
void DoFade(void);
void Render2dStuffAfterFade(void);
CSprite2d *LoadSplash(const char *name);
void DestroySplashScreen(void);
extern void (*DebugMenuProcess)(void);
extern void (*DebugMenuRender)(void);
@ -179,6 +186,30 @@ FrontendIdle(void)
DoRWStuffEndOfFrame();
}
bool
DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha)
{
CRGBA TopColor(TopRed, TopGreen, TopBlue, Alpha);
CRGBA BottomColor(BottomRed, BottomGreen, BottomBlue, Alpha);
float viewWindow = tan(DEGTORAD(CDraw::GetFOV() * 0.5f));
// ASPECT
float aspectRatio = CMenuManager::m_PrefsUseWideScreen ? 16.0f/9.0f : 4.0f/3.0f;
CameraSize(Scene.camera, nil, viewWindow, aspectRatio);
CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
if(!RsCameraBeginUpdate(Scene.camera))
return false;
CSprite2d::InitPerFrame();
if(Alpha != 0)
CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREENW, SCREENH), BottomColor, BottomColor, TopColor, TopColor);
return true;
}
bool
DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha)
{
@ -360,7 +391,7 @@ DoFade(void)
}
if(CDraw::FadeValue != 0 || CMenuManager::m_PrefsBrightness < 256){
// LoadSplash
CSprite2d *splash = LoadSplash(nil);
CRGBA fadeColor;
CRect rect;
@ -410,7 +441,7 @@ DoFade(void)
fadeColor.g = 255;
fadeColor.b = 255;
fadeColor.a = CDraw::FadeValue;
CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREENW, SCREENH), fadeColor, fadeColor, fadeColor, fadeColor);
splash->Draw(CRect(0.0f, 0.0f, SCREENW, SCREENH), fadeColor, fadeColor, fadeColor, fadeColor);
}
}
}
@ -422,6 +453,130 @@ Render2dStuffAfterFade(void)
CFont::DrawFonts();
}
CSprite2d splash;
int splashTxdId = -1;
CSprite2d*
LoadSplash(const char *name)
{
RwTexDictionary *txd;
char filename[140];
RwTexture *tex = nil;
if(name == nil)
return &splash;
if(splashTxdId == -1)
splashTxdId = CTxdStore::AddTxdSlot("splash");
txd = CTxdStore::GetSlot(splashTxdId)->texDict;
if(txd)
tex = RwTexDictionaryFindNamedTexture(txd, name);
// if texture is found, splash was already set up below
if(tex == nil){
CFileMgr::SetDir("TXD\\");
sprintf(filename, "%s.txd", name);
if(splash.m_pTexture)
splash.Delete();
if(txd)
CTxdStore::RemoveTxd(splashTxdId);
CTxdStore::LoadTxd(splashTxdId, filename);
CTxdStore::AddRef(splashTxdId);
CTxdStore::PushCurrentTxd();
CTxdStore::SetCurrentTxd(splashTxdId);
splash.SetTexture(name);
CTxdStore::PopCurrentTxd();
CFileMgr::SetDir("");
}
return &splash;
}
void
DestroySplashScreen(void)
{
splash.Delete();
if(splashTxdId != -1)
CTxdStore::RemoveTxdSlot(splashTxdId);
splashTxdId = -1;
}
float NumberOfChunksLoaded;
#define TOTALNUMCHUNKS 73.0f
// TODO: compare with PS2
void
LoadingScreen(char *str1, char *str2, char *splashscreen)
{
CSprite2d *splash;
#ifndef RANDOMSPLASH
if(CGame::frenchGame || CGame::germanGame || !CGame::nastyGame)
splashscreen = "mainsc2";
else
splashscreen = "mainsc1";
#endif
splash = LoadSplash(splashscreen);
if(RsGlobal.quit)
return;
if(DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255)){
CSprite2d::SetRecipNearClip();
CSprite2d::InitPerFrame();
CFont::InitPerFrame();
DefinedState();
RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
splash->Draw(CRect(0.0f, 0.0f, SCREENW, SCREENH), CRGBA(255, 255, 255, 255));
if(str1){
NumberOfChunksLoaded += 1;
float hpos = SCREEN_STRETCH_X(40);
float length = SCREENW - SCREEN_STRETCH_X(100);
float vpos = SCREENH - SCREEN_STRETCH_Y(13);
float height = SCREEN_STRETCH_Y(7);
CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(40, 53, 68, 255));
length *= NumberOfChunksLoaded/TOTALNUMCHUNKS;
CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(81, 106, 137, 255));
// this is done by the game but is unused
CFont::SetScale(SCREEN_STRETCH_X(2), SCREEN_STRETCH_Y(2));
CFont::SetPropOn();
CFont::SetRightJustifyOn();
CFont::SetFontStyle(FONT_HEADING);
#ifdef CHATTYSPLASH
// my attempt
static wchar tmpstr[80];
float scale = SCREEN_STRETCH_Y(0.8f);
vpos -= 50*scale;
CFont::SetScale(scale, scale);
CFont::SetPropOn();
CFont::SetRightJustifyOff();
CFont::SetFontStyle(FONT_BANK);
CFont::SetColor(CRGBA(255, 255, 255, 255));
AsciiToUnicode(str1, tmpstr);
CFont::PrintString(hpos, vpos, tmpstr);
vpos += 25*scale;
AsciiToUnicode(str2, tmpstr);
CFont::PrintString(hpos, vpos, tmpstr);
#endif
}
CFont::DrawFonts();
DoRWStuffEndOfFrame();
}
}
void
ResetLoadingScreenBar(void)
{
NumberOfChunksLoaded = 0.0f;
}
#include "rwcore.h"
#include "rpworld.h"
#include "rpmatfx.h"
@ -589,6 +744,7 @@ STARTPATCHES
InjectHook(0x48E480, Idle, PATCH_JUMP);
InjectHook(0x48E700, FrontendIdle, PATCH_JUMP);
InjectHook(0x48CF10, DoRWStuffStartOfFrame, PATCH_JUMP);
InjectHook(0x48D040, DoRWStuffStartOfFrame_Horizon, PATCH_JUMP);
InjectHook(0x48E030, RenderScene, PATCH_JUMP);
InjectHook(0x48E080, RenderDebugShit, PATCH_JUMP);
@ -597,6 +753,11 @@ STARTPATCHES
InjectHook(0x48E450, RenderMenus, PATCH_JUMP);
InjectHook(0x48D120, DoFade, PATCH_JUMP);
InjectHook(0x48E470, Render2dStuffAfterFade, PATCH_JUMP);
InjectHook(0x48D550, LoadSplash, PATCH_JUMP);
InjectHook(0x48D670, DestroySplashScreen, PATCH_JUMP);
InjectHook(0x48D770, LoadingScreen, PATCH_JUMP);
InjectHook(0x48D760, ResetLoadingScreenBar, PATCH_JUMP);
InjectHook(0x48D470, PluginAttach, PATCH_JUMP);
InjectHook(0x48D520, Initialise3D, PATCH_JUMP);

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

@ -61,6 +61,8 @@ int (*open_script_orig)(const char *path, const char *mode);
int
open_script(const char *path, const char *mode)
{
if(GetAsyncKeyState('G') & 0x8000)
return open_script_orig("main.scm", mode);
if(GetAsyncKeyState('D') & 0x8000)
return open_script_orig("main_d.scm", mode);
// if(GetAsyncKeyState('R') & 0x8000)
@ -104,8 +106,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 +113,30 @@ delayedPatches10(int a, int b)
return RsEventHandler_orig(a, b);
}
void __declspec(naked) HeadlightsFix()
{
static const float fMinusOne = -1.0f;
_asm
{
fld [esp+708h-690h]
fcomp fMinusOne
fnstsw ax
and ah, 5
cmp ah, 1
jnz HeadlightsFix_DontLimit
fld fMinusOne
fstp [esp+708h-690h]
HeadlightsFix_DontLimit:
fld [esp+708h-690h]
fabs
fld st
push 0x5382F2
retn
}
}
void
patch()
{
@ -121,6 +145,10 @@ patch()
Patch<float>(0x46BC61+6, 1.0f); // car distance
InjectHook(0x59E460, printf, PATCH_JUMP);
// stolen from silentpatch (sorry)
Patch<WORD>(0x5382BF, 0x0EEB);
InjectHook(0x5382EC, HeadlightsFix, PATCH_JUMP);
InterceptCall(&open_script_orig, open_script, 0x438869);
InterceptCall(&RsEventHandler_orig, delayedPatches10, 0x58275E);

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

@ -37,7 +37,7 @@ CCredits::PrintCreditSpace(float space, uint32 &line)
}
void
CCredits::PrintCreditText(float scaleX, float scaleY, wchar_t *text, uint32 &lineoffset, float scrolloffset)
CCredits::PrintCreditText(float scaleX, float scaleY, wchar *text, uint32 &lineoffset, float scrolloffset)
{
float start = SCREENH + 50.0f;
float y = lineoffset + start - scrolloffset;

View File

@ -11,5 +11,5 @@ public:
static bool AreCreditsDone(void) { return bCreditsGoing; }
static void Render(void);
static void PrintCreditSpace(float space, uint32 &line);
static void PrintCreditText(float scaleX, float scaleY, wchar_t *text, uint32 &lineoffset, float scrolloffset);
static void PrintCreditText(float scaleX, float scaleY, wchar *text, uint32 &lineoffset, float scrolloffset);
};

View File

@ -11,6 +11,9 @@
RpLight *&pAmbient = *(RpLight**)0x885B6C;
RpLight *&pDirect = *(RpLight**)0x880F7C;
RpLight **pExtraDirectionals = (RpLight**)0x60009C;
int *LightStrengths = (int*)0x87BEF0;
int &NumExtraDirLightsInWorld = *(int*)0x64C608;
RwRGBAReal &AmbientLightColourForFrame = *(RwRGBAReal*)0x6F46F8;
RwRGBAReal &AmbientLightColourForFrame_PedsCarsAndObjects = *(RwRGBAReal*)0x6F1D10;
@ -85,6 +88,151 @@ SetLightsWithTimeOfDayColour(RpWorld *)
}
}
RpWorld*
LightsCreate(RpWorld *world)
{
int i;
RwRGBAReal color;
RwFrame *frame;
if(world == nil)
return nil;
pAmbient = RpLightCreate(rpLIGHTAMBIENT);
RpLightSetFlags(pAmbient, rpLIGHTLIGHTATOMICS);
color.red = 0.25f;
color.green = 0.25f;
color.blue = 0.2f;
RpLightSetColor(pAmbient, &color);
pDirect = RpLightCreate(rpLIGHTDIRECTIONAL);
RpLightSetFlags(pDirect, rpLIGHTLIGHTATOMICS);
color.red = 1.0f;
color.green = 0.84f;
color.blue = 0.45f;
RpLightSetColor(pDirect, &color);
RpLightSetRadius(pDirect, 2.0f);
frame = RwFrameCreate();
RpLightSetFrame(pDirect, frame);
RwV3d axis = { 1.0f, 1.0f, 0.0f };
RwFrameRotate(frame, &axis, 160.0f, rwCOMBINEPRECONCAT);
RpWorldAddLight(world, pAmbient);
RpWorldAddLight(world, pDirect);
for(i = 0; i < NUMEXTRADIRECTIONALS; i++){
pExtraDirectionals[i] = RpLightCreate(rpLIGHTDIRECTIONAL);
RpLightSetFlags(pExtraDirectionals[i], 0);
color.red = 1.0f;
color.green = 0.5f;
color.blue = 0.0f;
RpLightSetColor(pExtraDirectionals[i], &color);
RpLightSetRadius(pExtraDirectionals[i], 2.0f);
frame = RwFrameCreate();
RpLightSetFrame(pExtraDirectionals[i], frame);
RpWorldAddLight(world, pExtraDirectionals[i]);
}
return world;
}
void
LightsDestroy(RpWorld *world)
{
int i;
if(world == nil)
return;
if(pAmbient){
RpWorldRemoveLight(world, pAmbient);
RpLightDestroy(pAmbient);
pAmbient = nil;
}
if(pDirect){
RpWorldRemoveLight(world, pDirect);
RwFrameDestroy(RpLightGetFrame(pDirect));
RpLightDestroy(pDirect);
pDirect = nil;
}
for(i = 0; i < NUMEXTRADIRECTIONALS; i++)
if(pExtraDirectionals[i]){
RpWorldRemoveLight(world, pExtraDirectionals[i]);
RwFrameDestroy(RpLightGetFrame(pExtraDirectionals[i]));
RpLightDestroy(pExtraDirectionals[i]);
pExtraDirectionals[i] = nil;
}
}
void
WorldReplaceNormalLightsWithScorched(RpWorld *world, float l)
{
RwRGBAReal color;
color.red = l;
color.green = l;
color.blue = l;
RpLightSetColor(pAmbient, &color);
RpLightSetFlags(pDirect, 0);
}
void
WorldReplaceScorchedLightsWithNormal(RpWorld *world)
{
RpLightSetColor(pAmbient, &AmbientLightColourForFrame);
RpLightSetFlags(pDirect, rpLIGHTLIGHTATOMICS);
}
void
AddAnExtraDirectionalLight(RpWorld *world, float dirx, float diry, float dirz, float red, float green, float blue)
{
float strength;
int weakest;
int i, n;
RwRGBAReal color;
RwV3d *dir;
strength = max(max(red, green), blue);
n = -1;
if(NumExtraDirLightsInWorld < NUMEXTRADIRECTIONALS)
n = NumExtraDirLightsInWorld;
else{
weakest = strength;
for(i = 0; i < NUMEXTRADIRECTIONALS; i++)
if(LightStrengths[i] < weakest){
weakest = LightStrengths[i];
n = i;
}
}
if(n < 0)
return;
color.red = red;
color.green = green;
color.blue = blue;
RpLightSetColor(pExtraDirectionals[n], &color);
dir = RwMatrixGetAt(RwFrameGetMatrix(RpLightGetFrame(pExtraDirectionals[n])));
dir->x = -dirx;
dir->y = -diry;
dir->z = -dirz;
RwMatrixUpdate(RwFrameGetMatrix(RpLightGetFrame(pExtraDirectionals[n])));
RwFrameUpdateObjects(RpLightGetFrame(pExtraDirectionals[n]));
RpLightSetFlags(pExtraDirectionals[n], rpLIGHTLIGHTATOMICS);
LightStrengths[n] = strength;
NumExtraDirLightsInWorld = min(NumExtraDirLightsInWorld+1, NUMEXTRADIRECTIONALS);
}
void
RemoveExtraDirectionalLights(RpWorld *world)
{
int i;
for(i = 0; i < NumExtraDirLightsInWorld; i++)
RpLightSetFlags(pExtraDirectionals[i], 0);
NumExtraDirLightsInWorld = 0;
}
void
SetAmbientAndDirectionalColours(float f)
{
@ -159,13 +307,27 @@ SetAmbientColoursToIndicateRoadGroup(int i)
RpLightSetColor(pAmbient, &AmbientLightColour);
}
void
SetAmbientColours(RwRGBAReal *color)
{
RpLightSetColor(pAmbient, color);
}
STARTPATCHES
InjectHook(0x526510, SetLightsWithTimeOfDayColour, PATCH_JUMP);
InjectHook(0x5269A0, LightsCreate, PATCH_JUMP);
InjectHook(0x526B40, LightsDestroy, PATCH_JUMP);
InjectHook(0x526C10, WorldReplaceNormalLightsWithScorched, PATCH_JUMP);
InjectHook(0x526C50, WorldReplaceScorchedLightsWithNormal, PATCH_JUMP);
InjectHook(0x526C70, AddAnExtraDirectionalLight, PATCH_JUMP);
InjectHook(0x526DB0, RemoveExtraDirectionalLights, PATCH_JUMP);
InjectHook(0x526DE0, SetAmbientAndDirectionalColours, PATCH_JUMP);
InjectHook(0x526E60, SetBrightMarkerColours, PATCH_JUMP);
InjectHook(0x526F10, ReSetAmbientAndDirectionalColours, PATCH_JUMP);
InjectHook(0x526F40, DeActivateDirectional, PATCH_JUMP);
InjectHook(0x526F50, ActivateDirectional, PATCH_JUMP);
InjectHook(0x526F60, SetAmbientColours, PATCH_JUMP);
InjectHook(0x526F60, (void (*)(void))SetAmbientColours, PATCH_JUMP);
InjectHook(0x526F80, SetAmbientColoursForPedsCarsAndObjects, PATCH_JUMP);
InjectHook(0x526FA0, (void (*)(RwRGBAReal*))SetAmbientColours, PATCH_JUMP);
ENDPATCHES

View File

@ -1,4 +1,12 @@
#pragma once
void SetLightsWithTimeOfDayColour(RpWorld *);
RpWorld *LightsCreate(RpWorld *world);
void LightsDestroy(RpWorld *world);
void WorldReplaceNormalLightsWithScorched(RpWorld *world, float l);
void WorldReplaceScorchedLightsWithNormal(RpWorld *world);
void AddAnExtraDirectionalLight(RpWorld *world, float dirx, float diry, float dirz, float red, float green, float blue);
void RemoveExtraDirectionalLights(RpWorld *world);
void SetAmbientAndDirectionalColours(float f);
void SetBrightMarkerColours(float f);
void ReSetAmbientAndDirectionalColours(void);
@ -6,4 +14,5 @@ void DeActivateDirectional(void);
void ActivateDirectional(void);
void SetAmbientColours(void);
void SetAmbientColoursForPedsCarsAndObjects(void);
void SetAmbientColoursToIndicateRoadGroup(int i);
void SetAmbientColoursToIndicateRoadGroup(int i);
void SetAmbientColours(RwRGBAReal *color);

View File

@ -1,13 +1,294 @@
#include "common.h"
#include "patcher.h"
#include "Lights.h"
#include "Camera.h"
#include "Weather.h"
#include "World.h"
#include "Collision.h"
#include "Sprite.h"
#include "Timer.h"
#include "PointLights.h"
int16 &CPointLights::NumLights = *(int16*)0x95CC3E;
CRegisteredPointLight *CPointLights::aLights = (CRegisteredPointLight*)0x7096D0;
WRAPPER void CPointLights::RenderFogEffect(void) { EAXJMP(0x510C30); }
//WRAPPER void CPointLights::RenderFogEffect(void) { EAXJMP(0x510C30); }
void
CPointLights::InitPerFrame(void)
{
NumLights = 0;
}
#define MAX_DIST 22.0f
void
CPointLights::AddLight(uint8 type, CVector coors, CVector dir, float radius, float red, float green, float blue, uint8 fogType, bool castExtraShadows)
{
CVector dist;
float distance;
// The check is done in some weird way in the game
// we're doing it a bit better here
if(NumLights >= NUMPOINTLIGHTS)
return;
dist = coors - TheCamera.GetPosition();
if(fabs(dist.x) < MAX_DIST && fabs(dist.y) < MAX_DIST){
distance = dist.Magnitude();
if(distance < MAX_DIST){
aLights[NumLights].type = type;
aLights[NumLights].fogType = fogType;
aLights[NumLights].coors = coors;
aLights[NumLights].dir = dir;
aLights[NumLights].radius = radius;
aLights[NumLights].castExtraShadows = castExtraShadows;
if(distance < MAX_DIST*0.75f){
aLights[NumLights].red = red;
aLights[NumLights].green = green;
aLights[NumLights].blue = blue;
}else{
float fade = 1.0f - (distance/MAX_DIST - 0.75f)*4.0f;
aLights[NumLights].red = red * fade;
aLights[NumLights].green = green * fade;
aLights[NumLights].blue = blue * fade;
}
NumLights++;
}
}
}
float
CPointLights::GenerateLightsAffectingObject(CVector *objCoors)
{
int i;
float ret;
CVector dist;
float radius, distance;
ret = 1.0f;
for(i = 0; i < NumLights; i++){
if(aLights[i].type == LIGHT_FOGONLY_3 || aLights[i].type == LIGHT_FOGONLY_4)
continue;
// same weird distance calculation. simplified here
dist = aLights[i].coors - *objCoors;
radius = aLights[i].radius;
if(fabs(dist.x) < radius &&
fabs(dist.y) < radius &&
fabs(dist.z) < radius){
distance = dist.Magnitude();
if(distance < radius){
float distNorm = distance/radius;
if(aLights[i].type == LIGHT_DARKEN){
// darken the object the closer it is
ret *= distNorm;
}else{
float intensity;
if(distNorm < 0.5f)
// near enough
intensity = 1.0f;
else
// attenuate
intensity = 1.0f - (distNorm - 0.5f)*2.0f;
if(distance != 0.0f){
CVector dir = dist / distance;
if(aLights[i].type == LIGHT_DIRECTIONAL){
float dot = -DotProduct(dir, aLights[i].dir);
intensity *= max((dot-0.5f)*2.0f, 0.0f);
}
if(intensity > 0.0f)
AddAnExtraDirectionalLight(Scene.world,
dir.x, dir.y, dir.z,
aLights[i].red*intensity, aLights[i].green*intensity, aLights[i].blue*intensity);
}
}
}
}
}
return ret;
}
extern RwRaster *&gpPointlightRaster;
void
CPointLights::RemoveLightsAffectingObject(void)
{
RemoveExtraDirectionalLights(Scene.world);
}
// for directional fog
#define FOG_AREA_LENGTH 12.0f
#define FOG_AREA_WIDTH 5.0f
// for pointlight fog
#define FOG_AREA_RADIUS 9.0f
float FogSizes[8] = { 1.3f, 2.0f, 1.7f, 2.0f, 1.4f, 2.1f, 1.5f, 2.3f };
void
CPointLights::RenderFogEffect(void)
{
int i;
float fogginess;
CColPoint point;
CEntity *entity;
float xmin, ymin;
float xmax, ymax;
int16 xi, yi;
CVector spriteCoors;
float spritew, spriteh;
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpPointlightRaster);
for(i = 0; i < NumLights; i++){
if(aLights[i].fogType != FOG_NORMAL && aLights[i].fogType != FOG_ALWAYS)
continue;
fogginess = aLights[i].fogType == FOG_ALWAYS ? 1.0f : CWeather::Foggyness;
if(fogginess == 0.0f)
continue;
if(aLights[i].type == LIGHT_DIRECTIONAL){
// TODO: test this. haven't found directional fog so far
float coors2X = aLights[i].coors.x + FOG_AREA_LENGTH*aLights[i].dir.x;
float coors2Y = aLights[i].coors.y + FOG_AREA_LENGTH*aLights[i].dir.y;
if(coors2X < aLights[i].coors.x){
xmin = coors2X;
xmax = aLights[i].coors.x;
}else{
xmax = coors2X;
xmin = aLights[i].coors.x;
}
if(coors2Y < aLights[i].coors.y){
ymin = coors2Y;
ymax = aLights[i].coors.y;
}else{
ymax = coors2Y;
ymin = aLights[i].coors.y;
}
xmin -= 5.0f;
ymin -= 5.0f;
xmax += 5.0f;
ymax += 5.0f;
for(xi = (int16)xmin - (int16)xmin % 4; xi <= (int16)xmax + 4; xi += 4){
for(yi = (int16)ymin - (int16)ymin % 4; yi <= (int16)ymax + 4; yi += 4){
// Some kind of pseudo random number?
int r = (xi ^ yi)>>2 & 0xF;
if((r & 1) == 0)
continue;
// Check if fog effect is close enough to directional line in x and y
float dx = xi - aLights[i].coors.x;
float dy = yi - aLights[i].coors.y;
float dot = dx*aLights[i].dir.x + dy*aLights[i].dir.y;
float distsq = sq(dx) + sq(dy);
float linedistsq = distsq - sq(dot);
if(dot > 0.0f && dot < FOG_AREA_LENGTH && linedistsq < sq(FOG_AREA_WIDTH)){
CVector fogcoors(xi, yi, aLights[i].coors.z + 1.0f);
if(CWorld::ProcessVerticalLine(fogcoors, fogcoors.z - 20.0f,
point, entity, true, false, false, false, true, false, nil)){
// Now same check again in xyz
fogcoors.z = point.point.z + 1.3f;
// actually we don't have to recalculate x and y, but the game does it that way
dx = xi - aLights[i].coors.x;
dy = yi - aLights[i].coors.y;
float dz = fogcoors.z - aLights[i].coors.z;
dot = dx*aLights[i].dir.x + dy*aLights[i].dir.y + dz*aLights[i].dir.z;
distsq = sq(dx) + sq(dy) + sq(dz);
linedistsq = distsq - sq(dot);
if(dot > 0.0f && dot < FOG_AREA_LENGTH && linedistsq < sq(FOG_AREA_WIDTH)){
float intensity = 158.0f * fogginess;
// more intensity the smaller the angle
intensity *= dot/sqrt(distsq);
// more intensity the closer to light source
intensity *= 1.0f - sq(dot/FOG_AREA_LENGTH);
// more intensity the closer to line
intensity *= 1.0f - sq(sqrt(linedistsq) / FOG_AREA_WIDTH);
if(CSprite::CalcScreenCoors(fogcoors, spriteCoors, &spritew, &spriteh, true)){
float rotation = (CTimer::GetTimeInMilliseconds()&0x1FFF) * 2*3.14f / 0x1FFF;
float size = FogSizes[r>>1];
CSprite::RenderOneXLUSprite_Rotate_Aspect(spriteCoors.x, spriteCoors.y, spriteCoors.z,
spritew * size, spriteh * size,
aLights[i].red * intensity, aLights[i].green * intensity, aLights[i].blue * intensity,
intensity, 1/spriteCoors.z, rotation, 255);
}
}
}
}
}
}
}else if(aLights[i].type == LIGHT_POINT || aLights[i].type == LIGHT_FOGONLY_3 || aLights[i].type == LIGHT_FOGONLY_4){
if(CWorld::ProcessVerticalLine(aLights[i].coors, aLights[i].coors.z - 20.0f,
point, entity, true, false, false, false, true, false, nil)){
xmin = aLights[i].coors.x - FOG_AREA_RADIUS;
ymin = aLights[i].coors.y - FOG_AREA_RADIUS;
xmax = aLights[i].coors.x + FOG_AREA_RADIUS;
ymax = aLights[i].coors.y + FOG_AREA_RADIUS;
for(xi = (int16)xmin - (int16)xmin % 2; xi <= (int16)xmax + 2; xi += 2){
for(yi = (int16)ymin - (int16)ymin % 2; yi <= (int16)ymax + 2; yi += 2){
// Some kind of pseudo random number?
int r = (xi ^ yi)>>1 & 0xF;
if((r & 1) == 0)
continue;
float dx = xi - aLights[i].coors.x;
float dy = yi - aLights[i].coors.y;
float lightdist = sqrt(sq(dx) + sq(dy));
if(lightdist < FOG_AREA_RADIUS){
dx = xi - TheCamera.GetPosition().x;
dy = yi - TheCamera.GetPosition().y;
float camdist = sqrt(sq(dx) + sq(dy));
if(camdist < MAX_DIST){
float intensity;
// distance fade
if(camdist < MAX_DIST/2)
intensity = 1.0f;
else
intensity = 1.0f - (camdist - MAX_DIST/2) / (MAX_DIST/2);
intensity *= 132.0f * fogginess;
// more intensity the closer to light source
intensity *= 1.0f - sq(lightdist / FOG_AREA_RADIUS);
CVector fogcoors(xi, yi, point.point.z + 1.6f);
if(CSprite::CalcScreenCoors(fogcoors, spriteCoors, &spritew, &spriteh, true)){
float rotation = (CTimer::GetTimeInMilliseconds()&0x3FFF) * 2*3.14f / 0x3FFF;
float size = FogSizes[r>>1];
CSprite::RenderOneXLUSprite_Rotate_Aspect(spriteCoors.x, spriteCoors.y, spriteCoors.z,
spritew * size, spriteh * size,
aLights[i].red * intensity, aLights[i].green * intensity, aLights[i].blue * intensity,
intensity, 1/spriteCoors.z, rotation, 255);
}
}
}
}
}
}
}
}
}
STARTPATCHES
InjectHook(0x510790, CPointLights::AddLight, PATCH_JUMP);
InjectHook(0x510960, CPointLights::GenerateLightsAffectingObject, PATCH_JUMP);
InjectHook(0x510C20, CPointLights::RemoveLightsAffectingObject, PATCH_JUMP);
InjectHook(0x510C30, CPointLights::RenderFogEffect, PATCH_JUMP);
ENDPATCHES

View File

@ -1,9 +1,43 @@
#pragma once
class CRegisteredPointLight
{
public:
CVector coors;
CVector dir;
float radius;
float red;
float green;
float blue;
int8 type;
int8 fogType;
bool castExtraShadows;
};
static_assert(sizeof(CRegisteredPointLight) == 0x2C, "CRegisteredPointLight: error");
class CPointLights
{
// Probably have to make this public for shadows later
static int16 &NumLights;
static CRegisteredPointLight *aLights; //[NUMPOINTLIGHTS]
public:
enum {
LIGHT_POINT,
LIGHT_DIRECTIONAL,
LIGHT_DARKEN, // no effects at all
// these have only fog, otherwise no difference?
LIGHT_FOGONLY_3,
LIGHT_FOGONLY_4,
};
enum {
FOG_NONE,
FOG_NORMAL, // taken from Foggyness
FOG_ALWAYS
};
static void InitPerFrame(void);
static void AddLight(uint8 type, CVector coors, CVector dir, float radius, float red, float green, float blue, uint8 fogType, bool castExtraShadows);
static float GenerateLightsAffectingObject(CVector *objCoors);
static void RemoveLightsAffectingObject(void);
static void RenderFogEffect(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);

View File

@ -78,7 +78,7 @@ CSprite2d::Delete(void)
}
void
CSprite2d::SetTexture(char *name)
CSprite2d::SetTexture(const char *name)
{
Delete();
if(name)
@ -86,7 +86,7 @@ CSprite2d::SetTexture(char *name)
}
void
CSprite2d::SetTexture(char *name, char *mask)
CSprite2d::SetTexture(const char *name, const char *mask)
{
Delete();
if(name)
@ -468,8 +468,8 @@ STARTPATCHES
InjectHook(0x51EA00, &CSprite2d::Delete, PATCH_JUMP);
InjectHook(0x51F950, &CSprite2d::SetRenderState, PATCH_JUMP);
InjectHook(0x51EA40, (void (CSprite2d::*)(char*))&CSprite2d::SetTexture, PATCH_JUMP);
InjectHook(0x51EA70, (void (CSprite2d::*)(char*,char*))&CSprite2d::SetTexture, PATCH_JUMP);
InjectHook(0x51EA40, (void (CSprite2d::*)(const char*))&CSprite2d::SetTexture, PATCH_JUMP);
InjectHook(0x51EA70, (void (CSprite2d::*)(const char*,const char*))&CSprite2d::SetTexture, PATCH_JUMP);
InjectHook(0x51EAA0, &CSprite2d::SetAddressing, PATCH_JUMP);
InjectHook(0x51EE90, (void (*)(const CRect&, C4, uint32))CSprite2d::SetVertices, PATCH_JUMP);

View File

@ -23,8 +23,8 @@ public:
~CSprite2d(void) { Delete(); };
void Delete(void);
void SetRenderState(void);
void SetTexture(char *name);
void SetTexture(char *name, char *mask);
void SetTexture(const char *name);
void SetTexture(const char *name, const char *mask);
void SetAddressing(RwTextureAddressMode addr);
void Draw(float x, float y, float w, float h, const CRGBA &col);
void Draw(const CRect &rect, const CRGBA &col);