Merge branch 'master' into master
This commit is contained in:
commit
809c81ea9c
@ -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); }
|
||||
|
@ -444,6 +444,7 @@ int m_iModeObbeCamIsInForCar;
|
||||
bool IsPointVisible(const CVector ¢er, const CMatrix *mat);
|
||||
bool IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat);
|
||||
bool IsBoxVisible(RwV3d *box, const CMatrix *mat);
|
||||
int GetLookDirection(void);
|
||||
|
||||
void Fade(float timeout, int16 direction);
|
||||
int GetScreenFadeStatus(void);
|
||||
|
20
src/Text.cpp
20
src/Text.cpp
@ -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);
|
||||
|
12
src/Text.h
12
src/Text.h
@ -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;
|
||||
|
@ -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]; }
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
165
src/main.cpp
165
src/main.cpp
@ -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);
|
||||
|
@ -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){
|
||||
|
32
src/re3.cpp
32
src/re3.cpp
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user