render -> renderer (original name)

This commit is contained in:
Sergeanur
2021-07-15 18:19:32 +03:00
parent 8018e40ebf
commit d0404cbdb7
65 changed files with 6 additions and 6 deletions

93
src/renderer/2dEffect.h Normal file
View File

@ -0,0 +1,93 @@
#pragma once
enum {
EFFECT_LIGHT,
EFFECT_PARTICLE,
EFFECT_ATTRACTOR
};
enum {
LIGHT_ON,
LIGHT_ON_NIGHT,
LIGHT_FLICKER,
LIGHT_FLICKER_NIGHT,
LIGHT_FLASH1,
LIGHT_FLASH1_NIGHT,
LIGHT_FLASH2,
LIGHT_FLASH2_NIGHT,
LIGHT_FLASH3,
LIGHT_FLASH3_NIGHT,
LIGHT_RANDOM_FLICKER,
LIGHT_RANDOM_FLICKER_NIGHT,
LIGHT_SPECIAL,
LIGHT_BRIDGE_FLASH1,
LIGHT_BRIDGE_FLASH2,
};
enum {
ATTRACTORTYPE_ICECREAM,
ATTRACTORTYPE_STARE
};
enum {
LIGHTFLAG_LOSCHECK = 1,
// same order as CPointLights flags, must start at 2
LIGHTFLAG_FOG_NORMAL = 2, // can have light and fog
LIGHTFLAG_FOG_ALWAYS = 4, // fog only
LIGHTFLAG_FOG = (LIGHTFLAG_FOG_NORMAL|LIGHTFLAG_FOG_ALWAYS)
};
class C2dEffect
{
public:
struct Light {
float dist;
float range; // of pointlight
float size;
float shadowSize;
uint8 lightType; // LIGHT_
uint8 roadReflection;
uint8 flareType;
uint8 shadowIntensity;
uint8 flags; // LIGHTFLAG_
RwTexture *corona;
RwTexture *shadow;
};
struct Particle {
int particleType;
CVector dir;
float scale;
};
struct Attractor {
CVector dir;
int8 type;
uint8 probability;
};
CVector pos;
CRGBA col;
uint8 type;
union {
Light light;
Particle particle;
Attractor attractor;
};
C2dEffect(void) {}
void Shutdown(void){
if(type == EFFECT_LIGHT){
if(light.corona)
RwTextureDestroy(light.corona);
#if GTA_VERSION >= GTA3_PC_11
light.corona = nil;
#endif
if(light.shadow)
RwTextureDestroy(light.shadow);
#if GTA_VERSION >= GTA3_PC_11
light.shadow = nil;
#endif
}
}
};
VALIDATE_SIZE(C2dEffect, 0x34);

129
src/renderer/Antennas.cpp Normal file
View File

@ -0,0 +1,129 @@
#include "common.h"
#include "main.h"
#include "Antennas.h"
CAntenna CAntennas::aAntennas[NUMANTENNAS];
void
CAntennas::Init(void)
{
int i;
for(i = 0; i < NUMANTENNAS; i++){
aAntennas[i].active = false;
aAntennas[i].updatedLastFrame = false;
}
}
// Free antennas that aren't used anymore
void
CAntennas::Update(void)
{
int i;
for(i = 0; i < NUMANTENNAS; i++){
if(aAntennas[i].active && !aAntennas[i].updatedLastFrame)
aAntennas[i].active = false;
aAntennas[i].updatedLastFrame = false;
}
}
// Add a new one or update an old one
void
CAntennas::RegisterOne(uint32 id, CVector dir, CVector position, float length)
{
int i, j;
for(i = 0; i < NUMANTENNAS; i++)
if(aAntennas[i].active && aAntennas[i].id == id)
break;
if(i >= NUMANTENNAS){
// not found, register new one
// find empty slot
for(i = 0; i < NUMANTENNAS; i++)
if(!aAntennas[i].active)
break;
// there is space
if(i < NUMANTENNAS){
aAntennas[i].active = true;
aAntennas[i].updatedLastFrame = true;
aAntennas[i].id = id;
aAntennas[i].segmentLength = length/6.0f;
for(j = 0; j < 6; j++){
aAntennas[i].pos[j] = position + dir*j*aAntennas[i].segmentLength;
aAntennas[i].speed[j] = CVector(0.0f, 0.0f, 0.0f);
}
}
}else{
// found, update
aAntennas[i].Update(dir, position);
aAntennas[i].updatedLastFrame = true;
}
}
static RwIm3DVertex vertexbufferA[2];
void
CAntennas::Render(void)
{
int i, j;
PUSH_RENDERGROUP("CAntennas::Render");
for(i = 0; i < NUMANTENNAS; i++){
if(!aAntennas[i].active)
continue;
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
for(j = 0; j < 5; j++){
RwIm3DVertexSetRGBA(&vertexbufferA[0], 200, 200, 200, 100);
RwIm3DVertexSetPos(&vertexbufferA[0],
aAntennas[i].pos[j].x,
aAntennas[i].pos[j].y,
aAntennas[i].pos[j].z);
RwIm3DVertexSetRGBA(&vertexbufferA[1], 200, 200, 200, 100);
RwIm3DVertexSetPos(&vertexbufferA[1],
aAntennas[i].pos[j+1].x,
aAntennas[i].pos[j+1].y,
aAntennas[i].pos[j+1].z);
// LittleTest();
if(RwIm3DTransform(vertexbufferA, 2, nil, 0)){
RwIm3DRenderLine(0, 1);
RwIm3DEnd();
}
}
}
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
POP_RENDERGROUP();
}
void
CAntenna::Update(CVector dir, CVector basepos)
{
int i;
pos[0] = basepos;
pos[1] = basepos + dir*segmentLength;
for(i = 2; i < 6; i++){
CVector basedir = pos[i-1] - pos[i-2];
CVector newdir = pos[i] - pos[i-1] + // drag along
dir*0.1f + // also drag up a bit for stiffness
speed[i]; // and keep moving
newdir.Normalise();
newdir *= segmentLength;
CVector newpos = pos[i-1] + (basedir + newdir)/2.0f;
speed[i] = (newpos - pos[i])*0.9f;
pos[i] = newpos;
}
}

25
src/renderer/Antennas.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
class CAntenna
{
public:
bool active;
bool updatedLastFrame;
uint32 id;
float segmentLength;
CVector pos[6];
CVector speed[6];
void Update(CVector dir, CVector pos);
};
class CAntennas
{
// no need to use game's array
static CAntenna aAntennas[NUMANTENNAS];
public:
static void Init(void);
static void Update(void);
static void RegisterOne(uint32 id, CVector dir, CVector position, float length);
static void Render(void);
};

466
src/renderer/Clouds.cpp Normal file
View File

@ -0,0 +1,466 @@
#include "common.h"
#include "main.h"
#include "Sprite.h"
#include "Sprite2d.h"
#include "General.h"
#include "Coronas.h"
#include "Camera.h"
#include "TxdStore.h"
#include "Weather.h"
#include "Clock.h"
#include "Timer.h"
#include "Timecycle.h"
#include "Renderer.h"
#include "Clouds.h"
#define SMALLSTRIPHEIGHT 4.0f
#define HORIZSTRIPHEIGHT 48.0f
RwTexture *gpCloudTex[5];
float CClouds::CloudRotation;
uint32 CClouds::IndividualRotation;
float CClouds::ms_cameraRoll;
float CClouds::ms_horizonZ;
CRGBA CClouds::ms_colourTop;
CRGBA CClouds::ms_colourBottom;
void
CClouds::Init(void)
{
CTxdStore::PushCurrentTxd();
CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle"));
gpCloudTex[0] = RwTextureRead("cloud1", nil);
gpCloudTex[1] = RwTextureRead("cloud2", nil);
gpCloudTex[2] = RwTextureRead("cloud3", nil);
gpCloudTex[3] = RwTextureRead("cloudhilit", nil);
gpCloudTex[4] = RwTextureRead("cloudmasked", nil);
CTxdStore::PopCurrentTxd();
CloudRotation = 0.0f;
}
void
CClouds::Shutdown(void)
{
RwTextureDestroy(gpCloudTex[0]);
#if GTA_VERSION >= GTA3_PC_11
gpCloudTex[0] = nil;
#endif
RwTextureDestroy(gpCloudTex[1]);
#if GTA_VERSION >= GTA3_PC_11
gpCloudTex[1] = nil;
#endif
RwTextureDestroy(gpCloudTex[2]);
#if GTA_VERSION >= GTA3_PC_11
gpCloudTex[2] = nil;
#endif
RwTextureDestroy(gpCloudTex[3]);
#if GTA_VERSION >= GTA3_PC_11
gpCloudTex[3] = nil;
#endif
RwTextureDestroy(gpCloudTex[4]);
#if GTA_VERSION >= GTA3_PC_11
gpCloudTex[4] = nil;
#endif
}
void
CClouds::Update(void)
{
float s = Sin(TheCamera.Orientation - 0.85f);
#ifdef FIX_BUGS
CloudRotation += CWeather::Wind*s*0.0025f*CTimer::GetTimeStepFix();
IndividualRotation += (CWeather::Wind*CTimer::GetTimeStep() + 0.3f*CTimer::GetTimeStepFix()) * 60.0f;
#else
CloudRotation += CWeather::Wind*s*0.0025f;
IndividualRotation += (CWeather::Wind*CTimer::GetTimeStep() + 0.3f) * 60.0f;
#endif
}
float StarCoorsX[9] = { 0.0f, 0.05f, 0.12f, 0.5f, 0.8f, 0.6f, 0.27f, 0.55f, 0.75f };
float StarCoorsY[9] = { 0.0f, 0.45f, 0.9f, 1.0f, 0.85f, 0.52f, 0.48f, 0.35f, 0.2f };
float StarSizes[9] = { 1.0f, 1.4f, 0.9f, 1.0f, 0.6f, 1.5f, 1.3f, 1.0f, 0.8f };
float LowCloudsX[12] = { 1.0f, 0.7f, 0.0f, -0.7f, -1.0f, -0.7f, 0.0f, 0.7f, 0.8f, -0.8f, 0.4f, -0.4f };
float LowCloudsY[12] = { 0.0f, -0.7f, -1.0f, -0.7f, 0.0f, 0.7f, 1.0f, 0.7f, 0.4f, 0.4f, -0.8f, -0.8f };
float LowCloudsZ[12] = { 0.0f, 1.0f, 0.5f, 0.0f, 1.0f, 0.3f, 0.9f, 0.4f, 1.3f, 1.4f, 1.2f, 1.7f };
float CoorsOffsetX[37] = {
0.0f, 60.0f, 72.0f, 48.0f, 21.0f, 12.0f,
9.0f, -3.0f, -8.4f, -18.0f, -15.0f, -36.0f,
-40.0f, -48.0f, -60.0f, -24.0f, 100.0f, 100.0f,
100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f,
100.0f, 100.0f, -30.0f, -20.0f, 10.0f, 30.0f,
0.0f, -100.0f, -100.0f, -100.0f, -100.0f, -100.0f, -100.0f
};
float CoorsOffsetY[37] = {
100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f,
100.0f, 100.0f, 100.0f, 100.0f, 100.0f, 100.0f,
100.0f, 100.0f, 100.0f, 100.0f, -30.0f, 10.0f,
-25.0f, -5.0f, 28.0f, -10.0f, 10.0f, 0.0f,
15.0f, 40.0f, -100.0f, -100.0f, -100.0f, -100.0f,
-100.0f, -40.0f, -20.0f, 0.0f, 10.0f, 30.0f, 35.0f
};
float CoorsOffsetZ[37] = {
2.0f, 1.0f, 0.0f, 0.3f, 0.7f, 1.4f,
1.7f, 0.24f, 0.7f, 1.3f, 1.6f, 1.0f,
1.2f, 0.3f, 0.7f, 1.4f, 0.0f, 0.1f,
0.5f, 0.4f, 0.55f, 0.75f, 1.0f, 1.4f,
1.7f, 2.0f, 2.0f, 2.3f, 1.9f, 2.4f,
2.0f, 2.0f, 1.5f, 1.2f, 1.7f, 1.5f, 2.1f
};
uint8 BowRed[6] = { 30, 30, 30, 10, 0, 15 };
uint8 BowGreen[6] = { 0, 15, 30, 30, 0, 0 };
uint8 BowBlue[6] = { 0, 0, 0, 10, 30, 30 };
void
CClouds::Render(void)
{
int i;
float szx, szy;
RwV3d screenpos;
RwV3d worldpos;
PUSH_RENDERGROUP("CClouds::Render");
CCoronas::SunBlockedByClouds = false;
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
CSprite::InitSpriteBuffer();
int minute = CClock::GetHours()*60 + CClock::GetMinutes();
RwV3d campos = TheCamera.GetPosition();
// Moon
int moonfadeout = Abs(minute - 180); // fully visible at 3AM
if(moonfadeout < 180){ // fade in/out 3 hours
float coverage = Max(CWeather::Foggyness, CWeather::CloudCoverage);
int brightness = (1.0f - coverage) * (180 - moonfadeout);
RwV3d pos = { 0.0f, -100.0f, 15.0f };
RwV3dAdd(&worldpos, &campos, &pos);
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[2]));
if(CCoronas::bSmallMoon){
szx *= 4.0f;
szy *= 4.0f;
}else{
szx *= 10.0f;
szy *= 10.0f;
}
CSprite::RenderOneXLUSprite(screenpos.x, screenpos.y, screenpos.z,
szx, szy, brightness, brightness, brightness, 255, 1.0f/screenpos.z, 255);
}
}
// The R* logo
int starintens = 0;
if(CClock::GetHours() < 22 && CClock::GetHours() > 5)
starintens = 0;
else if(CClock::GetHours() > 22 || CClock::GetHours() < 5)
starintens = 255;
else if(CClock::GetHours() == 22)
starintens = 255 * CClock::GetMinutes()/60.0f;
else if(CClock::GetHours() == 5)
starintens = 255 * (60 - CClock::GetMinutes())/60.0f;
if(starintens != 0){
float coverage = Max(CWeather::Foggyness, CWeather::CloudCoverage);
int brightness = (1.0f - coverage) * starintens;
// R
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
for(i = 0; i < 11; i++){
RwV3d pos = { 100.0f, 0.0f, 10.0f };
if(i >= 9) pos.x = -pos.x;
RwV3dAdd(&worldpos, &campos, &pos);
worldpos.y -= 90.0f*StarCoorsX[i%9];
worldpos.z += 80.0f*StarCoorsY[i%9];
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
float sz = 0.8f*StarSizes[i%9];
CSprite::RenderBufferedOneXLUSprite(screenpos.x, screenpos.y, screenpos.z,
szx*sz, szy*sz, brightness, brightness, brightness, 255, 1.0f/screenpos.z, 255);
}
}
CSprite::FlushSpriteBuffer();
// *
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
RwV3d pos = { 100.0f, 0.0f, 10.0f };
RwV3dAdd(&worldpos, &campos, &pos);
worldpos.y -= 90.0f;
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
brightness *= (CGeneral::GetRandomNumber()&127) / 640.0f + 0.5f;
CSprite::RenderOneXLUSprite(screenpos.x, screenpos.y, screenpos.z,
szx*5.0f, szy*5.0f, brightness, brightness, brightness, 255, 1.0f/screenpos.z, 255);
}
}
// Low clouds
float lowcloudintensity = 1.0f - Max(CWeather::Foggyness, CWeather::CloudCoverage);
int r = CTimeCycle::GetLowCloudsRed() * lowcloudintensity;
int g = CTimeCycle::GetLowCloudsGreen() * lowcloudintensity;
int b = CTimeCycle::GetLowCloudsBlue() * lowcloudintensity;
for(int cloudtype = 0; cloudtype < 3; cloudtype++){
for(i = cloudtype; i < 12; i += 3){
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCloudTex[cloudtype]));
RwV3d pos = { 800.0f*LowCloudsX[i], 800.0f*LowCloudsY[i], 60.0f*LowCloudsZ[i] };
worldpos.x = campos.x + pos.x;
worldpos.y = campos.y + pos.y;
worldpos.z = 40.0f + pos.z;
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false))
CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(screenpos.x, screenpos.y, screenpos.z,
szx*320.0f, szy*40.0f, r, g, b, 255, 1.0f/screenpos.z, ms_cameraRoll, 255);
}
CSprite::FlushSpriteBuffer();
}
// Fluffy clouds
float rot_sin = Sin(CloudRotation);
float rot_cos = Cos(CloudRotation);
int fluffyalpha = 160 * (1.0f - CWeather::Foggyness);
if(fluffyalpha != 0){
static bool bCloudOnScreen[37];
float hilight;
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCloudTex[4]));
for(i = 0; i < 37; i++){
RwV3d pos = { 2.0f*CoorsOffsetX[i], 2.0f*CoorsOffsetY[i], 40.0f*CoorsOffsetZ[i] + 40.0f };
worldpos.x = pos.x*rot_cos + pos.y*rot_sin + campos.x;
worldpos.y = pos.x*rot_sin - pos.y*rot_cos + campos.y;
worldpos.z = pos.z;
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
float sundist = Sqrt(sq(screenpos.x-CCoronas::SunScreenX) + sq(screenpos.y-CCoronas::SunScreenY));
int tr = CTimeCycle::GetFluffyCloudsTopRed();
int tg = CTimeCycle::GetFluffyCloudsTopGreen();
int tb = CTimeCycle::GetFluffyCloudsTopBlue();
int br = CTimeCycle::GetFluffyCloudsBottomRed();
int bg = CTimeCycle::GetFluffyCloudsBottomGreen();
int bb = CTimeCycle::GetFluffyCloudsBottomBlue();
if(sundist < SCREEN_WIDTH/2){
hilight = (1.0f - Max(CWeather::Foggyness, CWeather::CloudCoverage)) * (1.0f - sundist/(SCREEN_WIDTH/2));
tr = tr*(1.0f-hilight) + 255*hilight;
tg = tg*(1.0f-hilight) + 190*hilight;
tb = tb*(1.0f-hilight) + 190*hilight;
br = br*(1.0f-hilight) + 255*hilight;
bg = bg*(1.0f-hilight) + 190*hilight;
bb = bb*(1.0f-hilight) + 190*hilight;
if(sundist < SCREEN_WIDTH/10)
CCoronas::SunBlockedByClouds = true;
}else
hilight = 0.0f;
CSprite::RenderBufferedOneXLUSprite_Rotate_2Colours(screenpos.x, screenpos.y, screenpos.z,
szx*55.0f, szy*55.0f,
tr, tg, tb, br, bg, bb, 0.0f, -1.0f,
1.0f/screenpos.z,
(uint16)IndividualRotation/65336.0f * 6.28f + ms_cameraRoll,
fluffyalpha);
bCloudOnScreen[i] = true;
}else
bCloudOnScreen[i] = false;
}
CSprite::FlushSpriteBuffer();
// Highlights
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCloudTex[3]));
for(i = 0; i < 37; i++){
RwV3d pos = { 2.0f*CoorsOffsetX[i], 2.0f*CoorsOffsetY[i], 40.0f*CoorsOffsetZ[i] + 40.0f };
worldpos.x = pos.x*rot_cos + pos.y*rot_sin + campos.x;
worldpos.y = pos.x*rot_sin - pos.y*rot_cos + campos.y;
worldpos.z = pos.z;
if(bCloudOnScreen[i] && CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
// BUG: this is stupid....would have to do this for each cloud individually
if(hilight > 0.0f){
CSprite::RenderBufferedOneXLUSprite_Rotate_Aspect(screenpos.x, screenpos.y, screenpos.z,
szx*30.0f, szy*30.0f,
200*hilight, 0, 0, 255, 1.0f/screenpos.z,
1.7f - CGeneral::GetATanOfXY(screenpos.x-CCoronas::SunScreenX, screenpos.y-CCoronas::SunScreenY) + CClouds::ms_cameraRoll, 255);
}
}
}
CSprite::FlushSpriteBuffer();
}
// Rainbow
if(CWeather::Rainbow != 0.0f){
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
for(i = 0; i < 6; i++){
RwV3d pos = { i*1.5f, 100.0f, 5.0f };
RwV3dAdd(&worldpos, &campos, &pos);
if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false))
CSprite::RenderBufferedOneXLUSprite(screenpos.x, screenpos.y, screenpos.z,
2.0f*szx, 50.0*szy,
BowRed[i]*CWeather::Rainbow, BowGreen[i]*CWeather::Rainbow, BowBlue[i]*CWeather::Rainbow,
255, 1.0f/screenpos.z, 255);
}
CSprite::FlushSpriteBuffer();
}
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
POP_RENDERGROUP();
}
bool
UseDarkBackground(void)
{
return TheCamera.GetForward().z < -0.9f || gbShowCollisionPolys;
}
void
CClouds::RenderBackground(int16 topred, int16 topgreen, int16 topblue,
int16 botred, int16 botgreen, int16 botblue, int16 alpha)
{
PUSH_RENDERGROUP("CClouds::RenderBackground");
CVector left = TheCamera.GetRight();
float c = left.Magnitude2D();
if(c > 1.0f)
c = 1.0f;
ms_cameraRoll = Acos(c);
if(left.z < 0.0f)
ms_cameraRoll = -ms_cameraRoll;
if(UseDarkBackground()){
ms_colourTop.r = 50;
ms_colourTop.g = 50;
ms_colourTop.b = 50;
ms_colourTop.a = 255;
if(gbShowCollisionPolys){
if(CTimer::GetFrameCounter() & 1){
ms_colourTop.r = 0;
ms_colourTop.g = 0;
ms_colourTop.b = 0;
}else{
ms_colourTop.r = 255;
ms_colourTop.g = 255;
ms_colourTop.b = 255;
}
}
ms_colourBottom = ms_colourTop;
CRect r(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
CSprite2d::DrawRect(r, ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
}else{
ms_horizonZ = CSprite::CalcHorizonCoors();
// Draw top/bottom gradient
float gradheight = SCREEN_HEIGHT/2.0f;
float topedge = ms_horizonZ - gradheight;
float botpos, toppos;
if(ms_horizonZ > 0.0f && topedge < SCREEN_HEIGHT){
ms_colourTop.r = topred;
ms_colourTop.g = topgreen;
ms_colourTop.b = topblue;
ms_colourTop.a = alpha;
ms_colourBottom.r = botred;
ms_colourBottom.g = botgreen;
ms_colourBottom.b = botblue;
ms_colourBottom.a = alpha;
if(ms_horizonZ < SCREEN_HEIGHT)
botpos = ms_horizonZ;
else{
float f = (ms_horizonZ - SCREEN_HEIGHT)/gradheight;
ms_colourBottom.r = topred*f + (1.0f-f)*botred;
ms_colourBottom.g = topgreen*f + (1.0f-f)*botgreen;
ms_colourBottom.b = topblue*f + (1.0f-f)*botblue;
botpos = SCREEN_HEIGHT;
}
if(topedge >= 0.0f)
toppos = topedge;
else{
float f = (0.0f - topedge)/gradheight;
ms_colourTop.r = botred*f + (1.0f-f)*topred;
ms_colourTop.g = botgreen*f + (1.0f-f)*topgreen;
ms_colourTop.b = botblue*f + (1.0f-f)*topblue;
toppos = 0.0f;
}
CSprite2d::DrawRect(CRect(0, toppos, SCREEN_WIDTH, botpos),
ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
}
// draw the small stripe (whatever it's supposed to be)
if(ms_horizonZ > -SMALLSTRIPHEIGHT && ms_horizonZ < SCREEN_HEIGHT){
// Same colour as fog
ms_colourTop.r = (topred + 2 * botred) / 3;
ms_colourTop.g = (topgreen + 2 * botgreen) / 3;
ms_colourTop.b = (topblue + 2 * botblue) / 3;
CSprite2d::DrawRect(CRect(0, ms_horizonZ, SCREEN_WIDTH, ms_horizonZ+SMALLSTRIPHEIGHT),
ms_colourTop, ms_colourTop, ms_colourTop, ms_colourTop);
}
// Only top
if(topedge > 0.0f){
ms_colourTop.r = topred;
ms_colourTop.g = topgreen;
ms_colourTop.b = topblue;
ms_colourTop.a = alpha;
ms_colourBottom.r = topred;
ms_colourBottom.g = topgreen;
ms_colourBottom.b = topblue;
ms_colourBottom.a = alpha;
botpos = Min(SCREEN_HEIGHT, topedge);
CSprite2d::DrawRect(CRect(0, 0, SCREEN_WIDTH, botpos),
ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
}
// Set both to fog colour for RenderHorizon
ms_colourTop.r = (topred + 2 * botred) / 3;
ms_colourTop.g = (topgreen + 2 * botgreen) / 3;
ms_colourTop.b = (topblue + 2 * botblue) / 3;
ms_colourBottom.r = (topred + 2 * botred) / 3;
ms_colourBottom.g = (topgreen + 2 * botgreen) / 3;
ms_colourBottom.b = (topblue + 2 * botblue) / 3;
}
POP_RENDERGROUP();
}
void
CClouds::RenderHorizon(void)
{
if(UseDarkBackground())
return;
ms_colourBottom.a = 230;
ms_colourTop.a = 80;
if(ms_horizonZ > SCREEN_HEIGHT)
return;
PUSH_RENDERGROUP("CClouds::RenderHorizon");
float z1 = Min(ms_horizonZ + SMALLSTRIPHEIGHT, SCREEN_HEIGHT);
CSprite2d::DrawRectXLU(CRect(0, ms_horizonZ, SCREEN_WIDTH, z1),
ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
// This is just weird
float a = SCREEN_HEIGHT/400.0f * HORIZSTRIPHEIGHT +
SCREEN_HEIGHT/300.0f * Max(TheCamera.GetPosition().z, 0.0f);
float b = TheCamera.GetUp().z < 0.0f ?
SCREEN_HEIGHT :
SCREEN_HEIGHT * Abs(TheCamera.GetRight().z);
float z2 = z1 + (a + b)*TheCamera.LODDistMultiplier;
z2 = Min(z2, SCREEN_HEIGHT);
CSprite2d::DrawRect(CRect(0, z1, SCREEN_WIDTH, z2),
ms_colourBottom, ms_colourBottom, ms_colourTop, ms_colourTop);
POP_RENDERGROUP();
}

21
src/renderer/Clouds.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
class CClouds
{
public:
static float CloudRotation;
static uint32 IndividualRotation;
static float ms_cameraRoll;
static float ms_horizonZ;
static CRGBA ms_colourTop;
static CRGBA ms_colourBottom;
static void Init(void);
static void Shutdown(void);
static void Update(void);
static void Render(void);
static void RenderBackground(int16 topred, int16 topgreen, int16 topblue,
int16 botred, int16 botgreen, int16 botblue, int16 alpha);
static void RenderHorizon(void);
};

96
src/renderer/Console.cpp Normal file
View File

@ -0,0 +1,96 @@
#include "common.h"
#include <stdarg.h>
#include "Console.h"
#include "Font.h"
#include "Timer.h"
#define CONSOLE_X_POS (30.0f)
#define CONSOLE_Y_POS (10.0f)
#define CONSOLE_LINE_HEIGHT (12.0f)
CConsole TheConsole;
void
CConsole::AddLine(char *s, uint8 r, uint8 g, uint8 b)
{
char tempstr[MAX_STR_LEN+1];
while (strlen(s) > MAX_STR_LEN) {
strncpy(tempstr, s, MAX_STR_LEN);
tempstr[MAX_STR_LEN-1] = '\0';
s += MAX_STR_LEN - 1;
AddOneLine(tempstr, r, g, b);
}
AddOneLine(s, r, g, b);
}
void
CConsole::AddOneLine(char *s, uint8 r, uint8 g, uint8 b)
{
int32 StrIndex = (m_nLineCount + m_nCurrentLine) % MAX_LINES;
for (int32 i = 0; i < MAX_STR_LEN; i++) {
Buffers[StrIndex][i] = s[i];
if (s[i] == '\0') break;
}
uint8 _strNum1 = m_nLineCount;
if (_strNum1 < MAX_LINES)
_strNum1++;
m_aTimer[StrIndex] = CTimer::GetTimeInMilliseconds();
Buffers[StrIndex][MAX_STR_LEN-1] = '\0';
m_aRed[StrIndex] = r;
m_aGreen[StrIndex] = g;
m_aBlue[StrIndex] = b;
if (_strNum1 >= MAX_LINES)
m_nCurrentLine = (m_nCurrentLine + 1) % MAX_LINES;
else
m_nLineCount = _strNum1;
}
void
CConsole::Display()
{
CFont::SetPropOn();
CFont::SetBackgroundOff();
CFont::SetScale(0.6f, 0.6f);
CFont::SetCentreOff();
CFont::SetRightJustifyOff();
CFont::SetJustifyOn();
CFont::SetRightJustifyWrap(0.0f);
CFont::SetBackGroundOnlyTextOff();
CFont::SetFontStyle(FONT_BANK);
#ifndef FIX_BUGS
CFont::SetPropOff(); // not sure why this is here anyway
#endif
CFont::SetWrapx(RsGlobal.width);
while (m_nLineCount != 0 && CTimer::GetTimeInMilliseconds() - m_aTimer[m_nCurrentLine] > 20000) {
m_nLineCount--;
m_nCurrentLine = (m_nCurrentLine + 1) % MAX_LINES;
}
for (int16 i = 0; i < m_nLineCount; i++) {
int16 line = (i + m_nCurrentLine) % MAX_LINES;
CFont::SetColor(CRGBA(0, 0, 0, 200));
CFont::PrintString(CONSOLE_X_POS + 1.0f, CONSOLE_Y_POS + 1.0f + i * CONSOLE_LINE_HEIGHT, Buffers[line]);
CFont::SetColor(CRGBA(m_aRed[line], m_aGreen[line], m_aBlue[line], 200));
CFont::PrintString(CONSOLE_X_POS, CONSOLE_Y_POS + i * CONSOLE_LINE_HEIGHT, Buffers[line]);
}
}
void
cprintf(char* format, ...)
{
char s[256];
va_list vl1, vl2;
va_start(vl1, format);
va_copy(vl2, vl1);
vsprintf(s, format, vl1);
TheConsole.AddLine(s, 255, 255, 128);
}

27
src/renderer/Console.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
class CConsole
{
enum
{
MAX_LINES = 8, // BUG? only shows 7
MAX_STR_LEN = 40,
};
uint8 m_nLineCount;
uint8 m_nCurrentLine;
wchar Buffers[MAX_LINES][MAX_STR_LEN];
uint32 m_aTimer[MAX_LINES];
uint8 m_aRed[MAX_LINES];
uint8 m_aGreen[MAX_LINES];
uint8 m_aBlue[MAX_LINES];
public:
void AddLine(char *s, uint8 r, uint8 g, uint8 b);
void AddOneLine(char *s, uint8 r, uint8 g, uint8 b);
void Display();
void Init() { m_nCurrentLine = 0; m_nLineCount = 0; }
};
extern CConsole TheConsole;
void cprintf(char*, ...);

779
src/renderer/Coronas.cpp Normal file
View File

@ -0,0 +1,779 @@
#include "common.h"
#include "main.h"
#include "General.h"
#include "Entity.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"
#include "PointLights.h"
#include "Shadows.h"
#include "Clock.h"
#include "Bridge.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[9] = { nil, nil, nil, nil, nil, nil, nil, nil, nil };
float CCoronas::LightsMult = 1.0f;
float CCoronas::SunScreenX;
float CCoronas::SunScreenY;
bool CCoronas::bSmallMoon;
bool CCoronas::SunBlockedByClouds;
int CCoronas::bChangeBrightnessImmediately;
CRegisteredCorona CCoronas::aCoronas[NUMCORONAS];
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(uint32 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];
void
CCoronas::Render(void)
{
int i, j;
int screenw, screenh;
PUSH_RENDERGROUP("CCoronas::Render");
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 = true;
aCoronas[i].sightClear = false;
}else{
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(Abs(aCoronas[i].prevX[0] - aCoronas[i].prevX[1]) > 50.0f ||
Abs(aCoronas[i].prevY[0] - aCoronas[i].prevY[1]) > 50.0f)
aCoronas[i].hasValue[0] = false;
}
}
if(aCoronas[i].fadeAlpha && 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);
}
}
}
}
}
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)
continue;
for(j = 0; j < 5; j++){
if(!aCoronas[i].hasValue[j] || !aCoronas[i].hasValue[j+1])
continue;
int alpha1 = (float)(6 - j) / 6 * 128;
int alpha2 = (float)(6 - (j+1)) / 6 * 128;
RwIm2DVertexSetScreenX(&vertexbufferX[0], aCoronas[i].prevX[j]);
RwIm2DVertexSetScreenY(&vertexbufferX[0], aCoronas[i].prevY[j]);
RwIm2DVertexSetIntRGBA(&vertexbufferX[0], aCoronas[i].prevRed[j] * alpha1 / 256, aCoronas[i].prevGreen[j] * alpha1 / 256, aCoronas[i].prevBlue[j] * alpha1 / 256, 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] * alpha2 / 256, aCoronas[i].prevGreen[j+1] * alpha2 / 256, aCoronas[i].prevBlue[j+1] * alpha2 / 256, 255);
#ifdef FIX_BUGS
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));
#endif
RwIm2DRenderLine(vertexbufferX, 2, 0, 1);
}
}
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
POP_RENDERGROUP();
}
void
CCoronas::RenderReflections(void)
{
int i;
CColPoint point;
CEntity *entity;
if(CWeather::WetRoads > 0.0f){
PUSH_RENDERGROUP("CCoronas::RenderReflections");
#ifdef FIX_BUGS
CSprite::InitSpriteBuffer();
#endif
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 ||
aCoronas[i].reflection == 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;
}
}
// Don't draw if reflection is too high
if(aCoronas[i].renderReflection && aCoronas[i].heightAboveRoad < 20.0f){
// 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, 55.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);
float heightFade = (20.0f - aCoronas[i].heightAboveRoad)/20.0f;
int intensity = distanceFade*heightFade * 230.0 * CWeather::WetRoads;
CSprite::RenderBufferedOneXLUSprite(
#ifdef FIX_BUGS
spriteCoors.x, spriteCoors.y, spriteCoors.z,
#else
spriteCoors.x, spriteCoors.y, RwIm2DGetNearScreenZ(),
#endif
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);
POP_RENDERGROUP();
}else{
for(i = 0; i < NUMCORONAS; i++)
aCoronas[i].renderReflection = false;
}
}
void
CCoronas::DoSunAndMoon(void)
{
// yeah, moon is done somewhere else....
CVector sunCoors = CTimeCycle::GetSunDirection();
sunCoors *= 150.0f;
sunCoors += TheCamera.GetPosition();
if(CTimeCycle::GetSunDirection().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::GetSunDirection().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;
}
void
CEntity::ProcessLightsForEntity(void)
{
int i, n;
C2dEffect *effect;
CVector pos;
bool lightOn, lightFlickering;
uint32 flashTimer1, flashTimer2, flashTimer3;
if(bRenderDamaged || !bIsVisible || GetUp().z < 0.96f)
return;
flashTimer1 = 0;
flashTimer2 = 0;
flashTimer3 = 0;
n = CModelInfo::GetModelInfo(GetModelIndex())->GetNum2dEffects();
for(i = 0; i < n; i++, flashTimer1 += 0x80, flashTimer2 += 0x100, flashTimer3 += 0x200){
effect = CModelInfo::GetModelInfo(GetModelIndex())->Get2dEffect(i);
if(effect->type != EFFECT_LIGHT)
continue;
pos = GetMatrix() * effect->pos;
lightOn = false;
lightFlickering = false;
switch(effect->light.lightType){
case LIGHT_ON:
lightOn = true;
break;
case LIGHT_ON_NIGHT:
if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
lightOn = true;
break;
case LIGHT_FLICKER:
if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed) & 0x60)
lightOn = true;
else
lightFlickering = true;
if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed) & 3)
lightOn = true;
break;
case LIGHT_FLICKER_NIGHT:
if(CClock::GetHours() > 18 || CClock::GetHours() < 7 || CWeather::WetRoads > 0.5f){
if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed) & 0x60)
lightOn = true;
else
lightFlickering = true;
if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed) & 3)
lightOn = true;
}
break;
case LIGHT_FLASH1:
if((CTimer::GetTimeInMilliseconds() + flashTimer1) & 0x200)
lightOn = true;
break;
case LIGHT_FLASH1_NIGHT:
if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
if((CTimer::GetTimeInMilliseconds() + flashTimer1) & 0x200)
lightOn = true;
break;
case LIGHT_FLASH2:
if((CTimer::GetTimeInMilliseconds() + flashTimer2) & 0x400)
lightOn = true;
break;
case LIGHT_FLASH2_NIGHT:
if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
if((CTimer::GetTimeInMilliseconds() + flashTimer2) & 0x400)
lightOn = true;
break;
case LIGHT_FLASH3:
if((CTimer::GetTimeInMilliseconds() + flashTimer3) & 0x800)
lightOn = true;
break;
case LIGHT_FLASH3_NIGHT:
if(CClock::GetHours() > 18 || CClock::GetHours() < 7)
if((CTimer::GetTimeInMilliseconds() + flashTimer3) & 0x800)
lightOn = true;
break;
case LIGHT_RANDOM_FLICKER:
if(m_randomSeed > 16)
lightOn = true;
else{
if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed*8) & 0x60)
lightOn = true;
else
lightFlickering = true;
if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed*8) & 3)
lightOn = true;
}
break;
case LIGHT_RANDOM_FLICKER_NIGHT:
if(CClock::GetHours() > 18 || CClock::GetHours() < 7){
if(m_randomSeed > 16)
lightOn = true;
else{
if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed*8) & 0x60)
lightOn = true;
else
lightFlickering = true;
if((CTimer::GetTimeInMilliseconds()>>11 ^ m_randomSeed*8) & 3)
lightOn = true;
}
}
break;
case LIGHT_BRIDGE_FLASH1:
if(CBridge::ShouldLightsBeFlashing() && CTimer::GetTimeInMilliseconds() & 0x200)
lightOn = true;
break;
case LIGHT_BRIDGE_FLASH2:
if(CBridge::ShouldLightsBeFlashing() && (CTimer::GetTimeInMilliseconds() & 0x1FF) < 60)
lightOn = true;
break;
}
// Corona
if(lightOn)
CCoronas::RegisterCorona((uintptr)this + i,
effect->col.r, effect->col.g, effect->col.b, 255,
pos, effect->light.size, effect->light.dist,
effect->light.corona, effect->light.flareType, effect->light.roadReflection,
effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f);
else if(lightFlickering)
CCoronas::RegisterCorona((uintptr)this + i,
0, 0, 0, 255,
pos, effect->light.size, effect->light.dist,
effect->light.corona, effect->light.flareType, effect->light.roadReflection,
effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f);
// Pointlight
if(effect->light.flags & LIGHTFLAG_FOG_ALWAYS){
CPointLights::AddLight(CPointLights::LIGHT_FOGONLY_ALWAYS,
pos, CVector(0.0f, 0.0f, 0.0f),
effect->light.range,
effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f,
CPointLights::FOG_ALWAYS, true);
}else if(effect->light.flags & LIGHTFLAG_FOG_NORMAL && lightOn && effect->light.range == 0.0f){
CPointLights::AddLight(CPointLights::LIGHT_FOGONLY,
pos, CVector(0.0f, 0.0f, 0.0f),
effect->light.range,
effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f,
CPointLights::FOG_NORMAL, true);
}else if(lightOn && effect->light.range != 0.0f){
if(effect->col.r == 0 && effect->col.g == 0 && effect->col.b == 0){
CPointLights::AddLight(CPointLights::LIGHT_POINT,
pos, CVector(0.0f, 0.0f, 0.0f),
effect->light.range,
0.0f, 0.0f, 0.0f,
CPointLights::FOG_NONE, true);
}else{
CPointLights::AddLight(CPointLights::LIGHT_POINT,
pos, CVector(0.0f, 0.0f, 0.0f),
effect->light.range,
effect->col.r*CTimeCycle::GetSpriteBrightness()/255.0f,
effect->col.g*CTimeCycle::GetSpriteBrightness()/255.0f,
effect->col.b*CTimeCycle::GetSpriteBrightness()/255.0f,
// half-useless because LIGHTFLAG_FOG_ALWAYS can't be on
(effect->light.flags & LIGHTFLAG_FOG) >> 1,
true);
}
}
// Light shadow
if(effect->light.shadowSize != 0.0f){
if(lightOn){
CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_ADDITIVE,
effect->light.shadow, &pos,
effect->light.shadowSize, 0.0f,
0.0f, -effect->light.shadowSize,
128,
effect->col.r*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f,
effect->col.g*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f,
effect->col.b*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f,
15.0f, 1.0f, 40.0f, false, 0.0f);
}else if(lightFlickering){
CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_ADDITIVE,
effect->light.shadow, &pos,
effect->light.shadowSize, 0.0f,
0.0f, -effect->light.shadowSize,
0, 0.0f, 0.0f, 0.0f,
15.0f, 1.0f, 40.0f, false, 0.0f);
}
}
}
}

101
src/renderer/Coronas.h Normal file
View File

@ -0,0 +1,101 @@
#pragma once
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);
};
VALIDATE_SIZE(CRegisteredCorona, 0x80);
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(uint32 id, const CVector &coors, float drawDist, float someAngle);
static void Render(void);
static void RenderReflections(void);
static void DoSunAndMoon(void);
};

518
src/renderer/Credits.cpp Normal file
View File

@ -0,0 +1,518 @@
#include "common.h"
#include "Timer.h"
#include "Font.h"
#include "Frontend.h"
#include "RwHelper.h"
#include "Camera.h"
#include "Text.h"
#include "Credits.h"
bool CCredits::bCreditsGoing;
uint32 CCredits::CreditsStartTime;
void
CCredits::Init(void)
{
Stop();
}
void
CCredits::Start(void)
{
bCreditsGoing = true;
CreditsStartTime = CTimer::GetTimeInMilliseconds();
}
void
CCredits::Stop(void)
{
bCreditsGoing = false;
}
void
CCredits::PrintCreditSpace(float space, uint32 &line)
{
line += space * 25.0f;
}
void
CCredits::PrintCreditText(float scaleX, float scaleY, wchar *text, uint32 &lineoffset, float scrolloffset)
{
#ifdef FIX_BUGS
float start = DEFAULT_SCREEN_HEIGHT + 50.0f;
#else
float start = SCREEN_HEIGHT + 50.0f;
#endif
float y = lineoffset + start - scrolloffset;
if(y > -50.0f && y < start){
#ifdef FIX_BUGS
CFont::SetScale(SCREEN_SCALE_X(scaleX), SCREEN_SCALE_Y(scaleY));
CFont::PrintString(SCREEN_WIDTH/2.0f, SCREEN_SCALE_Y(y), (uint16*)text);
#else
CFont::SetScale(scaleX, scaleY);
CFont::PrintString(SCREEN_WIDTH/2.0f, y, (uint16*)text);
#endif
}
lineoffset += scaleY*25.0f;
}
void
CCredits::Render(void)
{
uint32 lineoffset;
float scrolloffset;
if(!bCreditsGoing || FrontEndMenuManager.m_bMenuActive)
return;
DefinedState();
lineoffset = 0;
scrolloffset = (CTimer::GetTimeInMilliseconds() - CreditsStartTime) / 24.0f;
CFont::SetJustifyOff();
CFont::SetBackgroundOff();
#ifdef FIX_BUGS
CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - 20));
#else
CFont::SetCentreSize(SCREEN_WIDTH - 20);
#endif
CFont::SetCentreOn();
CFont::SetPropOn();
CFont::SetColor(CRGBA(220, 220, 220, 220));
CFont::SetFontStyle(FONT_HEADING);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED002"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED003"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED004"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED005"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED006"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED007"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED008"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED009"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED010"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED011"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED012"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED013"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED014"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED015"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED016"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED017"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED018"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED019"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED020"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED021"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED022"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED245"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED023"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED024"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED025"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED026"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED027"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED028"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED257"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED029"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED030"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED031"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED032"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED033"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED244"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED034"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED035"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED247"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED036"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED037"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED038"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED039"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED040"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED041"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED042"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED043"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED044"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED045"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED046"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED047"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED048"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED049"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED050"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRD050A"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED051"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED052"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED053"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED054"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED055"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED056"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED248"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED249"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED250"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED251"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED252"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED253"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED057"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED058"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED059"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED254"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED255"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED060"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED061"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED062"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED063"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED064"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED065"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED066"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED067"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED068"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED069"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED070"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED071"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED072"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED073"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED074"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED075"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED076"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED077"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED078"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED079"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED080"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED081"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED082"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED083"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED084"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED242"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED259"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED260"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED261"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED262"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED085"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED086"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED087"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED088"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED089"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED090"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED091"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED094"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED095"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED096"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED097"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED098"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED099"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED263"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED264"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED265"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED267"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED270"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED266"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED100"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED101"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED102"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED103"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED104"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED105"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED106"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED268"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED269"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED107"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED108"), lineoffset, scrolloffset);
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED109"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED110"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED111"), lineoffset, scrolloffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED112"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED113"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED114"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED115"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED116"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED117"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED118"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED119"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED120"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED121"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED122"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED123"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED124"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED125"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED126"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED127"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED128"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED129"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED130"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED131"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED132"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED133"), lineoffset, scrolloffset);
if(CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_ITALIAN)
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED134"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED135"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED136"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRD136A"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED137"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRD137A"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED138"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRD138A"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRD138B"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED139"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.7f, 1.0f, TheText.Get("CRED140"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRD140A"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRD140B"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRD140C"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRD140D"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRD140E"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED141"), lineoffset, scrolloffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED142"), lineoffset, scrolloffset);
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED143"), lineoffset, scrolloffset);
PrintCreditSpace(1.0f, lineoffset);
PrintCreditText(1.0f, 1.0f, TheText.Get("CRED144"), lineoffset, scrolloffset);
PrintCreditSpace(1.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED145"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED146"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED147"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED148"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED149"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED150"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED151"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED152"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED153"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED154"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED155"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED156"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED157"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED158"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED159"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED160"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED161"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED162"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED163"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED164"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED165"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED166"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED167"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED168"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED169"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED170"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED171"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED172"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED173"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED174"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED175"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED176"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED177"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED178"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED179"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED180"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED181"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED182"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED183"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED184"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED185"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED186"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED187"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED188"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED189"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED190"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED191"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED192"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED193"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED194"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED195"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED196"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED197"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED198"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED199"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED200"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED201"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED202"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED203"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED204"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED205"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED206"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED207"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED208"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED209"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED210"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED211"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED212"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED213"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED214"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED215"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED216"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED241"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED217"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED218"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRD218A"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRD218B"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED219"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED220"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED221"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED222"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED223"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED224"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED225"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED226"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED227"), lineoffset, scrolloffset);
PrintCreditSpace(1.5f, lineoffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED228"), lineoffset, scrolloffset);
PrintCreditText(1.7f, 1.7f, TheText.Get("CRED229"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditText(1.4f, 0.82f, TheText.Get("CRED230"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED231"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED232"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED233"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED234"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED235"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED236"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED237"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED238"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED239"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED240"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("LITTLE"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("NICK"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED243"), lineoffset, scrolloffset);
PrintCreditText(1.4f, 1.4f, TheText.Get("CRED244"), lineoffset, scrolloffset);
PrintCreditSpace(2.0f, lineoffset);
PrintCreditSpace(2.0f, lineoffset);
CFont::DrawFonts();
if(TheCamera.m_WideScreenOn)
TheCamera.DrawBordersForWideScreen();
#ifdef FIX_BUGS
if(lineoffset + DEFAULT_SCREEN_HEIGHT - scrolloffset < -10.0f)
#else
if(lineoffset + SCREEN_HEIGHT - scrolloffset < -10.0f)
#endif
{
bCreditsGoing = false;
}
}
bool CCredits::AreCreditsDone(void)
{
return !bCreditsGoing;
}

15
src/renderer/Credits.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
class CCredits
{
static bool bCreditsGoing;
static uint32 CreditsStartTime;
public:
static void Init(void);
static void Start(void);
static void Stop(void);
static bool AreCreditsDone(void);
static void Render(void);
static void PrintCreditSpace(float space, uint32 &line);
static void PrintCreditText(float scaleX, float scaleY, wchar *text, uint32 &lineoffset, float scrolloffset);
};

95
src/renderer/Draw.cpp Normal file
View File

@ -0,0 +1,95 @@
#include "common.h"
#include "Draw.h"
#include "Frontend.h"
#include "Camera.h"
#include "CutsceneMgr.h"
#ifdef ASPECT_RATIO_SCALE
float CDraw::ms_fAspectRatio = DEFAULT_ASPECT_RATIO;
float CDraw::ms_fScaledFOV = 45.0f;
#endif
float CDraw::ms_fNearClipZ;
float CDraw::ms_fFarClipZ;
float CDraw::ms_fFOV = 45.0f;
float CDraw::ms_fLODDistance;
uint8 CDraw::FadeValue;
uint8 CDraw::FadeRed;
uint8 CDraw::FadeGreen;
uint8 CDraw::FadeBlue;
#ifdef PROPER_SCALING
bool CDraw::ms_bProperScaling = true;
#endif
#ifdef FIX_RADAR
bool CDraw::ms_bFixRadar = true;
#endif
#ifdef FIX_SPRITES
bool CDraw::ms_bFixSprites = true;
#endif
float
CDraw::FindAspectRatio(void)
{
#ifndef ASPECT_RATIO_SCALE
if(FrontEndMenuManager.m_PrefsUseWideScreen)
return 16.0f/9.0f;
else
return 4.0f/3.0f;
#else
switch (FrontEndMenuManager.m_PrefsUseWideScreen) {
case AR_AUTO:
return SCREEN_WIDTH / SCREEN_HEIGHT;
default:
case AR_4_3:
return 4.0f / 3.0f;
case AR_5_4:
return 5.0f / 4.0f;
case AR_16_10:
return 16.0f / 10.0f;
case AR_16_9:
return 16.0f / 9.0f;
case AR_21_9:
return 21.0f / 9.0f;
};
#endif
}
#ifdef ASPECT_RATIO_SCALE
// convert a 4:3 hFOV to vFOV,
// then convert that vFOV to hFOV for our aspect ratio,
// i.e. HOR+
float
CDraw::ConvertFOV(float hfov)
{
// => tan(hFOV/2) = tan(vFOV/2)*aspectRatio
// => tan(vFOV/2) = tan(hFOV/2)/aspectRatio
float ar1 = DEFAULT_ASPECT_RATIO;
float ar2 = GetAspectRatio();
hfov = DEGTORAD(hfov);
float vfov = Atan(tan(hfov/2) / ar1) *2;
hfov = Atan(tan(vfov/2) * ar2) *2;
return RADTODEG(hfov);
}
#endif
void
CDraw::SetFOV(float fov)
{
#ifdef ASPECT_RATIO_SCALE
if (!CCutsceneMgr::IsRunning())
ms_fScaledFOV = ConvertFOV(fov);
else
ms_fScaledFOV = fov;
#endif
ms_fFOV = fov;
}
#ifdef PROPER_SCALING
float CDraw::ScaleY(float y)
{
return ms_bProperScaling ? y : y * ((float)DEFAULT_SCREEN_HEIGHT/SCREEN_HEIGHT_NTSC);
}
#endif

73
src/renderer/Draw.h Normal file
View File

@ -0,0 +1,73 @@
#pragma once
enum eAspectRatio
{
// Make sure these work the same as FrontEndMenuManager.m_PrefsUseWideScreen
// without widescreen support
AR_AUTO,
AR_4_3,
AR_5_4,
AR_16_10,
AR_16_9,
AR_21_9,
AR_MAX,
};
class CDraw
{
private:
static float ms_fNearClipZ;
static float ms_fFarClipZ;
static float ms_fFOV;
#ifdef ASPECT_RATIO_SCALE
// we use this variable to scale a lot of 2D elements
// so better cache it
static float ms_fAspectRatio;
// similar thing for 3D rendering
static float ms_fScaledFOV;
#endif
public:
static float ms_fLODDistance; // set but unused?
static uint8 FadeValue;
static uint8 FadeRed;
static uint8 FadeGreen;
static uint8 FadeBlue;
#ifdef PROPER_SCALING
static bool ms_bProperScaling;
#endif
#ifdef FIX_RADAR
static bool ms_bFixRadar;
#endif
#ifdef FIX_SPRITES
static bool ms_bFixSprites;
#endif
static void SetNearClipZ(float nearclip) { ms_fNearClipZ = nearclip; }
static float GetNearClipZ(void) { return ms_fNearClipZ; }
static void SetFarClipZ(float farclip) { ms_fFarClipZ = farclip; }
static float GetFarClipZ(void) { return ms_fFarClipZ; }
static void SetFOV(float fov);
static float GetFOV(void) { return ms_fFOV; }
#ifdef ASPECT_RATIO_SCALE
static float GetScaledFOV(void) { return ms_fScaledFOV; }
#else
static float GetScaledFOV(void) { return ms_fFOV; }
#endif
static float FindAspectRatio(void);
#ifdef ASPECT_RATIO_SCALE
static float ConvertFOV(float fov);
static float GetAspectRatio(void) { return ms_fAspectRatio; }
static void SetAspectRatio(float ratio) { ms_fAspectRatio = ratio; }
#else
static float GetAspectRatio(void) { return FindAspectRatio(); }
#endif
#ifdef PROPER_SCALING
static float ScaleY(float y);
#endif
};

870
src/renderer/Fluff.cpp Normal file
View File

@ -0,0 +1,870 @@
#include "common.h"
#include "main.h"
#include "Entity.h"
#include "Fluff.h"
#include "Camera.h"
#include "Sprite.h"
#include "Coronas.h"
#include "General.h"
#include "Timer.h"
#include "Clock.h"
#include "Weather.h"
#include "Stats.h"
#include "maths.h"
#include "Frontend.h"
uint8 ScrollCharSet[59][5] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // ' '
{ 0x00, 0x00, 0x1D, 0x00, 0x00 }, // '!'
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // '"'
{ 0x0A, 0x1F, 0x0A, 0x1F, 0x0A }, // '#'
{ 0x00, 0x09, 0x1F, 0x12, 0x00 }, // '$'
{ 0x18, 0x18, 0x00, 0x03, 0x03 }, // '%'
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // '&'
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // '''
{ 0x01, 0x02, 0x04, 0x08, 0x10 }, // '('
{ 0x00, 0x00, 0x18, 0x00, 0x00 }, // ')'
{ 0x15, 0x04, 0x1F, 0x04, 0x15 }, // '*'
{ 0x00, 0x04, 0x0E, 0x04, 0x00 }, // '+'
{ 0x00, 0x00, 0x03, 0x00, 0x00 }, // ','
{ 0x00, 0x04, 0x04, 0x04, 0x00 }, // '-'
{ 0x00, 0x00, 0x01, 0x00, 0x00 }, // '.'
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // '/'
{ 0x0E, 0x11, 0x11, 0x11, 0x0E }, // '0'
{ 0x01, 0x09, 0x1F, 0x01, 0x01 }, // '1'
{ 0x03, 0x15, 0x15, 0x15, 0x09 }, // '2'
{ 0x11, 0x11, 0x15, 0x15, 0x0A }, // '3'
{ 0x02, 0x06, 0x0A, 0x1F, 0x02 }, // '4'
{ 0x1D, 0x15, 0x15, 0x15, 0x12 }, // '5'
{ 0x0E, 0x15, 0x15, 0x15, 0x12 }, // '6'
{ 0x18, 0x10, 0x13, 0x14, 0x18 }, // '7'
{ 0x0A, 0x15, 0x15, 0x15, 0x0A }, // '8'
{ 0x08, 0x15, 0x15, 0x15, 0x0E }, // '9'
{ 0x00, 0x00, 0x0A, 0x00, 0x00 }, // ':'
{ 0x18, 0x18, 0x00, 0x03, 0x03 }, // ';'
{ 0x04, 0x08, 0x1F, 0x08, 0x04 }, // '<'
{ 0x00, 0x0A, 0x0A, 0x0A, 0x00 }, // '='
{ 0x04, 0x02, 0x1F, 0x02, 0x04 }, // '>'
{ 0x10, 0x10, 0x15, 0x14, 0x1D }, // '?'
{ 0x00, 0x1C, 0x14, 0x1C, 0x00 }, // '@'
{ 0x0F, 0x12, 0x12, 0x12, 0x0F }, // 'A'
{ 0x1F, 0x15, 0x15, 0x15, 0x0A }, // 'B'
{ 0x0E, 0x11, 0x11, 0x11, 0x0A }, // 'C'
{ 0x1F, 0x11, 0x11, 0x11, 0x0E }, // 'D'
{ 0x1F, 0x15, 0x15, 0x11, 0x11 }, // 'E'
{ 0x1F, 0x14, 0x14, 0x10, 0x10 }, // 'F'
{ 0x0E, 0x11, 0x15, 0x15, 0x06 }, // 'G'
{ 0x1F, 0x04, 0x04, 0x04, 0x1F }, // 'H'
{ 0x11, 0x11, 0x1F, 0x11, 0x11 }, // 'I'
{ 0x02, 0x01, 0x01, 0x01, 0x1E }, // 'J'
{ 0x1F, 0x04, 0x0C, 0x12, 0x01 }, // 'K'
{ 0x1F, 0x01, 0x01, 0x01, 0x01 }, // 'L'
{ 0x1F, 0x08, 0x06, 0x08, 0x1F }, // 'M'
{ 0x1F, 0x08, 0x04, 0x02, 0x1F }, // 'N'
{ 0x0E, 0x11, 0x11, 0x11, 0x0E }, // 'O'
{ 0x1F, 0x12, 0x12, 0x12, 0x0C }, // 'P'
{ 0x0C, 0x12, 0x12, 0x13, 0x0D }, // 'Q'
{ 0x1F, 0x14, 0x14, 0x16, 0x09 }, // 'R'
{ 0x09, 0x15, 0x15, 0x15, 0x02 }, // 'S'
{ 0x10, 0x10, 0x1F, 0x10, 0x10 }, // 'T'
{ 0x1E, 0x01, 0x01, 0x01, 0x1E }, // 'U'
{ 0x1C, 0x02, 0x01, 0x02, 0x1C }, // 'V'
{ 0x1E, 0x01, 0x06, 0x01, 0x1E }, // 'W'
{ 0x11, 0x0A, 0x04, 0x0A, 0x11 }, // 'X'
{ 0x18, 0x04, 0x03, 0x04, 0x18 }, // 'Y'
{ 0x11, 0x13, 0x15, 0x19, 0x11 } // 'Z'
};
// ---------- CMovingThings ----------
enum eScrollBarTypes
{
SCROLL_BUSINESS,
SCROLL_TRAFFIC,
SCROLL_ENTERTAINMENT,
SCROLL_AIRPORT_DOORS,
SCROLL_AIRPORT_FRONT,
SCROLL_STORE,
SCROLL_USED_CARS
};
CScrollBar aScrollBars[11];
CTowerClock aTowerClocks[2];
CDigitalClock aDigitalClocks[3];
CMovingThing CMovingThings::StartCloseList;
CMovingThing CMovingThings::EndCloseList;
int16 CMovingThings::Num;
CMovingThing CMovingThings::aMovingThings[NUMMOVINGTHINGS];
void CMovingThings::Init()
{
StartCloseList.m_pNext = &CMovingThings::EndCloseList;
StartCloseList.m_pPrev = nil;
EndCloseList.m_pNext = nil;
EndCloseList.m_pPrev = &CMovingThings::StartCloseList;
Num = 0;
// Initialize scroll bars
aScrollBars[0].Init(CVector( 228.3f, -669.0f, 39.0f ), SCROLL_BUSINESS, 0.0f, 0.5f, 0.5f, 255, 128, 0, 0.3f);
aScrollBars[1].Init(CVector( 772.0f, 164.0f, -9.5f ), SCROLL_TRAFFIC, 0.0f, 0.5f, 0.25f, 128, 255, 0, 0.3f);
aScrollBars[2].Init(CVector(-1089.61f, -584.224f, 13.246f), SCROLL_AIRPORT_DOORS, 0.0f, -0.1706f, 0.107f, 255, 0, 0, 0.11f);
aScrollBars[3].Init(CVector(-1089.61f, -602.04602f, 13.246f), SCROLL_AIRPORT_DOORS, 0.0f, -0.1706f, 0.107f, 0, 255, 0, 0.11f);
aScrollBars[4].Init(CVector(-1089.61f, -619.81702f, 13.246f), SCROLL_AIRPORT_DOORS, 0.0f, -0.1706f, 0.107f, 255, 128, 0, 0.11f);
aScrollBars[5].Init(CVector(-754.578f, -633.50897f, 18.411f), SCROLL_AIRPORT_FRONT, 0.0f, 0.591f, 0.52f, 100, 100, 255, 0.3f);
aScrollBars[6].Init(CVector( -754.578f, -586.672f, 18.411f), SCROLL_AIRPORT_FRONT, 0.0f, 0.591f, 0.52f, 100, 100, 255, 0.3f);
aScrollBars[7].Init(CVector( 85.473f, -1069.512f, 30.5f ), SCROLL_STORE, 0.625f, -0.3125f, 0.727f, 100, 100, 255, 0.5f);
aScrollBars[8].Init(CVector( 74.823f, -1086.879f, 31.495f), SCROLL_ENTERTAINMENT, -0.2083f, 0.1041f, 0.5f, 255, 255, 128, 0.3f);
aScrollBars[9].Init(CVector( -36.459f, -1031.2371f, 32.534f), SCROLL_ENTERTAINMENT, -0.1442f, 0.0721f, 0.229f, 150, 255, 50, 0.3f);
aScrollBars[10].Init(CVector( 1208.0f, -62.208f, 19.157f), SCROLL_USED_CARS, 0.0642f, -0.20365f, 0.229f, 255, 128, 0, 0.3f);
// Initialize tower clocks
aTowerClocks[0].Init(CVector(59.4f, -1081.3f, 54.15f), -1.0f, 0.0f, 0, 0, 0, 80.0f, 2.0f);
aTowerClocks[1].Init(CVector(55.4f, -1083.6f, 54.15f), 0.0f, -1.0f, 0, 0, 0, 80.0f, 2.0f);
// Initialize digital clocks
CVector2D sz(3.7f, 2.144f);
sz.Normalise();
aDigitalClocks[0].Init(
CVector(54.485f - sz.x * 0.05f + sz.y * 0.3f, -1081.679f - sz.y * 0.05f - sz.x * 0.3f, 32.803f),
sz.y, -sz.x, 255, 0, 0, 100.0f, 0.8f
);
aDigitalClocks[1].Init(
CVector(60.564f + sz.x * 0.05f - sz.y * 0.3f, -1083.089f + sz.y * 0.05f + sz.x * 0.3f, 32.803f),
-sz.y, sz.x, 0, 0, 255, 100.0f, 0.8f
);
aDigitalClocks[2].Init(
CVector(58.145f - sz.y * 0.05f - sz.x * 0.3f, -1079.268f + sz.x * 0.05f - sz.y * 0.3f, 32.803f),
-sz.x, -sz.y, 0, 255, 0, 100.0f, 0.8f
);
}
void CMovingThings::Shutdown()
{
int i;
for (i = 0; i < ARRAY_SIZE(aScrollBars); ++i)
aScrollBars[i].SetVisibility(false);
for (i = 0; i < ARRAY_SIZE(aTowerClocks); ++i)
aTowerClocks[i].SetVisibility(false);
for (i = 0; i < ARRAY_SIZE(aDigitalClocks); ++i)
aDigitalClocks[i].SetVisibility(false);
}
void CMovingThings::Update()
{
int16 i;
#ifndef SQUEEZE_PERFORMANCE
const int TIME_SPAN = 64; // frames to process all aMovingThings
int block = CTimer::GetFrameCounter() % TIME_SPAN;
for (i = (block * NUMMOVINGTHINGS) / TIME_SPAN; i < ((block + 1) * NUMMOVINGTHINGS) / TIME_SPAN; i++) {
if (aMovingThings[i].m_nHidden == 1)
aMovingThings[i].Update();
}
for (i = 0; i < CMovingThings::Num; i++) {
if (aMovingThings[i].m_nHidden == 0)
aMovingThings[i].Update();
}
#endif
for (i = 0; i < ARRAY_SIZE(aScrollBars); ++i)
{
if (aScrollBars[i].IsVisible() || (CTimer::GetFrameCounter() + i) % 8 == 0)
aScrollBars[i].Update();
}
for (i = 0; i < ARRAY_SIZE(aTowerClocks); ++i)
{
if (aTowerClocks[i].IsVisible() || (CTimer::GetFrameCounter() + i) % 8 == 0)
aTowerClocks[i].Update();
}
for (i = 0; i < ARRAY_SIZE(aDigitalClocks); ++i)
{
if (aDigitalClocks[i].IsVisible() || (CTimer::GetFrameCounter() + i) % 8 == 0)
aDigitalClocks[i].Update();
}
}
void CMovingThings::Render()
{
int i;
PUSH_RENDERGROUP("CMovingThings::Render");
for (i = 0; i < ARRAY_SIZE(aScrollBars); ++i)
{
if (aScrollBars[i].IsVisible())
aScrollBars[i].Render();
}
for (i = 0; i < ARRAY_SIZE(aTowerClocks); ++i)
{
if (aTowerClocks[i].IsVisible())
aTowerClocks[i].Render();
}
for (i = 0; i < ARRAY_SIZE(aDigitalClocks); ++i)
{
if (aDigitalClocks[i].IsVisible())
aDigitalClocks[i].Render();
}
POP_RENDERGROUP();
}
// ---------- CMovingThing ----------
void CMovingThing::Update()
{
m_pEntity->GetMatrix().UpdateRW();
m_pEntity->UpdateRwFrame();
if (SQR(m_pEntity->GetPosition().x - TheCamera.GetPosition().x) + SQR(m_pEntity->GetPosition().y - TheCamera.GetPosition().y) < 40000.0f) {
if (m_nHidden == 1) {
AddToList(&CMovingThings::StartCloseList);
m_nHidden = 0;
}
} else {
if (m_nHidden == 0) {
RemoveFromList();
m_nHidden = 1;
}
}
}
void CMovingThing::AddToList(CMovingThing *pThing)
{
m_pNext = pThing->m_pNext;
m_pPrev = pThing;
pThing->m_pNext = this;
m_pNext->m_pPrev = this;
}
void CMovingThing::RemoveFromList()
{
m_pNext->m_pPrev = m_pPrev;
m_pPrev->m_pNext = m_pNext;
}
int16 CMovingThing::SizeList()
{
CMovingThing *next = m_pNext;
int16 count = 0;
while (next != nil) {
next = next->m_pNext;
count++;
}
return count;
}
// ---------- Find message functions ----------
const char* FindTunnelMessage()
{
if (CStats::CommercialPassed)
return "LIBERTY TUNNEL HAS BEEN OPENED TO ALL TRAFFIC . . . ";
if (CStats::IndustrialPassed)
return "FIRST PHASE LIBERTY TUNNEL HAS BEEN COMPLETED . . . ";
return "FIRST PHASE LIBERTY TUNNEL ABOUT TO BE COMPLETED . . . ";
}
const char* FindBridgeMessage()
{
if (CStats::CommercialPassed)
return "STAUNTON LIFT BRIDGE IS OPERATIONAL AGAIN ";
if (CStats::IndustrialPassed)
return "LONG DELAYS BEHIND US AS CALLAHAN BRIDGE IS FIXED . . . STAUNTON LIFT BRIDGE STUCK OPEN ";
return "CHAOS AS CALLAHAN BRIDGE IS UNDER REPAIR. . . ";
}
char String_Time[] = "THE TIME IS 12:34 ";
const char* FindTimeMessage()
{
String_Time[12] = '0' + CClock::GetHours() / 10;
String_Time[13] = '0' + CClock::GetHours() % 10;
String_Time[15] = '0' + CClock::GetMinutes() / 10;
String_Time[16] = '0' + CClock::GetMinutes() % 10;
return String_Time;
}
char String_DigitalClock[] = "12:34";
const char* FindDigitalClockMessage()
{
if (((CTimer::GetTimeInMilliseconds() >> 10) & 7) < 6)
{
String_DigitalClock[0] = '0' + CClock::GetHours() / 10;
String_DigitalClock[1] = '0' + CClock::GetHours() % 10;
String_DigitalClock[2] = CTimer::GetTimeInMilliseconds() & 0x200 ? ':' : ' ';
String_DigitalClock[3] = '0' + CClock::GetMinutes() / 10;
String_DigitalClock[4] = '0' + CClock::GetMinutes() % 10;
}
else
{
// they didn't use rad2deg here because of 3.14
int temperature = 13.0f - 6.0f * Cos((CClock::GetMinutes() + 60.0f * CClock::GetHours()) / (4.0f * 180.0f / 3.14f) - 1.0f);
String_DigitalClock[0] = '0' + temperature / 10;
if (String_DigitalClock[0] == '0')
String_DigitalClock[0] = ' ';
String_DigitalClock[1] = '0' + temperature % 10;
String_DigitalClock[2] = ' ';
String_DigitalClock[3] = '@';
String_DigitalClock[4] = 'C';
}
return String_DigitalClock;
}
// ---------- CScrollBar ----------
void CScrollBar::Init(CVector position, uint8 type, float sizeX, float sizeY, float sizeZ, uint8 red, uint8 green, uint8 blue, float scale)
{
for (int i = 0; i < ARRAY_SIZE(m_MessageBar); ++i)
m_MessageBar[i] = 0;
m_pMessage = ". ";
m_MessageCurrentChar = 0;
m_MessageLength = 2;
m_Counter = 0;
m_bVisible = false;
m_Position = position;
m_Type = type;
m_Size.x = sizeX;
m_Size.y = sizeY;
m_Size.z = sizeZ;
m_uRed = red;
m_uGreen = green;
m_uBlue = blue;
m_fScale = scale;
}
void CScrollBar::Update()
{
float distanceFromCamera = (TheCamera.GetPosition() - m_Position).Magnitude();
if (distanceFromCamera > 100.0f)
{
m_bVisible = false;
return;
}
m_bVisible = true;
if (distanceFromCamera < 75.0f)
m_fIntensity = 1.0f;
else
m_fIntensity = 1.0f - 4.0f * (distanceFromCamera - 75.0f) / 100.0f;
m_Counter = (m_Counter + 1) % 8;
// if message is fully printed, load up the next one
if (m_Counter == 0 && ++m_MessageCurrentChar >= m_MessageLength)
{
const char* previousMessage = m_pMessage;
switch (m_Type)
{
case SCROLL_BUSINESS:
while (previousMessage == m_pMessage)
{
switch (CGeneral::GetRandomNumber() % 7)
{
case 0:
m_pMessage = "SHARES UYE<10% DWD<20% NDWE>22% . . . ";
break;
case 1:
m_pMessage = "CRIME WAVE HITS LIBERTY CITY . . . ";
break;
case 2:
m_pMessage = "SHARES OBR>29% MADD<76% LEZ<11% ADAMSKI>53% AAG>110%. . . ";
break;
case 3:
m_pMessage = FindTunnelMessage();
break;
case 4:
m_pMessage = FindBridgeMessage();
break;
case 5:
m_pMessage = FindTimeMessage();
break;
case 6:
if (CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_FRENCH || CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_GERMAN)
m_pMessage = FindTimeMessage();
else
m_pMessage = "WWW.GRANDTHEFTAUTO3.COM ";
break;
}
}
break;
case SCROLL_TRAFFIC:
while (previousMessage == m_pMessage)
{
switch (CGeneral::GetRandomNumber() % 8)
{
case 0:
m_pMessage = "DRIVE CAREFULLY . . . ";
break;
case 1:
m_pMessage = "RECENT WAVE OF CARJACKINGS. KEEP YOUR DOORS LOCKED !!! ";
break;
case 2:
m_pMessage = "CHECK YOUR SPEED . . . ";
break;
case 3:
m_pMessage = "KEEP YOUR EYES ON THE ROAD AND NOT ON THIS SIGN ";
break;
case 4:
if (CWeather::Foggyness > 0.5f)
m_pMessage = "POOR VISIBILITY ! ";
else if (CWeather::WetRoads > 0.5f)
m_pMessage = "ROADS ARE SLIPPERY ! ";
else
m_pMessage = "ENJOY YOUR TRIP ";
break;
case 5:
m_pMessage = FindTunnelMessage();
break;
case 6:
m_pMessage = FindBridgeMessage();
break;
case 7:
m_pMessage = FindTimeMessage();
break;
}
}
break;
case SCROLL_ENTERTAINMENT:
while (previousMessage == m_pMessage)
{
switch (CGeneral::GetRandomNumber() % 12)
{
case 0:
m_pMessage = " )69TH STREET) STILL HOLDS TOP POSITION THIS MONTH AT THE BOX-OFFICE WITH )MY FAIR LADYBOY) JUST CREEPING UP BEHIND. ";
break;
case 1:
m_pMessage = " TALKING OF )FANNIE). THERE IS STILL TIME TO CATCH THIS LOVELY FAMILY MUSICAL, ABOUT THE ORPHAN WHO IS SO EASILY TAKEN IN BY ANY MAN WITH LOADS OF MONEY. ";
break;
case 2:
m_pMessage = " DO NOT MISS )GTA3, THE MUSICAL) . . . ";
break;
case 3:
m_pMessage =
" STILL RUNNING ARE )RATS) AND )GUYS AND DOGS), BETWEEN THEN THEY SHOULD HAVE THE LEGS TO LAST TILL THE AND OF THE YEAR. . . "
" ALSO FOR FOUR LEGGED FANS, THE STAGE VERSION OF THE GRITTY REALISTIC )SATERDAY NIGHT BEAVER) OPENED LAST WEEKEND,"
" AND I FOR ONE CERTAINLY ENJOYED THAT. ";
break;
case 4:
m_pMessage =
" NOW SHOWING STATE-WIDE, ARNOLD STEELONE, HOLLYWOODS BEST LIVING SPECIAL EFFECT, APPEARS AGAIN AS A HALF_MAN,"
" HALF ANDROID IN THE HALF-BAKED ROMP, )TOP DOWN CITY). AN HOMAGE TO HIS EARLIER TWO MULTI_MILLION MAKING MOVIES,"
" IN WHICH HE PLAYED TWO-DEE, AN OUT OF CONTROL MONSTER, INTENT ON CORRUPTING CIVILISATION! ";
break;
case 5:
m_pMessage =
" ALSO APPEARING THIS WEEK )HALF-COCKED) SEES CHUCK SCHWARTZ UP TO HIS USUAL NONSENSE AS HE TAKES ON HALF OF LIBERTY CITY"
" IN AN ATTEMPT TO SAVE HIS CROSS-DRESSING LADY-BOY SIDEKICK, )MISS PING-PONG), FROM A GANG OF RUTHLESS COSMETIC SURGEONS. ";
break;
case 6:
m_pMessage =
" STILL SHOWING: )SOLDIERS OF MISFORTUNE), ATTROCIOUS ACTING WHICH SEES BOYZ 2 GIRLZ) TRANSITION FROM THE CHARTS TO THE BIG SCREEN,"
" AT LEAST THEY ALL DIE AT THE END. . . ";
break;
case 7:
m_pMessage =
" )BADFELLAS) IS STILL GOING STRONG WITH CROWDS ALMOST BEING PUSHED INTO CINEMAS TO SEE THIS ONE."
" ANOTHER ONE WORTH LOOKING INTO IS )THE TUNNEL). ";
break;
case 8:
m_pMessage = FindTunnelMessage();
break;
case 9:
m_pMessage = FindBridgeMessage();
break;
case 10:
m_pMessage = FindTimeMessage();
break;
case 11:
m_pMessage = "WWW.ROCKSTARGAMES.COM ";
break;
}
}
break;
case SCROLL_AIRPORT_DOORS:
while (previousMessage == m_pMessage)
{
switch (CGeneral::GetRandomNumber() % 4)
{
case 0:
m_pMessage = "WELCOME TO LIBERTY CITY . . . ";
break;
case 1:
m_pMessage = "PLEASE HAVE YOUR PASSPORT READY . . . ";
break;
case 2:
m_pMessage = "PLACE KEYS, FIREARMS, CHANGE AND OTHER METAL OBJECTS ON THE TRAY PLEASE . . . ";
break;
case 3:
m_pMessage = FindTimeMessage();
break;
}
}
break;
case SCROLL_AIRPORT_FRONT:
while (previousMessage == m_pMessage)
{
switch (CGeneral::GetRandomNumber() % 4)
{
case 0:
m_pMessage = "WELCOME TO FRANCIS INTERNATIONAL AIRPORT . . . ";
break;
case 1:
m_pMessage = "PLEASE DO NOT LEAVE LUGGAGE UNATTENDED . . . ";
break;
case 2:
m_pMessage = "FOLLOW 1 FOR LONG AND SHORT TERM PARKING ";
break;
case 3:
m_pMessage = FindTimeMessage();
break;
}
}
break;
case SCROLL_STORE:
while (previousMessage == m_pMessage)
{
switch (CGeneral::GetRandomNumber() % 10)
{
case 0:
m_pMessage = "WWW.ROCKSTARGAMES.COM ";
break;
case 1:
m_pMessage = "GTA3 OUT NOW . . . ";
break;
case 2:
m_pMessage = "OUR STUFF IS CHEAP CHEAP CHEAP ";
break;
case 3:
m_pMessage = "BUY 12 CDS GET ONE FREE . . . ";
break;
case 4:
m_pMessage = "APPEARING IN SHOP SOON, )THE BLOODY CHOPPERS), WITH THEIR NEW ALBUM, )IS THAT MY DAUGHTER?) ";
break;
case 5:
m_pMessage = "THIS MONTH IS OUR CRAZY CLEAROUT MONTH, EVERYTHING MUST GO, CDS, DVDS, STAFF, EVEN OUR CARPETS! ";
break;
case 6:
m_pMessage =
"OUT THIS WEEK: THE THEME TUNE TO )BOYS TO GIRLS) FIRST MOVIE )SOLDIERS OF MISFORTUNE), "
"THE SINGLE )LET ME IN YOU)RE BODY-BAG) IS TAKEN FROM THE SOUNDTRACK ALBUM, )BOOT CAMP BOYS). "
"ALSO INCLUDES THE SMASH SINGLE, )PRAY IT GOES OK). ";
break;
case 7:
m_pMessage =
"ALBUMS OUT THIS WEEK: MARYDANCING, )MUTHA O) CHRIST), FEATURING THE SINGLE )WASH HIM OFF), "
"ALSO CRAIG GRAYS) DEBUT, )FADE AWAY), INCLUDES THE SINGLE OF THE SAME NAME. . . ";
break;
case 8:
m_pMessage =
"ON THE FILM FRONT, A NELY COMPILED COMPILATION OF ARNOLD STEELONES GREATEST MOVIES ON DVD. "
"THE PACK INCLUDES THE EARLY )BY-CEP), THE CULT CLASSIC )FUTURE ANNHILATOR), AND THE HILARIOUS CROSS-DRESSING COMEDY )SISTERS). "
"ONE FOR ALL THE FAMILY. . . ";
break;
case 9:
m_pMessage = FindTimeMessage();
break;
}
}
break;
case SCROLL_USED_CARS:
while (previousMessage == m_pMessage)
{
switch (CGeneral::GetRandomNumber() % 11)
{
case 0:
m_pMessage = "QUICK, TAKE A LOOK AT OUR CURRENT STOCK )CAUSE THESE AUTOS ARE MOVIN) FAST . . . ";
break;
case 1:
m_pMessage = "THAT)S RIGHT, HERE AT )CAPITAL AUTO SALES) OUR VEHICLES ARE SO GOOD THAT THEY PRACTICALLY DRIVE THEMSELVES OFF OUR LOT . . . ";
break;
case 2:
m_pMessage = "EASY CREDIT ON ALL CARS . . . ";
break;
case 3:
m_pMessage = "FEEL LIKE A STUD IN ONE OF OUR STALLIONS OR TEST-DRIVE OUR BANSHEE, IT)S A REAL STEAL!!! ";
break;
case 4:
m_pMessage = "TRY OUR HARDY PERENNIAL, IT)LL LAST YOU THE WHOLE YEAR. OUR BOBCATS AIN)T NO PUSSIES EITHER!!! ";
break;
case 5:
m_pMessage = "IF IT)S A GUARANTEE YOU'RE AFTER, GO SOMEWHERE ELSE, )CAPITAL) CARS ARE THAT GOOD THEY DON)T NEED GUARANTEES!!! ";
break;
case 6:
m_pMessage = "TOP DOLLAR OFFERED FOR YOUR OLD WHEELS, NOT YOUR CAR, JUST IT)S WHEELS. . . ";
break;
case 7:
m_pMessage = "THAT)S RIGHT WE)RE CAR SILLY. TEST DRIVE ANY CAR, YOU WON)T WANT TO BRING IT BACK!!! ";
break;
case 8:
m_pMessage = "FREE FLUFFY DICE WITH ALL PURCHASES. . .";
break;
case 9:
if (CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_FRENCH || CMenuManager::m_PrefsLanguage == CMenuManager::LANGUAGE_GERMAN)
m_pMessage = "QUICK, TAKE A LOOK AT OUR CURRENT STOCK )CAUSE THESE AUTOS ARE MOVIN) FAST . . . ";
else
m_pMessage = "HTTP:((ROCKSTARGAMES.COM(GRANDTHEFTAUTO3(CAPITALAUTOS ";
break;
case 10:
m_pMessage = FindTimeMessage();
break;
}
}
break;
}
m_MessageLength = (uint32)strlen(m_pMessage);
m_MessageCurrentChar = 0;
}
// Scroll
for (int i = 0; i < ARRAY_SIZE(m_MessageBar)-1; i++)
m_MessageBar[i] = m_MessageBar[i + 1];
m_MessageBar[ARRAY_SIZE(m_MessageBar)-1] = m_Counter < 5 ? ScrollCharSet[m_pMessage[m_MessageCurrentChar] - ' '][m_Counter] : 0;
// Introduce some random displaying glitches; signs aren't supposed to be perfect :P
switch (CGeneral::GetRandomNumber() & 0xFF)
{
case 0x0D: m_MessageBar[ARRAY_SIZE(m_MessageBar)-1] = 0; break;
case 0xE3: m_MessageBar[ARRAY_SIZE(m_MessageBar)-1] = 0xE3; break;
case 0x64: m_MessageBar[ARRAY_SIZE(m_MessageBar)-1] = ~m_MessageBar[ARRAY_SIZE(m_MessageBar)-1]; break;
}
}
void CScrollBar::Render()
{
if (!TheCamera.IsSphereVisible(m_Position, 2.0f * 20.0f * (ABS(m_Size.x) + ABS(m_Size.y))))
return;
CSprite::InitSpriteBuffer();
// Calculate intensity of colours
uint8 r = m_fIntensity * m_uRed;
uint8 g = m_fIntensity * m_uGreen;
uint8 b = m_fIntensity * m_uBlue;
// Set render states
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
CVector coronaCoord, screenCoord;
float screenW, screenH;
for (int i = 1; i < ARRAY_SIZE(m_MessageBar); ++i)
{
for (int j = 0; j < 5; ++j)
{
coronaCoord.x = m_Position.x + m_Size.x * i;
coronaCoord.y = m_Position.y + m_Size.y * i;
coronaCoord.z = m_Position.z + m_Size.z * j;
// Render main coronas
if (m_MessageBar[i] & (1 << j))
{
if (CSprite::CalcScreenCoors(coronaCoord, &screenCoord, &screenW, &screenH, true))
{
CSprite::RenderBufferedOneXLUSprite(
screenCoord.x, screenCoord.y, screenCoord.z,
screenW * m_fScale, screenH * m_fScale,
r, g, b,
255, 1.0f / screenCoord.z, 255);
}
}
// Render smaller and faded coronas for a trailing effect
else if (m_MessageBar[i - 1] & (1 << j))
{
if (CSprite::CalcScreenCoors(coronaCoord, &screenCoord, &screenW, &screenH, true))
{
CSprite::RenderBufferedOneXLUSprite(
screenCoord.x, screenCoord.y, screenCoord.z,
screenW * m_fScale * 0.8f,
screenH * m_fScale * 0.8f,
r / 2,
g / 2,
b / 2,
255, 1.0f / screenCoord.z, 255);
}
}
}
}
CSprite::FlushSpriteBuffer();
}
// ---------- CTowerClock ----------
void CTowerClock::Init(CVector position, float sizeX, float sizeY, uint8 red, uint8 green, uint8 blue, float drawDistance, float scale)
{
m_bVisible = false;
m_Position = position;
m_Size.x = sizeX;
m_Size.y = sizeY;
m_Size.z = 0.0f;
m_uRed = red;
m_uGreen = green;
m_uBlue = blue;
m_fDrawDistance = drawDistance;
m_fScale = scale;
}
void CTowerClock::Update()
{
float distanceFromCamera = (TheCamera.GetPosition() - m_Position).Magnitude();
if (distanceFromCamera < m_fDrawDistance)
{
m_bVisible = true;
if (distanceFromCamera < 0.75f * m_fDrawDistance)
m_fIntensity = 1.0f;
else
m_fIntensity = 1.0f - (distanceFromCamera - 0.75f * m_fDrawDistance) * 4.0f / m_fDrawDistance;
}
else
m_bVisible = false;
}
RwIm3DVertex TempV[4];
void CTowerClock::Render()
{
if (TheCamera.IsSphereVisible(m_Position, m_fScale))
{
// Calculate angle for each clock index
float angleHour = 2.0f * (float)PI * (CClock::GetMinutes() + 60.0f * CClock::GetHours()) / 720.0f;
float angleMinute = 2.0f * (float)PI * (CClock::GetSeconds() + 60.0f * CClock::GetMinutes()) / 3600.0f;
// Prepare render states
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
// Set vertices colors
RwIm3DVertexSetRGBA(&TempV[0], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f));
RwIm3DVertexSetRGBA(&TempV[1], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f));
RwIm3DVertexSetRGBA(&TempV[2], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f));
RwIm3DVertexSetRGBA(&TempV[3], m_uRed, m_uGreen, m_uBlue, (uint8)(m_fIntensity * 255.0f));
// Set vertices position
RwIm3DVertexSetPos(&TempV[0], m_Position.x, m_Position.y, m_Position.z);
RwIm3DVertexSetPos(
&TempV[1],
m_Position.x + Sin(angleMinute) * m_fScale * m_Size.x,
m_Position.y + Sin(angleMinute) * m_fScale * m_Size.y,
m_Position.z + Cos(angleMinute) * m_fScale
);
RwIm3DVertexSetPos(&TempV[2], m_Position.x, m_Position.y, m_Position.z);
RwIm3DVertexSetPos(
&TempV[3],
m_Position.x + Sin(angleHour) * 0.75f * m_fScale * m_Size.x,
m_Position.y + Sin(angleHour) * 0.75f * m_fScale * m_Size.y,
m_Position.z + Cos(angleHour) * 0.75f * m_fScale
);
LittleTest();
// Draw lines
if (RwIm3DTransform(TempV, 4, nil, 0))
{
RwIm3DRenderLine(0, 1);
RwIm3DRenderLine(2, 3);
RwIm3DEnd();
}
}
}
// ---------- CDigitalClock ----------
void CDigitalClock::Init(CVector position, float sizeX, float sizeY, uint8 red, uint8 green, uint8 blue, float drawDistance, float scale)
{
m_bVisible = false;
m_Position = position;
m_Size.x = sizeX;
m_Size.y = sizeY;
m_Size.z = 0.0f;
m_uRed = red;
m_uGreen = green;
m_uBlue = blue;
m_fDrawDistance = drawDistance;
m_fScale = scale;
}
void CDigitalClock::Update()
{
float distanceFromCamera = (TheCamera.GetPosition() - m_Position).Magnitude();
if (distanceFromCamera < m_fDrawDistance)
{
m_bVisible = true;
if (distanceFromCamera < 0.75f * m_fDrawDistance)
m_fIntensity = 1.0f;
else
m_fIntensity = 1.0f - (distanceFromCamera - 0.75f * m_fDrawDistance) * 4.0f / m_fDrawDistance;
}
else
m_bVisible = false;
}
void CDigitalClock::Render()
{
if (TheCamera.IsSphereVisible(m_Position, 5.0f * m_fScale))
{
CSprite::InitSpriteBuffer();
// Simulate flicker
float currentIntensity = m_fIntensity * CGeneral::GetRandomNumberInRange(0x300, 0x400) / 1024.0f;
uint8 r = currentIntensity * m_uRed;
uint8 g = currentIntensity * m_uGreen;
uint8 b = currentIntensity * m_uBlue;
// Set render states
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
const char* clockMessage = FindDigitalClockMessage();
CVector coronaCoord, screenCoord;
float screenW, screenH;
for (int c = 0; c < 5; ++c) // for each char to be displayed
{
for (int i = 0; i < 5; ++i) // for each column of coronas
{
for (int j = 0; j < 5; ++j) // for each row of coronas
{
if (ScrollCharSet[clockMessage[c] - ' '][i] & (1 << j))
{
coronaCoord.x = m_Position.x + (8 * c + i) * m_Size.x * m_fScale / 8.0f;
coronaCoord.y = m_Position.y + (8 * c + i) * m_Size.y * m_fScale / 8.0f;
coronaCoord.z = m_Position.z + j * m_fScale / 8.0f;
if (CSprite::CalcScreenCoors(coronaCoord, &screenCoord, &screenW, &screenH, true))
{
CSprite::RenderBufferedOneXLUSprite(
screenCoord.x, screenCoord.y, screenCoord.z,
screenW * m_fScale * 0.12f,
screenW * m_fScale * 0.12f,
r, g, b,
255,
1.0f / screenCoord.z,
255);
}
}
}
}
}
CSprite::FlushSpriteBuffer();
}
}

106
src/renderer/Fluff.h Normal file
View File

@ -0,0 +1,106 @@
#pragma once
#include "common.h"
#include "Vector.h"
class CMovingThing
{
public:
CMovingThing *m_pNext;
CMovingThing *m_pPrev;
int16 m_nType;
int16 m_nHidden;
CVector m_vecPosn;
CEntity* m_pEntity;
void Update();
void AddToList(CMovingThing *pThing);
void RemoveFromList();
int16 SizeList();
};
#define NUMMOVINGTHINGS 128
class CMovingThings
{
public:
static CMovingThing StartCloseList;
static CMovingThing EndCloseList;
static int16 Num;
static CMovingThing aMovingThings[NUMMOVINGTHINGS];
static void Init();
static void Shutdown();
static void Update();
static void Render();
};
class CScrollBar
{
private:
uint8 m_Counter;
const char* m_pMessage;
CVector m_Position;
uint32 m_MessageCurrentChar;
uint32 m_MessageLength;
CVector m_Size;
float m_fIntensity;
uint8 m_MessageBar[40];
uint8 m_Type;
bool m_bVisible;
uint8 m_uRed;
uint8 m_uGreen;
uint8 m_uBlue;
float m_fScale;
public:
void SetVisibility(bool visible) { m_bVisible = visible; }
bool IsVisible() { return m_bVisible; }
void Init(CVector, uint8, float, float, float, uint8, uint8, uint8, float);
void Update();
void Render();
};
class CTowerClock
{
private:
CVector m_Position;
CVector m_Size;
float m_fDrawDistance;
float m_fScale;
uint8 m_uRed;
uint8 m_uGreen;
uint8 m_uBlue;
bool m_bVisible;
float m_fIntensity;
public:
void SetVisibility(bool visible) { m_bVisible = visible; }
bool IsVisible() { return m_bVisible; }
void Init(CVector, float, float, uint8, uint8, uint8, float, float);
void Update();
void Render();
};
class CDigitalClock
{
private:
CVector m_Position;
CVector m_Size;
float m_fDrawDistance;
float m_fScale;
uint8 m_uRed;
uint8 m_uGreen;
uint8 m_uBlue;
bool m_bVisible;
float m_fIntensity;
public:
void SetVisibility(bool visible) { m_bVisible = visible; }
bool IsVisible() { return m_bVisible; }
void Init(CVector, float, float, uint8, uint8, uint8, float, float);
void Update();
void Render();
};

1628
src/renderer/Font.cpp Normal file

File diff suppressed because it is too large Load Diff

182
src/renderer/Font.h Normal file
View File

@ -0,0 +1,182 @@
#pragma once
#include "Sprite2d.h"
void AsciiToUnicode(const char *src, wchar *dst);
void UnicodeStrcpy(wchar *dst, const wchar *src);
void UnicodeStrcat(wchar *dst, wchar *append);
int UnicodeStrlen(const wchar *str);
struct CFontDetails
{
CRGBA color;
float scaleX;
float scaleY;
float slant;
float slantRefX;
float slantRefY;
bool8 justify;
bool8 centre;
bool8 rightJustify;
bool8 background;
bool8 backgroundOnlyText;
bool8 proportional;
float alphaFade;
CRGBA backgroundColor;
float wrapX;
float centreSize;
float rightJustifyWrap;
int16 style;
int32 bank;
int16 dropShadowPosition;
CRGBA dropColor;
};
class CSprite2d;
enum {
FONT_BANK,
FONT_PAGER,
FONT_HEADING,
#ifdef MORE_LANGUAGES
FONT_JAPANESE,
#endif
MAX_FONTS
};
enum {
ALIGN_LEFT,
ALIGN_CENTER,
ALIGN_RIGHT,
};
#ifdef MORE_LANGUAGES
enum
{
FONT_LANGSET_EFIGS,
FONT_LANGSET_RUSSIAN,
FONT_LANGSET_POLISH,
FONT_LANGSET_JAPANESE,
LANGSET_MAX
};
#define FONT_LOCALE(style) (CFont::IsJapanese() ? FONT_JAPANESE : style)
#else
#define FONT_LOCALE(style) (style)
#endif
#ifdef BUTTON_ICONS
enum
{
BUTTON_NONE = -1,
#if 0 // unused
BUTTON_UP,
BUTTON_DOWN,
BUTTON_LEFT,
BUTTON_RIGHT,
#endif
BUTTON_CROSS,
BUTTON_CIRCLE,
BUTTON_SQUARE,
BUTTON_TRIANGLE,
BUTTON_L1,
BUTTON_L2,
BUTTON_L3,
BUTTON_R1,
BUTTON_R2,
BUTTON_R3,
MAX_BUTTON_ICONS
};
#endif // BUTTON_ICONS
class CFont
{
#ifdef MORE_LANGUAGES
static int16 Size[LANGSET_MAX][MAX_FONTS][193];
static uint8 LanguageSet;
static int32 Slot;
#else
static int16 Size[MAX_FONTS][193];
#endif
static bool16 NewLine;
public:
static CSprite2d Sprite[MAX_FONTS];
static CFontDetails Details;
#ifdef BUTTON_ICONS
static int32 ButtonsSlot;
static CSprite2d ButtonSprite[MAX_BUTTON_ICONS];
static int PS2Symbol;
static void LoadButtons(const char *txdPath);
static void DrawButton(float x, float y);
#endif // BUTTON_ICONS
static void Initialise(void);
static void Shutdown(void);
static void InitPerFrame(void);
static void PrintChar(float x, float y, wchar c);
static void PrintString(float x, float y, wchar *s);
static void PrintStringFromBottom(float x, float y, wchar *str);
#ifdef XBOX_SUBTITLES
static void PrintOutlinedString(float x, float y, wchar *str, float outlineStrength, bool fromBottom, CRGBA outlineColor);
#endif
static int GetNumberLines(float xstart, float ystart, wchar *s);
static void GetTextRect(CRect *rect, float xstart, float ystart, wchar *s);
#ifdef MORE_LANGUAGES
static bool PrintString(float x, float y, wchar *start, wchar* &end, float spwidth, float japX);
#else
static void PrintString(float x, float y, wchar *start, wchar *end, float spwidth);
#endif
static float GetCharacterWidth(wchar c);
static float GetCharacterSize(wchar c);
static float GetStringWidth(wchar *s, bool spaces = false);
#ifdef MORE_LANGUAGES
static float GetStringWidth_Jap(wchar* s);
#endif
static uint16 *GetNextSpace(wchar *s);
#ifdef MORE_LANGUAGES
static uint16 *ParseToken(wchar *s, wchar*, bool japShit = false);
#else
static uint16 *ParseToken(wchar *s, wchar*);
#endif
static void DrawFonts(void);
static uint16 character_code(uint8 c);
static void SetScale(float x, float y);
static void SetSlantRefPoint(float x, float y);
static void SetSlant(float s);
static void SetJustifyOn(void);
static void SetJustifyOff(void);
static void SetRightJustifyOn(void);
static void SetRightJustifyOff(void);
static void SetCentreOn(void);
static void SetCentreOff(void);
static void SetWrapx(float x);
static void SetCentreSize(float s);
static void SetBackgroundOn(void);
static void SetBackgroundOff(void);
static void SetBackGroundOnlyTextOn(void);
static void SetBackGroundOnlyTextOff(void);
static void SetPropOn(void);
static void SetPropOff(void);
static void SetFontStyle(int16 style);
static void SetRightJustifyWrap(float wrap);
static void SetAlphaFade(float fade);
static void SetDropShadowPosition(int16 pos);
static void SetBackgroundColor(CRGBA col);
static void SetColor(CRGBA col);
static void SetDropColor(CRGBA col);
#ifdef MORE_LANGUAGES
static void ReloadFonts(uint8 set);
// japanese stuff
static bool IsAnsiCharacter(wchar* s);
static bool IsJapanesePunctuation(wchar* str);
static bool IsJapanese() { return LanguageSet == FONT_LANGSET_JAPANESE; }
static bool IsJapaneseFont() { return IsJapanese() && (Details.style == FONT_JAPANESE || Details.style == FONT_PAGER); }
#endif
};

719
src/renderer/Glass.cpp Normal file
View File

@ -0,0 +1,719 @@
#include "common.h"
#include "Glass.h"
#include "Timer.h"
#include "Object.h"
#include "General.h"
#include "AudioScriptObject.h"
#include "World.h"
#include "Timecycle.h"
#include "Particle.h"
#include "Camera.h"
#include "RenderBuffer.h"
#include "Shadows.h"
#include "ModelIndices.h"
#include "main.h"
#include "soundlist.h"
uint32 CGlass::NumGlassEntities;
CEntity *CGlass::apEntitiesToBeRendered[NUM_GLASSENTITIES];
CFallingGlassPane CGlass::aGlassPanes[NUM_GLASSPANES];
CVector2D CentersWithTriangle[NUM_GLASSTRIANGLES];
const CVector2D CoorsWithTriangle[NUM_GLASSTRIANGLES][3] =
{
{
CVector2D(0.0f, 0.0f),
CVector2D(0.0f, 1.0f),
CVector2D(0.4f, 0.5f)
},
{
CVector2D(0.0f, 1.0f),
CVector2D(1.0f, 1.0f),
CVector2D(0.4f, 0.5f)
},
{
CVector2D(0.0f, 0.0f),
CVector2D(0.4f, 0.5f),
CVector2D(0.7f, 0.0f)
},
{
CVector2D(0.7f, 0.0f),
CVector2D(0.4f, 0.5f),
CVector2D(1.0f, 1.0f)
},
{
CVector2D(0.7f, 0.0f),
CVector2D(1.0f, 1.0f),
CVector2D(1.0f, 0.0f)
}
};
#define TEMPBUFFERVERTHILIGHTOFFSET 0
#define TEMPBUFFERINDEXHILIGHTOFFSET 0
#define TEMPBUFFERVERTHILIGHTSIZE 128
#define TEMPBUFFERINDEXHILIGHTSIZE 512
#define TEMPBUFFERVERTSHATTEREDOFFSET TEMPBUFFERVERTHILIGHTSIZE
#define TEMPBUFFERINDEXSHATTEREDOFFSET TEMPBUFFERINDEXHILIGHTSIZE
#define TEMPBUFFERVERTSHATTEREDSIZE 192
#define TEMPBUFFERINDEXSHATTEREDSIZE 768
#define TEMPBUFFERVERTREFLECTIONOFFSET TEMPBUFFERVERTSHATTEREDSIZE
#define TEMPBUFFERINDEXREFLECTIONOFFSET TEMPBUFFERINDEXSHATTEREDSIZE
#define TEMPBUFFERVERTREFLECTIONSIZE 256
#define TEMPBUFFERINDEXREFLECTIONSIZE 1024
int32 TempBufferIndicesStoredHiLight = 0;
int32 TempBufferVerticesStoredHiLight = 0;
int32 TempBufferIndicesStoredShattered = 0;
int32 TempBufferVerticesStoredShattered = 0;
int32 TempBufferIndicesStoredReflection = 0;
int32 TempBufferVerticesStoredReflection = 0;
void
CFallingGlassPane::Update(void)
{
if ( CTimer::GetTimeInMilliseconds() >= m_nTimer )
{
// Apply MoveSpeed
GetPosition() += m_vecMoveSpeed * CTimer::GetTimeStep();
// Apply Gravity
m_vecMoveSpeed.z -= 0.02f * CTimer::GetTimeStep();
// Apply TurnSpeed
GetRight() += CrossProduct(m_vecTurn, GetRight());
GetForward() += CrossProduct(m_vecTurn, GetForward());
GetUp() += CrossProduct(m_vecTurn, GetUp());
if ( GetPosition().z < m_fGroundZ )
{
CVector pos;
CVector dir;
m_bActive = false;
pos = CVector(GetPosition().x, GetPosition().y, m_fGroundZ);
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_LIGHT_BREAK, pos);
RwRGBA color = { 255, 255, 255, 255 };
static int32 nFrameGen = 0;
for ( int32 i = 0; i < 4; i++ )
{
dir.x = CGeneral::GetRandomNumberInRange(-0.35f, 0.35f);
dir.y = CGeneral::GetRandomNumberInRange(-0.35f, 0.35f);
dir.z = CGeneral::GetRandomNumberInRange(0.05f, 0.20f);
CParticle::AddParticle(PARTICLE_CAR_DEBRIS,
pos,
dir,
nil,
CGeneral::GetRandomNumberInRange(0.02f, 0.2f),
color,
CGeneral::GetRandomNumberInRange(-40, 40),
0,
++nFrameGen & 3,
500);
}
}
}
}
void
CFallingGlassPane::Render(void)
{
float distToCamera = (TheCamera.GetPosition() - GetPosition()).Magnitude();
CVector fwdNorm = GetForward();
fwdNorm.Normalise();
uint8 alpha = CGlass::CalcAlphaWithNormal(&fwdNorm);
#ifdef FIX_BUGS
uint16 time = Clamp(CTimer::GetTimeInMilliseconds() > m_nTimer ? CTimer::GetTimeInMilliseconds() - m_nTimer : 0u, 0u, 500u);
#else
uint16 time = Clamp(CTimer::GetTimeInMilliseconds() - m_nTimer, 0, 500);
#endif
uint8 color = int32( float(alpha) * (float(time) / 500) );
if ( TempBufferIndicesStoredHiLight >= TEMPBUFFERINDEXHILIGHTSIZE-7 || TempBufferVerticesStoredHiLight >= TEMPBUFFERVERTHILIGHTSIZE-4 )
CGlass::RenderHiLightPolys();
// HiLight Polys
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], color, color, color, color);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], 0.5f);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], 0.5f);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], 0.5f);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], 0.6f);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], 0.6f);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], 0.6f);
ASSERT(m_nTriIndex < NUM_GLASSTRIANGLES);
CVector2D p0 = CoorsWithTriangle[m_nTriIndex][0] - CentersWithTriangle[m_nTriIndex];
CVector2D p1 = CoorsWithTriangle[m_nTriIndex][1] - CentersWithTriangle[m_nTriIndex];
CVector2D p2 = CoorsWithTriangle[m_nTriIndex][2] - CentersWithTriangle[m_nTriIndex];
CVector v0 = *this * CVector(p0.x, 0.0f, p0.y);
CVector v1 = *this * CVector(p1.x, 0.0f, p1.y);
CVector v2 = *this * CVector(p2.x, 0.0f, p2.y);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], v0.x, v0.y, v0.z);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], v1.x, v1.y, v1.z);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], v2.x, v2.y, v2.z);
TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 0] = TempBufferVerticesStoredHiLight + 0;
TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 1] = TempBufferVerticesStoredHiLight + 1;
TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 2] = TempBufferVerticesStoredHiLight + 2;
TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 3] = TempBufferVerticesStoredHiLight + 0;
TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 4] = TempBufferVerticesStoredHiLight + 2;
TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 5] = TempBufferVerticesStoredHiLight + 1;
TempBufferVerticesStoredHiLight += 3;
TempBufferIndicesStoredHiLight += 6;
if ( m_bShattered )
{
if ( TempBufferIndicesStoredShattered >= TEMPBUFFERINDEXSHATTEREDSIZE-7 || TempBufferVerticesStoredShattered >= TEMPBUFFERVERTSHATTEREDSIZE-4 )
CGlass::RenderShatteredPolys();
uint8 shatteredColor = 255;
if ( distToCamera > 30.0f )
shatteredColor = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 255);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], shatteredColor, shatteredColor, shatteredColor, shatteredColor);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], shatteredColor, shatteredColor, shatteredColor, shatteredColor);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], shatteredColor, shatteredColor, shatteredColor, shatteredColor);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 4.0f * CoorsWithTriangle[m_nTriIndex][0].x * m_fStep);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 4.0f * CoorsWithTriangle[m_nTriIndex][0].y * m_fStep);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 4.0f * CoorsWithTriangle[m_nTriIndex][1].x * m_fStep);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 4.0f * CoorsWithTriangle[m_nTriIndex][1].y * m_fStep);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 4.0f * CoorsWithTriangle[m_nTriIndex][2].x * m_fStep);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 4.0f * CoorsWithTriangle[m_nTriIndex][2].y * m_fStep);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], v0.x, v0.y, v0.z);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], v1.x, v1.y, v1.z);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], v2.x, v2.y, v2.z);
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 0] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 0;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 1] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 1;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 2] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 2;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 3] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 0;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 4] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 2;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 5] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 1;
TempBufferIndicesStoredShattered += 6;
TempBufferVerticesStoredShattered += 3;
}
}
void
CGlass::Init(void)
{
for ( int32 i = 0; i < NUM_GLASSPANES; i++ )
aGlassPanes[i].m_bActive = false;
for ( int32 i = 0; i < NUM_GLASSTRIANGLES; i++ )
CentersWithTriangle[i] = (CoorsWithTriangle[i][0] + CoorsWithTriangle[i][1] + CoorsWithTriangle[i][2]) / 3;
}
void
CGlass::Update(void)
{
for ( int32 i = 0; i < NUM_GLASSPANES; i++ )
{
if ( aGlassPanes[i].m_bActive )
aGlassPanes[i].Update();
}
}
void
CGlass::Render(void)
{
TempBufferVerticesStoredHiLight = 0;
TempBufferIndicesStoredHiLight = 0;
TempBufferVerticesStoredShattered = TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferIndicesStoredShattered = TEMPBUFFERINDEXSHATTEREDOFFSET;
TempBufferVerticesStoredReflection = TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferIndicesStoredReflection = TEMPBUFFERINDEXREFLECTIONOFFSET;
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE);
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void *)rwFILTERLINEAR);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE);
RwRenderStateSet(rwRENDERSTATEFOGCOLOR, (void *)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255));
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE);
PUSH_RENDERGROUP("CGlass::Render");
for ( int32 i = 0; i < NUM_GLASSPANES; i++ )
{
if ( aGlassPanes[i].m_bActive )
aGlassPanes[i].Render();
}
for ( uint32 i = 0; i < NumGlassEntities; i++ )
RenderEntityInGlass(apEntitiesToBeRendered[i]);
POP_RENDERGROUP();
NumGlassEntities = 0;
RenderHiLightPolys();
RenderShatteredPolys();
RenderReflectionPolys();
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)TRUE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE);
}
CFallingGlassPane *
CGlass::FindFreePane(void)
{
for ( int32 i = 0; i < NUM_GLASSPANES; i++ )
{
if ( !aGlassPanes[i].m_bActive )
return &aGlassPanes[i];
}
return nil;
}
void
CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector point,
float moveSpeed, bool cracked, bool explosion)
{
float upLen = up.Magnitude();
float rightLen = right.Magnitude();
float upSteps = upLen + 0.75f;
if ( upSteps < 1.0f ) upSteps = 1.0f;
float rightSteps = rightLen + 0.75f;
if ( rightSteps < 1.0f ) rightSteps = 1.0f;
uint32 ysteps = (uint32)upSteps;
if ( ysteps > 3 ) ysteps = 3;
uint32 xsteps = (uint32)rightSteps;
if ( xsteps > 3 ) xsteps = 3;
if ( explosion )
{
if ( ysteps > 1 ) ysteps = 1;
if ( xsteps > 1 ) xsteps = 1;
}
float upScl = upLen / float(ysteps);
float rightScl = rightLen / float(xsteps);
bool bZFound;
float groundZ = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &bZFound);
if ( !bZFound ) groundZ = pos.z - 2.0f;
for ( uint32 y = 0; y < ysteps; y++ )
{
for ( uint32 x = 0; x < xsteps; x++ )
{
float stepy = float(y) * upLen / float(ysteps);
float stepx = float(x) * rightLen / float(xsteps);
for ( int32 i = 0; i < NUM_GLASSTRIANGLES; i++ )
{
CFallingGlassPane *pane = FindFreePane();
if ( pane )
{
pane->m_nTriIndex = i;
pane->GetRight() = (right * rightScl) / rightLen;
#ifdef FIX_BUGS
pane->GetUp() = (up * upScl) / upLen;
#else
pane->GetUp() = (up * upScl) / rightLen; // copypaste bug
#endif
CVector fwd = CrossProduct(pane->GetRight(), pane->GetUp());
fwd.Normalise();
pane->GetForward() = fwd;
pane->GetPosition() = right / rightLen * (rightScl * CentersWithTriangle[i].x + stepx)
+ up / upLen * (upScl * CentersWithTriangle[i].y + stepy)
+ pos;
pane->m_vecMoveSpeed.x = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0015f + speed.x;
pane->m_vecMoveSpeed.y = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0015f + speed.y;
pane->m_vecMoveSpeed.z = 0.0f + speed.z;
if ( moveSpeed != 0.0f )
{
CVector dist = pane->GetPosition() - point;
dist.Normalise();
pane->m_vecMoveSpeed += moveSpeed * dist;
}
pane->m_vecTurn.x = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.002f;
pane->m_vecTurn.y = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.002f;
pane->m_vecTurn.z = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.002f;
switch ( type )
{
case 0:
pane->m_nTimer = CTimer::GetTimeInMilliseconds();
break;
case 1:
float dist = (pane->GetPosition() - point).Magnitude();
pane->m_nTimer = uint32(dist*100 + CTimer::GetTimeInMilliseconds());
break;
}
pane->m_fGroundZ = groundZ;
pane->m_bShattered = cracked;
pane->m_fStep = upLen / float(ysteps);
pane->m_bActive = true;
}
}
}
}
}
void
CGlass::AskForObjectToBeRenderedInGlass(CEntity *entity)
{
#ifdef FIX_BUGS
if ( NumGlassEntities < NUM_GLASSENTITIES )
#else
if ( NumGlassEntities < NUM_GLASSENTITIES-1 )
#endif
{
apEntitiesToBeRendered[NumGlassEntities++] = entity;
}
}
void
CGlass::RenderEntityInGlass(CEntity *entity)
{
ASSERT(entity!=nil);
CObject *object = (CObject *)entity;
if ( object->bGlassBroken )
return;
float distToCamera = (TheCamera.GetPosition() - object->GetPosition()).Magnitude();
if ( distToCamera > 40.0f )
return;
CVector fwdNorm = object->GetForward();
fwdNorm.Normalise();
uint8 alpha = CalcAlphaWithNormal(&fwdNorm);
CColModel *col = object->GetColModel();
ASSERT(col!=nil);
if ( col->numTriangles >= 2 )
{
CVector a = object->GetMatrix() * col->vertices[0].Get();
CVector b = object->GetMatrix() * col->vertices[1].Get();
CVector c = object->GetMatrix() * col->vertices[2].Get();
CVector d = object->GetMatrix() * col->vertices[3].Get();
if ( object->bGlassCracked )
{
uint8 color = 255;
if ( distToCamera > 30.0f )
color = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 255);
if ( TempBufferIndicesStoredShattered >= TEMPBUFFERINDEXSHATTEREDSIZE-13 || TempBufferVerticesStoredShattered >= TEMPBUFFERVERTSHATTEREDSIZE-5 )
RenderShatteredPolys();
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], color, color, color, color);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 0.0f);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 0.0f);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 16.0f);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 0.0f);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 0.0f);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 16.0f);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], 16.0f);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], 16.0f);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], a.x, a.y, a.z);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], b.x, b.y, b.z);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], c.x, c.y, c.z);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], d.x, d.y, d.z);
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 0] = col->triangles[0].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 1] = col->triangles[0].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 2] = col->triangles[0].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 3] = col->triangles[1].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 4] = col->triangles[1].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 5] = col->triangles[1].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 6] = col->triangles[0].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 7] = col->triangles[0].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 8] = col->triangles[0].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 9] = col->triangles[1].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 10] = col->triangles[1].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 11] = col->triangles[1].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET;
TempBufferIndicesStoredShattered += 12;
TempBufferVerticesStoredShattered += 4;
}
if ( TempBufferIndicesStoredReflection >= TEMPBUFFERINDEXREFLECTIONSIZE-13 || TempBufferVerticesStoredReflection >= TEMPBUFFERVERTREFLECTIONSIZE-5 )
RenderReflectionPolys();
uint8 color = 100;
if ( distToCamera > 30.0f )
color = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 100);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], color, color, color, color);
RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], color, color, color, color);
float FwdAngle = CGeneral::GetATanOfXY(TheCamera.GetForward().x, TheCamera.GetForward().y);
float v = 2.0f * TheCamera.GetForward().z * 0.2f;
float u = float(object->m_randomSeed & 15) * 0.02f + (FwdAngle / TWOPI);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], u);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], v);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], u+0.2f);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], v);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], u);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], v+0.2f);
RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], u+0.2f);
RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], v+0.2f);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], a.x, a.y, a.z);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], b.x, b.y, b.z);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], c.x, c.y, c.z);
RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], d.x, d.y, d.z);
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 0] = col->triangles[0].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 1] = col->triangles[0].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 2] = col->triangles[0].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 3] = col->triangles[1].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 4] = col->triangles[1].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 5] = col->triangles[1].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 6] = col->triangles[0].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 7] = col->triangles[0].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 8] = col->triangles[0].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 9] = col->triangles[1].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 10] = col->triangles[1].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 11] = col->triangles[1].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET;
TempBufferIndicesStoredReflection += 12;
TempBufferVerticesStoredReflection += 4;
}
}
int32
CGlass::CalcAlphaWithNormal(CVector *normal)
{
ASSERT(normal!=nil);
float fwdDir = 2.0f * DotProduct(*normal, TheCamera.GetForward());
float fwdDot = DotProduct(TheCamera.GetForward()-fwdDir*(*normal), CVector(0.57f, 0.57f, -0.57f));
return int32(lerp(fwdDot*fwdDot*fwdDot*fwdDot*fwdDot*fwdDot, 20.0f, 255.0f));
}
void
CGlass::RenderHiLightPolys(void)
{
if ( TempBufferVerticesStoredHiLight != TEMPBUFFERVERTHILIGHTOFFSET )
{
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)RwTextureGetRaster(gpShadowExplosionTex));
LittleTest();
if ( RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStoredHiLight, nil, rwIM3D_VERTEXUV) )
{
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStoredHiLight);
RwIm3DEnd();
}
TempBufferVerticesStoredHiLight = TEMPBUFFERVERTHILIGHTOFFSET;
TempBufferIndicesStoredHiLight = TEMPBUFFERINDEXHILIGHTOFFSET;
}
}
void
CGlass::RenderShatteredPolys(void)
{
if ( TempBufferVerticesStoredShattered != TEMPBUFFERVERTSHATTEREDOFFSET )
{
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)RwTextureGetRaster(gpCrackedGlassTex));
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA);
LittleTest();
if ( RwIm3DTransform(&TempBufferRenderVertices[TEMPBUFFERVERTSHATTEREDOFFSET], TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET, nil, rwIM3D_VERTEXUV) )
{
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, &TempBufferRenderIndexList[TEMPBUFFERINDEXSHATTEREDOFFSET], TempBufferIndicesStoredShattered - TEMPBUFFERINDEXSHATTEREDOFFSET);
RwIm3DEnd();
}
TempBufferIndicesStoredShattered = TEMPBUFFERINDEXSHATTEREDOFFSET;
TempBufferVerticesStoredShattered = TEMPBUFFERVERTSHATTEREDOFFSET;
}
}
void
CGlass::RenderReflectionPolys(void)
{
if ( TempBufferVerticesStoredReflection != TEMPBUFFERVERTREFLECTIONOFFSET )
{
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)RwTextureGetRaster(gpShadowHeadLightsTex));
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA);
LittleTest();
if ( RwIm3DTransform(&TempBufferRenderVertices[TEMPBUFFERVERTREFLECTIONOFFSET], TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET, nil, rwIM3D_VERTEXUV) )
{
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, &TempBufferRenderIndexList[TEMPBUFFERINDEXREFLECTIONOFFSET], TempBufferIndicesStoredReflection - TEMPBUFFERINDEXREFLECTIONOFFSET);
RwIm3DEnd();
}
TempBufferIndicesStoredReflection = TEMPBUFFERINDEXREFLECTIONOFFSET;
TempBufferVerticesStoredReflection = TEMPBUFFERVERTREFLECTIONOFFSET;
}
}
void
CGlass::WindowRespondsToCollision(CEntity *entity, float amount, CVector speed, CVector point, bool explosion)
{
ASSERT(entity!=nil);
CObject *object = (CObject *)entity;
if ( object->bGlassBroken )
return;
object->bGlassCracked = true;
CColModel *col = object->GetColModel();
ASSERT(col!=nil);
CVector a = object->GetMatrix() * col->vertices[0].Get();
CVector b = object->GetMatrix() * col->vertices[1].Get();
CVector c = object->GetMatrix() * col->vertices[2].Get();
CVector d = object->GetMatrix() * col->vertices[3].Get();
float minx = Min(Min(a.x, b.x), Min(c.x, d.x));
float maxx = Max(Max(a.x, b.x), Max(c.x, d.x));
float miny = Min(Min(a.y, b.y), Min(c.y, d.y));
float maxy = Max(Max(a.y, b.y), Max(c.y, d.y));
float minz = Min(Min(a.z, b.z), Min(c.z, d.z));
float maxz = Max(Max(a.z, b.z), Max(c.z, d.z));
if ( amount > 300.0f )
{
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_L, object->GetPosition());
GeneratePanesForWindow(0,
CVector(minx, miny, minz),
CVector(0.0f, 0.0f, maxz-minz),
CVector(maxx-minx, maxy-miny, 0.0f),
speed, point, 0.1f, !!object->bGlassCracked, explosion);
}
else
{
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_BREAK_S, object->GetPosition());
GeneratePanesForWindow(1,
CVector(minx, miny, minz),
CVector(0.0f, 0.0f, maxz-minz),
CVector(maxx-minx, maxy-miny, 0.0f),
speed, point, 0.1f, !!object->bGlassCracked, explosion);
}
object->bGlassBroken = true;
object->GetMatrix().GetPosition().z = -100.0f;
}
void
CGlass::WindowRespondsToSoftCollision(CEntity *entity, float amount)
{
ASSERT(entity!=nil);
CObject *object = (CObject *)entity;
if ( amount > 50.0f && !object->bGlassCracked )
{
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_CRACK, object->GetPosition());
object->bGlassCracked = true;
}
}
void
CGlass::WasGlassHitByBullet(CEntity *entity, CVector point)
{
ASSERT(entity!=nil);
CObject *object = (CObject *)entity;
if ( IsGlass(object->GetModelIndex()) )
{
if ( !object->bGlassCracked )
{
PlayOneShotScriptObject(SCRIPT_SOUND_GLASS_CRACK, object->GetPosition());
object->bGlassCracked = true;
}
else
{
if ( (CGeneral::GetRandomNumber() & 3) == 2 )
WindowRespondsToCollision(object, 0.0f, CVector(0.0f, 0.0f, 0.0f), point, false);
}
}
}
void
CGlass::WindowRespondsToExplosion(CEntity *entity, CVector point)
{
ASSERT(entity!=nil);
CObject *object = (CObject *)entity;
CVector distToGlass = object->GetPosition() - point;
float fDistToGlass = distToGlass.Magnitude();
if ( fDistToGlass < 10.0f )
{
distToGlass *= (0.3f / fDistToGlass); // normalise
WindowRespondsToCollision(object, 10000.0f, distToGlass, object->GetPosition(), true);
}
else
{
if ( fDistToGlass < 30.0f )
object->bGlassCracked = true;
}
}

52
src/renderer/Glass.h Normal file
View File

@ -0,0 +1,52 @@
#pragma once
class CEntity;
class CFallingGlassPane : public CMatrix
{
public:
CVector m_vecMoveSpeed;
CVector m_vecTurn;
uint32 m_nTimer;
float m_fGroundZ;
float m_fStep;
uint8 m_nTriIndex;
bool m_bActive;
bool m_bShattered;
CFallingGlassPane() { }
~CFallingGlassPane() { }
void Update(void);
void Render(void);
};
VALIDATE_SIZE(CFallingGlassPane, 0x70);
enum
{
NUM_GLASSTRIANGLES = 5,
};
class CGlass
{
static uint32 NumGlassEntities;
static CEntity *apEntitiesToBeRendered[NUM_GLASSENTITIES];
static CFallingGlassPane aGlassPanes[NUM_GLASSPANES];
public:
static void Init(void);
static void Update(void);
static void Render(void);
static CFallingGlassPane *FindFreePane(void);
static void GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector point, float moveSpeed, bool cracked, bool explosion);
static void AskForObjectToBeRenderedInGlass(CEntity *entity);
static void RenderEntityInGlass(CEntity *entity);
static int32 CalcAlphaWithNormal(CVector *normal);
static void RenderHiLightPolys(void);
static void RenderShatteredPolys(void);
static void RenderReflectionPolys(void);
static void WindowRespondsToCollision(CEntity *entity, float amount, CVector speed, CVector point, bool explosion);
static void WindowRespondsToSoftCollision(CEntity *entity, float amount);
static void WasGlassHitByBullet(CEntity *entity, CVector point);
static void WindowRespondsToExplosion(CEntity *entity, CVector point);
};

1713
src/renderer/Hud.cpp Normal file

File diff suppressed because it is too large Load Diff

81
src/renderer/Hud.h Normal file
View File

@ -0,0 +1,81 @@
#pragma once
#include "Sprite2d.h"
#define HELP_MSG_LENGTH 256
enum eItems
{
ITEM_NONE = -1,
ITEM_ARMOUR = 3,
ITEM_HEALTH = 4,
ITEM_RADAR = 8
};
enum eSprites
{
HUD_FIST,
HUD_BAT,
HUD_PISTOL,
HUD_UZI,
HUD_SHOTGUN,
HUD_AK47,
HUD_M16,
HUD_SNIPER,
HUD_ROCKET,
HUD_FLAME,
HUD_MOLOTOV,
HUD_GRENADE,
HUD_DETONATOR,
HUD_RADARDISC = 15,
HUD_PAGER = 16,
HUD_SITESNIPER = 20,
HUD_SITEM16,
HUD_SITEROCKET,
NUM_HUD_SPRITES,
};
class CHud
{
public:
static int16 m_ItemToFlash;
static CSprite2d Sprites[NUM_HUD_SPRITES];
static wchar *m_pZoneName;
static wchar *m_pLastZoneName;
static wchar *m_ZoneToPrint;
static wchar m_Message[256];
static wchar m_BigMessage[6][128];
static wchar m_PagerMessage[256];
static uint32 m_ZoneNameTimer;
static int32 m_ZoneFadeTimer;
static uint32 m_ZoneState;
static wchar m_HelpMessage[HELP_MSG_LENGTH];
static wchar m_LastHelpMessage[HELP_MSG_LENGTH];
static wchar m_HelpMessageToPrint[HELP_MSG_LENGTH];
static uint32 m_HelpMessageTimer;
static int32 m_HelpMessageFadeTimer;
static uint32 m_HelpMessageState;
static bool m_HelpMessageQuick;
static float m_HelpMessageDisplayTime;
static int32 SpriteBrightness;
static bool m_Wants_To_Draw_Hud;
static bool m_Wants_To_Draw_3dMarkers;
static wchar *m_pVehicleName;
static wchar *m_pLastVehicleName;
static uint32 m_VehicleNameTimer;
static int32 m_VehicleFadeTimer;
static uint32 m_VehicleState;
static wchar *m_pVehicleNameToPrint;
public:
static void Initialise();
static void Shutdown();
static void ReInitialise();
static void GetRidOfAllHudMessages();
static void SetZoneName(wchar *name);
static void SetHelpMessage(wchar *message, bool quick);
static void SetVehicleName(wchar *name);
static void Draw();
static void DrawAfterFade();
static void SetMessage(wchar *message);
static void SetBigMessage(wchar *message, uint16 style);
static void SetPagerMessage(wchar *message);
};

View File

@ -0,0 +1,9 @@
#include "common.h"
#include "Instance.h"
void
CInstance::Shutdown()
{
GetMatrix().Detach();
}

14
src/renderer/Instance.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include "Placeable.h"
// unused
class CInstance : public CPlaceable
{
public:
int m_modelIndex;
public:
~CInstance() { }
void Shutdown();
};

74
src/renderer/Lines.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "common.h"
#include "main.h"
#include "Lines.h"
// This is super inefficient, why split the line into segments at all?
void
CLines::RenderLineWithClipping(float x1, float y1, float z1, float x2, float y2, float z2, uint32 c1, uint32 c2)
{
static RwIm3DVertex v[2];
#ifdef THIS_IS_STUPID
int i;
float f1, f2;
float len = sqrt(sq(x1-x2) + sq(y1-y2) + sq(z1-z2));
int numsegs = len/1.5f + 1.0f;
RwRGBA col1;
col1.red = c1>>24;
col1.green = c1>>16;
col1.blue = c1>>8;
col1.alpha = c1;
RwRGBA col2;
col2.red = c2>>24;
col2.green = c2>>16;
col2.blue = c2>>8;
col2.alpha = c2;
float dx = x2 - x1;
float dy = y2 - y1;
float dz = z2 - z1;
for(i = 0; i < numsegs; i++){
f1 = (float)i/numsegs;
f2 = (float)(i+1)/numsegs;
RwIm3DVertexSetRGBA(&v[0], (int)(col1.red + (col2.red-col1.red)*f1),
(int)(col1.green + (col2.green-col1.green)*f1),
(int)(col1.blue + (col2.blue-col1.blue)*f1),
(int)(col1.alpha + (col2.alpha-col1.alpha)*f1));
RwIm3DVertexSetRGBA(&v[1], (int)(col1.red + (col2.red-col1.red)*f2),
(int)(col1.green + (col2.green-col1.green)*f2),
(int)(col1.blue + (col2.blue-col1.blue)*f2),
(int)(col1.alpha + (col2.alpha-col1.alpha)*f2));
RwIm3DVertexSetPos(&v[0], x1 + dx*f1, y1 + dy*f1, z1 + dz*f1);
RwIm3DVertexSetPos(&v[1], x1 + dx*f2, y1 + dy*f2, z1 + dz*f2);
LittleTest();
if(RwIm3DTransform(v, 2, nil, 0)){
RwIm3DRenderLine(0, 1);
RwIm3DEnd();
}
}
#else
RwRGBA col1;
col1.red = c1>>24;
col1.green = c1>>16;
col1.blue = c1>>8;
col1.alpha = c1;
RwRGBA col2;
col2.red = c2>>24;
col2.green = c2>>16;
col2.blue = c2>>8;
col2.alpha = c2;
RwIm3DVertexSetRGBA(&v[0], col1.red, col1.green, col1.blue, col1.alpha);
RwIm3DVertexSetRGBA(&v[1], col2.red, col2.green, col2.blue, col2.alpha);
RwIm3DVertexSetPos(&v[0], x1, y1, z1);
RwIm3DVertexSetPos(&v[1], x2, y2, z2);
LittleTest();
if(RwIm3DTransform(v, 2, nil, 0)){
RwIm3DRenderLine(0, 1);
RwIm3DEnd();
}
#endif
}

7
src/renderer/Lines.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
class CLines
{
public:
static void RenderLineWithClipping(float x1, float y1, float z1, float x2, float y2, float z2, uint32 c1, uint32 c2);
};

325
src/renderer/MBlur.cpp Normal file
View File

@ -0,0 +1,325 @@
#ifndef LIBRW
#define WITHD3D
#endif
#include "common.h"
#ifndef LIBRW
#include <d3d8caps.h>
#endif
#include "main.h"
#include "RwHelper.h"
#include "Camera.h"
#include "MBlur.h"
#include "postfx.h"
// Originally taken from RW example 'mblur'
RwRaster *CMBlur::pFrontBuffer;
bool CMBlur::ms_bJustInitialised;
bool CMBlur::ms_bScaledBlur;
bool CMBlur::BlurOn;
static RwIm2DVertex Vertex[4];
static RwImVertexIndex Index[6] = { 0, 1, 2, 0, 2, 3 };
#ifndef LIBRW
extern "C" D3DCAPS8 _RwD3D8DeviceCaps;
#endif
RwBool
CMBlur::MotionBlurOpen(RwCamera *cam)
{
#ifdef EXTENDED_COLOURFILTER
CPostFX::Open(cam);
return TRUE;
#else
#ifdef GTA_PS2
RwRect rect = {0, 0, 0, 0};
if (pFrontBuffer)
return TRUE;
BlurOn = true;
rect.w = RwRasterGetWidth(RwCameraGetRaster(cam));
rect.h = RwRasterGetHeight(RwCameraGetRaster(cam));
pFrontBuffer = RwRasterCreate(0, 0, 0, rwRASTERDONTALLOCATE|rwRASTERTYPECAMERATEXTURE);
if (!pFrontBuffer)
{
printf("Error creating raster\n");
return FALSE;
}
RwRaster *raster = RwRasterSubRaster(pFrontBuffer, RwCameraGetRaster(cam), &rect);
if (!raster)
{
RwRasterDestroy(pFrontBuffer);
pFrontBuffer = NULL;
printf("Error subrastering\n");
return FALSE;
}
CreateImmediateModeData(cam, &rect);
#else
RwRect rect = { 0, 0, 0, 0 };
if(pFrontBuffer)
MotionBlurClose();
#ifndef LIBRW
extern void _GetVideoMemInfo(LPDWORD total, LPDWORD avaible);
DWORD total, avaible;
_GetVideoMemInfo(&total, &avaible);
debug("Available video memory %d\n", avaible);
#endif
if(BlurOn)
{
uint32 width = Pow(2.0f, int32(log2(RwRasterGetWidth (RwCameraGetRaster(cam))))+1);
uint32 height = Pow(2.0f, int32(log2(RwRasterGetHeight(RwCameraGetRaster(cam))))+1);
uint32 depth = RwRasterGetDepth(RwCameraGetRaster(cam));
#ifndef LIBRW
extern DWORD _dwMemTotalVideo;
if ( _RwD3D8DeviceCaps.MaxTextureWidth >= width && _RwD3D8DeviceCaps.MaxTextureHeight >= height )
{
total = _dwMemTotalVideo - 3 *
( RwRasterGetDepth(RwCameraGetRaster(cam))
* RwRasterGetHeight(RwCameraGetRaster(cam))
* RwRasterGetWidth(RwCameraGetRaster(cam)) / 8 );
BlurOn = total >= height*width*(depth/8) + (12*1024*1024) /*12 MB*/;
}
else
BlurOn = false;
#endif
if ( BlurOn )
{
ms_bScaledBlur = false;
rect.w = width;
rect.h = height;
pFrontBuffer = RwRasterCreate(rect.w, rect.h, depth, rwRASTERTYPECAMERATEXTURE);
if ( !pFrontBuffer )
{
debug("MBlurOpen can't create raster.");
BlurOn = false;
rect.w = RwRasterGetWidth(RwCameraGetRaster(cam));
rect.h = RwRasterGetHeight(RwCameraGetRaster(cam));
}
else
ms_bJustInitialised = true;
}
else
{
rect.w = RwRasterGetWidth(RwCameraGetRaster(cam));
rect.h = RwRasterGetHeight(RwCameraGetRaster(cam));
}
#ifndef LIBRW
_GetVideoMemInfo(&total, &avaible);
debug("Available video memory %d\n", avaible);
#endif
CreateImmediateModeData(cam, &rect);
}
else
{
rect.w = RwRasterGetWidth(RwCameraGetRaster(cam));
rect.h = RwRasterGetHeight(RwCameraGetRaster(cam));
CreateImmediateModeData(cam, &rect);
}
return TRUE;
#endif
#endif
}
RwBool
CMBlur::MotionBlurClose(void)
{
#ifdef EXTENDED_COLOURFILTER
CPostFX::Close();
#else
if(pFrontBuffer){
RwRasterDestroy(pFrontBuffer);
pFrontBuffer = nil;
return TRUE;
}
#endif
return FALSE;
}
void
CMBlur::CreateImmediateModeData(RwCamera *cam, RwRect *rect)
{
float zero, xmax, ymax;
if(RwRasterGetDepth(RwCameraGetRaster(cam)) == 16){
zero = HALFPX;
xmax = rect->w + HALFPX;
ymax = rect->h + HALFPX;
}else{
zero = -HALFPX;
xmax = rect->w - HALFPX;
ymax = rect->h - HALFPX;
}
RwIm2DVertexSetScreenX(&Vertex[0], zero);
RwIm2DVertexSetScreenY(&Vertex[0], zero);
RwIm2DVertexSetScreenZ(&Vertex[0], RwIm2DGetNearScreenZ());
RwIm2DVertexSetCameraZ(&Vertex[0], RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetRecipCameraZ(&Vertex[0], 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetU(&Vertex[0], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetV(&Vertex[0], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetIntRGBA(&Vertex[0], 255, 255, 255, 255);
RwIm2DVertexSetScreenX(&Vertex[1], zero);
RwIm2DVertexSetScreenY(&Vertex[1], ymax);
RwIm2DVertexSetScreenZ(&Vertex[1], RwIm2DGetNearScreenZ());
RwIm2DVertexSetCameraZ(&Vertex[1], RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetRecipCameraZ(&Vertex[1], 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetU(&Vertex[1], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetV(&Vertex[1], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetIntRGBA(&Vertex[1], 255, 255, 255, 255);
RwIm2DVertexSetScreenX(&Vertex[2], xmax);
RwIm2DVertexSetScreenY(&Vertex[2], ymax);
RwIm2DVertexSetScreenZ(&Vertex[2], RwIm2DGetNearScreenZ());
RwIm2DVertexSetCameraZ(&Vertex[2], RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetRecipCameraZ(&Vertex[2], 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetU(&Vertex[2], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetV(&Vertex[2], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetIntRGBA(&Vertex[2], 255, 255, 255, 255);
RwIm2DVertexSetScreenX(&Vertex[3], xmax);
RwIm2DVertexSetScreenY(&Vertex[3], zero);
RwIm2DVertexSetScreenZ(&Vertex[3], RwIm2DGetNearScreenZ());
RwIm2DVertexSetCameraZ(&Vertex[3], RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetRecipCameraZ(&Vertex[3], 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetU(&Vertex[3], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetV(&Vertex[3], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam));
RwIm2DVertexSetIntRGBA(&Vertex[3], 255, 255, 255, 255);
}
void
CMBlur::MotionBlurRender(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blur, int32 type, uint32 bluralpha)
{
#ifdef EXTENDED_COLOURFILTER
CPostFX::Render(cam, red, green, blue, blur, type, bluralpha);
#else
PUSH_RENDERGROUP("CMBlur::MotionBlurRender");
RwRGBA color = { (RwUInt8)red, (RwUInt8)green, (RwUInt8)blue, (RwUInt8)blur };
#ifdef GTA_PS2
if( pFrontBuffer )
OverlayRender(cam, pFrontBuffer, color, type, bluralpha);
#else
if(BlurOn){
if(pFrontBuffer){
if(ms_bJustInitialised)
ms_bJustInitialised = false;
else
OverlayRender(cam, pFrontBuffer, color, type, bluralpha);
}
RwRasterPushContext(pFrontBuffer);
RwRasterRenderFast(RwCameraGetRaster(cam), 0, 0);
RwRasterPopContext();
}else{
OverlayRender(cam, nil, color, type, bluralpha);
}
#endif
POP_RENDERGROUP();
#endif
}
void
CMBlur::OverlayRender(RwCamera *cam, RwRaster *raster, RwRGBA color, int32 type, int32 bluralpha)
{
int r, g, b, a;
r = color.red;
g = color.green;
b = color.blue;
a = color.alpha;
DefinedState();
switch(type)
{
case MOTION_BLUR_SECURITY_CAM:
r = 0;
g = 255;
b = 0;
a = 128;
break;
case MOTION_BLUR_INTRO:
r = 100;
g = 220;
b = 230;
a = 158;
break;
case MOTION_BLUR_INTRO2:
r = 80;
g = 255;
b = 230;
a = 138;
break;
case MOTION_BLUR_INTRO3:
r = 255;
g = 60;
b = 60;
a = 200;
break;
case MOTION_BLUR_INTRO4:
r = 255;
g = 180;
b = 180;
a = 128;
break;
}
if(!BlurOn){
r = Min(r*0.6f, 255.0f);
g = Min(g*0.6f, 255.0f);
b = Min(b*0.6f, 255.0f);
if(type != MOTION_BLUR_SNIPER)
a = Min(a*0.6f, 255.0f);
// game clamps to 255 here, but why?
}
RwIm2DVertexSetIntRGBA(&Vertex[0], r, g, b, a);
RwIm2DVertexSetIntRGBA(&Vertex[1], r, g, b, a);
RwIm2DVertexSetIntRGBA(&Vertex[2], r, g, b, a);
RwIm2DVertexSetIntRGBA(&Vertex[3], r, g, b, a);
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERNEAREST);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, BlurOn ? raster : nil);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6);
a = bluralpha/2;
if(a < 30)
a = 30;
if(BlurOn && a != 0){ // the second condition should always be true
RwIm2DVertexSetIntRGBA(&Vertex[0], 255, 255, 255, a);
RwIm2DVertexSetIntRGBA(&Vertex[1], 255, 255, 255, a);
RwIm2DVertexSetIntRGBA(&Vertex[2], 255, 255, 255, a);
RwIm2DVertexSetIntRGBA(&Vertex[3], 255, 255, 255, a);
RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6);
}
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
}

17
src/renderer/MBlur.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
class CMBlur
{
public:
static RwRaster *pFrontBuffer;
static bool ms_bJustInitialised;
static bool ms_bScaledBlur;
static bool BlurOn;
public:
static RwBool MotionBlurOpen(RwCamera *cam);
static RwBool MotionBlurClose(void);
static void CreateImmediateModeData(RwCamera *cam, RwRect *rect);
static void MotionBlurRender(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blur, int32 type, uint32 bluralpha);
static void OverlayRender(RwCamera *cam, RwRaster *raster, RwRGBA color, int32 type, int32 bluralpha);
};

1902
src/renderer/Particle.cpp Normal file

File diff suppressed because it is too large Load Diff

94
src/renderer/Particle.h Normal file
View File

@ -0,0 +1,94 @@
#pragma once
#include "ParticleMgr.h"
class CEntity;
class CParticle
{
public:
enum
{
RAND_TABLE_SIZE = 20,
SIN_COS_TABLE_SIZE = 1024
};
CVector m_vecPosition;
CVector m_vecVelocity;
CVector m_vecScreenPosition;
uint32 m_nTimeWhenWillBeDestroyed;
uint32 m_nTimeWhenColorWillBeChanged;
float m_fZGround;
CVector m_vecParticleMovementOffset;
int16 m_nCurrentZRotation;
uint16 m_nZRotationTimer;
float m_fCurrentZRadius;
uint16 m_nZRadiusTimer;
float m_fSize;
float m_fExpansionRate;
uint16 m_nFadeToBlackTimer;
uint16 m_nFadeAlphaTimer;
uint8 m_nColorIntensity;
uint8 m_nAlpha;
uint16 m_nCurrentFrame;
int16 m_nAnimationSpeedTimer;
int16 m_nRotationStep;
int16 m_nRotation;
RwRGBA m_Color;
CParticle *m_pNext;
CParticle()
{
;
}
~CParticle()
{
;
}
static float ms_afRandTable[RAND_TABLE_SIZE];
static CParticle *m_pUnusedListHead;
static float m_SinTable[SIN_COS_TABLE_SIZE];
static float m_CosTable[SIN_COS_TABLE_SIZE];
static float Sin(int32 value) { return m_SinTable[value]; }
static float Cos(int32 value) { return m_CosTable[value]; }
static void ReloadConfig();
static void Initialise();
static void Shutdown();
static CParticle *AddParticle(tParticleType type, CVector const &vecPos, CVector const &vecDir, CEntity *pEntity = nil, float fSize = 0.0f, int32 nRotationSpeed = 0, int32 nRotation = 0, int32 nCurFrame = 0, int32 nLifeSpan = 0);
static CParticle *AddParticle(tParticleType type, CVector const &vecPos, CVector const &vecDir, CEntity *pEntity, float fSize, RwRGBA const &color, int32 nRotationSpeed = 0, int32 nRotation = 0, int32 nCurFrame = 0, int32 nLifeSpan = 0);
static void Update();
static void Render();
static void RemovePSystem(tParticleType type);
static void RemoveParticle(CParticle *pParticle, CParticle *pPrevParticle, tParticleSystemData *pPSystemData);
static void _Next(CParticle *&pParticle, CParticle *&pPrevParticle, tParticleSystemData *pPSystemData, bool bRemoveParticle)
{
if ( bRemoveParticle )
{
RemoveParticle(pParticle, pPrevParticle, pPSystemData);
if ( pPrevParticle )
pParticle = pPrevParticle->m_pNext;
else
pParticle = pPSystemData->m_pParticles;
}
else
{
pPrevParticle = pParticle;
pParticle = pParticle->m_pNext;
}
}
static void AddJetExplosion(CVector const &vecPos, float fPower, float fSize);
static void AddYardieDoorSmoke(CVector const &vecPos, CMatrix const &matMatrix);
};
VALIDATE_SIZE(CParticle, 0x68);

View File

@ -0,0 +1,243 @@
#include "common.h"
#include "main.h"
#include "FileMgr.h"
#include "ParticleMgr.h"
cParticleSystemMgr mod_ParticleSystemManager;
const char *ParticleFilename = "PARTICLE.CFG";
cParticleSystemMgr::cParticleSystemMgr()
{
memset(this, 0, sizeof(*this));
}
void cParticleSystemMgr::Initialise()
{
LoadParticleData();
for ( int32 i = 0; i < MAX_PARTICLES; i++ )
m_aParticles[i].m_pParticles = nil;
}
void cParticleSystemMgr::LoadParticleData()
{
CFileMgr::SetDir("DATA");
CFileMgr::LoadFile(ParticleFilename, work_buff, ARRAY_SIZE(work_buff), "r");
CFileMgr::SetDir("");
tParticleSystemData *entry = nil;
int32 type = PARTICLE_FIRST;
char *lineStart = (char *)work_buff;
char *lineEnd = lineStart + 1;
char line[500];
char delims[4];
while ( true )
{
ASSERT(lineStart != nil);
ASSERT(lineEnd != nil);
while ( *lineEnd != '\n' )
++lineEnd;
int32 lineLength = lineEnd - lineStart;
ASSERT(lineLength < 500);
strncpy(line, lineStart, lineLength);
line[lineLength] = '\0';
if ( !strcmp(line, ";the end") )
break;
if ( *line != ';' )
{
int32 param = CFG_PARAM_FIRST;
strcpy(delims, " \t");
char *value = strtok(line, delims);
ASSERT(value != nil);
do
{
switch ( param )
{
case CFG_PARAM_PARTICLE_TYPE_NAME:
ASSERT(type < MAX_PARTICLES);
entry = &m_aParticles[type];
ASSERT(entry != nil);
entry->m_Type = (tParticleType)type++;
strcpy(entry->m_aName, value);
break;
case CFG_PARAM_RENDER_COLOURING_R:
entry->m_RenderColouring.red = atoi(value);
break;
case CFG_PARAM_RENDER_COLOURING_G:
entry->m_RenderColouring.green = atoi(value);
break;
case CFG_PARAM_RENDER_COLOURING_B:
entry->m_RenderColouring.blue = atoi(value);
break;
case CFG_PARAM_INITIAL_COLOR_VARIATION:
entry->m_InitialColorVariation = Min(atoi(value), 100);
break;
case CFG_PARAM_FADE_DESTINATION_COLOR_R:
entry->m_FadeDestinationColor.red = atoi(value);
break;
case CFG_PARAM_FADE_DESTINATION_COLOR_G:
entry->m_FadeDestinationColor.green = atoi(value);
break;
case CFG_PARAM_FADE_DESTINATION_COLOR_B:
entry->m_FadeDestinationColor.blue = atoi(value);
break;
case CFG_PARAM_COLOR_FADE_TIME:
entry->m_ColorFadeTime = atoi(value);
break;
case CFG_PARAM_DEFAULT_INITIAL_RADIUS:
entry->m_fDefaultInitialRadius = atof(value);
break;
case CFG_PARAM_EXPANSION_RATE:
entry->m_fExpansionRate = atof(value);
break;
case CFG_PARAM_INITIAL_INTENSITY:
entry->m_nFadeToBlackInitialIntensity = atoi(value);
break;
case CFG_PARAM_FADE_TIME:
entry->m_nFadeToBlackTime = atoi(value);
break;
case CFG_PARAM_FADE_AMOUNT:
entry->m_nFadeToBlackAmount = atoi(value);
break;
case CFG_PARAM_INITIAL_ALPHA_INTENSITY:
entry->m_nFadeAlphaInitialIntensity = atoi(value);
break;
case CFG_PARAM_FADE_ALPHA_TIME:
entry->m_nFadeAlphaTime = atoi(value);
break;
case CFG_PARAM_FADE_ALPHA_AMOUNT:
entry->m_nFadeAlphaAmount = atoi(value);
break;
case CFG_PARAM_INITIAL_ANGLE:
entry->m_nZRotationInitialAngle = atoi(value);
break;
case CFG_PARAM_CHANGE_TIME:
entry->m_nZRotationChangeTime = atoi(value);
break;
case CFG_PARAM_ANGLE_CHANGE_AMOUNT:
entry->m_nZRotationAngleChangeAmount = atoi(value);
break;
case CFG_PARAM_INITIAL_Z_RADIUS:
entry->m_fInitialZRadius = atof(value);
break;
case CFG_PARAM_Z_RADIUS_CHANGE_TIME:
entry->m_nZRadiusChangeTime = atoi(value);
break;
case CFG_PARAM_Z_RADIUS_CHANGE_AMOUNT:
entry->m_fZRadiusChangeAmount = atof(value);
break;
case CFG_PARAM_ANIMATION_SPEED:
entry->m_nAnimationSpeed = atoi(value);
break;
case CFG_PARAM_START_ANIMATION_FRAME:
entry->m_nStartAnimationFrame = atoi(value);
break;
case CFG_PARAM_FINAL_ANIMATION_FRAME:
entry->m_nFinalAnimationFrame = atoi(value);
break;
case CFG_PARAM_ROTATION_SPEED:
entry->m_nRotationSpeed = atoi(value);
break;
case CFG_PARAM_GRAVITATIONAL_ACCELERATION:
entry->m_fGravitationalAcceleration = atof(value);
break;
case CFG_PARAM_FRICTION_DECCELERATION:
entry->m_nFrictionDecceleration = atoi(value);
break;
case CFG_PARAM_LIFE_SPAN:
entry->m_nLifeSpan = atoi(value);
break;
case CFG_PARAM_POSITION_RANDOM_ERROR:
entry->m_fPositionRandomError = atof(value);
break;
case CFG_PARAM_VELOCITY_RANDOM_ERROR:
entry->m_fVelocityRandomError = atof(value);
break;
case CFG_PARAM_EXPANSION_RATE_ERROR:
entry->m_fExpansionRateError = atof(value);
break;
case CFG_PARAM_ROTATION_RATE_ERROR:
entry->m_nRotationRateError = atoi(value);
break;
case CFG_PARAM_LIFE_SPAN_ERROR_SHAPE:
entry->m_nLifeSpanErrorShape = atoi(value);
break;
case CFG_PARAM_TRAIL_LENGTH_MULTIPLIER:
entry->m_fTrailLengthMultiplier = atof(value);
break;
case CFG_PARAM_PARTICLE_CREATE_RANGE:
entry->m_fCreateRange = SQR(atof(value));
break;
case CFG_PARAM_FLAGS:
entry->Flags = atoi(value);
break;
}
value = strtok(nil, delims);
param++;
if ( param > CFG_PARAM_LAST )
param = CFG_PARAM_FIRST;
} while ( value != nil );
}
lineEnd++;
lineStart = lineEnd;
lineEnd++;
}
}

130
src/renderer/ParticleMgr.h Normal file
View File

@ -0,0 +1,130 @@
#pragma once
#include "ParticleType.h"
class CParticle;
enum
{
ZCHECK_FIRST = BIT(0),
ZCHECK_STEP = BIT(1),
DRAW_OPAQUE = BIT(2),
SCREEN_TRAIL = BIT(3),
SPEED_TRAIL = BIT(4),
RAND_VERT_V = BIT(5),
CYCLE_ANIM = BIT(6),
DRAW_DARK = BIT(7),
VERT_TRAIL = BIT(8),
_FLAG9 = BIT(9), // unused
DRAWTOP2D = BIT(10),
CLIPOUT2D = BIT(11),
ZCHECK_BUMP = BIT(12),
ZCHECK_BUMP_FIRST = BIT(13)
};
struct tParticleSystemData
{
tParticleType m_Type;
char m_aName[20];
float m_fCreateRange;
float m_fDefaultInitialRadius;
float m_fExpansionRate;
uint16 m_nZRotationInitialAngle;
int16 m_nZRotationAngleChangeAmount;
uint16 m_nZRotationChangeTime;
uint16 m_nZRadiusChangeTime;
float m_fInitialZRadius;
float m_fZRadiusChangeAmount;
uint16 m_nFadeToBlackTime;
int16 m_nFadeToBlackAmount;
uint8 m_nFadeToBlackInitialIntensity;
uint8 m_nFadeAlphaInitialIntensity;
uint16 m_nFadeAlphaTime;
int16 m_nFadeAlphaAmount;
uint16 m_nStartAnimationFrame;
uint16 m_nFinalAnimationFrame;
uint16 m_nAnimationSpeed;
uint16 m_nRotationSpeed;
float m_fGravitationalAcceleration;
int32 m_nFrictionDecceleration;
int32 m_nLifeSpan;
float m_fPositionRandomError;
float m_fVelocityRandomError;
float m_fExpansionRateError;
int32 m_nRotationRateError;
uint32 m_nLifeSpanErrorShape;
float m_fTrailLengthMultiplier;
uint32 Flags;
RwRGBA m_RenderColouring;
uint8 m_InitialColorVariation;
RwRGBA m_FadeDestinationColor;
uint32 m_ColorFadeTime;
RwRaster **m_ppRaster;
CParticle *m_pParticles;
};
VALIDATE_SIZE(tParticleSystemData, 0x88);
class cParticleSystemMgr
{
enum
{
CFG_PARAM_PARTICLE_TYPE_NAME = 0,
CFG_PARAM_RENDER_COLOURING_R,
CFG_PARAM_RENDER_COLOURING_G,
CFG_PARAM_RENDER_COLOURING_B,
CFG_PARAM_INITIAL_COLOR_VARIATION,
CFG_PARAM_FADE_DESTINATION_COLOR_R,
CFG_PARAM_FADE_DESTINATION_COLOR_G,
CFG_PARAM_FADE_DESTINATION_COLOR_B,
CFG_PARAM_COLOR_FADE_TIME,
CFG_PARAM_DEFAULT_INITIAL_RADIUS,
CFG_PARAM_EXPANSION_RATE,
CFG_PARAM_INITIAL_INTENSITY,
CFG_PARAM_FADE_TIME,
CFG_PARAM_FADE_AMOUNT,
CFG_PARAM_INITIAL_ALPHA_INTENSITY,
CFG_PARAM_FADE_ALPHA_TIME,
CFG_PARAM_FADE_ALPHA_AMOUNT,
CFG_PARAM_INITIAL_ANGLE,
CFG_PARAM_CHANGE_TIME,
CFG_PARAM_ANGLE_CHANGE_AMOUNT,
CFG_PARAM_INITIAL_Z_RADIUS,
CFG_PARAM_Z_RADIUS_CHANGE_TIME,
CFG_PARAM_Z_RADIUS_CHANGE_AMOUNT,
CFG_PARAM_ANIMATION_SPEED,
CFG_PARAM_START_ANIMATION_FRAME,
CFG_PARAM_FINAL_ANIMATION_FRAME,
CFG_PARAM_ROTATION_SPEED,
CFG_PARAM_GRAVITATIONAL_ACCELERATION,
CFG_PARAM_FRICTION_DECCELERATION,
CFG_PARAM_LIFE_SPAN,
CFG_PARAM_POSITION_RANDOM_ERROR,
CFG_PARAM_VELOCITY_RANDOM_ERROR,
CFG_PARAM_EXPANSION_RATE_ERROR,
CFG_PARAM_ROTATION_RATE_ERROR,
CFG_PARAM_LIFE_SPAN_ERROR_SHAPE,
CFG_PARAM_TRAIL_LENGTH_MULTIPLIER,
CFG_PARAM_PARTICLE_CREATE_RANGE,
CFG_PARAM_FLAGS,
MAX_CFG_PARAMS,
CFG_PARAM_FIRST = CFG_PARAM_PARTICLE_TYPE_NAME,
CFG_PARAM_LAST = CFG_PARAM_FLAGS
};
public:
tParticleSystemData m_aParticles[MAX_PARTICLES];
cParticleSystemMgr();
void Initialise();
void LoadParticleData();
void RangeCheck(tParticleSystemData *pData) { }
};
VALIDATE_SIZE(cParticleSystemMgr, 0x2420);
extern cParticleSystemMgr mod_ParticleSystemManager;

View File

@ -0,0 +1,77 @@
#pragma once
enum tParticleType
{
PARTICLE_SPARK = 0,
PARTICLE_SPARK_SMALL,
PARTICLE_WHEEL_DIRT,
PARTICLE_WHEEL_WATER,
PARTICLE_BLOOD,
PARTICLE_BLOOD_SMALL,
PARTICLE_BLOOD_SPURT,
PARTICLE_DEBRIS,
PARTICLE_DEBRIS2,
PARTICLE_WATER,
PARTICLE_FLAME,
PARTICLE_FIREBALL,
PARTICLE_GUNFLASH,
PARTICLE_GUNFLASH_NOANIM,
PARTICLE_GUNSMOKE,
PARTICLE_GUNSMOKE2,
PARTICLE_SMOKE,
PARTICLE_SMOKE_SLOWMOTION,
PARTICLE_GARAGEPAINT_SPRAY,
PARTICLE_SHARD,
PARTICLE_SPLASH,
PARTICLE_CARFLAME,
PARTICLE_STEAM,
PARTICLE_STEAM2,
PARTICLE_STEAM_NY,
PARTICLE_STEAM_NY_SLOWMOTION,
PARTICLE_ENGINE_STEAM,
PARTICLE_RAINDROP,
PARTICLE_RAINDROP_SMALL,
PARTICLE_RAIN_SPLASH,
PARTICLE_RAIN_SPLASH_BIGGROW,
PARTICLE_RAIN_SPLASHUP,
PARTICLE_WATERSPRAY,
PARTICLE_EXPLOSION_MEDIUM,
PARTICLE_EXPLOSION_LARGE,
PARTICLE_EXPLOSION_MFAST,
PARTICLE_EXPLOSION_LFAST,
PARTICLE_CAR_SPLASH,
PARTICLE_BOAT_SPLASH,
PARTICLE_BOAT_THRUSTJET,
PARTICLE_BOAT_WAKE,
PARTICLE_WATER_HYDRANT,
PARTICLE_WATER_CANNON,
PARTICLE_EXTINGUISH_STEAM,
PARTICLE_PED_SPLASH,
PARTICLE_PEDFOOT_DUST,
PARTICLE_HELI_DUST,
PARTICLE_HELI_ATTACK,
PARTICLE_ENGINE_SMOKE,
PARTICLE_ENGINE_SMOKE2,
PARTICLE_CARFLAME_SMOKE,
PARTICLE_FIREBALL_SMOKE,
PARTICLE_PAINT_SMOKE,
PARTICLE_TREE_LEAVES,
PARTICLE_CARCOLLISION_DUST,
PARTICLE_CAR_DEBRIS,
PARTICLE_HELI_DEBRIS,
PARTICLE_EXHAUST_FUMES,
PARTICLE_RUBBER_SMOKE,
PARTICLE_BURNINGRUBBER_SMOKE,
PARTICLE_BULLETHIT_SMOKE,
PARTICLE_GUNSHELL_FIRST,
PARTICLE_GUNSHELL,
PARTICLE_GUNSHELL_BUMP1,
PARTICLE_GUNSHELL_BUMP2,
PARTICLE_TEST,
PARTICLE_BIRD_FRONT,
PARTICLE_RAINDROP_2D,
MAX_PARTICLES,
PARTICLE_FIRST = PARTICLE_SPARK,
PARTICLE_LAST = PARTICLE_RAINDROP_2D
};

166
src/renderer/PlayerSkin.cpp Normal file
View File

@ -0,0 +1,166 @@
#include "common.h"
#include "main.h"
#include "PlayerSkin.h"
#include "TxdStore.h"
#include "rtbmp.h"
#include "ClumpModelInfo.h"
#include "VisibilityPlugins.h"
#include "World.h"
#include "PlayerInfo.h"
#include "CdStream.h"
#include "FileMgr.h"
#include "Directory.h"
#include "RwHelper.h"
#include "Timer.h"
#include "Lights.h"
#include "MemoryMgr.h"
RpClump *gpPlayerClump;
float gOldFov;
int CPlayerSkin::m_txdSlot;
void
FindPlayerDff(uint32 &offset, uint32 &size)
{
int file;
CDirectory::DirectoryInfo info;
file = CFileMgr::OpenFile("models\\gta3.dir", "rb");
do {
if (!CFileMgr::Read(file, (char*)&info, sizeof(CDirectory::DirectoryInfo)))
return;
} while (strcasecmp("player.dff", info.name) != 0);
offset = info.offset;
size = info.size;
}
void
LoadPlayerDff(void)
{
RwStream *stream;
RwMemory mem;
uint32 offset, size;
uint8 *buffer;
bool streamWasAdded = false;
if (CdStreamGetNumImages() == 0) {
CdStreamAddImage("models\\gta3.img");
streamWasAdded = true;
}
FindPlayerDff(offset, size);
buffer = (uint8*)RwMallocAlign(size << 11, 2048);
CdStreamRead(0, buffer, offset, size);
CdStreamSync(0);
mem.start = buffer;
mem.length = size << 11;
stream = RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem);
if (RwStreamFindChunk(stream, rwID_CLUMP, nil, nil))
gpPlayerClump = RpClumpStreamRead(stream);
RwStreamClose(stream, &mem);
RwFreeAlign(buffer);
if (streamWasAdded)
CdStreamRemoveImages();
}
void
CPlayerSkin::Initialise(void)
{
m_txdSlot = CTxdStore::AddTxdSlot("skin");
CTxdStore::Create(m_txdSlot);
CTxdStore::AddRef(m_txdSlot);
}
void
CPlayerSkin::Shutdown(void)
{
CTxdStore::RemoveTxdSlot(m_txdSlot);
}
RwTexture *
CPlayerSkin::GetSkinTexture(const char *texName)
{
RwTexture *tex;
RwRaster *raster;
int32 width, height, depth, format;
CTxdStore::PushCurrentTxd();
CTxdStore::SetCurrentTxd(m_txdSlot);
tex = RwTextureRead(texName, NULL);
CTxdStore::PopCurrentTxd();
if (tex != nil) return tex;
if (strcmp(DEFAULT_SKIN_NAME, texName) == 0)
sprintf(gString, "models\\generic\\player.bmp");
else
sprintf(gString, "skins\\%s.bmp", texName);
if (RwImage *image = RtBMPImageRead(gString)) {
RwImageFindRasterFormat(image, rwRASTERTYPETEXTURE, &width, &height, &depth, &format);
raster = RwRasterCreate(width, height, depth, format);
RwRasterSetFromImage(raster, image);
tex = RwTextureCreate(raster);
RwTextureSetName(tex, texName);
#ifdef FIX_BUGS
RwTextureSetFilterMode(tex, rwFILTERLINEAR); // filtering bugfix from VC
#endif
RwTexDictionaryAddTexture(CTxdStore::GetSlot(m_txdSlot)->texDict, tex);
RwImageDestroy(image);
}
return tex;
}
void
CPlayerSkin::BeginFrontendSkinEdit(void)
{
LoadPlayerDff();
RpClumpForAllAtomics(gpPlayerClump, CClumpModelInfo::SetAtomicRendererCB, (void*)CVisibilityPlugins::RenderPlayerCB);
CWorld::Players[0].LoadPlayerSkin();
gOldFov = CDraw::GetFOV();
CDraw::SetFOV(30.0f);
}
void
CPlayerSkin::EndFrontendSkinEdit(void)
{
RpClumpDestroy(gpPlayerClump);
gpPlayerClump = NULL;
CDraw::SetFOV(gOldFov);
}
void
CPlayerSkin::RenderFrontendSkinEdit(void)
{
static float rotation = 0.0f;
RwRGBAReal AmbientColor = { 0.65f, 0.65f, 0.65f, 1.0f };
const RwV3d pos = { 1.35f, 0.35f, 7.725f };
const RwV3d axis1 = { 1.0f, 0.0f, 0.0f };
const RwV3d axis2 = { 0.0f, 0.0f, 1.0f };
static uint32 LastFlash = 0;
RwFrame *frame = RpClumpGetFrame(gpPlayerClump);
if (CTimer::GetTimeInMillisecondsPauseMode() - LastFlash > 7) {
rotation += 2.0f;
if (rotation > 360.0f)
rotation -= 360.0f;
LastFlash = CTimer::GetTimeInMillisecondsPauseMode();
}
RwFrameTransform(frame, RwFrameGetMatrix(RwCameraGetFrame(Scene.camera)), rwCOMBINEREPLACE);
RwFrameTranslate(frame, &pos, rwCOMBINEPRECONCAT);
RwFrameRotate(frame, &axis1, -90.0f, rwCOMBINEPRECONCAT);
RwFrameRotate(frame, &axis2, rotation, rwCOMBINEPRECONCAT);
RwFrameUpdateObjects(frame);
SetAmbientColours(&AmbientColor);
RpClumpRender(gpPlayerClump);
}

15
src/renderer/PlayerSkin.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#define DEFAULT_SKIN_NAME "$$\"\""
class CPlayerSkin
{
static int m_txdSlot;
public:
static void Initialise();
static void Shutdown();
static RwTexture *GetSkinTexture(const char *texName);
static void BeginFrontendSkinEdit();
static void EndFrontendSkinEdit();
static void RenderFrontendSkinEdit();
};

View File

@ -0,0 +1,289 @@
#include "common.h"
#include "main.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;
CRegisteredPointLight CPointLights::aLights[NUMPOINTLIGHTS];
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(Abs(dist.x) < MAX_DIST && Abs(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(Const 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 || aLights[i].type == LIGHT_FOGONLY_ALWAYS)
continue;
// same weird distance calculation. simplified here
dist = aLights[i].coors - *objCoors;
radius = aLights[i].radius;
if(Abs(dist.x) < radius &&
Abs(dist.y) < radius &&
Abs(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;
// distance fade
if(distNorm < 0.5f)
intensity = 1.0f;
else
intensity = 1.0f - (distNorm - 0.5f)/(1.0f - 0.5f);
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;
PUSH_RENDERGROUP("CPointLights::RenderFogEffect");
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_NORMAL ? CWeather::Foggyness : 1.0f;
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 + 10.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 / 0x2000;
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 || aLights[i].type == LIGHT_FOGONLY_ALWAYS){
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 / 0x4000;
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);
}
}
}
}
}
}
}
}
POP_RENDERGROUP();
}

View File

@ -0,0 +1,45 @@
#pragma once
class CRegisteredPointLight
{
public:
CVector coors;
CVector dir;
float radius;
float red;
float green;
float blue;
int8 type;
int8 fogType;
bool castExtraShadows;
};
VALIDATE_SIZE(CRegisteredPointLight, 0x2C);
class CPointLights
{
public:
static int16 NumLights;
static CRegisteredPointLight aLights[NUMPOINTLIGHTS];
enum {
LIGHT_POINT,
LIGHT_DIRECTIONAL,
LIGHT_DARKEN, // no effects at all
// these have only fog, otherwise no difference?
// only used by CEntity::ProcessLightsForEntity it seems
// and there used together with fog type
LIGHT_FOGONLY_ALWAYS,
LIGHT_FOGONLY,
};
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(Const CVector *objCoors);
static void RemoveLightsAffectingObject(void);
static void RenderFogEffect(void);
};

View File

@ -0,0 +1,52 @@
#include "common.h"
#include "RenderBuffer.h"
int32 TempBufferVerticesStored;
int32 TempBufferIndicesStored;
RwIm3DVertex TempBufferRenderVertices[TEMPBUFFERVERTSIZE];
RwImVertexIndex TempBufferRenderIndexList[TEMPBUFFERINDEXSIZE];
int RenderBuffer::VerticesToBeStored;
int RenderBuffer::IndicesToBeStored;
void
RenderBuffer::ClearRenderBuffer(void)
{
TempBufferVerticesStored = 0;
TempBufferIndicesStored = 0;
}
void
RenderBuffer::StartStoring(int numIndices, int numVertices, RwImVertexIndex **indexStart, RwIm3DVertex **vertexStart)
{
if(TempBufferIndicesStored + numIndices >= TEMPBUFFERINDEXSIZE)
RenderStuffInBuffer();
if(TempBufferVerticesStored + numVertices >= TEMPBUFFERVERTSIZE)
RenderStuffInBuffer();
*indexStart = &TempBufferRenderIndexList[TempBufferIndicesStored];
*vertexStart = &TempBufferRenderVertices[TempBufferVerticesStored];
IndicesToBeStored = numIndices;
VerticesToBeStored = numVertices;
}
void
RenderBuffer::StopStoring(void)
{
int i;
for(i = TempBufferIndicesStored; i < TempBufferIndicesStored+IndicesToBeStored; i++)
TempBufferRenderIndexList[i] += TempBufferVerticesStored;
TempBufferIndicesStored += IndicesToBeStored;
TempBufferVerticesStored += VerticesToBeStored;
}
void
RenderBuffer::RenderStuffInBuffer(void)
{
if(TempBufferVerticesStored && RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
RwIm3DEnd();
}
ClearRenderBuffer();
}

View File

@ -0,0 +1,18 @@
class RenderBuffer
{
public:
static int VerticesToBeStored;
static int IndicesToBeStored;
static void ClearRenderBuffer(void);
static void StartStoring(int numIndices, int numVertices, RwImVertexIndex **indexStart, RwIm3DVertex **vertexStart);
static void StopStoring(void);
static void RenderStuffInBuffer(void);
};
#define TEMPBUFFERVERTSIZE 256
#define TEMPBUFFERINDEXSIZE 1024
extern int32 TempBufferVerticesStored;
extern int32 TempBufferIndicesStored;
extern RwIm3DVertex TempBufferRenderVertices[TEMPBUFFERVERTSIZE];
extern RwImVertexIndex TempBufferRenderIndexList[TEMPBUFFERINDEXSIZE];

1838
src/renderer/Renderer.cpp Normal file

File diff suppressed because it is too large Load Diff

119
src/renderer/Renderer.h Normal file
View File

@ -0,0 +1,119 @@
#pragma once
class CEntity;
#ifdef FIX_BUGS
#define LOD_DISTANCE (300.0f*TheCamera.LODDistMultiplier)
#else
#define LOD_DISTANCE 300.0f
#endif
#define FADE_DISTANCE 20.0f
#define STREAM_DISTANCE 30.0f
#ifdef EXTRA_MODEL_FLAGS
#define BACKFACE_CULLING_ON SetCullMode(rwCULLMODECULLBACK)
#define BACKFACE_CULLING_OFF SetCullMode(rwCULLMODECULLNONE)
#else
#define BACKFACE_CULLING_ON
#define BACKFACE_CULLING_OFF
#endif
extern bool gbShowPedRoadGroups;
extern bool gbShowCarRoadGroups;
extern bool gbShowCollisionPolys;
extern bool gbShowCollisionLines;
extern bool gbShowCullZoneDebugStuff;
extern bool gbDisableZoneCull; // not original
extern bool gbBigWhiteDebugLightSwitchedOn;
extern bool gbDontRenderBuildings;
extern bool gbDontRenderBigBuildings;
extern bool gbDontRenderPeds;
extern bool gbDontRenderObjects;
extern bool gbDontRenderVehicles;
class CVehicle;
class CPtrList;
// unused
struct BlockedRange
{
float a, b; // unknown
BlockedRange *prev, *next;
};
class CRenderer
{
static int32 ms_nNoOfVisibleEntities;
static CEntity *ms_aVisibleEntityPtrs[NUMVISIBLEENTITIES];
static int32 ms_nNoOfInVisibleEntities;
static CEntity *ms_aInVisibleEntityPtrs[NUMINVISIBLEENTITIES];
#ifdef NEW_RENDERER
static int32 ms_nNoOfVisibleVehicles;
static CEntity *ms_aVisibleVehiclePtrs[NUMVISIBLEENTITIES];
// for cWorldStream emulation
static int32 ms_nNoOfVisibleBuildings;
static CEntity *ms_aVisibleBuildingPtrs[NUMVISIBLEENTITIES];
#endif
static CVector ms_vecCameraPosition;
static CVehicle *m_pFirstPersonVehicle;
// unused
static BlockedRange aBlockedRanges[16];
static BlockedRange *pFullBlockedRanges;
static BlockedRange *pEmptyBlockedRanges;
public:
static float ms_lodDistScale;
static bool m_loadingPriority;
static void Init(void);
static void Shutdown(void);
static void PreRender(void);
static void RenderRoads(void);
static void RenderFadingInEntities(void);
static void RenderEverythingBarRoads(void);
static void RenderVehiclesButNotBoats(void);
static void RenderBoats(void);
static void RenderOneRoad(CEntity *);
static void RenderOneNonRoad(CEntity *);
static void RenderFirstPersonVehicle(void);
static void RenderCollisionLines(void);
// unused
static void RenderBlockBuildingLines(void);
static int32 SetupEntityVisibility(CEntity *ent);
static int32 SetupBigBuildingVisibility(CEntity *ent);
static void ConstructRenderList(void);
static void ScanWorld(void);
static void RequestObjectsInFrustum(void);
static void ScanSectorPoly(RwV2d *poly, int32 numVertices, void (*scanfunc)(CPtrList *));
static void ScanBigBuildingList(CPtrList &list);
static void ScanSectorList(CPtrList *lists);
static void ScanSectorList_Priority(CPtrList *lists);
static void ScanSectorList_Subway(CPtrList *lists);
static void ScanSectorList_RequestModels(CPtrList *lists);
static void SortBIGBuildings(void);
static void SortBIGBuildingsForSectorList(CPtrList *list);
static bool ShouldModelBeStreamed(CEntity *ent);
static bool IsEntityCullZoneVisible(CEntity *ent);
static bool IsVehicleCullZoneVisible(CEntity *ent);
static void RemoveVehiclePedLights(CEntity *ent, bool reset);
#ifdef NEW_RENDERER
static void ClearForFrame(void);
static void RenderPeds(void);
static void RenderVehicles(void); // also renders peds in LCS
static void RenderOneBuilding(CEntity *ent, float camdist = 0.0f);
static void RenderWorld(int pass); // like cWorldStream::Render(int)
static void RenderWater(void); // keep-out polys and water
#endif
static void InsertEntityIntoList(CEntity *ent);
};

436
src/renderer/Rubbish.cpp Normal file
View File

@ -0,0 +1,436 @@
#include "common.h"
#include "main.h"
#include "General.h"
#include "Timer.h"
#include "Weather.h"
#include "Camera.h"
#include "World.h"
#include "Vehicle.h"
#include "ZoneCull.h"
#include "TxdStore.h"
#include "RenderBuffer.h"
#include "Rubbish.h"
#define RUBBISH_MAX_DIST (18.0f)
#define RUBBISH_FADE_DIST (16.5f)
RwTexture *gpRubbishTexture[4];
RwImVertexIndex RubbishIndexList[6];
RwImVertexIndex RubbishIndexList2[6]; // unused
RwIm3DVertex RubbishVertices[4];
bool CRubbish::bRubbishInvisible;
int CRubbish::RubbishVisibility;
COneSheet CRubbish::aSheets[NUM_RUBBISH_SHEETS];
COneSheet CRubbish::StartEmptyList;
COneSheet CRubbish::EndEmptyList;
COneSheet CRubbish::StartStaticsList;
COneSheet CRubbish::EndStaticsList;
COneSheet CRubbish::StartMoversList;
COneSheet CRubbish::EndMoversList;
void
COneSheet::AddToList(COneSheet *list)
{
this->m_next = list->m_next;
this->m_prev = list;
list->m_next = this;
this->m_next->m_prev = this;
}
void
COneSheet::RemoveFromList(void)
{
m_next->m_prev = m_prev;
m_prev->m_next = m_next;
}
void
CRubbish::Render(void)
{
int type;
PUSH_RENDERGROUP("CRubbish::Render");
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
for(type = 0; type < 4; type++){
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRubbishTexture[type]));
TempBufferIndicesStored = 0;
TempBufferVerticesStored = 0;
COneSheet *sheet;
for(sheet = &aSheets[type*NUM_RUBBISH_SHEETS / 4];
sheet < &aSheets[(type+1)*NUM_RUBBISH_SHEETS / 4];
sheet++){
if(sheet->m_state == 0)
continue;
uint32 alpha = 128;
CVector pos;
if(sheet->m_state == 1){
pos = sheet->m_basePos;
if(!sheet->m_isVisible)
alpha = 0;
}else{
pos = sheet->m_animatedPos;
// Not fully visible during animation, calculate current alpha
if(!sheet->m_isVisible || !sheet->m_targetIsVisible){
float t = (float)(CTimer::GetTimeInMilliseconds() - sheet->m_moveStart)/sheet->m_moveDuration;
float f1 = sheet->m_isVisible ? 1.0f-t : 0.0f;
float f2 = sheet->m_targetIsVisible ? t : 0.0f;
alpha = 128 * (f1+f2);
}
}
float camDist = (pos - TheCamera.GetPosition()).Magnitude2D();
if(camDist < RUBBISH_MAX_DIST){
if(camDist >= RUBBISH_FADE_DIST)
alpha -= alpha*(camDist-RUBBISH_FADE_DIST)/(RUBBISH_MAX_DIST-RUBBISH_FADE_DIST);
alpha = (RubbishVisibility*alpha)/256;
float vx = Sin(sheet->m_angle) * 0.4f;
float vy = Cos(sheet->m_angle) * 0.4f;
int v = TempBufferVerticesStored;
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+0], pos.x + vx, pos.y + vy, pos.z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+0], 255, 255, 255, alpha);
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+1], pos.x - vy, pos.y + vx, pos.z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+1], 255, 255, 255, alpha);
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+2], pos.x + vy, pos.y - vx, pos.z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+2], 255, 255, 255, alpha);
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+3], pos.x - vx, pos.y - vy, pos.z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+3], 255, 255, 255, alpha);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+0], 0.0f);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+0], 0.0f);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+1], 1.0f);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+1], 0.0f);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+2], 0.0f);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+2], 1.0f);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+3], 1.0f);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+3], 1.0f);
int i = TempBufferIndicesStored;
TempBufferRenderIndexList[i+0] = RubbishIndexList[0] + TempBufferVerticesStored;
TempBufferRenderIndexList[i+1] = RubbishIndexList[1] + TempBufferVerticesStored;
TempBufferRenderIndexList[i+2] = RubbishIndexList[2] + TempBufferVerticesStored;
TempBufferRenderIndexList[i+3] = RubbishIndexList[3] + TempBufferVerticesStored;
TempBufferRenderIndexList[i+4] = RubbishIndexList[4] + TempBufferVerticesStored;
TempBufferRenderIndexList[i+5] = RubbishIndexList[5] + TempBufferVerticesStored;
TempBufferVerticesStored += 4;
TempBufferIndicesStored += 6;
}
}
if(TempBufferIndicesStored != 0){
LittleTest();
if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
RwIm3DEnd();
}
}
}
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
POP_RENDERGROUP();
}
void
CRubbish::StirUp(CVehicle *veh)
{
if((CTimer::GetFrameCounter() ^ (veh->m_randomSeed&3)) == 0)
return;
if(Abs(veh->GetPosition().x - TheCamera.GetPosition().x) < 20.0f &&
Abs(veh->GetPosition().y - TheCamera.GetPosition().y) < 20.0f)
if(Abs(veh->GetMoveSpeed().x) > 0.05f || Abs(veh->GetMoveSpeed().y) > 0.05f){
float speed = veh->GetMoveSpeed().Magnitude2D();
if(speed > 0.05f){
bool movingForward = DotProduct2D(veh->GetMoveSpeed(), veh->GetForward()) > 0.0f;
COneSheet *sheet = StartStaticsList.m_next;
CVector2D size = veh->GetColModel()->boundingBox.max;
// Check all static sheets
while(sheet != &EndStaticsList){
COneSheet *next = sheet->m_next;
CVector2D carToSheet = sheet->m_basePos - veh->GetPosition();
float distFwd = DotProduct2D(carToSheet, veh->GetForward());
// sheet has to be a bit behind car
if(movingForward && distFwd < -0.5f*size.y && distFwd > -1.5f*size.y ||
!movingForward && distFwd > 0.5f*size.y && distFwd < 1.5f*size.y){
float distSide = Abs(DotProduct2D(carToSheet, veh->GetRight()));
if(distSide < 1.5*size.x){
// Check with higher speed for sheet directly behind car
float speedToCheck = distSide < size.x ? speed : speed*0.5f;
if(speedToCheck > 0.05f){
sheet->m_state = 2;
if(speedToCheck > 0.15f)
sheet->m_animationType = 2;
else
sheet->m_animationType = 1;
sheet->m_moveDuration = 2000;
sheet->m_xDist = veh->GetMoveSpeed().x;
sheet->m_yDist = veh->GetMoveSpeed().y;
float dist = Sqrt(SQR(sheet->m_xDist)+SQR(sheet->m_yDist));
sheet->m_xDist *= 25.0f*speed/dist;
sheet->m_yDist *= 25.0f*speed/dist;
sheet->m_animHeight = 3.0f*speed;
sheet->m_moveStart = CTimer::GetTimeInMilliseconds();
float tx = sheet->m_basePos.x + sheet->m_xDist;
float ty = sheet->m_basePos.y + sheet->m_yDist;
float tz = sheet->m_basePos.z + 3.0f;
sheet->m_targetZ = CWorld::FindGroundZFor3DCoord(tx, ty, tz, nil) + 0.1f;
sheet->RemoveFromList();
sheet->AddToList(&StartMoversList);
}
}
}
sheet = next;
}
}
}
}
static float aAnimations[3][34] = {
{ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
// Normal move
{ 0.0f, 0.05f, 0.12f, 0.25f, 0.42f, 0.57f, 0.68f, 0.8f, 0.86f, 0.9f, 0.93f, 0.95f, 0.96f, 0.97f, 0.98f, 0.99f, 1.0f, // XY movemnt
0.15f, 0.35f, 0.6f, 0.9f, 1.2f, 1.25f, 1.3f, 1.2f, 1.1f, 0.95f, 0.8f, 0.6f, 0.45f, 0.3f, 0.2f, 0.1f, 0 }, // Z movement
// Stirred up by fast vehicle
{ 0.0f, 0.05f, 0.12f, 0.25f, 0.42f, 0.57f, 0.68f, 0.8f, 0.95f, 1.1f, 1.15f, 1.18f, 1.15f, 1.1f, 1.05f, 1.03f, 1.0f,
0.15f, 0.35f, 0.6f, 0.9f, 1.2f, 1.25f, 1.3f, 1.2f, 1.1f, 0.95f, 0.8f, 0.6f, 0.45f, 0.3f, 0.2f, 0.1f, 0 }
};
void
CRubbish::Update(void)
{
bool foundGround;
// FRAMETIME
if(bRubbishInvisible)
RubbishVisibility = Max(RubbishVisibility-5, 0);
else
RubbishVisibility = Min(RubbishVisibility+5, 255);
// Spawn a new sheet
COneSheet *sheet = StartEmptyList.m_next;
if(sheet != &EndEmptyList){
float spawnDist;
float spawnAngle;
spawnDist = (CGeneral::GetRandomNumber()&0xFF)/256.0f + RUBBISH_MAX_DIST;
uint8 r = CGeneral::GetRandomNumber();
if(r&1)
spawnAngle = (CGeneral::GetRandomNumber()&0xFF)/256.0f * 6.28f;
else
spawnAngle = (r-128)/160.0f + TheCamera.Orientation;
sheet->m_basePos.x = TheCamera.GetPosition().x + spawnDist*Sin(spawnAngle);
sheet->m_basePos.y = TheCamera.GetPosition().y + spawnDist*Cos(spawnAngle);
sheet->m_basePos.z = CWorld::FindGroundZFor3DCoord(sheet->m_basePos.x, sheet->m_basePos.y, TheCamera.GetPosition().z, &foundGround) + 0.1f;
if(foundGround){
// Found ground, so add to statics list
sheet->m_angle = (CGeneral::GetRandomNumber()&0xFF)/256.0f * 6.28f;
sheet->m_state = 1;
if(CCullZones::FindAttributesForCoors(sheet->m_basePos, nil) & ATTRZONE_NORAIN)
sheet->m_isVisible = false;
else
sheet->m_isVisible = true;
sheet->RemoveFromList();
sheet->AddToList(&StartStaticsList);
}
}
// Process animation
sheet = StartMoversList.m_next;
while(sheet != &EndMoversList){
uint32 currentTime = CTimer::GetTimeInMilliseconds() - sheet->m_moveStart;
if(currentTime < sheet->m_moveDuration){
// Animation
int step = 16 * currentTime / sheet->m_moveDuration; // 16 steps in animation
int stepTime = sheet->m_moveDuration/16; // time in each step
float s = (float)(currentTime - stepTime*step) / stepTime; // position on step
float t = (float)currentTime / sheet->m_moveDuration; // position on total animation
// factors for xy and z-movment
float fxy = aAnimations[sheet->m_animationType][step]*(1.0f-s) + aAnimations[sheet->m_animationType][step+1]*s;
float fz = aAnimations[sheet->m_animationType][step+17]*(1.0f-s) + aAnimations[sheet->m_animationType][step+1+17]*s;
sheet->m_animatedPos.x = sheet->m_basePos.x + fxy*sheet->m_xDist;
sheet->m_animatedPos.y = sheet->m_basePos.y + fxy*sheet->m_yDist;
sheet->m_animatedPos.z = (1.0f-t)*sheet->m_basePos.z + t*sheet->m_targetZ + fz*sheet->m_animHeight;
sheet->m_angle += CTimer::GetTimeStep()*0.04f;
if(sheet->m_angle > 6.28f)
sheet->m_angle -= 6.28f;
sheet = sheet->m_next;
}else{
// End of animation, back into statics list
sheet->m_basePos.x += sheet->m_xDist;
sheet->m_basePos.y += sheet->m_yDist;
sheet->m_basePos.z = sheet->m_targetZ;
sheet->m_state = 1;
sheet->m_isVisible = sheet->m_targetIsVisible;
COneSheet *next = sheet->m_next;
sheet->RemoveFromList();
sheet->AddToList(&StartStaticsList);
sheet = next;
}
}
// Stir up a sheet by wind
// FRAMETIME
int freq;
if(CWeather::Wind < 0.1f)
freq = 31;
else if(CWeather::Wind < 0.4f)
freq = 7;
else if(CWeather::Wind < 0.7f)
freq = 1;
else
freq = 0;
if((CTimer::GetFrameCounter() & freq) == 0){
// Pick a random sheet and set animation state if static
int i = CGeneral::GetRandomNumber() % NUM_RUBBISH_SHEETS;
if(aSheets[i].m_state == 1){
aSheets[i].m_moveStart = CTimer::GetTimeInMilliseconds();
aSheets[i].m_moveDuration = CWeather::Wind*1500.0f + 1000.0f;
aSheets[i].m_animHeight = 0.2f;
aSheets[i].m_xDist = 3.0f*CWeather::Wind;
aSheets[i].m_yDist = 3.0f*CWeather::Wind;
// Check if target position is ok
float tx = aSheets[i].m_basePos.x + aSheets[i].m_xDist;
float ty = aSheets[i].m_basePos.y + aSheets[i].m_yDist;
float tz = aSheets[i].m_basePos.z + 3.0f;
aSheets[i].m_targetZ = CWorld::FindGroundZFor3DCoord(tx, ty, tz, &foundGround) + 0.1f;
if(CCullZones::FindAttributesForCoors(CVector(tx, ty, aSheets[i].m_targetZ), nil) & ATTRZONE_NORAIN)
aSheets[i].m_targetIsVisible = false;
else
aSheets[i].m_targetIsVisible = true;
if(foundGround){
// start animation
aSheets[i].m_state = 2;
aSheets[i].m_animationType = 1;
aSheets[i].RemoveFromList();
aSheets[i].AddToList(&StartMoversList);
}
}
}
// Remove sheets that are too far away
int i = (CTimer::GetFrameCounter()%(NUM_RUBBISH_SHEETS/4))*4;
int last = ((CTimer::GetFrameCounter()%(NUM_RUBBISH_SHEETS/4)) + 1)*4;
for(; i < last; i++){
if(aSheets[i].m_state == 1 &&
(aSheets[i].m_basePos - TheCamera.GetPosition()).MagnitudeSqr2D() > SQR(RUBBISH_MAX_DIST+1.0f)){
aSheets[i].m_state = 0;
aSheets[i].RemoveFromList();
aSheets[i].AddToList(&StartEmptyList);
}
}
}
void
CRubbish::SetVisibility(bool visible)
{
bRubbishInvisible = !visible;
}
void
CRubbish::Init(void)
{
int i;
for(i = 0; i < NUM_RUBBISH_SHEETS; i++){
aSheets[i].m_state = 0;
if(i < NUM_RUBBISH_SHEETS-1)
aSheets[i].m_next = &aSheets[i+1];
else
aSheets[i].m_next = &EndEmptyList;
if(i > 0)
aSheets[i].m_prev = &aSheets[i-1];
else
aSheets[i].m_prev = &StartEmptyList;
}
StartEmptyList.m_next = &aSheets[0];
StartEmptyList.m_prev = nil;
EndEmptyList.m_next = nil;
EndEmptyList.m_prev = &aSheets[NUM_RUBBISH_SHEETS-1];
StartStaticsList.m_next = &EndStaticsList;
StartStaticsList.m_prev = nil;
EndStaticsList.m_next = nil;
EndStaticsList.m_prev = &StartStaticsList;
StartMoversList.m_next = &EndMoversList;
StartMoversList.m_prev = nil;
EndMoversList.m_next = nil;
EndMoversList.m_prev = &StartMoversList;
// unused
RwIm3DVertexSetU(&RubbishVertices[0], 0.0f);
RwIm3DVertexSetV(&RubbishVertices[0], 0.0f);
RwIm3DVertexSetU(&RubbishVertices[1], 1.0f);
RwIm3DVertexSetV(&RubbishVertices[1], 0.0f);
RwIm3DVertexSetU(&RubbishVertices[2], 0.0f);
RwIm3DVertexSetV(&RubbishVertices[2], 1.0f);
RwIm3DVertexSetU(&RubbishVertices[3], 1.0f);
RwIm3DVertexSetV(&RubbishVertices[3], 1.0f);
// unused
RubbishIndexList2[0] = 0;
RubbishIndexList2[1] = 2;
RubbishIndexList2[2] = 1;
RubbishIndexList2[3] = 1;
RubbishIndexList2[4] = 2;
RubbishIndexList2[5] = 3;
RubbishIndexList[0] = 0;
RubbishIndexList[1] = 1;
RubbishIndexList[2] = 2;
RubbishIndexList[3] = 1;
RubbishIndexList[4] = 3;
RubbishIndexList[5] = 2;
CTxdStore::PushCurrentTxd();
int slot = CTxdStore::FindTxdSlot("particle");
CTxdStore::SetCurrentTxd(slot);
gpRubbishTexture[0] = RwTextureRead("gameleaf01_64", nil);
gpRubbishTexture[1] = RwTextureRead("gameleaf02_64", nil);
gpRubbishTexture[2] = RwTextureRead("newspaper01_64", nil);
gpRubbishTexture[3] = RwTextureRead("newspaper02_64", nil);
CTxdStore::PopCurrentTxd();
RubbishVisibility = 255;
bRubbishInvisible = false;
}
void
CRubbish::Shutdown(void)
{
RwTextureDestroy(gpRubbishTexture[0]);
#if GTA_VERSION >= GTA3_PC_11
gpRubbishTexture[0] = nil;
#endif
RwTextureDestroy(gpRubbishTexture[1]);
#if GTA_VERSION >= GTA3_PC_11
gpRubbishTexture[1] = nil;
#endif
RwTextureDestroy(gpRubbishTexture[2]);
#if GTA_VERSION >= GTA3_PC_11
gpRubbishTexture[2] = nil;
#endif
RwTextureDestroy(gpRubbishTexture[3]);
#if GTA_VERSION >= GTA3_PC_11
gpRubbishTexture[3] = nil;
#endif
}

55
src/renderer/Rubbish.h Normal file
View File

@ -0,0 +1,55 @@
#pragma once
class CVehicle;
enum {
// NB: not all values are allowed, check the code
#ifdef SQUEEZE_PERFORMANCE
NUM_RUBBISH_SHEETS = 32
#else
NUM_RUBBISH_SHEETS = 64
#endif
};
class COneSheet
{
public:
CVector m_basePos;
CVector m_animatedPos;
float m_targetZ;
int8 m_state;
int8 m_animationType;
uint32 m_moveStart;
uint32 m_moveDuration;
float m_animHeight;
float m_xDist;
float m_yDist;
float m_angle;
bool m_isVisible;
bool m_targetIsVisible;
COneSheet *m_next;
COneSheet *m_prev;
void AddToList(COneSheet *list);
void RemoveFromList(void);
};
class CRubbish
{
static bool bRubbishInvisible;
static int RubbishVisibility;
static COneSheet aSheets[NUM_RUBBISH_SHEETS];
static COneSheet StartEmptyList;
static COneSheet EndEmptyList;
static COneSheet StartStaticsList;
static COneSheet EndStaticsList;
static COneSheet StartMoversList;
static COneSheet EndMoversList;
public:
static void Render(void);
static void StirUp(CVehicle *veh); // CAutomobile on PS2
static void Update(void);
static void SetVisibility(bool visible);
static void Init(void);
static void Shutdown(void);
};

1785
src/renderer/Shadows.cpp Normal file

File diff suppressed because it is too large Load Diff

180
src/renderer/Shadows.h Normal file
View File

@ -0,0 +1,180 @@
#pragma once
#define MAX_STOREDSHADOWS 48
#define MAX_POLYBUNCHES 300
#define MAX_STATICSHADOWS 64
#define MAX_PERMAMENTSHADOWS 48
class CEntity;
enum eShadowType
{
SHADOWTYPE_NONE = 0,
SHADOWTYPE_DARK,
SHADOWTYPE_ADDITIVE,
SHADOWTYPE_INVCOLOR
};
enum eShadowTextureType
{
SHADOWTEX_NONE = 0,
SHADOWTEX_CAR,
SHADOWTEX_PED,
SHADOWTEX_EXPLOSION,
SHADOWTEX_HELI,
SHADOWTEX_HEADLIGHTS,
SHADOWTEX_BLOOD
};
class CStoredShadow
{
public:
CVector m_vecPos;
CVector2D m_vecFront;
CVector2D m_vecSide;
float m_fZDistance;
float m_fScale;
int16 m_nIntensity;
uint8 m_ShadowType;
uint8 m_nRed;
uint8 m_nGreen;
uint8 m_nBlue;
struct
{
uint8 bDrawOnWater : 1;
uint8 bRendered : 1;
//uint8 bDrawOnBuildings : 1;
} m_nFlags;
RwTexture *m_pTexture;
CStoredShadow()
{ }
};
VALIDATE_SIZE(CStoredShadow, 0x30);
class CPolyBunch
{
public:
int16 m_nNumVerts;
CVector m_aVerts[7];
uint8 m_aU[7];
uint8 m_aV[7];
CPolyBunch *m_pNext;
CPolyBunch()
{ }
};
VALIDATE_SIZE(CPolyBunch, 0x6C);
class CStaticShadow
{
public:
uint32 m_nId;
CPolyBunch *m_pPolyBunch;
uint32 m_nTimeCreated;
CVector m_vecPosn;
CVector2D m_vecFront;
CVector2D m_vecSide;
float m_fZDistance;
float m_fScale;
uint8 m_nType;
int16 m_nIntensity; // unsigned ?
uint8 m_nRed;
uint8 m_nGreen;
uint8 m_nBlue;
bool m_bJustCreated;
bool m_bRendered;
bool m_bTemp;
RwTexture *m_pTexture;
CStaticShadow()
{ }
void Free();
};
VALIDATE_SIZE(CStaticShadow, 0x40);
class CPermanentShadow
{
public:
CVector m_vecPos;
CVector2D m_vecFront;
CVector2D m_vecSide;
float m_fZDistance;
float m_fScale;
int16 m_nIntensity;
uint8 m_nType; // eShadowType
uint8 m_nRed;
uint8 m_nGreen;
uint8 m_nBlue;
uint32 m_nTimeCreated;
uint32 m_nLifeTime;
RwTexture *m_pTexture;
CPermanentShadow()
{ }
};
VALIDATE_SIZE(CPermanentShadow, 0x38);
class CPtrList;
class CAutomobile;
class CPed;
class CShadows
{
public:
static int16 ShadowsStoredToBeRendered;
static CStoredShadow asShadowsStored [MAX_STOREDSHADOWS];
static CPolyBunch aPolyBunches [MAX_POLYBUNCHES];
static CStaticShadow aStaticShadows [MAX_STATICSHADOWS];
static CPolyBunch *pEmptyBunchList;
static CPermanentShadow aPermanentShadows[MAX_PERMAMENTSHADOWS];
static void Init (void);
static void Shutdown (void);
static void AddPermanentShadow ( uint8 ShadowType, RwTexture *pTexture, CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity, uint8 nRed, uint8 nGreen, uint8 nBlue, float fZDistance, uint32 nTime, float fScale);
static void StoreStaticShadow (uint32 nID, uint8 ShadowType, RwTexture *pTexture, Const CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity, uint8 nRed, uint8 nGreen, uint8 nBlue, float fZDistance, float fScale, float fDrawDistance, bool bTempShadow, float fUpDistance);
static void StoreShadowToBeRendered ( uint8 ShadowType, CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity, uint8 nRed, uint8 nGreen, uint8 nBlue);
static void StoreShadowToBeRendered ( uint8 ShadowType, RwTexture *pTexture, CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity, uint8 nRed, uint8 nGreen, uint8 nBlue, float fZDistance, bool bDrawOnWater, float fScale);
static void StoreShadowForCar (CAutomobile *pCar);
static void StoreCarLightShadow (CAutomobile *pCar, int32 nID, RwTexture *pTexture, CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, uint8 nRed, uint8 nGreen, uint8 nBlue, float fMaxViewAngle);
static void StoreShadowForPed (CPed *pPed, float fDisplacementX, float fDisplacementY, float fFrontX, float fFrontY, float fSideX, float fSideY);
static void StoreShadowForPedObject (CEntity *pPedObject, float fDisplacementX, float fDisplacementY, float fFrontX, float fFrontY, float fSideX, float fSideY);
static void StoreShadowForTree (CEntity *pTree);
static void StoreShadowForPole (CEntity *pPole, float fOffsetX, float fOffsetY, float fOffsetZ, float fPoleHeight, float fPoleWidth, uint32 nID);
static void SetRenderModeForShadowType (uint8 ShadowType);
static void RenderStoredShadows (void);
static void RenderStaticShadows (void);
static void GeneratePolysForStaticShadow (int16 nStaticShadowID);
static void CastShadowSectorList (CPtrList &PtrList, float fStartX, float fStartY, float fEndX, float fEndY,
CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity, uint8 nRed, uint8 nGreen, uint8 nBlue, float fZDistance, float fScale, CPolyBunch **ppPolyBunch);
static void CastShadowEntity (CEntity *pEntity, float fStartX, float fStartY, float fEndX, float fEndY,
CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity, uint8 nRed, uint8 nGreen, uint8 nBlue, float fZDistance, float fScale, CPolyBunch **ppPolyBunch);
static void UpdateStaticShadows (void);
static void UpdatePermanentShadows (void);
static void CalcPedShadowValues (CVector vecLightDir, float *pfFrontX, float *pfFrontY, float *pfSideX, float *pfSideY, float *pfDisplacementX, float *pfDisplacementY);
static void RenderExtraPlayerShadows (void);
static void TidyUpShadows (void);
static void RenderIndicatorShadow (uint32 nID, uint8 ShadowType, RwTexture *pTexture, CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity);
};
extern RwTexture *gpShadowCarTex;
extern RwTexture *gpShadowPedTex;
extern RwTexture *gpShadowHeliTex;
extern RwTexture *gpShadowExplosionTex;
extern RwTexture *gpShadowHeadLightsTex;
extern RwTexture *gpOutline1Tex;
extern RwTexture *gpOutline2Tex;
extern RwTexture *gpOutline3Tex;
extern RwTexture *gpBloodPoolTex;
extern RwTexture *gpReflectionTex;
extern RwTexture *gpGoalMarkerTex;
extern RwTexture *gpWalkDontTex;
extern RwTexture *gpCrackedGlassTex;
extern RwTexture *gpPostShadowTex;
extern RwTexture *gpGoalTex;

262
src/renderer/Skidmarks.cpp Normal file
View File

@ -0,0 +1,262 @@
#include "common.h"
#include "main.h"
#include "TxdStore.h"
#include "Timer.h"
#include "Replay.h"
#include "Skidmarks.h"
CSkidmark CSkidmarks::aSkidmarks[NUMSKIDMARKS];
RwImVertexIndex SkidmarkIndexList[SKIDMARK_LENGTH * 6];
RwIm3DVertex SkidmarkVertices[SKIDMARK_LENGTH * 2];
RwTexture *gpSkidTex;
RwTexture *gpSkidBloodTex;
RwTexture *gpSkidMudTex;
void
CSkidmarks::Init(void)
{
int i, ix, slot;
CTxdStore::PushCurrentTxd();
slot = CTxdStore::FindTxdSlot("particle");
CTxdStore::SetCurrentTxd(slot);
gpSkidTex = RwTextureRead("particleskid", nil);
gpSkidBloodTex = RwTextureRead("particleskidblood", nil);
gpSkidMudTex = RwTextureRead("particleskidmud", nil);
CTxdStore::PopCurrentTxd();
for(i = 0; i < NUMSKIDMARKS; i++){
aSkidmarks[i].m_state = 0;
aSkidmarks[i].m_wasUpdated = false;
}
ix = 0;
for(i = 0; i < SKIDMARK_LENGTH; i++){
SkidmarkIndexList[i*6+0] = ix+0;
SkidmarkIndexList[i*6+1] = ix+2;
SkidmarkIndexList[i*6+2] = ix+1;
SkidmarkIndexList[i*6+3] = ix+1;
SkidmarkIndexList[i*6+4] = ix+2;
SkidmarkIndexList[i*6+5] = ix+3;
ix += 2;
}
for(i = 0; i < SKIDMARK_LENGTH; i++){
RwIm3DVertexSetU(&SkidmarkVertices[i*2 + 0], 0.0f);
RwIm3DVertexSetV(&SkidmarkVertices[i*2 + 0], i*5.01f);
RwIm3DVertexSetU(&SkidmarkVertices[i*2 + 1], 1.0f);
RwIm3DVertexSetV(&SkidmarkVertices[i*2 + 1], i*5.01f);
}
}
void
CSkidmarks::Shutdown(void)
{
RwTextureDestroy(gpSkidTex);
#if GTA_VERSION >= GTA3_PC_11
gpSkidTex = nil;
#endif
RwTextureDestroy(gpSkidBloodTex);
#if GTA_VERSION >= GTA3_PC_11
gpSkidBloodTex = nil;
#endif
RwTextureDestroy(gpSkidMudTex);
#if GTA_VERSION >= GTA3_PC_11
gpSkidMudTex = nil;
#endif
}
void
CSkidmarks::Clear(void)
{
int i;
for(i = 0; i < NUMSKIDMARKS; i++){
aSkidmarks[i].m_state = 0;
aSkidmarks[i].m_wasUpdated = false;
}
}
void
CSkidmarks::Update(void)
{
int i;
uint32 t1 = CTimer::GetTimeInMilliseconds() + 2500;
uint32 t2 = CTimer::GetTimeInMilliseconds() + 5000;
uint32 t3 = CTimer::GetTimeInMilliseconds() + 10000;
uint32 t4 = CTimer::GetTimeInMilliseconds() + 20000;
for(i = 0; i < NUMSKIDMARKS; i++){
switch(aSkidmarks[i].m_state){
case 1:
if(!aSkidmarks[i].m_wasUpdated){
// Didn't continue this one last time, so finish it and set fade times
aSkidmarks[i].m_state = 2;
if(aSkidmarks[i].m_last < 4){
aSkidmarks[i].m_fadeStart = t1;
aSkidmarks[i].m_fadeEnd = t2;
}else if(aSkidmarks[i].m_last < 9){
aSkidmarks[i].m_fadeStart = t2;
aSkidmarks[i].m_fadeEnd = t3;
}else{
aSkidmarks[i].m_fadeStart = t3;
aSkidmarks[i].m_fadeEnd = t4;
}
}
break;
case 2:
if(CTimer::GetTimeInMilliseconds() > aSkidmarks[i].m_fadeEnd)
aSkidmarks[i].m_state = 0;
break;
}
aSkidmarks[i].m_wasUpdated = false;
}
}
void
CSkidmarks::Render(void)
{
int i, j;
RwTexture *lastTex = nil;
PUSH_RENDERGROUP("CSkidmarks::Render");
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
for(i = 0; i < NUMSKIDMARKS; i++){
if(aSkidmarks[i].m_state == 0 || aSkidmarks[i].m_last < 1)
continue;
if(aSkidmarks[i].m_isBloody){
if(lastTex != gpSkidBloodTex){
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidBloodTex));
lastTex = gpSkidBloodTex;
}
}else if(aSkidmarks[i].m_isMuddy){
if(lastTex != gpSkidMudTex){
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidMudTex));
lastTex = gpSkidMudTex;
}
}else{
if(lastTex != gpSkidTex){
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidTex));
lastTex = gpSkidTex;
}
}
uint32 fade, alpha;
if(aSkidmarks[i].m_state == 1 || CTimer::GetTimeInMilliseconds() < aSkidmarks[i].m_fadeStart)
fade = 255;
else
fade = 255*(aSkidmarks[i].m_fadeEnd - CTimer::GetTimeInMilliseconds()) / (aSkidmarks[i].m_fadeEnd - aSkidmarks[i].m_fadeStart);
for(j = 0; j <= aSkidmarks[i].m_last; j++){
alpha = 128;
if(j == 0 || j == aSkidmarks[i].m_last && aSkidmarks[i].m_state == 2)
alpha = 0;
alpha = alpha*fade/256;
CVector p1 = aSkidmarks[i].m_pos[j] + aSkidmarks[i].m_side[j];
CVector p2 = aSkidmarks[i].m_pos[j] - aSkidmarks[i].m_side[j];
RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+0], 255, 255, 255, alpha);
RwIm3DVertexSetPos(&SkidmarkVertices[j*2+0], p1.x, p1.y, p1.z+0.1f);
RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+1], 255, 255, 255, alpha);
RwIm3DVertexSetPos(&SkidmarkVertices[j*2+1], p2.x, p2.y, p2.z+0.1f);
}
LittleTest();
if(RwIm3DTransform(SkidmarkVertices, 2*(aSkidmarks[i].m_last+1), nil, rwIM3D_VERTEXUV)){
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, SkidmarkIndexList, 6*aSkidmarks[i].m_last);
RwIm3DEnd();
}
}
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
POP_RENDERGROUP();
}
void
CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody)
{
int i;
CVector2D fwd(fwdX, fwdY);
if(CReplay::IsPlayingBack())
return;
// Find a skidmark to continue
for(i = 0; i < NUMSKIDMARKS; i++)
if(aSkidmarks[i].m_state == 1 && aSkidmarks[i].m_id == id)
break;
if(i < NUMSKIDMARKS){
// Continue this one
if(aSkidmarks[i].m_isBloody != *isBloody){
// Blood-status changed, end this one
aSkidmarks[i].m_state = 2;
aSkidmarks[i].m_fadeStart = CTimer::GetTimeInMilliseconds() + 10000;
aSkidmarks[i].m_fadeEnd = CTimer::GetTimeInMilliseconds() + 20000;
return;
}
aSkidmarks[i].m_wasUpdated = true;
if(CTimer::GetTimeInMilliseconds() - aSkidmarks[i].m_lastUpdate <= 100){
// Last update was recently, just change last coords
aSkidmarks[i].m_pos[aSkidmarks[i].m_last] = pos;
return;
}
aSkidmarks[i].m_lastUpdate = CTimer::GetTimeInMilliseconds();
if(aSkidmarks[i].m_last >= SKIDMARK_LENGTH-1){
// No space to continue, end it
aSkidmarks[i].m_state = 2;
aSkidmarks[i].m_fadeStart = CTimer::GetTimeInMilliseconds() + 10000;
aSkidmarks[i].m_fadeEnd = CTimer::GetTimeInMilliseconds() + 20000;
*isBloody = false; // stpo blood marks at end
return;
}
aSkidmarks[i].m_last++;
aSkidmarks[i].m_pos[aSkidmarks[i].m_last] = pos;
CVector2D right(aSkidmarks[i].m_pos[aSkidmarks[i].m_last].y - aSkidmarks[i].m_pos[aSkidmarks[i].m_last - 1].y,
aSkidmarks[i].m_pos[aSkidmarks[i].m_last - 1].x - aSkidmarks[i].m_pos[aSkidmarks[i].m_last].x);
right.NormaliseSafe();
fwd.NormaliseSafe();
float turn = DotProduct2D(fwd, right);
turn = Abs(turn) + 1.0f;
aSkidmarks[i].m_side[aSkidmarks[i].m_last] = CVector(right.x, right.y, 0.0f) * turn * 0.125f;
if(aSkidmarks[i].m_last == 1)
aSkidmarks[i].m_side[0] = aSkidmarks[i].m_side[1];
if(aSkidmarks[i].m_last > 8)
*isBloody = false; // stop blood marks after 8
return;
}
// Start a new one
for(i = 0; i < NUMSKIDMARKS; i++)
if(aSkidmarks[i].m_state == 0)
break;
if(i < NUMSKIDMARKS){
// Found a free slot
aSkidmarks[i].m_state = 1;
aSkidmarks[i].m_id = id;
aSkidmarks[i].m_pos[0] = pos;
aSkidmarks[i].m_side[0] = CVector(0.0f, 0.0f, 0.0f);
aSkidmarks[i].m_wasUpdated = true;
aSkidmarks[i].m_last = 0;
aSkidmarks[i].m_lastUpdate = CTimer::GetTimeInMilliseconds() - 1000;
aSkidmarks[i].m_isBloody = *isBloody;
aSkidmarks[i].m_isMuddy = *isMuddy;
}else
*isBloody = false; // stop blood marks if no space
}

32
src/renderer/Skidmarks.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
enum { SKIDMARK_LENGTH = 16 };
class CSkidmark
{
public:
uint8 m_state;
bool m_wasUpdated;
bool m_isBloody;
bool m_isMuddy;
uintptr m_id;
int16 m_last;
uint32 m_lastUpdate;
uint32 m_fadeStart;
uint32 m_fadeEnd;
CVector m_pos[SKIDMARK_LENGTH];
CVector m_side[SKIDMARK_LENGTH];
};
class CSkidmarks
{
static CSkidmark aSkidmarks[NUMSKIDMARKS];
public:
static void Init(void);
static void Shutdown(void);
static void Clear(void);
static void Update(void);
static void Render(void);
static void RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody);
};

1194
src/renderer/SpecialFX.cpp Normal file

File diff suppressed because it is too large Load Diff

224
src/renderer/SpecialFX.h Normal file
View File

@ -0,0 +1,224 @@
#pragma once
class CSpecialFX
{
public:
static void Render(void);
static void Update(void);
static void Init(void);
static void Shutdown(void);
};
class CRegisteredMotionBlurStreak
{
public:
uintptr m_id;
uint8 m_red;
uint8 m_green;
uint8 m_blue;
CVector m_pos1[3];
CVector m_pos2[3];
bool m_isValid[3];
void Update(void);
void Render(void);
};
class CMotionBlurStreaks
{
static CRegisteredMotionBlurStreak aStreaks[NUMMBLURSTREAKS];
public:
static void Init(void);
static void Update(void);
static void RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2);
static void Render(void);
};
struct CBulletTrace
{
CVector m_vecCurrentPos;
CVector m_vecTargetPos;
bool m_bInUse;
uint8 m_framesInUse;
uint8 m_lifeTime;
void Update(void);
};
class CBulletTraces
{
public:
static CBulletTrace aTraces[NUMBULLETTRACES];
static void Init(void);
static void AddTrace(CVector*, CVector*);
static void Render(void);
static void Update(void);
};
enum
{
MARKERTYPE_0 = 0,
MARKERTYPE_ARROW,
MARKERTYPE_2,
MARKERTYPE_3,
MARKERTYPE_CYLINDER,
NUMMARKERTYPES,
MARKERTYPE_INVALID = 0x101
};
class C3dMarker
{
public:
CMatrix m_Matrix;
RpAtomic *m_pAtomic;
RpMaterial *m_pMaterial;
uint16 m_nType;
bool m_bIsUsed;
uint32 m_nIdentifier;
RwRGBA m_Color;
uint16 m_nPulsePeriod;
int16 m_nRotateRate;
uint32 m_nStartTime;
float m_fPulseFraction;
float m_fStdSize;
float m_fSize;
float m_fBrightness;
float m_fCameraRange;
bool AddMarker(uint32 identifier, uint16 type, float fSize, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
void DeleteMarkerObject();
void Render();
};
class C3dMarkers
{
public:
static void Init();
static void Shutdown();
static C3dMarker *PlaceMarker(uint32 id, uint16 type, CVector &pos, float size, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
static void PlaceMarkerSet(uint32 id, uint16 type, CVector &pos, float size, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
static void Render();
static void Update();
static C3dMarker m_aMarkerArray[NUM3DMARKERS];
static int32 NumActiveMarkers;
static RpClump* m_pRpClumpArray[NUMMARKERTYPES];
};
enum
{
BRIGHTLIGHT_INVALID,
BRIGHTLIGHT_TRAFFIC_GREEN,
BRIGHTLIGHT_TRAFFIC_YELLOW,
BRIGHTLIGHT_TRAFFIC_RED,
// white
BRIGHTLIGHT_FRONT_LONG,
BRIGHTLIGHT_FRONT_SMALL,
BRIGHTLIGHT_FRONT_BIG,
BRIGHTLIGHT_FRONT_TALL,
// red
BRIGHTLIGHT_REAR_LONG,
BRIGHTLIGHT_REAR_SMALL,
BRIGHTLIGHT_REAR_BIG,
BRIGHTLIGHT_REAR_TALL,
BRIGHTLIGHT_SIREN, // unused
BRIGHTLIGHT_FRONT = BRIGHTLIGHT_FRONT_LONG,
BRIGHTLIGHT_REAR = BRIGHTLIGHT_REAR_LONG,
};
class CBrightLight
{
public:
CVector m_pos;
CVector m_up;
CVector m_side;
CVector m_front;
float m_camDist;
uint8 m_type;
uint8 m_red;
uint8 m_green;
uint8 m_blue;
};
class CBrightLights
{
static int NumBrightLights;
static CBrightLight aBrightLights[NUMBRIGHTLIGHTS];
public:
static void Init(void);
static void RegisterOne(CVector pos, CVector up, CVector side, CVector front,
uint8 type, uint8 red = 0, uint8 green = 0, uint8 blue = 0);
static void Render(void);
static void RenderOutGeometryBuffer(void);
};
enum
{
SHINYTEXT_WALK = 1,
SHINYTEXT_FLAT
};
class CShinyText
{
public:
CVector m_verts[4];
CVector2D m_texCoords[4];
float m_camDist;
uint8 m_type;
uint8 m_red;
uint8 m_green;
uint8 m_blue;
};
class CShinyTexts
{
static int NumShinyTexts;
static CShinyText aShinyTexts[NUMSHINYTEXTS];
public:
static void Init(void);
static void RegisterOne(CVector p0, CVector p1, CVector p2, CVector p3,
float u0, float v0, float u1, float v1, float u2, float v2, float u3, float v3,
uint8 type, uint8 red, uint8 green, uint8 blue, float maxDist);
static void Render(void);
static void RenderOutGeometryBuffer(void);
};
class CMoneyMessage
{
friend class CMoneyMessages;
uint32 m_nTimeRegistered;
CVector m_vecPosition;
wchar m_aText[16];
CRGBA m_Colour;
float m_fSize;
float m_fOpacity;
public:
void Render();
};
class CMoneyMessages
{
static CMoneyMessage aMoneyMessages[NUMMONEYMESSAGES];
public:
static void Init();
static void Render();
static void RegisterOne(CVector vecPos, const char *pText, uint8 bRed, uint8 bGreen, uint8 bBlue, float fSize, float fOpacity);
};
class CSpecialParticleStuff
{
static uint32 BoatFromStart;
public:
static void CreateFoamAroundObject(CMatrix*, float, float, float, int32);
static void StartBoatFoamAnimation();
static void UpdateBoatFoamAnimation(CMatrix*);
};

603
src/renderer/Sprite.cpp Normal file
View File

@ -0,0 +1,603 @@
#include "common.h"
#include "main.h"
#include "Draw.h"
#include "Camera.h"
#include "Sprite.h"
#ifdef ASPECT_RATIO_SCALE
#include "Frontend.h"
#endif
float CSprite::m_f2DNearScreenZ;
float CSprite::m_f2DFarScreenZ;
float CSprite::m_fRecipNearClipPlane;
int32 CSprite::m_bFlushSpriteBufferSwitchZTest;
float
CSprite::CalcHorizonCoors(void)
{
CVector p = TheCamera.GetPosition() + CVector(TheCamera.CamFrontXNorm, TheCamera.CamFrontYNorm, 0.0f)*3000.0f;
p.z = 0.0f;
p = TheCamera.m_viewMatrix * p;
return p.y * SCREEN_HEIGHT / p.z;
}
bool
CSprite::CalcScreenCoors(const RwV3d &in, RwV3d *out, float *outw, float *outh, bool farclip)
{
CVector viewvec = TheCamera.m_viewMatrix * in;
*out = viewvec;
if(out->z <= CDraw::GetNearClipZ() + 1.0f) return false;
if(out->z >= CDraw::GetFarClipZ() && farclip) return false;
float recip = 1.0f/out->z;
out->x *= SCREEN_WIDTH * recip;
out->y *= SCREEN_HEIGHT * recip;
const float fov = DefaultFOV;
// this is used to scale correctly if you zoom in with sniper rifle
float fovScale = fov / CDraw::GetFOV();
#ifdef FIX_SPRITES
*outw = CDraw::ms_bFixSprites ? (fovScale * recip * SCREEN_HEIGHT) : (fovScale * SCREEN_SCALE_AR(recip) * SCREEN_WIDTH);
#else
*outw = fovScale * SCREEN_SCALE_AR(recip) * SCREEN_WIDTH;
#endif
*outh = fovScale * recip * SCREEN_HEIGHT;
return true;
}
#define SPRITEBUFFERSIZE 64
static int32 nSpriteBufferIndex;
static RwIm2DVertex SpriteBufferVerts[SPRITEBUFFERSIZE*6];
static RwIm2DVertex verts[4];
void
CSprite::InitSpriteBuffer(void)
{
m_f2DNearScreenZ = RwIm2DGetNearScreenZ();
m_f2DFarScreenZ = RwIm2DGetFarScreenZ();
}
void
CSprite::InitSpriteBuffer2D(void)
{
m_fRecipNearClipPlane = 1.0f / RwCameraGetNearClipPlane(Scene.camera);
InitSpriteBuffer();
}
void
CSprite::FlushSpriteBuffer(void)
{
if(nSpriteBufferIndex > 0){
if(m_bFlushSpriteBufferSwitchZTest){
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
RwIm2DRenderPrimitive(rwPRIMTYPETRILIST, SpriteBufferVerts, nSpriteBufferIndex*6);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
}else
RwIm2DRenderPrimitive(rwPRIMTYPETRILIST, SpriteBufferVerts, nSpriteBufferIndex*6);
nSpriteBufferIndex = 0;
}
}
void
CSprite::RenderOneXLUSprite(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, uint8 a)
{
static short indices[] = { 0, 1, 2, 3 };
// 0---3
// | |
// 1---2
float xs[4];
float ys[4];
float us[4];
float vs[4];
int i;
xs[0] = x-w; us[0] = 0.0f;
xs[1] = x-w; us[1] = 0.0f;
xs[2] = x+w; us[2] = 1.0f;
xs[3] = x+w; us[3] = 1.0f;
ys[0] = y-h; vs[0] = 0.0f;
ys[1] = y+h; vs[1] = 1.0f;
ys[2] = y+h; vs[2] = 1.0f;
ys[3] = y-h; vs[3] = 0.0f;
// clip
for(i = 0; i < 4; i++){
if(xs[i] < 0.0f){
us[i] = -xs[i] / (2.0f*w);
xs[i] = 0.0f;
}
if(xs[i] > SCREEN_WIDTH){
us[i] = 1.0f - (xs[i]-SCREEN_WIDTH) / (2.0f*w);
xs[i] = SCREEN_WIDTH;
}
if(ys[i] < 0.0f){
vs[i] = -ys[i] / (2.0f*h);
ys[i] = 0.0f;
}
if(ys[i] > SCREEN_HEIGHT){
vs[i] = 1.0f - (ys[i]-SCREEN_HEIGHT) / (2.0f*h);
ys[i] = SCREEN_HEIGHT;
}
}
// (DrawZ - DrawNear)/(DrawFar - DrawNear) = (SpriteZ-SpriteNear)/(SpriteFar-SpriteNear)
// So to calculate SpriteZ:
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::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(rotation);
float s = Sin(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] > SCREEN_WIDTH && xs[1] > SCREEN_WIDTH &&
xs[2] > SCREEN_WIDTH && xs[3] > SCREEN_WIDTH) return;
if(ys[0] > SCREEN_HEIGHT && ys[1] > SCREEN_HEIGHT &&
ys[2] > SCREEN_HEIGHT && ys[3] > SCREEN_HEIGHT) 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)
{
m_bFlushSpriteBufferSwitchZTest = 0;
// 0---3
// | |
// 1---2
float xs[4];
float ys[4];
float us[4];
float vs[4];
int i;
xs[0] = x-w; us[0] = 0.0f;
xs[1] = x-w; us[1] = 0.0f;
xs[2] = x+w; us[2] = 1.0f;
xs[3] = x+w; us[3] = 1.0f;
ys[0] = y-h; vs[0] = 0.0f;
ys[1] = y+h; vs[1] = 1.0f;
ys[2] = y+h; vs[2] = 1.0f;
ys[3] = y-h; vs[3] = 0.0f;
// clip
for(i = 0; i < 4; i++){
if(xs[i] < 0.0f){
us[i] = -xs[i] / (2.0f*w);
xs[i] = 0.0f;
}
if(xs[i] > SCREEN_WIDTH){
us[i] = 1.0f - (xs[i]-SCREEN_WIDTH) / (2.0f*w);
xs[i] = SCREEN_WIDTH;
}
if(ys[i] < 0.0f){
vs[i] = -ys[i] / (2.0f*h);
ys[i] = 0.0f;
}
if(ys[i] > SCREEN_HEIGHT){
vs[i] = 1.0f - (ys[i]-SCREEN_HEIGHT) / (2.0f*h);
ys[i] = SCREEN_HEIGHT;
}
}
float screenz = m_f2DNearScreenZ +
(z-CDraw::GetNearClipZ())*(m_f2DFarScreenZ-m_f2DNearScreenZ)*CDraw::GetFarClipZ() /
((CDraw::GetFarClipZ()-CDraw::GetNearClipZ())*z);
RwIm2DVertex *vert = &SpriteBufferVerts[nSpriteBufferIndex*6];
static int indices[6] = { 0, 1, 2, 3, 0, 2 };
for(i = 0; i < 6; i++){
RwIm2DVertexSetScreenX(&vert[i], xs[indices[i]]);
RwIm2DVertexSetScreenY(&vert[i], ys[indices[i]]);
RwIm2DVertexSetScreenZ(&vert[i], screenz);
RwIm2DVertexSetCameraZ(&vert[i], z);
RwIm2DVertexSetRecipCameraZ(&vert[i], recipz);
RwIm2DVertexSetIntRGBA(&vert[i], r*intens>>8, g*intens>>8, b*intens>>8, a);
RwIm2DVertexSetU(&vert[i], us[indices[i]], recipz);
RwIm2DVertexSetV(&vert[i], vs[indices[i]], recipz);
}
nSpriteBufferIndex++;
if(nSpriteBufferIndex >= SPRITEBUFFERSIZE)
FlushSpriteBuffer();
}
void
CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, float rotation, uint8 a)
{
m_bFlushSpriteBufferSwitchZTest = 0;
// TODO: replace with lookup
float c = Cos(DEGTORAD(rotation));
float s = Sin(DEGTORAD(rotation));
float xs[4];
float ys[4];
float us[4];
float vs[4];
int i;
xs[0] = x - c*w - s*h; us[0] = 0.0f;
xs[1] = x - c*w + s*h; us[1] = 0.0f;
xs[2] = x + c*w + s*h; us[2] = 1.0f;
xs[3] = x + c*w - s*h; us[3] = 1.0f;
ys[0] = y - c*h + s*w; vs[0] = 0.0f;
ys[1] = y + c*h + s*w; vs[1] = 1.0f;
ys[2] = y + c*h - s*w; vs[2] = 1.0f;
ys[3] = y - c*h - s*w; 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] > SCREEN_WIDTH && xs[1] > SCREEN_WIDTH &&
xs[2] > SCREEN_WIDTH && xs[3] > SCREEN_WIDTH) return;
if(ys[0] > SCREEN_HEIGHT && ys[1] > SCREEN_HEIGHT &&
ys[2] > SCREEN_HEIGHT && ys[3] > SCREEN_HEIGHT) return;
float screenz = m_f2DNearScreenZ +
(z-CDraw::GetNearClipZ())*(m_f2DFarScreenZ-m_f2DNearScreenZ)*CDraw::GetFarClipZ() /
((CDraw::GetFarClipZ()-CDraw::GetNearClipZ())*z);
RwIm2DVertex *vert = &SpriteBufferVerts[nSpriteBufferIndex*6];
static int indices[6] = { 0, 1, 2, 3, 0, 2 };
for(i = 0; i < 6; i++){
RwIm2DVertexSetScreenX(&vert[i], xs[indices[i]]);
RwIm2DVertexSetScreenY(&vert[i], ys[indices[i]]);
RwIm2DVertexSetScreenZ(&vert[i], screenz);
RwIm2DVertexSetCameraZ(&vert[i], z);
RwIm2DVertexSetRecipCameraZ(&vert[i], recipz);
RwIm2DVertexSetIntRGBA(&vert[i], r*intens>>8, g*intens>>8, b*intens>>8, a);
RwIm2DVertexSetU(&vert[i], us[indices[i]], recipz);
RwIm2DVertexSetV(&vert[i], vs[indices[i]], recipz);
}
nSpriteBufferIndex++;
if(nSpriteBufferIndex >= SPRITEBUFFERSIZE)
FlushSpriteBuffer();
}
void
CSprite::RenderBufferedOneXLUSprite_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)
{
m_bFlushSpriteBufferSwitchZTest = 0;
float c = Cos(rotation);
float s = Sin(rotation);
float xs[4];
float ys[4];
float us[4];
float vs[4];
int i;
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] > SCREEN_WIDTH && xs[1] > SCREEN_WIDTH &&
xs[2] > SCREEN_WIDTH && xs[3] > SCREEN_WIDTH) return;
if(ys[0] > SCREEN_HEIGHT && ys[1] > SCREEN_HEIGHT &&
ys[2] > SCREEN_HEIGHT && ys[3] > SCREEN_HEIGHT) return;
float screenz = m_f2DNearScreenZ +
(z-CDraw::GetNearClipZ())*(m_f2DFarScreenZ-m_f2DNearScreenZ)*CDraw::GetFarClipZ() /
((CDraw::GetFarClipZ()-CDraw::GetNearClipZ())*z);
RwIm2DVertex *vert = &SpriteBufferVerts[nSpriteBufferIndex*6];
static int indices[6] = { 0, 1, 2, 3, 0, 2 };
for(i = 0; i < 6; i++){
RwIm2DVertexSetScreenX(&vert[i], xs[indices[i]]);
RwIm2DVertexSetScreenY(&vert[i], ys[indices[i]]);
RwIm2DVertexSetScreenZ(&vert[i], screenz);
RwIm2DVertexSetCameraZ(&vert[i], z);
RwIm2DVertexSetRecipCameraZ(&vert[i], recipz);
RwIm2DVertexSetIntRGBA(&vert[i], r*intens>>8, g*intens>>8, b*intens>>8, a);
RwIm2DVertexSetU(&vert[i], us[indices[i]], recipz);
RwIm2DVertexSetV(&vert[i], vs[indices[i]], recipz);
}
nSpriteBufferIndex++;
if(nSpriteBufferIndex >= SPRITEBUFFERSIZE)
FlushSpriteBuffer();
}
void
CSprite::RenderBufferedOneXLUSprite_Rotate_2Colours(float x, float y, float z, float w, float h, uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2, float cx, float cy, float recipz, float rotation, uint8 a)
{
m_bFlushSpriteBufferSwitchZTest = 0;
float c = Cos(rotation);
float s = Sin(rotation);
float xs[4];
float ys[4];
float us[4];
float vs[4];
float cf[4];
int i;
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] > SCREEN_WIDTH && xs[1] > SCREEN_WIDTH &&
xs[2] > SCREEN_WIDTH && xs[3] > SCREEN_WIDTH) return;
if(ys[0] > SCREEN_HEIGHT && ys[1] > SCREEN_HEIGHT &&
ys[2] > SCREEN_HEIGHT && ys[3] > SCREEN_HEIGHT) return;
// Colour factors, cx/y is the direction in which colours change from rgb1 to rgb2
cf[0] = (cx*(-c-s) + cy*(-c+s))*0.5f + 0.5f;
cf[0] = Clamp(cf[0], 0.0f, 1.0f);
cf[1] = (cx*(-c+s) + cy*( c+s))*0.5f + 0.5f;
cf[1] = Clamp(cf[1], 0.0f, 1.0f);
cf[2] = (cx*( c+s) + cy*( c-s))*0.5f + 0.5f;
cf[2] = Clamp(cf[2], 0.0f, 1.0f);
cf[3] = (cx*( c-s) + cy*(-c-s))*0.5f + 0.5f;
cf[3] = Clamp(cf[3], 0.0f, 1.0f);
float screenz = m_f2DNearScreenZ +
(z-CDraw::GetNearClipZ())*(m_f2DFarScreenZ-m_f2DNearScreenZ)*CDraw::GetFarClipZ() /
((CDraw::GetFarClipZ()-CDraw::GetNearClipZ())*z);
RwIm2DVertex *vert = &SpriteBufferVerts[nSpriteBufferIndex*6];
static int indices[6] = { 0, 1, 2, 3, 0, 2 };
for(i = 0; i < 6; i++){
RwIm2DVertexSetScreenX(&vert[i], xs[indices[i]]);
RwIm2DVertexSetScreenY(&vert[i], ys[indices[i]]);
RwIm2DVertexSetScreenZ(&vert[i], screenz);
RwIm2DVertexSetCameraZ(&vert[i], z);
RwIm2DVertexSetRecipCameraZ(&vert[i], recipz);
RwIm2DVertexSetIntRGBA(&vert[i],
r1*cf[indices[i]] + r2*(1.0f - cf[indices[i]]),
g1*cf[indices[i]] + g2*(1.0f - cf[indices[i]]),
b1*cf[indices[i]] + b2*(1.0f - cf[indices[i]]),
a);
RwIm2DVertexSetU(&vert[i], us[indices[i]], recipz);
RwIm2DVertexSetV(&vert[i], vs[indices[i]], recipz);
}
nSpriteBufferIndex++;
if(nSpriteBufferIndex >= SPRITEBUFFERSIZE)
FlushSpriteBuffer();
}
void
CSprite::Set6Vertices2D(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
{
float screenz, recipz;
float z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
screenz = m_f2DNearScreenZ;
recipz = m_fRecipNearClipPlane;
RwIm2DVertexSetScreenX(&verts[0], r.left);
RwIm2DVertexSetScreenY(&verts[0], r.top);
RwIm2DVertexSetScreenZ(&verts[0], screenz);
RwIm2DVertexSetCameraZ(&verts[0], z);
RwIm2DVertexSetRecipCameraZ(&verts[0], recipz);
RwIm2DVertexSetIntRGBA(&verts[0], c2.r, c2.g, c2.b, c2.a);
RwIm2DVertexSetU(&verts[0], 0.0f, recipz);
RwIm2DVertexSetV(&verts[0], 0.0f, recipz);
RwIm2DVertexSetScreenX(&verts[1], r.right);
RwIm2DVertexSetScreenY(&verts[1], r.top);
RwIm2DVertexSetScreenZ(&verts[1], screenz);
RwIm2DVertexSetCameraZ(&verts[1], z);
RwIm2DVertexSetRecipCameraZ(&verts[1], recipz);
RwIm2DVertexSetIntRGBA(&verts[1], c3.r, c3.g, c3.b, c3.a);
RwIm2DVertexSetU(&verts[1], 1.0f, recipz);
RwIm2DVertexSetV(&verts[1], 0.0f, recipz);
RwIm2DVertexSetScreenX(&verts[2], r.right);
RwIm2DVertexSetScreenY(&verts[2], r.bottom);
RwIm2DVertexSetScreenZ(&verts[2], screenz);
RwIm2DVertexSetCameraZ(&verts[2], z);
RwIm2DVertexSetRecipCameraZ(&verts[2], recipz);
RwIm2DVertexSetIntRGBA(&verts[2], c1.r, c1.g, c1.b, c1.a);
RwIm2DVertexSetU(&verts[2], 1.0f, recipz);
RwIm2DVertexSetV(&verts[2], 1.0f, recipz);
RwIm2DVertexSetScreenX(&verts[3], r.left);
RwIm2DVertexSetScreenY(&verts[3], r.bottom);
RwIm2DVertexSetScreenZ(&verts[3], screenz);
RwIm2DVertexSetCameraZ(&verts[3], z);
RwIm2DVertexSetRecipCameraZ(&verts[3], recipz);
RwIm2DVertexSetIntRGBA(&verts[3], c0.r, c0.g, c0.b, c0.a);
RwIm2DVertexSetU(&verts[3], 0.0f, recipz);
RwIm2DVertexSetV(&verts[3], 1.0f, recipz);
RwIm2DVertexSetScreenX(&verts[4], r.left);
RwIm2DVertexSetScreenY(&verts[4], r.top);
RwIm2DVertexSetScreenZ(&verts[4], screenz);
RwIm2DVertexSetCameraZ(&verts[4], z);
RwIm2DVertexSetRecipCameraZ(&verts[4], recipz);
RwIm2DVertexSetIntRGBA(&verts[4], c2.r, c2.g, c2.b, c2.a);
RwIm2DVertexSetU(&verts[4], 0.0f, recipz);
RwIm2DVertexSetV(&verts[4], 0.0f, recipz);
RwIm2DVertexSetScreenX(&verts[5], r.right);
RwIm2DVertexSetScreenY(&verts[5], r.bottom);
RwIm2DVertexSetScreenZ(&verts[5], screenz);
RwIm2DVertexSetCameraZ(&verts[5], z);
RwIm2DVertexSetRecipCameraZ(&verts[5], recipz);
RwIm2DVertexSetIntRGBA(&verts[5], c1.r, c1.g, c1.b, c1.a);
RwIm2DVertexSetU(&verts[5], 1.0f, recipz);
RwIm2DVertexSetV(&verts[5], 1.0f, recipz);
}
void
CSprite::Set6Vertices2D(RwIm2DVertex *verts, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
{
float screenz, recipz;
float z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
screenz = m_f2DNearScreenZ;
recipz = m_fRecipNearClipPlane;
RwIm2DVertexSetScreenX(&verts[0], x3);
RwIm2DVertexSetScreenY(&verts[0], y3);
RwIm2DVertexSetScreenZ(&verts[0], screenz);
RwIm2DVertexSetCameraZ(&verts[0], z);
RwIm2DVertexSetRecipCameraZ(&verts[0], recipz);
RwIm2DVertexSetIntRGBA(&verts[0], c2.r, c2.g, c2.b, c2.a);
RwIm2DVertexSetU(&verts[0], 0.0f, recipz);
RwIm2DVertexSetV(&verts[0], 0.0f, recipz);
RwIm2DVertexSetScreenX(&verts[1], x4);
RwIm2DVertexSetScreenY(&verts[1], y4);
RwIm2DVertexSetScreenZ(&verts[1], screenz);
RwIm2DVertexSetCameraZ(&verts[1], z);
RwIm2DVertexSetRecipCameraZ(&verts[1], recipz);
RwIm2DVertexSetIntRGBA(&verts[1], c3.r, c3.g, c3.b, c3.a);
RwIm2DVertexSetU(&verts[1], 1.0f, recipz);
RwIm2DVertexSetV(&verts[1], 0.0f, recipz);
RwIm2DVertexSetScreenX(&verts[2], x2);
RwIm2DVertexSetScreenY(&verts[2], y2);
RwIm2DVertexSetScreenZ(&verts[2], screenz);
RwIm2DVertexSetCameraZ(&verts[2], z);
RwIm2DVertexSetRecipCameraZ(&verts[2], recipz);
RwIm2DVertexSetIntRGBA(&verts[2], c1.r, c1.g, c1.b, c1.a);
RwIm2DVertexSetU(&verts[2], 1.0f, recipz);
RwIm2DVertexSetV(&verts[2], 1.0f, recipz);
RwIm2DVertexSetScreenX(&verts[3], x1);
RwIm2DVertexSetScreenY(&verts[3], y1);
RwIm2DVertexSetScreenZ(&verts[3], screenz);
RwIm2DVertexSetCameraZ(&verts[3], z);
RwIm2DVertexSetRecipCameraZ(&verts[3], recipz);
RwIm2DVertexSetIntRGBA(&verts[3], c0.r, c0.g, c0.b, c0.a);
RwIm2DVertexSetU(&verts[3], 0.0f, recipz);
RwIm2DVertexSetV(&verts[3], 1.0f, recipz);
RwIm2DVertexSetScreenX(&verts[4], x3);
RwIm2DVertexSetScreenY(&verts[4], y3);
RwIm2DVertexSetScreenZ(&verts[4], screenz);
RwIm2DVertexSetCameraZ(&verts[4], z);
RwIm2DVertexSetRecipCameraZ(&verts[4], recipz);
RwIm2DVertexSetIntRGBA(&verts[4], c2.r, c2.g, c2.b, c2.a);
RwIm2DVertexSetU(&verts[4], 0.0f, recipz);
RwIm2DVertexSetV(&verts[4], 0.0f, recipz);
RwIm2DVertexSetScreenX(&verts[5], x2);
RwIm2DVertexSetScreenY(&verts[5], y2);
RwIm2DVertexSetScreenZ(&verts[5], screenz);
RwIm2DVertexSetCameraZ(&verts[5], z);
RwIm2DVertexSetRecipCameraZ(&verts[5], recipz);
RwIm2DVertexSetIntRGBA(&verts[5], c1.r, c1.g, c1.b, c1.a);
RwIm2DVertexSetU(&verts[5], 1.0f, recipz);
RwIm2DVertexSetV(&verts[5], 1.0f, recipz);
}
void
CSprite::RenderBufferedOneXLUSprite2D(float x, float y, float w, float h, const RwRGBA &colour, int16 intens, uint8 alpha)
{
m_bFlushSpriteBufferSwitchZTest = 1;
CRGBA col(intens * colour.red >> 8, intens * colour.green >> 8, intens * colour.blue >> 8, alpha);
CRect rect(x - w, y - h, x + h, y + h);
Set6Vertices2D(&SpriteBufferVerts[6 * nSpriteBufferIndex], rect, col, col, col, col);
nSpriteBufferIndex++;
if(nSpriteBufferIndex >= SPRITEBUFFERSIZE)
FlushSpriteBuffer();
}
void
CSprite::RenderBufferedOneXLUSprite2D_Rotate_Dimension(float x, float y, float w, float h, const RwRGBA &colour, int16 intens, float rotation, uint8 alpha)
{
m_bFlushSpriteBufferSwitchZTest = 1;
CRGBA col(intens * colour.red >> 8, intens * colour.green >> 8, intens * colour.blue >> 8, alpha);
float c = Cos(DEGTORAD(rotation));
float s = Sin(DEGTORAD(rotation));
Set6Vertices2D(&SpriteBufferVerts[6 * nSpriteBufferIndex],
x + c*w - s*h,
y - c*h - s*w,
x + c*w + s*h,
y + c*h - s*w,
x - c*w - s*h,
y - c*h + s*w,
x - c*w + s*h,
y + c*h + s*w,
col, col, col, col);
nSpriteBufferIndex++;
if(nSpriteBufferIndex >= SPRITEBUFFERSIZE)
FlushSpriteBuffer();
}

28
src/renderer/Sprite.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
class CSprite
{
static float m_f2DNearScreenZ;
static float m_f2DFarScreenZ;
static float m_fRecipNearClipPlane;
static int32 m_bFlushSpriteBufferSwitchZTest;
public:
static float CalcHorizonCoors(void);
static bool CalcScreenCoors(const RwV3d &in, RwV3d *out, float *outw, float *outh, bool farclip);
static void InitSpriteBuffer(void);
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);
// cx/y is the direction in which the colour changes
static void RenderBufferedOneXLUSprite_Rotate_2Colours(float x, float y, float z, float w, float h, uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2, float cx, float cy, float recipz, float rotation, uint8 a);
static void Set6Vertices2D(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
static void Set6Vertices2D(RwIm2DVertex *verts, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
static void RenderBufferedOneXLUSprite2D(float x, float y, float w, float h, const RwRGBA &colour, int16 intens, uint8 alpha);
static void RenderBufferedOneXLUSprite2D_Rotate_Dimension(float x, float y, float w, float h, const RwRGBA &colour, int16 intens, float rotation, uint8 alpha);
};

490
src/renderer/Sprite2d.cpp Normal file
View File

@ -0,0 +1,490 @@
#include "common.h"
#include "main.h"
#include "Draw.h"
#include "Camera.h"
#include "Sprite2d.h"
#include "Font.h"
RwIm2DVertex CSprite2d::maVertices[8];
float CSprite2d::RecipNearClip;
int32 CSprite2d::mCurrentBank;
RwTexture *CSprite2d::mpBankTextures[10];
int32 CSprite2d::mCurrentSprite[10];
int32 CSprite2d::mBankStart[10];
RwIm2DVertex CSprite2d::maBankVertices[500];
void
CSprite2d::SetRecipNearClip(void)
{
RecipNearClip = 1.0f / RwCameraGetNearClipPlane(Scene.camera);
}
void
CSprite2d::InitPerFrame(void)
{
int i;
mCurrentBank = 0;
for(i = 0; i < 10; i++)
mCurrentSprite[i] = 0;
#ifndef SQUEEZE_PERFORMANCE
for(i = 0; i < 10; i++)
mpBankTextures[i] = nil;
#endif
}
int32
CSprite2d::GetBank(int32 n, RwTexture *tex)
{
#ifndef SQUEEZE_PERFORMANCE
mpBankTextures[mCurrentBank] = tex;
#endif
mCurrentSprite[mCurrentBank] = 0;
mBankStart[mCurrentBank+1] = mBankStart[mCurrentBank] + n;
return mCurrentBank++;
}
void
CSprite2d::AddSpriteToBank(int32 bank, const CRect &rect, const CRGBA &col,
float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2)
{
SetVertices(&maBankVertices[6 * (mCurrentSprite[bank] + mBankStart[bank])],
rect, col, col, col, col,
u0, v0, u1, v1, u2, v2, u3, v3);
mCurrentSprite[bank]++;
if(mCurrentSprite[bank] + mBankStart[bank] >= mBankStart[bank+1]){
DrawBank(bank);
mCurrentSprite[bank] = 0;
}
}
void
CSprite2d::DrawBank(int32 bank)
{
if(mCurrentSprite[bank] == 0)
return;
#ifndef SQUEEZE_PERFORMANCE
RwRenderStateSet(rwRENDERSTATETEXTURERASTER,
mpBankTextures[bank] ? RwTextureGetRaster(mpBankTextures[bank]) : nil);
#else
CFont::Sprite[bank].SetRenderState();
#endif
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
RwIm2DRenderPrimitive(rwPRIMTYPETRILIST, &maBankVertices[6*mBankStart[bank]], 6*mCurrentSprite[bank]);
mCurrentSprite[bank] = 0;
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
}
void
CSprite2d::Delete(void)
{
if(m_pTexture){
RwTextureDestroy(m_pTexture);
m_pTexture = nil;
}
}
void
CSprite2d::SetTexture(const char *name)
{
Delete();
if(name)
m_pTexture = RwTextureRead(name, nil);
}
void
CSprite2d::SetTexture(const char *name, const char *mask)
{
Delete();
if(name)
m_pTexture = RwTextureRead(name, mask);
}
void
CSprite2d::SetAddressing(RwTextureAddressMode addr)
{
if(m_pTexture)
RwTextureSetAddressing(m_pTexture, addr);
}
void
CSprite2d::SetRenderState(void)
{
if(m_pTexture)
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(m_pTexture));
else
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
}
void
CSprite2d::Draw(float x, float y, float w, float h, const CRGBA &col)
{
SetVertices(CRect(x, y, x + w, y + h), col, col, col, col, 0);
SetRenderState();
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
}
void
CSprite2d::Draw(const CRect &rect, const CRGBA &col)
{
SetVertices(rect, col, col, col, col, 0);
SetRenderState();
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
}
void
CSprite2d::Draw(const CRect &rect, const CRGBA &col,
float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2)
{
SetVertices(rect, col, col, col, col, u0, v0, u1, v1, u3, v3, u2, v2);
SetRenderState();
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
}
void
CSprite2d::Draw(const CRect &rect, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
{
SetVertices(rect, c0, c1, c2, c3, 0);
SetRenderState();
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
}
void
CSprite2d::Draw(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, const CRGBA &col)
{
SetVertices(x1, y1, x2, y2, x3, y3, x4, y4, col, col, col, col);
SetRenderState();
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
}
// Arguments:
// 2---3
// | |
// 0---1
void
CSprite2d::SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3, uint32 far)
{
float screenz, z, recipz;
if(far){
screenz = RwIm2DGetFarScreenZ();
z = RwCameraGetFarClipPlane(Scene.camera);
}else{
screenz = RwIm2DGetNearScreenZ();
z = 1.0f/RecipNearClip;
}
recipz = 1.0f/z;
float offset = 1.0f/1024.0f;
// This is what we draw:
// 0---1
// | / |
// 3---2
RwIm2DVertexSetScreenX(&maVertices[0], r.left);
RwIm2DVertexSetScreenY(&maVertices[0], r.top);
RwIm2DVertexSetScreenZ(&maVertices[0], screenz);
RwIm2DVertexSetCameraZ(&maVertices[0], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[0], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[0], c2.r, c2.g, c2.b, c2.a);
RwIm2DVertexSetU(&maVertices[0], 0.0f+offset, recipz);
RwIm2DVertexSetV(&maVertices[0], 0.0f+offset, recipz);
RwIm2DVertexSetScreenX(&maVertices[1], r.right);
RwIm2DVertexSetScreenY(&maVertices[1], r.top);
RwIm2DVertexSetScreenZ(&maVertices[1], screenz);
RwIm2DVertexSetCameraZ(&maVertices[1], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[1], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[1], c3.r, c3.g, c3.b, c3.a);
RwIm2DVertexSetU(&maVertices[1], 1.0f+offset, recipz);
RwIm2DVertexSetV(&maVertices[1], 0.0f+offset, recipz);
RwIm2DVertexSetScreenX(&maVertices[2], r.right);
RwIm2DVertexSetScreenY(&maVertices[2], r.bottom);
RwIm2DVertexSetScreenZ(&maVertices[2], screenz);
RwIm2DVertexSetCameraZ(&maVertices[2], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[2], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[2], c1.r, c1.g, c1.b, c1.a);
RwIm2DVertexSetU(&maVertices[2], 1.0f+offset, recipz);
RwIm2DVertexSetV(&maVertices[2], 1.0f+offset, recipz);
RwIm2DVertexSetScreenX(&maVertices[3], r.left);
RwIm2DVertexSetScreenY(&maVertices[3], r.bottom);
RwIm2DVertexSetScreenZ(&maVertices[3], screenz);
RwIm2DVertexSetCameraZ(&maVertices[3], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[3], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[3], c0.r, c0.g, c0.b, c0.a);
RwIm2DVertexSetU(&maVertices[3], 0.0f+offset, recipz);
RwIm2DVertexSetV(&maVertices[3], 1.0f+offset, recipz);
}
void
CSprite2d::SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2)
{
float screenz, z, recipz;
screenz = RwIm2DGetNearScreenZ();
z = 1.0f/RecipNearClip;
recipz = 1.0f/z;
// This is what we draw:
// 0---1
// | / |
// 3---2
RwIm2DVertexSetScreenX(&maVertices[0], r.left);
RwIm2DVertexSetScreenY(&maVertices[0], r.top);
RwIm2DVertexSetScreenZ(&maVertices[0], screenz);
RwIm2DVertexSetCameraZ(&maVertices[0], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[0], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[0], c2.r, c2.g, c2.b, c2.a);
RwIm2DVertexSetU(&maVertices[0], u0, recipz);
RwIm2DVertexSetV(&maVertices[0], v0, recipz);
RwIm2DVertexSetScreenX(&maVertices[1], r.right);
RwIm2DVertexSetScreenY(&maVertices[1], r.top);
RwIm2DVertexSetScreenZ(&maVertices[1], screenz);
RwIm2DVertexSetCameraZ(&maVertices[1], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[1], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[1], c3.r, c3.g, c3.b, c3.a);
RwIm2DVertexSetU(&maVertices[1], u1, recipz);
RwIm2DVertexSetV(&maVertices[1], v1, recipz);
RwIm2DVertexSetScreenX(&maVertices[2], r.right);
RwIm2DVertexSetScreenY(&maVertices[2], r.bottom);
RwIm2DVertexSetScreenZ(&maVertices[2], screenz);
RwIm2DVertexSetCameraZ(&maVertices[2], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[2], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[2], c1.r, c1.g, c1.b, c1.a);
RwIm2DVertexSetU(&maVertices[2], u2, recipz);
RwIm2DVertexSetV(&maVertices[2], v2, recipz);
RwIm2DVertexSetScreenX(&maVertices[3], r.left);
RwIm2DVertexSetScreenY(&maVertices[3], r.bottom);
RwIm2DVertexSetScreenZ(&maVertices[3], screenz);
RwIm2DVertexSetCameraZ(&maVertices[3], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[3], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[3], c0.r, c0.g, c0.b, c0.a);
RwIm2DVertexSetU(&maVertices[3], u3, recipz);
RwIm2DVertexSetV(&maVertices[3], v3, recipz);
}
void
CSprite2d::SetVertices(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
{
float screenz, recipz;
float z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
screenz = RwIm2DGetNearScreenZ();
recipz = RecipNearClip;
RwIm2DVertexSetScreenX(&maVertices[0], x3);
RwIm2DVertexSetScreenY(&maVertices[0], y3);
RwIm2DVertexSetScreenZ(&maVertices[0], screenz);
RwIm2DVertexSetCameraZ(&maVertices[0], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[0], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[0], c2.r, c2.g, c2.b, c2.a);
RwIm2DVertexSetU(&maVertices[0], 0.0f, recipz);
RwIm2DVertexSetV(&maVertices[0], 0.0f, recipz);
RwIm2DVertexSetScreenX(&maVertices[1], x4);
RwIm2DVertexSetScreenY(&maVertices[1], y4);
RwIm2DVertexSetScreenZ(&maVertices[1], screenz);
RwIm2DVertexSetCameraZ(&maVertices[1], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[1], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[1], c3.r, c3.g, c3.b, c3.a);
RwIm2DVertexSetU(&maVertices[1], 1.0f, recipz);
RwIm2DVertexSetV(&maVertices[1], 0.0f, recipz);
RwIm2DVertexSetScreenX(&maVertices[2], x2);
RwIm2DVertexSetScreenY(&maVertices[2], y2);
RwIm2DVertexSetScreenZ(&maVertices[2], screenz);
RwIm2DVertexSetCameraZ(&maVertices[2], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[2], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[2], c1.r, c1.g, c1.b, c1.a);
RwIm2DVertexSetU(&maVertices[2], 1.0f, recipz);
RwIm2DVertexSetV(&maVertices[2], 1.0f, recipz);
RwIm2DVertexSetScreenX(&maVertices[3], x1);
RwIm2DVertexSetScreenY(&maVertices[3], y1);
RwIm2DVertexSetScreenZ(&maVertices[3], screenz);
RwIm2DVertexSetCameraZ(&maVertices[3], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[3], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[3], c0.r, c0.g, c0.b, c0.a);
RwIm2DVertexSetU(&maVertices[3], 0.0f, recipz);
RwIm2DVertexSetV(&maVertices[3], 1.0f, recipz);
}
void
CSprite2d::SetVertices(int n, float *positions, float *uvs, const CRGBA &col)
{
int i;
float screenz, recipz, z;
screenz = RwIm2DGetNearScreenZ();
recipz = RecipNearClip;
z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
for(i = 0; i < n; i++){
RwIm2DVertexSetScreenX(&maVertices[i], positions[i*2 + 0]);
RwIm2DVertexSetScreenY(&maVertices[i], positions[i*2 + 1]);
RwIm2DVertexSetScreenZ(&maVertices[i], screenz + 0.0001f);
RwIm2DVertexSetCameraZ(&maVertices[i], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[i], recipz);
RwIm2DVertexSetIntRGBA(&maVertices[i], col.r, col.g, col.b, col.a);
RwIm2DVertexSetU(&maVertices[i], uvs[i*2 + 0], recipz);
RwIm2DVertexSetV(&maVertices[i], uvs[i*2 + 1], recipz);
}
}
void
CSprite2d::SetMaskVertices(int n, float *positions)
{
int i;
float screenz, recipz, z;
screenz = RwIm2DGetNearScreenZ();
recipz = RecipNearClip;
z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
for(i = 0; i < n; i++){
RwIm2DVertexSetScreenX(&maVertices[i], positions[i*2 + 0]);
RwIm2DVertexSetScreenY(&maVertices[i], positions[i*2 + 1]);
RwIm2DVertexSetScreenZ(&maVertices[i], screenz);
RwIm2DVertexSetCameraZ(&maVertices[i], z);
RwIm2DVertexSetRecipCameraZ(&maVertices[i], recipz);
#if !defined(GTA_PS2_STUFF) && defined(RWLIBS)
RwIm2DVertexSetIntRGBA(&maVertices[i], 0, 0, 0, 0);
#else
RwIm2DVertexSetIntRGBA(&maVertices[i], 255, 255, 255, 255);
#endif
}
}
void
CSprite2d::SetVertices(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2)
{
float screenz, recipz, z;
screenz = RwIm2DGetNearScreenZ();
recipz = RecipNearClip;
z = RwCameraGetNearClipPlane(Scene.camera); // not done by game
RwIm2DVertexSetScreenX(&verts[0], r.left);
RwIm2DVertexSetScreenY(&verts[0], r.top);
RwIm2DVertexSetScreenZ(&verts[0], screenz);
RwIm2DVertexSetCameraZ(&verts[0], z);
RwIm2DVertexSetRecipCameraZ(&verts[0], recipz);
RwIm2DVertexSetIntRGBA(&verts[0], c2.r, c2.g, c2.b, c2.a);
RwIm2DVertexSetU(&verts[0], u0, recipz);
RwIm2DVertexSetV(&verts[0], v0, recipz);
RwIm2DVertexSetScreenX(&verts[1], r.left);
RwIm2DVertexSetScreenY(&verts[1], r.bottom);
RwIm2DVertexSetScreenZ(&verts[1], screenz);
RwIm2DVertexSetCameraZ(&verts[1], z);
RwIm2DVertexSetRecipCameraZ(&verts[1], recipz);
RwIm2DVertexSetIntRGBA(&verts[1], c0.r, c0.g, c0.b, c0.a);
RwIm2DVertexSetU(&verts[1], u2, recipz);
RwIm2DVertexSetV(&verts[1], v2, recipz);
RwIm2DVertexSetScreenX(&verts[2], r.right);
RwIm2DVertexSetScreenY(&verts[2], r.bottom);
RwIm2DVertexSetScreenZ(&verts[2], screenz);
RwIm2DVertexSetCameraZ(&verts[2], z);
RwIm2DVertexSetRecipCameraZ(&verts[2], recipz);
RwIm2DVertexSetIntRGBA(&verts[2], c1.r, c1.g, c1.b, c1.a);
RwIm2DVertexSetU(&verts[2], u3, recipz);
RwIm2DVertexSetV(&verts[2], v3, recipz);
RwIm2DVertexSetScreenX(&verts[3], r.left);
RwIm2DVertexSetScreenY(&verts[3], r.top);
RwIm2DVertexSetScreenZ(&verts[3], screenz);
RwIm2DVertexSetCameraZ(&verts[3], z);
RwIm2DVertexSetRecipCameraZ(&verts[3], recipz);
RwIm2DVertexSetIntRGBA(&verts[3], c2.r, c2.g, c2.b, c2.a);
RwIm2DVertexSetU(&verts[3], u0, recipz);
RwIm2DVertexSetV(&verts[3], v0, recipz);
RwIm2DVertexSetScreenX(&verts[4], r.right);
RwIm2DVertexSetScreenY(&verts[4], r.bottom);
RwIm2DVertexSetScreenZ(&verts[4], screenz);
RwIm2DVertexSetCameraZ(&verts[4], z);
RwIm2DVertexSetRecipCameraZ(&verts[4], recipz);
RwIm2DVertexSetIntRGBA(&verts[4], c1.r, c1.g, c1.b, c1.a);
RwIm2DVertexSetU(&verts[4], u3, recipz);
RwIm2DVertexSetV(&verts[4], v3, recipz);
RwIm2DVertexSetScreenX(&verts[5], r.right);
RwIm2DVertexSetScreenY(&verts[5], r.top);
RwIm2DVertexSetScreenZ(&verts[5], screenz);
RwIm2DVertexSetCameraZ(&verts[5], z);
RwIm2DVertexSetRecipCameraZ(&verts[5], recipz);
RwIm2DVertexSetIntRGBA(&verts[5], c3.r, c3.g, c3.b, c3.a);
RwIm2DVertexSetU(&verts[5], u1, recipz);
RwIm2DVertexSetV(&verts[5], v1, recipz);
}
void
CSprite2d::DrawRect(const CRect &r, const CRGBA &col)
{
SetVertices(r, col, col, col, col, false);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(col.a != 255));
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, maVertices, 4);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD);
}
void
CSprite2d::DrawRect(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
{
SetVertices(r, c0, c1, c2, c3, false);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, maVertices, 4);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
}
void
CSprite2d::DrawRectXLU(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
{
SetVertices(r, c0, c1, c2, c3, false);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
}
void CSprite2d::Draw2DPolygon(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, const CRGBA &color)
{
SetVertices(x1, y1, x2, y2, x3, y3, x4, y4, color, color, color, color);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, 0);
RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(color.a != 255));
RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD);
}

53
src/renderer/Sprite2d.h Normal file
View File

@ -0,0 +1,53 @@
#pragma once
class CSprite2d
{
static float RecipNearClip;
static int32 mCurrentBank;
static RwTexture *mpBankTextures[10];
static int32 mCurrentSprite[10];
static int32 mBankStart[10];
static RwIm2DVertex maBankVertices[500];
static RwIm2DVertex maVertices[8];
public:
RwTexture *m_pTexture;
static void SetRecipNearClip(void);
static void InitPerFrame(void);
static int32 GetBank(int32 n, RwTexture *tex);
static void AddSpriteToBank(int32 bank, const CRect &rect, const CRGBA &col,
float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2);
static void DrawBank(int32 bank);
CSprite2d(void) : m_pTexture(nil) {};
~CSprite2d(void) { Delete(); };
void Delete(void);
void SetRenderState(void);
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);
void Draw(const CRect &rect, const CRGBA &col,
float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2);
void Draw(const CRect &rect, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
void Draw(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, const CRGBA &col);
static void SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3, uint32 far);
static void SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2);
static void SetVertices(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
static void SetVertices(int n, float *positions, float *uvs, const CRGBA &col);
static void SetMaskVertices(int n, float *positions);
static void SetVertices(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2);
static void DrawRect(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
static void DrawRect(const CRect &r, const CRGBA &col);
static void DrawRectXLU(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
static void Draw2DPolygon(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, const CRGBA &color);
static RwIm2DVertex* GetVertices() { return maVertices; };
};

41
src/renderer/TexList.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "common.h"
#include "TexList.h"
#include "rtbmp.h"
#include "FileMgr.h"
bool CTexList::ms_nTexUsed[MAX_TEXUSED];
void
CTexList::Initialise()
{}
void
CTexList::Shutdown()
{}
RwTexture *
CTexList::SetTexture(int32 slot, char *name)
{
return nil;
}
int32
CTexList::GetFirstFreeTexture()
{
for (int32 i = 0; i < MAX_TEXUSED; i++)
if (!ms_nTexUsed[i])
return i;
return -1;
}
RwTexture *
CTexList::LoadFileNameTexture(char *name)
{
return SetTexture(GetFirstFreeTexture(), name);
}
void
CTexList::LoadGlobalTextureList()
{
CFileMgr::SetDir("TEXTURES");
}

14
src/renderer/TexList.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
class CTexList
{
enum { MAX_TEXUSED = 400, };
static bool ms_nTexUsed[MAX_TEXUSED];
public:
static void Initialise();
static void Shutdown();
static RwTexture *SetTexture(int32 slot, char *name);
static int32 GetFirstFreeTexture();
static RwTexture *LoadFileNameTexture(char *name);
static void LoadGlobalTextureList();
};

317
src/renderer/Timecycle.cpp Normal file
View File

@ -0,0 +1,317 @@
#include "common.h"
#include "main.h"
#include "Clock.h"
#include "Weather.h"
#include "Camera.h"
#include "Shadows.h"
#include "ZoneCull.h"
#include "CutsceneMgr.h"
#include "FileMgr.h"
#include "Timecycle.h"
int32 CTimeCycle::m_nAmbientRed[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nAmbientGreen[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nAmbientBlue[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nDirectionalRed[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nDirectionalGreen[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nDirectionalBlue[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSkyTopRed[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSkyTopGreen[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSkyTopBlue[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSkyBottomRed[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSkyBottomGreen[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSkyBottomBlue[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSunCoreRed[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSunCoreGreen[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSunCoreBlue[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSunCoronaRed[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSunCoronaGreen[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nSunCoronaBlue[NUMHOURS][NUMWEATHERS];
float CTimeCycle::m_fSunSize[NUMHOURS][NUMWEATHERS];
float CTimeCycle::m_fSpriteSize[NUMHOURS][NUMWEATHERS];
float CTimeCycle::m_fSpriteBrightness[NUMHOURS][NUMWEATHERS];
int16 CTimeCycle::m_nShadowStrength[NUMHOURS][NUMWEATHERS];
int16 CTimeCycle::m_nLightShadowStrength[NUMHOURS][NUMWEATHERS];
int16 CTimeCycle::m_nTreeShadowStrength[NUMHOURS][NUMWEATHERS];
float CTimeCycle::m_fFogStart[NUMHOURS][NUMWEATHERS];
float CTimeCycle::m_fFarClip[NUMHOURS][NUMWEATHERS];
float CTimeCycle::m_fLightsOnGroundBrightness[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nLowCloudsRed[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nLowCloudsGreen[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nLowCloudsBlue[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nFluffyCloudsTopRed[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nFluffyCloudsTopGreen[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nFluffyCloudsTopBlue[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nFluffyCloudsBottomRed[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nFluffyCloudsBottomGreen[NUMHOURS][NUMWEATHERS];
int32 CTimeCycle::m_nFluffyCloudsBottomBlue[NUMHOURS][NUMWEATHERS];
float CTimeCycle::m_fBlurRed[NUMHOURS][NUMWEATHERS];
float CTimeCycle::m_fBlurGreen[NUMHOURS][NUMWEATHERS];
float CTimeCycle::m_fBlurBlue[NUMHOURS][NUMWEATHERS];
float CTimeCycle::m_fBlurAlpha[NUMHOURS][NUMWEATHERS];
float CTimeCycle::m_fCurrentAmbientRed;
float CTimeCycle::m_fCurrentAmbientGreen;
float CTimeCycle::m_fCurrentAmbientBlue;
float CTimeCycle::m_fCurrentDirectionalRed;
float CTimeCycle::m_fCurrentDirectionalGreen;
float CTimeCycle::m_fCurrentDirectionalBlue;
int32 CTimeCycle::m_nCurrentSkyTopRed;
int32 CTimeCycle::m_nCurrentSkyTopGreen;
int32 CTimeCycle::m_nCurrentSkyTopBlue;
int32 CTimeCycle::m_nCurrentSkyBottomRed;
int32 CTimeCycle::m_nCurrentSkyBottomGreen;
int32 CTimeCycle::m_nCurrentSkyBottomBlue;
int32 CTimeCycle::m_nCurrentSunCoreRed;
int32 CTimeCycle::m_nCurrentSunCoreGreen;
int32 CTimeCycle::m_nCurrentSunCoreBlue;
int32 CTimeCycle::m_nCurrentSunCoronaRed;
int32 CTimeCycle::m_nCurrentSunCoronaGreen;
int32 CTimeCycle::m_nCurrentSunCoronaBlue;
float CTimeCycle::m_fCurrentSunSize;
float CTimeCycle::m_fCurrentSpriteSize;
float CTimeCycle::m_fCurrentSpriteBrightness;
int32 CTimeCycle::m_nCurrentShadowStrength;
int32 CTimeCycle::m_nCurrentLightShadowStrength;
int32 CTimeCycle::m_nCurrentTreeShadowStrength;
float CTimeCycle::m_fCurrentFogStart;
float CTimeCycle::m_fCurrentFarClip;
float CTimeCycle::m_fCurrentLightsOnGroundBrightness;
int32 CTimeCycle::m_nCurrentLowCloudsRed;
int32 CTimeCycle::m_nCurrentLowCloudsGreen;
int32 CTimeCycle::m_nCurrentLowCloudsBlue;
int32 CTimeCycle::m_nCurrentFluffyCloudsTopRed;
int32 CTimeCycle::m_nCurrentFluffyCloudsTopGreen;
int32 CTimeCycle::m_nCurrentFluffyCloudsTopBlue;
int32 CTimeCycle::m_nCurrentFluffyCloudsBottomRed;
int32 CTimeCycle::m_nCurrentFluffyCloudsBottomGreen;
int32 CTimeCycle::m_nCurrentFluffyCloudsBottomBlue;
float CTimeCycle::m_fCurrentBlurRed;
float CTimeCycle::m_fCurrentBlurGreen;
float CTimeCycle::m_fCurrentBlurBlue;
float CTimeCycle::m_fCurrentBlurAlpha;
int32 CTimeCycle::m_nCurrentFogColourRed;
int32 CTimeCycle::m_nCurrentFogColourGreen;
int32 CTimeCycle::m_nCurrentFogColourBlue;
int32 CTimeCycle::m_FogReduction;
int32 CTimeCycle::m_CurrentStoredValue;
CVector CTimeCycle::m_VectorToSun[16];
float CTimeCycle::m_fShadowFrontX[16];
float CTimeCycle::m_fShadowFrontY[16];
float CTimeCycle::m_fShadowSideX[16];
float CTimeCycle::m_fShadowSideY[16];
float CTimeCycle::m_fShadowDisplacementX[16];
float CTimeCycle::m_fShadowDisplacementY[16];
void
CTimeCycle::Initialise(void)
{
int w, h;
int li, bi;
char line[1040];
int ambR, ambG, ambB;
int dirR, dirG, dirB;
int skyTopR, skyTopG, skyTopB;
int skyBotR, skyBotG, skyBotB;
int sunCoreR, sunCoreG, sunCoreB;
int sunCoronaR, sunCoronaG, sunCoronaB;
float sunSz, sprSz, sprBght;
int shad, lightShad, treeShad;
float farClp, fogSt, lightGnd;
int cloudR, cloudG, cloudB;
int fluffyTopR, fluffyTopG, fluffyTopB;
int fluffyBotR, fluffyBotG, fluffyBotB;
float blurR, blurG, blurB, blurA;
debug("Intialising CTimeCycle...\n");
CFileMgr::SetDir("DATA");
CFileMgr::LoadFile("TIMECYC.DAT", work_buff, sizeof(work_buff), "rb");
CFileMgr::SetDir("");
line[0] = '\0';
bi = 0;
for(w = 0; w < NUMWEATHERS; w++)
for(h = 0; h < NUMHOURS; h++){
li = 0;
while(work_buff[bi] == '/'){
while(work_buff[bi] != '\n')
bi++;
bi++;
}
while(work_buff[bi] != '\n')
line[li++] = work_buff[bi++];
line[li] = '\0';
bi++;
sscanf(line, "%d %d %d %d %d %d %d %d %d %d %d %d "
"%d %d %d %d %d %d %f %f %f %d %d %d %f %f %f "
"%d %d %d %d %d %d %d %d %d %f %f %f %f",
&ambR, &ambG, &ambB,
&dirR, &dirG, &dirB,
&skyTopR, &skyTopG, &skyTopB,
&skyBotR, &skyBotG, &skyBotB,
&sunCoreR, &sunCoreG, &sunCoreB,
&sunCoronaR, &sunCoronaG, &sunCoronaB,
&sunSz, &sprSz, &sprBght,
&shad, &lightShad, &treeShad,
&farClp, &fogSt, &lightGnd,
&cloudR, &cloudG, &cloudB,
&fluffyTopR, &fluffyTopG, &fluffyTopB,
&fluffyBotR, &fluffyBotG, &fluffyBotB,
&blurR, &blurG, &blurB, &blurA);
m_nAmbientRed[h][w] = ambR;
m_nAmbientGreen[h][w] = ambG;
m_nAmbientBlue[h][w] = ambB;
m_nDirectionalRed[h][w] = dirR;
m_nDirectionalGreen[h][w] = dirG;
m_nDirectionalBlue[h][w] = dirB;
m_nSkyTopRed[h][w] = skyTopR;
m_nSkyTopGreen[h][w] = skyTopG;
m_nSkyTopBlue[h][w] = skyTopB;
m_nSkyBottomRed[h][w] = skyBotR;
m_nSkyBottomGreen[h][w] = skyBotG;
m_nSkyBottomBlue[h][w] = skyBotB;
m_nSunCoreRed[h][w] = sunCoreR;
m_nSunCoreGreen[h][w] = sunCoreG;
m_nSunCoreBlue[h][w] = sunCoreB;
m_nSunCoronaRed[h][w] = sunCoronaR;
m_nSunCoronaGreen[h][w] = sunCoronaG;
m_nSunCoronaBlue[h][w] = sunCoronaB;
m_fSunSize[h][w] = sunSz;
m_fSpriteSize[h][w] = sprSz;
m_fSpriteBrightness[h][w] = sprBght;
m_nShadowStrength[h][w] = shad;
m_nLightShadowStrength[h][w] = lightShad;
m_nTreeShadowStrength[h][w] = treeShad;
m_fFarClip[h][w] = farClp;
m_fFogStart[h][w] = fogSt;
m_fLightsOnGroundBrightness[h][w] = lightGnd;
m_nLowCloudsRed[h][w] = cloudR;
m_nLowCloudsGreen[h][w] = cloudG;
m_nLowCloudsBlue[h][w] = cloudB;
m_nFluffyCloudsTopRed[h][w] = fluffyTopR;
m_nFluffyCloudsTopGreen[h][w] = fluffyTopG;
m_nFluffyCloudsTopBlue[h][w] = fluffyTopB;
m_nFluffyCloudsBottomRed[h][w] = fluffyBotR;
m_nFluffyCloudsBottomGreen[h][w] = fluffyBotG;
m_nFluffyCloudsBottomBlue[h][w] = fluffyBotB;
m_fBlurRed[h][w] = blurR;
m_fBlurGreen[h][w] = blurG;
m_fBlurBlue[h][w] = blurB;
m_fBlurAlpha[h][w] = blurA;
}
m_FogReduction = 0;
debug("CTimeCycle ready\n");
}
void
CTimeCycle::Update(void)
{
int h1 = CClock::GetHours();
int h2 = (h1+1)%24;
int w1 = CWeather::OldWeatherType;
int w2 = CWeather::NewWeatherType;
float timeInterp = CClock::GetMinutes()/60.0f;
// coefficients for a bilinear interpolation
float c0 = (1.0f-timeInterp) * (1.0f-CWeather::InterpolationValue);
float c1 = timeInterp * (1.0f-CWeather::InterpolationValue);
float c2 = (1.0f-timeInterp) * CWeather::InterpolationValue;
float c3 = timeInterp * CWeather::InterpolationValue;
#define INTERP(v) v[h1][w1]*c0 + v[h2][w1]*c1 + v[h1][w2]*c2 + v[h2][w2]*c3
m_nCurrentSkyTopRed = INTERP(m_nSkyTopRed);
m_nCurrentSkyTopGreen = INTERP(m_nSkyTopGreen);
m_nCurrentSkyTopBlue = INTERP(m_nSkyTopBlue);
m_nCurrentSkyBottomRed = INTERP(m_nSkyBottomRed);
m_nCurrentSkyBottomGreen = INTERP(m_nSkyBottomGreen);
m_nCurrentSkyBottomBlue = INTERP(m_nSkyBottomBlue);
m_fCurrentAmbientRed = INTERP(m_nAmbientRed);
m_fCurrentAmbientGreen = INTERP(m_nAmbientGreen);
m_fCurrentAmbientBlue = INTERP(m_nAmbientBlue);
m_fCurrentAmbientRed /= 255.0f;
m_fCurrentAmbientGreen /= 255.0f;
m_fCurrentAmbientBlue /= 255.0f;
m_fCurrentDirectionalRed = INTERP(m_nDirectionalRed);
m_fCurrentDirectionalGreen = INTERP(m_nDirectionalGreen);
m_fCurrentDirectionalBlue = INTERP(m_nDirectionalBlue);
m_fCurrentDirectionalRed /= 255.0f;
m_fCurrentDirectionalGreen /= 255.0f;
m_fCurrentDirectionalBlue /= 255.0f;
m_nCurrentSunCoreRed = INTERP(m_nSunCoreRed);
m_nCurrentSunCoreGreen = INTERP(m_nSunCoreGreen);
m_nCurrentSunCoreBlue = INTERP(m_nSunCoreBlue);
m_nCurrentSunCoronaRed = INTERP(m_nSunCoronaRed);
m_nCurrentSunCoronaGreen = INTERP(m_nSunCoronaGreen);
m_nCurrentSunCoronaBlue = INTERP(m_nSunCoronaBlue);
m_fCurrentSunSize = INTERP(m_fSunSize);
m_fCurrentSpriteSize = INTERP(m_fSpriteSize);
m_fCurrentSpriteBrightness = INTERP(m_fSpriteBrightness);
m_nCurrentShadowStrength = INTERP(m_nShadowStrength);
m_nCurrentLightShadowStrength = INTERP(m_nLightShadowStrength);
m_nCurrentTreeShadowStrength = INTERP(m_nTreeShadowStrength);
m_fCurrentFarClip = INTERP(m_fFarClip);
m_fCurrentFogStart = INTERP(m_fFogStart);
m_fCurrentLightsOnGroundBrightness = INTERP(m_fLightsOnGroundBrightness);
m_nCurrentLowCloudsRed = INTERP(m_nLowCloudsRed);
m_nCurrentLowCloudsGreen = INTERP(m_nLowCloudsGreen);
m_nCurrentLowCloudsBlue = INTERP(m_nLowCloudsBlue);
m_nCurrentFluffyCloudsTopRed = INTERP(m_nFluffyCloudsTopRed);
m_nCurrentFluffyCloudsTopGreen = INTERP(m_nFluffyCloudsTopGreen);
m_nCurrentFluffyCloudsTopBlue = INTERP(m_nFluffyCloudsTopBlue);
m_nCurrentFluffyCloudsBottomRed = INTERP(m_nFluffyCloudsBottomRed);
m_nCurrentFluffyCloudsBottomGreen = INTERP(m_nFluffyCloudsBottomGreen);
m_nCurrentFluffyCloudsBottomBlue = INTERP(m_nFluffyCloudsBottomBlue);
m_fCurrentBlurRed = INTERP(m_fBlurRed);
m_fCurrentBlurGreen = INTERP(m_fBlurGreen);
m_fCurrentBlurBlue = INTERP(m_fBlurBlue);
m_fCurrentBlurAlpha = INTERP(m_fBlurAlpha);
if(TheCamera.m_BlurType == MOTION_BLUR_NONE || TheCamera.m_BlurType == MOTION_BLUR_LIGHT_SCENE)
TheCamera.SetMotionBlur(m_fCurrentBlurRed, m_fCurrentBlurGreen, m_fCurrentBlurBlue, m_fCurrentBlurAlpha, MOTION_BLUR_LIGHT_SCENE);
if(m_FogReduction != 0)
m_fCurrentFarClip = Max(m_fCurrentFarClip, m_FogReduction/64.0f * 650.0f);
m_nCurrentFogColourRed = (m_nCurrentSkyTopRed + 2*m_nCurrentSkyBottomRed) / 3;
m_nCurrentFogColourGreen = (m_nCurrentSkyTopGreen + 2*m_nCurrentSkyBottomGreen) / 3;
m_nCurrentFogColourBlue = (m_nCurrentSkyTopBlue + 2*m_nCurrentSkyBottomBlue) / 3;
m_CurrentStoredValue = (m_CurrentStoredValue+1)&0xF;
float sunAngle = 2*PI*(CClock::GetMinutes() + CClock::GetHours()*60)/(24*60);
CVector &sunPos = GetSunDirection();
sunPos.x = Sin(sunAngle);
sunPos.y = 1.0f;
sunPos.z = 0.2f - Cos(sunAngle);
sunPos.Normalise();
CShadows::CalcPedShadowValues(sunPos,
&m_fShadowFrontX[m_CurrentStoredValue], &m_fShadowFrontY[m_CurrentStoredValue],
&m_fShadowSideX[m_CurrentStoredValue], &m_fShadowSideY[m_CurrentStoredValue],
&m_fShadowDisplacementX[m_CurrentStoredValue], &m_fShadowDisplacementY[m_CurrentStoredValue]);
if(TheCamera.GetForward().z < -0.9f ||
!CWeather::bScriptsForceRain && (CCullZones::PlayerNoRain() || CCullZones::CamNoRain() || CCutsceneMgr::IsRunning()))
m_FogReduction = Min(m_FogReduction+1, 64);
else
m_FogReduction = Max(m_FogReduction-1, 0);
}

152
src/renderer/Timecycle.h Normal file
View File

@ -0,0 +1,152 @@
#pragma once
class CTimeCycle
{
static int32 m_nAmbientRed[NUMHOURS][NUMWEATHERS];
static int32 m_nAmbientGreen[NUMHOURS][NUMWEATHERS];
static int32 m_nAmbientBlue[NUMHOURS][NUMWEATHERS];
static int32 m_nDirectionalRed[NUMHOURS][NUMWEATHERS];
static int32 m_nDirectionalGreen[NUMHOURS][NUMWEATHERS];
static int32 m_nDirectionalBlue[NUMHOURS][NUMWEATHERS];
static int32 m_nSkyTopRed[NUMHOURS][NUMWEATHERS];
static int32 m_nSkyTopGreen[NUMHOURS][NUMWEATHERS];
static int32 m_nSkyTopBlue[NUMHOURS][NUMWEATHERS];
static int32 m_nSkyBottomRed[NUMHOURS][NUMWEATHERS];
static int32 m_nSkyBottomGreen[NUMHOURS][NUMWEATHERS];
static int32 m_nSkyBottomBlue[NUMHOURS][NUMWEATHERS];
static int32 m_nSunCoreRed[NUMHOURS][NUMWEATHERS];
static int32 m_nSunCoreGreen[NUMHOURS][NUMWEATHERS];
static int32 m_nSunCoreBlue[NUMHOURS][NUMWEATHERS];
static int32 m_nSunCoronaRed[NUMHOURS][NUMWEATHERS];
static int32 m_nSunCoronaGreen[NUMHOURS][NUMWEATHERS];
static int32 m_nSunCoronaBlue[NUMHOURS][NUMWEATHERS];
static float m_fSunSize[NUMHOURS][NUMWEATHERS];
static float m_fSpriteSize[NUMHOURS][NUMWEATHERS];
static float m_fSpriteBrightness[NUMHOURS][NUMWEATHERS];
static int16 m_nShadowStrength[NUMHOURS][NUMWEATHERS];
static int16 m_nLightShadowStrength[NUMHOURS][NUMWEATHERS];
static int16 m_nTreeShadowStrength[NUMHOURS][NUMWEATHERS];
static float m_fFogStart[NUMHOURS][NUMWEATHERS];
static float m_fFarClip[NUMHOURS][NUMWEATHERS];
static float m_fLightsOnGroundBrightness[NUMHOURS][NUMWEATHERS];
static int32 m_nLowCloudsRed[NUMHOURS][NUMWEATHERS];
static int32 m_nLowCloudsGreen[NUMHOURS][NUMWEATHERS];
static int32 m_nLowCloudsBlue[NUMHOURS][NUMWEATHERS];
static int32 m_nFluffyCloudsTopRed[NUMHOURS][NUMWEATHERS];
static int32 m_nFluffyCloudsTopGreen[NUMHOURS][NUMWEATHERS];
static int32 m_nFluffyCloudsTopBlue[NUMHOURS][NUMWEATHERS];
static int32 m_nFluffyCloudsBottomRed[NUMHOURS][NUMWEATHERS];
static int32 m_nFluffyCloudsBottomGreen[NUMHOURS][NUMWEATHERS];
static int32 m_nFluffyCloudsBottomBlue[NUMHOURS][NUMWEATHERS];
static float m_fBlurRed[NUMHOURS][NUMWEATHERS];
static float m_fBlurGreen[NUMHOURS][NUMWEATHERS];
static float m_fBlurBlue[NUMHOURS][NUMWEATHERS];
static float m_fBlurAlpha[NUMHOURS][NUMWEATHERS];
static float m_fCurrentAmbientRed;
static float m_fCurrentAmbientGreen;
static float m_fCurrentAmbientBlue;
static float m_fCurrentDirectionalRed;
static float m_fCurrentDirectionalGreen;
static float m_fCurrentDirectionalBlue;
static int32 m_nCurrentSkyTopRed;
static int32 m_nCurrentSkyTopGreen;
static int32 m_nCurrentSkyTopBlue;
static int32 m_nCurrentSkyBottomRed;
static int32 m_nCurrentSkyBottomGreen;
static int32 m_nCurrentSkyBottomBlue;
static int32 m_nCurrentSunCoreRed;
static int32 m_nCurrentSunCoreGreen;
static int32 m_nCurrentSunCoreBlue;
static int32 m_nCurrentSunCoronaRed;
static int32 m_nCurrentSunCoronaGreen;
static int32 m_nCurrentSunCoronaBlue;
static float m_fCurrentSunSize;
static float m_fCurrentSpriteSize;
static float m_fCurrentSpriteBrightness;
static int32 m_nCurrentShadowStrength;
static int32 m_nCurrentLightShadowStrength;
static int32 m_nCurrentTreeShadowStrength;
static float m_fCurrentFogStart;
static float m_fCurrentFarClip;
static float m_fCurrentLightsOnGroundBrightness;
static int32 m_nCurrentLowCloudsRed;
static int32 m_nCurrentLowCloudsGreen;
static int32 m_nCurrentLowCloudsBlue;
static int32 m_nCurrentFluffyCloudsTopRed;
static int32 m_nCurrentFluffyCloudsTopGreen;
static int32 m_nCurrentFluffyCloudsTopBlue;
static int32 m_nCurrentFluffyCloudsBottomRed;
static int32 m_nCurrentFluffyCloudsBottomGreen;
static int32 m_nCurrentFluffyCloudsBottomBlue;
static float m_fCurrentBlurRed;
static float m_fCurrentBlurGreen;
static float m_fCurrentBlurBlue;
static float m_fCurrentBlurAlpha;
static int32 m_nCurrentFogColourRed;
static int32 m_nCurrentFogColourGreen;
static int32 m_nCurrentFogColourBlue;
static int32 m_FogReduction;
public:
static int32 m_CurrentStoredValue;
static CVector m_VectorToSun[16];
static float m_fShadowFrontX[16];
static float m_fShadowFrontY[16];
static float m_fShadowSideX[16];
static float m_fShadowSideY[16];
static float m_fShadowDisplacementX[16];
static float m_fShadowDisplacementY[16];
static float GetAmbientRed(void) { return m_fCurrentAmbientRed; }
static float GetAmbientGreen(void) { return m_fCurrentAmbientGreen; }
static float GetAmbientBlue(void) { return m_fCurrentAmbientBlue; }
static float GetDirectionalRed(void) { return m_fCurrentDirectionalRed; }
static float GetDirectionalGreen(void) { return m_fCurrentDirectionalGreen; }
static float GetDirectionalBlue(void) { return m_fCurrentDirectionalBlue; }
static int32 GetSkyTopRed(void) { return m_nCurrentSkyTopRed; }
static int32 GetSkyTopGreen(void) { return m_nCurrentSkyTopGreen; }
static int32 GetSkyTopBlue(void) { return m_nCurrentSkyTopBlue; }
static int32 GetSkyBottomRed(void) { return m_nCurrentSkyBottomRed; }
static int32 GetSkyBottomGreen(void) { return m_nCurrentSkyBottomGreen; }
static int32 GetSkyBottomBlue(void) { return m_nCurrentSkyBottomBlue; }
static int32 GetSunCoreRed(void) { return m_nCurrentSunCoreRed; }
static int32 GetSunCoreGreen(void) { return m_nCurrentSunCoreGreen; }
static int32 GetSunCoreBlue(void) { return m_nCurrentSunCoreBlue; }
static int32 GetSunCoronaRed(void) { return m_nCurrentSunCoronaRed; }
static int32 GetSunCoronaGreen(void) { return m_nCurrentSunCoronaGreen; }
static int32 GetSunCoronaBlue(void) { return m_nCurrentSunCoronaBlue; }
static float GetSunSize(void) { return m_fCurrentSunSize; }
static float GetSpriteBrightness(void) { return m_fCurrentSpriteBrightness; }
static float GetSpriteSize(void) { return m_fCurrentSpriteSize; }
static int32 GetShadowStrength(void) { return m_nCurrentShadowStrength; }
static int32 GetLightShadowStrength(void) { return m_nCurrentLightShadowStrength; }
static float GetLightOnGroundBrightness(void) { return m_fCurrentLightsOnGroundBrightness; }
static float GetFarClip(void) { return m_fCurrentFarClip; }
static float GetFogStart(void) { return m_fCurrentFogStart; }
static int32 GetLowCloudsRed(void) { return m_nCurrentLowCloudsRed; }
static int32 GetLowCloudsGreen(void) { return m_nCurrentLowCloudsGreen; }
static int32 GetLowCloudsBlue(void) { return m_nCurrentLowCloudsBlue; }
static int32 GetFluffyCloudsTopRed(void) { return m_nCurrentFluffyCloudsTopRed; }
static int32 GetFluffyCloudsTopGreen(void) { return m_nCurrentFluffyCloudsTopGreen; }
static int32 GetFluffyCloudsTopBlue(void) { return m_nCurrentFluffyCloudsTopBlue; }
static int32 GetFluffyCloudsBottomRed(void) { return m_nCurrentFluffyCloudsBottomRed; }
static int32 GetFluffyCloudsBottomGreen(void) { return m_nCurrentFluffyCloudsBottomGreen; }
static int32 GetFluffyCloudsBottomBlue(void) { return m_nCurrentFluffyCloudsBottomBlue; }
static int32 GetFogRed(void) { return m_nCurrentFogColourRed; }
static int32 GetFogGreen(void) { return m_nCurrentFogColourGreen; }
static int32 GetFogBlue(void) { return m_nCurrentFogColourBlue; }
static int32 GetFogReduction(void) { return m_FogReduction; }
static void Initialise(void);
static void Update(void);
static CVector &GetSunDirection(void) { return m_VectorToSun[m_CurrentStoredValue]; }
static float GetShadowFrontX(void) { return m_fShadowFrontX[m_CurrentStoredValue]; }
static float GetShadowFrontY(void) { return m_fShadowFrontY[m_CurrentStoredValue]; }
static float GetShadowSideX(void) { return m_fShadowSideX[m_CurrentStoredValue]; }
static float GetShadowSideY(void) { return m_fShadowSideY[m_CurrentStoredValue]; }
static float GetShadowDisplacementX(void) { return m_fShadowDisplacementX[m_CurrentStoredValue]; }
static float GetShadowDisplacementY(void) { return m_fShadowDisplacementY[m_CurrentStoredValue]; }
};

View File

@ -0,0 +1,307 @@
#include "common.h"
#include "WaterCannon.h"
#include "Vector.h"
#include "General.h"
#include "main.h"
#include "Timer.h"
#include "Pools.h"
#include "Ped.h"
#include "AnimManager.h"
#include "Fire.h"
#include "WaterLevel.h"
#include "Camera.h"
#define WATERCANNONVERTS 4
#define WATERCANNONINDEXES 12
RwIm3DVertex WaterCannonVertices[WATERCANNONVERTS];
RwImVertexIndex WaterCannonIndexList[WATERCANNONINDEXES];
CWaterCannon CWaterCannons::aCannons[NUM_WATERCANNONS];
void CWaterCannon::Init(void)
{
m_nId = 0;
m_nCur = 0;
m_nTimeCreated = CTimer::GetTimeInMilliseconds();
for ( int32 i = 0; i < NUM_SEGMENTPOINTS; i++ )
m_abUsed[i] = false;
RwIm3DVertexSetU(&WaterCannonVertices[0], 0.0f);
RwIm3DVertexSetV(&WaterCannonVertices[0], 0.0f);
RwIm3DVertexSetU(&WaterCannonVertices[1], 1.0f);
RwIm3DVertexSetV(&WaterCannonVertices[1], 0.0f);
RwIm3DVertexSetU(&WaterCannonVertices[2], 0.0f);
RwIm3DVertexSetV(&WaterCannonVertices[2], 0.0f);
RwIm3DVertexSetU(&WaterCannonVertices[3], 1.0f);
RwIm3DVertexSetV(&WaterCannonVertices[3], 0.0f);
WaterCannonIndexList[0] = 0;
WaterCannonIndexList[1] = 1;
WaterCannonIndexList[2] = 2;
WaterCannonIndexList[3] = 1;
WaterCannonIndexList[4] = 3;
WaterCannonIndexList[5] = 2;
WaterCannonIndexList[6] = 0;
WaterCannonIndexList[7] = 2;
WaterCannonIndexList[8] = 1;
WaterCannonIndexList[9] = 1;
WaterCannonIndexList[10] = 2;
WaterCannonIndexList[11] = 3;
}
void CWaterCannon::Update_OncePerFrame(int16 index)
{
ASSERT(index < NUM_WATERCANNONS);
if (CTimer::GetTimeInMilliseconds() > m_nTimeCreated + WATERCANNON_LIFETIME )
{
m_nCur = (m_nCur + 1) % NUM_SEGMENTPOINTS;
m_abUsed[m_nCur] = false;
}
for ( int32 i = 0; i < NUM_SEGMENTPOINTS; i++ )
{
if ( m_abUsed[i] )
{
m_avecVelocity[i].z += -WATERCANNON_GRAVITY * CTimer::GetTimeStep();
m_avecPos[i] += m_avecVelocity[i] * CTimer::GetTimeStep();
}
}
int32 extinguishingPoint = CGeneral::GetRandomNumber() & (NUM_SEGMENTPOINTS - 1);
if ( m_abUsed[extinguishingPoint] )
gFireManager.ExtinguishPoint(m_avecPos[extinguishingPoint], 3.0f);
if ( ((index + CTimer::GetFrameCounter()) & 3) == 0 )
PushPeds();
// free if unused
int32 i = 0;
while ( 1 )
{
if ( m_abUsed[i] )
break;
if ( ++i >= NUM_SEGMENTPOINTS )
{
m_nId = 0;
return;
}
}
}
void CWaterCannon::Update_NewInput(CVector *pos, CVector *dir)
{
ASSERT(pos != NULL);
ASSERT(dir != NULL);
m_avecPos[m_nCur] = *pos;
m_avecVelocity[m_nCur] = *dir;
m_abUsed[m_nCur] = true;
}
void CWaterCannon::Render(void)
{
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)gpWaterRaster);
float v = float(CGeneral::GetRandomNumber() & 255) / 256;
RwIm3DVertexSetV(&WaterCannonVertices[0], v);
RwIm3DVertexSetV(&WaterCannonVertices[1], v);
RwIm3DVertexSetV(&WaterCannonVertices[2], v);
RwIm3DVertexSetV(&WaterCannonVertices[3], v);
int16 pointA = m_nCur % NUM_SEGMENTPOINTS;
int16 pointB = pointA - 1;
if ( pointB < 0 )
pointB += NUM_SEGMENTPOINTS;
bool bInit = false;
CVector norm;
for ( int32 i = 0; i < NUM_SEGMENTPOINTS - 1; i++ )
{
if ( m_abUsed[pointA] && m_abUsed[pointB] )
{
if ( !bInit )
{
CVector cp = CrossProduct(m_avecPos[pointB] - m_avecPos[pointA], TheCamera.GetForward());
norm = cp * (0.05f / cp.Magnitude());
bInit = true;
}
float dist = float(i*i*i) / 300.0f + 1.0f;
float brightness = float(i) / NUM_SEGMENTPOINTS;
int32 color = (int32)((1.0f - brightness*brightness) * 255.0f);
CVector offset = dist * norm;
RwIm3DVertexSetRGBA(&WaterCannonVertices[0], color, color, color, color);
RwIm3DVertexSetPos (&WaterCannonVertices[0], m_avecPos[pointA].x - offset.x, m_avecPos[pointA].y - offset.y, m_avecPos[pointA].z - offset.z);
RwIm3DVertexSetRGBA(&WaterCannonVertices[1], color, color, color, color);
RwIm3DVertexSetPos (&WaterCannonVertices[1], m_avecPos[pointA].x + offset.x, m_avecPos[pointA].y + offset.y, m_avecPos[pointA].z + offset.z);
RwIm3DVertexSetRGBA(&WaterCannonVertices[2], color, color, color, color);
RwIm3DVertexSetPos (&WaterCannonVertices[2], m_avecPos[pointB].x - offset.x, m_avecPos[pointB].y - offset.y, m_avecPos[pointB].z - offset.z);
RwIm3DVertexSetRGBA(&WaterCannonVertices[3], color, color, color, color);
RwIm3DVertexSetPos (&WaterCannonVertices[3], m_avecPos[pointB].x + offset.x, m_avecPos[pointB].y + offset.y, m_avecPos[pointB].z + offset.z);
LittleTest();
if ( RwIm3DTransform(WaterCannonVertices, WATERCANNONVERTS, NULL, rwIM3D_VERTEXUV) )
{
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, WaterCannonIndexList, WATERCANNONINDEXES);
RwIm3DEnd();
}
}
pointA = pointB--;
if ( pointB < 0 )
pointB += NUM_SEGMENTPOINTS;
}
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)TRUE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)FALSE);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE);
}
void CWaterCannon::PushPeds(void)
{
float minx = 10000.0f;
float maxx = -10000.0f;
float miny = 10000.0f;
float maxy = -10000.0f;
float minz = 10000.0f;
float maxz = -10000.0f;
for ( int32 i = 0; i < NUM_SEGMENTPOINTS; i++ )
{
if ( m_abUsed[i] )
{
minx = Min(minx, m_avecPos[i].x);
maxx = Max(maxx, m_avecPos[i].x);
miny = Min(miny, m_avecPos[i].y);
maxy = Max(maxy, m_avecPos[i].y);
minz = Min(minz, m_avecPos[i].z);
maxz = Max(maxz, m_avecPos[i].z);
}
}
for ( int32 i = CPools::GetPedPool()->GetSize() - 1; i >= 0; i--)
{
CPed *ped = CPools::GetPedPool()->GetSlot(i);
if ( ped )
{
if ( ped->GetPosition().x > minx && ped->GetPosition().x < maxx
&& ped->GetPosition().y > miny && ped->GetPosition().y < maxy
&& ped->GetPosition().z > minz && ped->GetPosition().z < maxz )
{
for ( int32 j = 0; j < NUM_SEGMENTPOINTS; j++ )
{
if ( m_abUsed[j] )
{
CVector dist = m_avecPos[j] - ped->GetPosition();
if ( dist.MagnitudeSqr() < 5.0f )
{
int32 localDir = ped->GetLocalDirection(CVector2D(1.0f, 0.0f));
ped->bIsStanding = false;
ped->ApplyMoveForce(0.0f, 0.0f, 2.0f * CTimer::GetTimeStep());
ped->m_vecMoveSpeed.x = (0.6f * m_avecVelocity[j].x + ped->m_vecMoveSpeed.x) * 0.5f;
ped->m_vecMoveSpeed.y = (0.6f * m_avecVelocity[j].y + ped->m_vecMoveSpeed.y) * 0.5f;
ped->SetFall(2000, AnimationId(ANIM_STD_HIGHIMPACT_FRONT + localDir), 0);
CFire *fire = ped->m_pFire;
if ( fire )
fire->Extinguish();
j = NUM_SEGMENTPOINTS;
}
}
}
}
}
}
}
void CWaterCannons::Init(void)
{
for ( int32 i = 0; i < NUM_WATERCANNONS; i++ )
aCannons[i].Init();
}
void CWaterCannons::UpdateOne(uint32 id, CVector *pos, CVector *dir)
{
ASSERT(pos != NULL);
ASSERT(dir != NULL);
// find the one by id
{
int32 n = 0;
while ( n < NUM_WATERCANNONS && id != aCannons[n].m_nId )
n++;
if ( n < NUM_WATERCANNONS )
{
aCannons[n].Update_NewInput(pos, dir);
return;
}
}
// if no luck then find a free one
{
int32 n = 0;
while ( n < NUM_WATERCANNONS && 0 != aCannons[n].m_nId )
n++;
if ( n < NUM_WATERCANNONS )
{
aCannons[n].Init();
aCannons[n].m_nId = id;
aCannons[n].Update_NewInput(pos, dir);
return;
}
}
}
void CWaterCannons::Update(void)
{
for ( int32 i = 0; i < NUM_WATERCANNONS; i++ )
{
if ( aCannons[i].m_nId != 0 )
aCannons[i].Update_OncePerFrame(i);
}
}
void CWaterCannons::Render(void)
{
PUSH_RENDERGROUP("CWaterCannons::Render");
for ( int32 i = 0; i < NUM_WATERCANNONS; i++ )
{
if ( aCannons[i].m_nId != 0 )
aCannons[i].Render();
}
POP_RENDERGROUP();
}

View File

@ -0,0 +1,39 @@
#pragma once
#define WATERCANNON_GRAVITY (0.009f)
#define WATERCANNON_LIFETIME (150)
class CWaterCannon
{
public:
enum
{
NUM_SEGMENTPOINTS = 16,
};
int32 m_nId;
int16 m_nCur;
uint32 m_nTimeCreated;
CVector m_avecPos[NUM_SEGMENTPOINTS];
CVector m_avecVelocity[NUM_SEGMENTPOINTS];
bool m_abUsed[NUM_SEGMENTPOINTS];
void Init(void);
void Update_OncePerFrame(int16 index);
void Update_NewInput(CVector *pos, CVector *dir);
void Render(void);
void PushPeds(void);
};
VALIDATE_SIZE(CWaterCannon, 412);
class CWaterCannons
{
public:
static CWaterCannon aCannons[NUM_WATERCANNONS];
static void Init(void);
static void UpdateOne(uint32 id, CVector *pos, CVector *dir);
static void Update();
static void Render(void);
};

1554
src/renderer/WaterLevel.cpp Normal file

File diff suppressed because it is too large Load Diff

103
src/renderer/WaterLevel.h Normal file
View File

@ -0,0 +1,103 @@
#pragma once
#define WATER_Z_OFFSET (1.5f)
#define NO_WATER -128
#define MAX_SMALL_SECTORS 128
#define MAX_LARGE_SECTORS 64
#define MAX_HUGE_SECTORS 32
#define MAX_EXTRAHUGE_SECTORS 16
#define SMALL_SECTOR_SIZE 32
#define LARGE_SECTOR_SIZE 64
#define HUGE_SECTOR_SIZE 128
#define EXTRAHUGE_SECTOR_SIZE 256
#define WATER_START_X -2048.0f
#define WATER_END_X 2048.0f
#define WATER_START_Y -2048.0f
#define WATER_END_Y 2048.0f
#define WATER_WIDTH ((WATER_END_X - WATER_START_X))
#define WATER_HEIGHT ((WATER_END_Y - WATER_START_Y))
#define WATER_UNSIGN_X(x) ( (x) + (WATER_WIDTH /2) )
#define WATER_UNSIGN_Y(y) ( (y) + (WATER_HEIGHT/2) )
#define WATER_SIGN_X(x) ( (x) - (WATER_WIDTH /2) )
#define WATER_SIGN_Y(y) ( (y) - (WATER_HEIGHT/2) )
// 32
#define WATER_SMALL_X(x) ( WATER_UNSIGN_X(x) / MAX_SMALL_SECTORS )
#define WATER_SMALL_Y(y) ( WATER_UNSIGN_Y(y) / MAX_SMALL_SECTORS )
#define WATER_FROM_SMALL_SECTOR_X(x) ( ((x) - (MAX_SMALL_SECTORS/2) ) * SMALL_SECTOR_SIZE )
#define WATER_FROM_SMALL_SECTOR_Y(y) ( ((y) - (MAX_SMALL_SECTORS/2) ) * SMALL_SECTOR_SIZE )
#define WATER_TO_SMALL_SECTOR_X(x) ( WATER_UNSIGN_X(x) / SMALL_SECTOR_SIZE )
#define WATER_TO_SMALL_SECTOR_Y(y) ( WATER_UNSIGN_Y(y) / SMALL_SECTOR_SIZE )
// 64
#define WATER_LARGE_X(x) ( WATER_UNSIGN_X(x) / MAX_LARGE_SECTORS )
#define WATER_LARGE_Y(y) ( WATER_UNSIGN_Y(y) / MAX_LARGE_SECTORS )
#define WATER_FROM_LARGE_SECTOR_X(x) ( ((x) - (MAX_LARGE_SECTORS/2) ) * LARGE_SECTOR_SIZE )
#define WATER_FROM_LARGE_SECTOR_Y(y) ( ((y) - (MAX_LARGE_SECTORS/2) ) * LARGE_SECTOR_SIZE )
#define WATER_TO_LARGE_SECTOR_X(x) ( WATER_UNSIGN_X(x) / LARGE_SECTOR_SIZE )
#define WATER_TO_LARGE_SECTOR_Y(y) ( WATER_UNSIGN_Y(y) / LARGE_SECTOR_SIZE )
// 128
#define WATER_HUGE_X(x) ( WATER_UNSIGN_X(x) / MAX_HUGE_SECTORS )
#define WATER_HUGE_Y(y) ( WATER_UNSIGN_Y(y) / MAX_HUGE_SECTORS )
#define WATER_FROM_HUGE_SECTOR_X(x) ( ((x) - (MAX_HUGE_SECTORS/2) ) * HUGE_SECTOR_SIZE )
#define WATER_FROM_HUGE_SECTOR_Y(y) ( ((y) - (MAX_HUGE_SECTORS/2) ) * HUGE_SECTOR_SIZE )
#define WATER_TO_HUGE_SECTOR_X(x) ( WATER_UNSIGN_X(x) / HUGE_SECTOR_SIZE )
#define WATER_TO_HUGE_SECTOR_Y(y) ( WATER_UNSIGN_Y(y) / HUGE_SECTOR_SIZE )
// 256
#define WATER_EXTRAHUGE_X(x) ( WATER_UNSIGN_X(x) / MAX_EXTRAHUGE_SECTORS )
#define WATER_EXTRAHUGE_Y(y) ( WATER_UNSIGN_Y(y) / MAX_EXTRAHUGE_SECTORS )
#define WATER_FROM_EXTRAHUGE_SECTOR_X(x) ( ((x) - (MAX_EXTRAHUGE_SECTORS/2)) * EXTRAHUGE_SECTOR_SIZE )
#define WATER_FROM_EXTRAHUGE_SECTOR_Y(y) ( ((y) - (MAX_EXTRAHUGE_SECTORS/2)) * EXTRAHUGE_SECTOR_SIZE )
#define WATER_TO_EXTRAHUGE_SECTOR_X(x) ( WATER_UNSIGN_X(x) / EXTRAHUGE_SECTOR_SIZE )
#define WATER_TO_EXTRAHUGE_SECTOR_Y(y) ( WATER_UNSIGN_Y(y) / EXTRAHUGE_SECTOR_SIZE )
#define MAX_BOAT_WAKES 8
extern RwRaster* gpWaterRaster;
extern bool gbDontRenderWater;
class CWaterLevel
{
static int32 ms_nNoOfWaterLevels;
static float ms_aWaterZs[48];
static CRect ms_aWaterRects[48];
static int8 aWaterBlockList[MAX_LARGE_SECTORS][MAX_LARGE_SECTORS];
static int8 aWaterFineBlockList[MAX_SMALL_SECTORS][MAX_SMALL_SECTORS];
static bool WavesCalculatedThisFrame;
static RpAtomic *ms_pWavyAtomic;
static RpGeometry *apGeomArray[MAX_BOAT_WAKES];
static int16 nGeomUsed;
public:
static void Initialise(Const char *pWaterDat); // out of class in III PC and later because of SecuROM
static void Shutdown();
static void CreateWavyAtomic();
static void DestroyWavyAtomic();
static void AddWaterLevel(float fXLeft, float fYBottom, float fXRight, float fYTop, float fLevel);
static bool WaterLevelAccordingToRectangles(float fX, float fY, float *pfOutLevel = nil);
static bool TestVisibilityForFineWaterBlocks(const CVector &worldPos);
static void RemoveIsolatedWater();
static bool GetWaterLevel(float fX, float fY, float fZ, float *pfOutLevel, bool bDontCheckZ);
static bool GetWaterLevel(CVector coors, float *pfOutLevel, bool bDontCheckZ) { return GetWaterLevel(coors.x, coors.y, coors.z, pfOutLevel, bDontCheckZ); }
static bool GetWaterLevelNoWaves(float fX, float fY, float fZ, float *pfOutLevel);
static void RenderWater();
static void RenderOneFlatSmallWaterPoly (float fX, float fY, float fZ, RwRGBA const &color);
static void RenderOneFlatLargeWaterPoly (float fX, float fY, float fZ, RwRGBA const &color);
static void RenderOneFlatHugeWaterPoly (float fX, float fY, float fZ, RwRGBA const &color);
static void RenderOneFlatExtraHugeWaterPoly(float fX, float fY, float fZ, RwRGBA const &color);
static void RenderOneWavySector (float fX, float fY, float fZ, RwRGBA const &color, bool bUnk = false);
static float CalcDistanceToWater(float fX, float fY);
static void RenderAndEmptyRenderBuffer();
static void AllocateBoatWakeArray();
static void FreeBoatWakeArray();
};

552
src/renderer/Weather.cpp Normal file
View File

@ -0,0 +1,552 @@
#include "common.h"
#include "Weather.h"
#include "Camera.h"
#include "Clock.h"
#include "CutsceneMgr.h"
#include "DMAudio.h"
#include "General.h"
#include "Pad.h"
#include "Particle.h"
#include "RenderBuffer.h"
#include "Stats.h"
#include "Shadows.h"
#include "Timecycle.h"
#include "Timer.h"
#include "Vehicle.h"
#include "World.h"
#include "ZoneCull.h"
int32 CWeather::SoundHandle = -1;
int32 CWeather::WeatherTypeInList;
int16 CWeather::OldWeatherType;
int16 CWeather::NewWeatherType;
int16 CWeather::ForcedWeatherType;
bool CWeather::LightningFlash;
bool CWeather::LightningBurst;
uint32 CWeather::LightningStart;
uint32 CWeather::LightningFlashLastChange;
uint32 CWeather::WhenToPlayLightningSound;
uint32 CWeather::LightningDuration;
float CWeather::Foggyness;
float CWeather::CloudCoverage;
float CWeather::Wind;
float CWeather::Rain;
float CWeather::InterpolationValue;
float CWeather::WetRoads;
float CWeather::Rainbow;
bool CWeather::bScriptsForceRain;
bool CWeather::Stored_StateStored;
float CWeather::Stored_InterpolationValue;
int16 CWeather::Stored_OldWeatherType;
int16 CWeather::Stored_NewWeatherType;
float CWeather::Stored_Rain;
tRainStreak Streaks[NUM_RAIN_STREAKS];
const int16 WeatherTypesList[] = {
WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
WEATHER_CLOUDY, WEATHER_CLOUDY, WEATHER_RAINY, WEATHER_RAINY,
WEATHER_CLOUDY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
WEATHER_CLOUDY, WEATHER_FOGGY, WEATHER_FOGGY, WEATHER_CLOUDY,
WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_CLOUDY, WEATHER_CLOUDY,
WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
WEATHER_CLOUDY, WEATHER_CLOUDY, WEATHER_RAINY, WEATHER_RAINY,
WEATHER_CLOUDY, WEATHER_RAINY, WEATHER_CLOUDY, WEATHER_SUNNY,
WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
WEATHER_SUNNY, WEATHER_FOGGY, WEATHER_FOGGY, WEATHER_SUNNY,
WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_RAINY, WEATHER_CLOUDY,
};
const float Windyness[] = {
0.0f, // WEATHER_SUNNY
0.7f, // WEATHER_CLOUDY
1.0f, // WEATHER_RAINY
0.5f // WEATHER_FOGGY
};
#define MIN_TIME_BETWEEN_LIGHTNING_FLASH_CHANGES (50)
#define RAIN_CHANGE_SPEED (0.003f)
#define DROPLETS_LEFT_OFFSET (10.0f)
#define DROPLETS_RIGHT_OFFSET (10.0f)
#define DROPLETS_TOP_OFFSET (10.0f)
#define DROPLETS_BOTTOM_OFFSET (10.0f)
#define STREAK_U (10.0f)
#define STREAK_V (18.0f)
#define LARGE_STREAK_COEFFICIENT (1.23f)
#define STREAK_MIN_DISTANCE (8.0f)
#define STREAK_MAX_DISTANCE (16.0f)
#define SPLASH_CHECK_RADIUS (7.0f)
#define SPLASH_OFFSET_RADIUS (2.0f)
#define STREAK_LIFETIME (4.0f)
#define STREAK_INTEROLATION_TIME (0.3f)
#define RAIN_COLOUR_R (200)
#define RAIN_COLOUR_G (200)
#define RAIN_COLOUR_B (256)
#define RAIN_ALPHA (255)
void CWeather::Init(void)
{
NewWeatherType = WEATHER_SUNNY;
bScriptsForceRain = false;
OldWeatherType = WEATHER_CLOUDY;
Stored_StateStored = false;
InterpolationValue = 0.0f;
WhenToPlayLightningSound = 0;
WeatherTypeInList = 0;
ForcedWeatherType = WEATHER_RANDOM;
SoundHandle = DMAudio.CreateEntity(AUDIOTYPE_WEATHER, (void*)1);
if (SoundHandle >= 0)
DMAudio.SetEntityStatus(SoundHandle, TRUE);
}
void CWeather::Update(void)
{
float fNewInterpolation = CClock::GetMinutes() * 1.0f / 60;
if (fNewInterpolation < InterpolationValue) {
// new hour
OldWeatherType = NewWeatherType;
if (ForcedWeatherType >= 0)
NewWeatherType = ForcedWeatherType;
else {
WeatherTypeInList = (WeatherTypeInList + 1) % ARRAY_SIZE(WeatherTypesList);
NewWeatherType = WeatherTypesList[WeatherTypeInList];
#ifdef FIX_BUGS
}
if (NewWeatherType == WEATHER_RAINY)
CStats::mmRain += CGeneral::GetRandomNumber() & 7;
#else
if (NewWeatherType == WEATHER_RAINY)
CStats::mmRain += CGeneral::GetRandomNumber() & 7;
}
#endif
}
InterpolationValue = fNewInterpolation;
if (CPad::GetPad(1)->GetRightShockJustDown()) {
NewWeatherType = (NewWeatherType + 1) % WEATHER_TOTAL;
OldWeatherType = NewWeatherType;
}
// Lightning
if (NewWeatherType != WEATHER_RAINY || OldWeatherType != WEATHER_RAINY) {
LightningFlash = false;
LightningBurst = false;
}
else{
if (LightningBurst) {
if ((CGeneral::GetRandomNumber() & 255) >= 32) {
// 0.875 probability
if (CTimer::GetTimeInMilliseconds() - LightningFlashLastChange > MIN_TIME_BETWEEN_LIGHTNING_FLASH_CHANGES) {
bool bOldLightningFlash = LightningFlash;
LightningFlash = CGeneral::GetRandomTrueFalse();
if (LightningFlash != bOldLightningFlash)
LightningFlashLastChange = CTimer::GetTimeInMilliseconds();
}
}
else {
// 0.125 probability
LightningBurst = false;
LightningDuration = Min(CTimer::GetFrameCounter() - LightningStart, 20);
LightningFlash = false;
WhenToPlayLightningSound = CTimer::GetTimeInMilliseconds() + 150 * (20 - LightningDuration);
}
}
else {
if (CGeneral::GetRandomNumber() >= 200) {
// lower probability on PC due to randomness bug
LightningFlash = false;
}
else {
LightningBurst = true;
LightningStart = CTimer::GetFrameCounter();
LightningFlashLastChange = CTimer::GetTimeInMilliseconds();
LightningFlash = true;
}
}
}
if (WhenToPlayLightningSound && CTimer::GetTimeInMilliseconds() > WhenToPlayLightningSound) {
DMAudio.PlayOneShot(SoundHandle, SOUND_LIGHTNING, LightningDuration);
CPad::GetPad(0)->StartShake(40 * LightningDuration + 100, 2 * LightningDuration + 80);
WhenToPlayLightningSound = 0;
}
// Wet roads
if (OldWeatherType == WEATHER_RAINY) {
if (NewWeatherType == WEATHER_RAINY)
WetRoads = 1.0f;
else
WetRoads = 1.0f - InterpolationValue;
}
else {
if (NewWeatherType == WEATHER_RAINY)
WetRoads = InterpolationValue;
else
WetRoads = 0.0f;
}
// Rain
#ifndef VC_RAIN_NERF
float fNewRain;
if (NewWeatherType == WEATHER_RAINY) {
// if raining for >1 hour, values: 0, 0.33, 0.66, 0.99, switching every ~16.5s
fNewRain = ((uint16)CTimer::GetTimeInMilliseconds() >> 14) * 0.33f;
if (OldWeatherType != WEATHER_RAINY) {
if (InterpolationValue < 0.4f)
// if rain has just started (<24 minutes), always 0.5
fNewRain = 0.5f;
else
// if rain is ongoing for >24 minutes, values: 0.25, 0.5, 0.75, 1.0, switching every ~16.5s
fNewRain = 0.25f + ((uint16)CTimer::GetTimeInMilliseconds() >> 14) * 0.25f;
}
}
else
fNewRain = 0.0f;
if (Rain != fNewRain) { // ok to use comparasion
if (Rain < fNewRain)
Rain = Min(fNewRain, Rain + RAIN_CHANGE_SPEED * CTimer::GetTimeStep());
else
Rain = Max(fNewRain, Rain - RAIN_CHANGE_SPEED * CTimer::GetTimeStep());
}
#else
float fNewRain;
if (NewWeatherType == WEATHER_RAINY) {
// if raining for >1 hour, values: 0, 0.33, switching every ~16.5s
fNewRain = (((uint16)CTimer::GetTimeInMilliseconds() >> 14) & 1) * 0.33f;
if (OldWeatherType != WEATHER_RAINY) {
if (InterpolationValue < 0.4f)
// if rain has just started (<24 minutes), always 0.5
fNewRain = 0.5f;
else
// if rain is ongoing for >24 minutes, values: 0.25, 0.5, switching every ~16.5s
fNewRain = 0.25f + (((uint16)CTimer::GetTimeInMilliseconds() >> 14) & 1) * 0.25f;
}
fNewRain = Max(fNewRain, 0.5f);
}
else
fNewRain = 0.0f;
Rain = fNewRain;
#endif
// Clouds
if (OldWeatherType != WEATHER_SUNNY)
CloudCoverage = 1.0f - InterpolationValue;
else
CloudCoverage = 0.0f;
if (NewWeatherType != WEATHER_SUNNY)
CloudCoverage += InterpolationValue;
// Fog
if (OldWeatherType == WEATHER_FOGGY)
Foggyness = 1.0f - InterpolationValue;
else
Foggyness = 0.0f;
if (NewWeatherType == WEATHER_FOGGY)
Foggyness += InterpolationValue;
if (OldWeatherType == WEATHER_RAINY && NewWeatherType == WEATHER_SUNNY && InterpolationValue < 0.5f && CClock::GetHours() > 6 && CClock::GetHours() < 21)
Rainbow = 1.0f - 4.0f * Abs(InterpolationValue - 0.25f) / 4.0f;
else
Rainbow = 0.0f;
Wind = InterpolationValue * Windyness[NewWeatherType] + (1.0f - InterpolationValue) * Windyness[OldWeatherType];
AddRain();
}
void CWeather::ForceWeather(int16 weather)
{
ForcedWeatherType = weather;
}
void CWeather::ForceWeatherNow(int16 weather)
{
OldWeatherType = weather;
NewWeatherType = weather;
ForcedWeatherType = weather;
}
void CWeather::ReleaseWeather()
{
ForcedWeatherType = -1;
}
void CWeather::AddRain()
{
if (CCullZones::CamNoRain() || CCullZones::PlayerNoRain())
return;
if (TheCamera.GetLookingLRBFirstPerson()) {
CVehicle* pVehicle = FindPlayerVehicle();
if (pVehicle && pVehicle->CarHasRoof()) {
CParticle::RemovePSystem(PARTICLE_RAINDROP_2D);
return;
}
}
if (Rain <= 0.1f)
return;
static RwRGBA colour;
float screen_width = SCREEN_WIDTH;
float screen_height = SCREEN_HEIGHT;
int cur_frame = (int)(3 * Rain) & 3;
int num_drops = (int)(2 * Rain) + 2;
static int STATIC_RAIN_ANGLE = -45;
static int count = 1500;
static int add_angle = 1;
if (--count == 0) {
count = 1;
if (add_angle) {
STATIC_RAIN_ANGLE += 12;
if (STATIC_RAIN_ANGLE > 45) {
count = 1500;
add_angle = !add_angle;
}
}
else {
STATIC_RAIN_ANGLE -= 12;
if (STATIC_RAIN_ANGLE < -45) {
count = 1500;
add_angle = !add_angle;
}
}
}
float rain_angle = DEGTORAD(STATIC_RAIN_ANGLE + ((STATIC_RAIN_ANGLE < 0) ? 360 : 0));
float sin_angle = Sin(rain_angle);
float cos_angle = Cos(rain_angle);
float base_x = 0.0f * cos_angle - 1.0f * sin_angle;
float base_y = 1.0f * cos_angle + 0.0f * sin_angle;
CVector xpos(0.0f, 0.0f, 0.0f);
for (int i = 0; i < 2 * num_drops; i++) {
CVector dir;
dir.x = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_x) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
dir.y = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_y) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
dir.z = 0;
CParticle::AddParticle(PARTICLE_RAINDROP_2D, xpos, dir, nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
colour, 0, rain_angle + CGeneral::GetRandomNumberInRange(-10, 10), cur_frame);
xpos.x += screen_width / (2 * num_drops);
xpos.x += CGeneral::GetRandomNumberInRange(-25.0f, 25.0f);
}
CVector ypos(0.0f, 0.0f, 0.0f);
for (int i = 0; i < num_drops; i++) {
CVector dir;
dir.x = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_x) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
dir.y = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_y) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
dir.z = 0;
CParticle::AddParticle(PARTICLE_RAINDROP_2D, ypos, dir, nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
colour, 0, rain_angle + CGeneral::GetRandomNumberInRange(-10, 10), cur_frame);
ypos.y += screen_width / num_drops;
ypos.y += CGeneral::GetRandomNumberInRange(-25.0f, 25.0f);
}
CVector ypos2(0.0f, 0.0f, 0.0f);
for (int i = 0; i < num_drops; i++) {
CVector dir;
dir.x = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_x) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
dir.y = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_y) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
dir.z = 0;
CParticle::AddParticle(PARTICLE_RAINDROP_2D, ypos2, dir, nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
colour, 0, rain_angle + CGeneral::GetRandomNumberInRange(-10, 10), cur_frame);
ypos2.y += screen_width / num_drops;
ypos2.y += CGeneral::GetRandomNumberInRange(-25.0f, 25.0f);
}
for (int i = 0; i < num_drops; i++) {
CVector pos;
pos.x = CGeneral::GetRandomNumberInRange(DROPLETS_LEFT_OFFSET, screen_width - DROPLETS_RIGHT_OFFSET);
pos.y = CGeneral::GetRandomNumberInRange(DROPLETS_TOP_OFFSET, screen_height - DROPLETS_TOP_OFFSET);
pos.z = 0.0f;
CParticle::AddParticle(PARTICLE_RAINDROP_2D, pos, CVector(0.0f, 0.0f, 0.0f), nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
colour, CGeneral::GetRandomNumberInRange(-10, 10), 360 - rain_angle + CGeneral::GetRandomNumberInRange(-30, 30), cur_frame, 50);
}
int num_splash_attempts = (int)(3 * Rain) + 1;
int num_splashes = (int)(3 * Rain) + 4;
CVector splash_points[4];
splash_points[0] = CVector(-RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
splash_points[1] = CVector(RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
splash_points[2] = 4.0f * CVector(-RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
splash_points[3] = 4.0f * CVector(RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
RwV3dTransformPoints(splash_points, splash_points, 4, RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera)));
CVector fp = (splash_points[0] + splash_points[1] + splash_points[2] + splash_points[3]) / 4;
for (int i = 0; i < num_splash_attempts; i++) {
CColPoint point;
CEntity* entity;
CVector np = fp + CVector(CGeneral::GetRandomNumberInRange(-SPLASH_CHECK_RADIUS, SPLASH_CHECK_RADIUS), CGeneral::GetRandomNumberInRange(-SPLASH_CHECK_RADIUS, SPLASH_CHECK_RADIUS), 0.0f);
if (CWorld::ProcessVerticalLine(np + CVector(0.0f, 0.0f, 40.0f), -40.0f, point, entity, true, false, false, false, true, false, nil)) {
for (int j = 0; j < num_splashes; j++)
CParticle::AddParticle((CGeneral::GetRandomTrueFalse() ? PARTICLE_RAIN_SPLASH : PARTICLE_RAIN_SPLASHUP),
CVector(
np.x + CGeneral::GetRandomNumberInRange(-SPLASH_OFFSET_RADIUS, SPLASH_OFFSET_RADIUS),
np.y + CGeneral::GetRandomNumberInRange(-SPLASH_OFFSET_RADIUS, SPLASH_OFFSET_RADIUS),
point.point.z + 0.1f),
CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, colour);
}
}
}
void RenderOneRainStreak(CVector pos, CVector unused, int intensity, bool scale, float distance)
{
static float RandomTex;
static float RandomTexX;
static float RandomTexY;
TempBufferRenderIndexList[TempBufferIndicesStored + 0] = TempBufferVerticesStored + 0;
TempBufferRenderIndexList[TempBufferIndicesStored + 1] = TempBufferVerticesStored + 2;
TempBufferRenderIndexList[TempBufferIndicesStored + 2] = TempBufferVerticesStored + 1;
TempBufferRenderIndexList[TempBufferIndicesStored + 3] = TempBufferVerticesStored + 0;
TempBufferRenderIndexList[TempBufferIndicesStored + 4] = TempBufferVerticesStored + 3;
TempBufferRenderIndexList[TempBufferIndicesStored + 5] = TempBufferVerticesStored + 2;
TempBufferRenderIndexList[TempBufferIndicesStored + 6] = TempBufferVerticesStored + 1;
TempBufferRenderIndexList[TempBufferIndicesStored + 7] = TempBufferVerticesStored + 2;
TempBufferRenderIndexList[TempBufferIndicesStored + 8] = TempBufferVerticesStored + 4;
TempBufferRenderIndexList[TempBufferIndicesStored + 9] = TempBufferVerticesStored + 2;
TempBufferRenderIndexList[TempBufferIndicesStored + 10] = TempBufferVerticesStored + 3;
TempBufferRenderIndexList[TempBufferIndicesStored + 11] = TempBufferVerticesStored + 4;
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 0], 0, 0, 0, 0);
RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 0], pos.x + 11.0f * TheCamera.GetUp().x, pos.y + 11.0f * TheCamera.GetUp().y, pos.z + 11.0f * TheCamera.GetUp().z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 1], 0, 0, 0, 0);
RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 1], pos.x - 9.0f * TheCamera.GetRight().x, pos.y - 9.0f * TheCamera.GetRight().y, pos.z - 9.0f * TheCamera.GetRight().z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 2], RAIN_COLOUR_R * intensity / 256, RAIN_COLOUR_G * intensity / 256, RAIN_COLOUR_B * intensity / 256, RAIN_ALPHA);
RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 2], pos.x, pos.y, pos.z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 3], 0, 0, 0, 0);
RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 3], pos.x + 9.0f * TheCamera.GetRight().x, pos.y + 9.0f * TheCamera.GetRight().y, pos.z + 9.0f * TheCamera.GetRight().z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 4], 0, 0, 0, 0);
RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 4], pos.x - 11.0f * TheCamera.GetUp().x, pos.y - 11.0f * TheCamera.GetUp().y, pos.z - 11.0f * TheCamera.GetUp().z);
float u = STREAK_U;
float v = STREAK_V;
if (scale) {
u *= LARGE_STREAK_COEFFICIENT;
v *= LARGE_STREAK_COEFFICIENT;
}
float distance_coefficient;
if (distance < STREAK_MIN_DISTANCE)
distance_coefficient = 1.0f;
else if (distance > STREAK_MAX_DISTANCE)
distance_coefficient = 0.5f;
else
distance_coefficient = 1.0f - 0.5f * (distance - STREAK_MIN_DISTANCE) / (STREAK_MAX_DISTANCE - STREAK_MIN_DISTANCE);
u *= distance_coefficient;
v *= distance_coefficient;
if (!CTimer::GetIsPaused()) {
RandomTex = ((CGeneral::GetRandomNumber() & 255) - 128) * 0.01f;
RandomTexX = (CGeneral::GetRandomNumber() & 127) * 0.01f;
RandomTexY = (CGeneral::GetRandomNumber() & 127) * 0.01f;
}
RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 0], 0.5f * u - RandomTex + RandomTexX);
RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 0], -v * 0.5f + RandomTexY);
RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 1], RandomTexX);
RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 1], RandomTexY);
RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 2], 0.5f * u + RandomTexX);
RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 2], RandomTexY);
RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 3], u + RandomTexX);
RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 3], RandomTexY);
RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 4], 0.5f * u + RandomTex + RandomTexX);
RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 5], 0.5f * v + RandomTexY);
TempBufferIndicesStored += 12;
TempBufferVerticesStored += 5;
}
void CWeather::RenderRainStreaks(void)
{
if (CTimer::GetIsCodePaused())
return;
int base_intensity = (64.0f - CTimeCycle::GetFogReduction()) / 64.0f * int(255 * Rain);
if (base_intensity == 0)
return;
TempBufferIndicesStored = 0;
TempBufferVerticesStored = 0;
for (int i = 0; i < NUM_RAIN_STREAKS; i++) {
if (Streaks[i].timer) {
float secondsElapsed = (CTimer::GetTimeInMilliseconds() - Streaks[i].timer) / 1024.0f;
if (secondsElapsed > STREAK_LIFETIME)
Streaks[i].timer = 0;
else{
int intensity;
if (secondsElapsed < STREAK_INTEROLATION_TIME)
intensity = base_intensity * 0.5f * secondsElapsed / STREAK_INTEROLATION_TIME;
else if (secondsElapsed > (STREAK_LIFETIME - STREAK_INTEROLATION_TIME))
intensity = (STREAK_LIFETIME - secondsElapsed) * 0.5f * base_intensity / STREAK_INTEROLATION_TIME;
else
intensity = base_intensity * 0.5f;
CVector dir = Streaks[i].direction;
dir.Normalise();
CVector pos = Streaks[i].position + secondsElapsed * Streaks[i].direction;
RenderOneRainStreak(pos, dir, intensity, false, (pos - TheCamera.GetPosition()).Magnitude());
#ifndef FIX_BUGS // remove useless code
if (secondsElapsed > 1.0f && secondsElapsed < STREAK_LIFETIME - 1.0f) {
CGeneral::GetRandomNumber(), CGeneral::GetRandomNumber();
}
#endif
}
}
else if ((CGeneral::GetRandomNumber() & 0xF00) == 0){
// 1/16 probability
Streaks[i].direction = CVector(4.0f, 4.0f, -4.0f);
Streaks[i].position = 6.0f * TheCamera.GetForward() + TheCamera.GetPosition() + CVector(-1.8f * Streaks[i].direction.x, -1.8f * Streaks[i].direction.y, 8.0f);
if (!CCutsceneMgr::IsRunning()) {
Streaks[i].position.x += 2.0f * FindPlayerSpeed().x * 60.0f;
Streaks[i].position.y += 2.0f * FindPlayerSpeed().y * 60.0f;
}
else
Streaks[i].position += (TheCamera.GetPosition() - TheCamera.m_RealPreviousCameraPosition) * 20.0f;
Streaks[i].position.x += ((CGeneral::GetRandomNumber() & 255) - 128) * 0.08f;
Streaks[i].position.y += ((CGeneral::GetRandomNumber() & 255) - 128) * 0.08f;
Streaks[i].timer = CTimer::GetTimeInMilliseconds();
}
}
if (TempBufferIndicesStored){
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEFOGTYPE, (void*)rwFOGTYPELINEAR);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRainDropTex[3]));
if (RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, 1))
{
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
RwIm3DEnd();
}
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
}
TempBufferVerticesStored = 0;
TempBufferIndicesStored = 0;
}
void CWeather::StoreWeatherState()
{
Stored_StateStored = true;
Stored_InterpolationValue = InterpolationValue;
Stored_Rain = Rain;
Stored_NewWeatherType = NewWeatherType;
Stored_OldWeatherType = OldWeatherType;
}
void CWeather::RestoreWeatherState()
{
#ifdef FIX_BUGS // it's not used anyway though
Stored_StateStored = false;
#endif
InterpolationValue = Stored_InterpolationValue;
Rain = Stored_Rain;
NewWeatherType = Stored_NewWeatherType;
OldWeatherType = Stored_OldWeatherType;
}

71
src/renderer/Weather.h Normal file
View File

@ -0,0 +1,71 @@
enum {
WEATHER_SUNNY,
WEATHER_CLOUDY,
WEATHER_RAINY,
WEATHER_FOGGY
};
class CWeather
{
public:
enum {
WEATHER_RANDOM = -1,
WEATHER_SUNNY = 0,
WEATHER_CLOUDY = 1,
WEATHER_RAINY = 2,
WEATHER_FOGGY = 3,
WEATHER_TOTAL = 4
};
static int32 SoundHandle;
static int32 WeatherTypeInList;
static int16 OldWeatherType;
static int16 NewWeatherType;
static int16 ForcedWeatherType;
static bool LightningFlash;
static bool LightningBurst;
static uint32 LightningStart;
static uint32 LightningFlashLastChange;
static uint32 WhenToPlayLightningSound;
static uint32 LightningDuration;
static float Foggyness;
static float CloudCoverage;
static float Wind;
static float Rain;
static float InterpolationValue;
static float WetRoads;
static float Rainbow;
static bool bScriptsForceRain;
static bool Stored_StateStored;
static float Stored_InterpolationValue;
static int16 Stored_OldWeatherType;
static int16 Stored_NewWeatherType;
static float Stored_Rain;
static void RenderRainStreaks(void);
static void Update(void);
static void Init(void);
static void ReleaseWeather();
static void ForceWeather(int16);
static void ForceWeatherNow(int16);
static void StoreWeatherState();
static void RestoreWeatherState();
static void AddRain();
};
enum {
NUM_RAIN_STREAKS = 35
};
struct tRainStreak
{
CVector position;
CVector direction;
uint32 timer;
};
extern RwTexture* gpRainDropTex[4];