summaryrefslogtreecommitdiffstats
path: root/src/renderer/Renderer.cpp
diff options
context:
space:
mode:
authorSergeanur <s.anureev@yandex.ua>2021-07-15 17:19:32 +0200
committerSergeanur <s.anureev@yandex.ua>2021-07-17 23:04:26 +0200
commitd0404cbdb77bd82abf578ce28093990db94743f2 (patch)
tree1a7232c3dcdd6c371ab5fbde0fc6bf04c5bc7005 /src/renderer/Renderer.cpp
parentMerge pull request #1217 from Nopey/master (diff)
downloadre3-d0404cbdb77bd82abf578ce28093990db94743f2.tar
re3-d0404cbdb77bd82abf578ce28093990db94743f2.tar.gz
re3-d0404cbdb77bd82abf578ce28093990db94743f2.tar.bz2
re3-d0404cbdb77bd82abf578ce28093990db94743f2.tar.lz
re3-d0404cbdb77bd82abf578ce28093990db94743f2.tar.xz
re3-d0404cbdb77bd82abf578ce28093990db94743f2.tar.zst
re3-d0404cbdb77bd82abf578ce28093990db94743f2.zip
Diffstat (limited to 'src/renderer/Renderer.cpp')
-rw-r--r--src/renderer/Renderer.cpp1838
1 files changed, 1838 insertions, 0 deletions
diff --git a/src/renderer/Renderer.cpp b/src/renderer/Renderer.cpp
new file mode 100644
index 00000000..1c0bd445
--- /dev/null
+++ b/src/renderer/Renderer.cpp
@@ -0,0 +1,1838 @@
+#define WITHD3D
+#include "common.h"
+
+#include "main.h"
+#include "Lights.h"
+#include "ModelInfo.h"
+#include "Treadable.h"
+#include "Ped.h"
+#include "Vehicle.h"
+#include "Boat.h"
+#include "Heli.h"
+#include "Object.h"
+#include "PathFind.h"
+#include "Collision.h"
+#include "VisibilityPlugins.h"
+#include "Clock.h"
+#include "World.h"
+#include "Camera.h"
+#include "ModelIndices.h"
+#include "Streaming.h"
+#include "Shadows.h"
+#include "PointLights.h"
+#include "Renderer.h"
+#include "Frontend.h"
+#include "custompipes.h"
+#include "Debug.h"
+
+bool gbShowPedRoadGroups;
+bool gbShowCarRoadGroups;
+bool gbShowCollisionPolys;
+bool gbShowCollisionLines;
+bool gbShowCullZoneDebugStuff;
+bool gbDisableZoneCull; // not original
+bool gbBigWhiteDebugLightSwitchedOn;
+
+bool gbDontRenderBuildings;
+bool gbDontRenderBigBuildings;
+bool gbDontRenderPeds;
+bool gbDontRenderObjects;
+bool gbDontRenderVehicles;
+
+int32 EntitiesRendered;
+int32 EntitiesNotRendered;
+int32 RenderedBigBuildings;
+int32 RenderedBuildings;
+int32 RenderedCars;
+int32 RenderedPeds;
+int32 RenderedObjects;
+int32 RenderedDummies;
+int32 TestedBigBuildings;
+int32 TestedBuildings;
+int32 TestedCars;
+int32 TestedPeds;
+int32 TestedObjects;
+int32 TestedDummies;
+
+// unused
+int16 TestCloseThings;
+int16 TestBigThings;
+
+struct EntityInfo
+{
+ CEntity *ent;
+ float sort;
+};
+
+CLinkList<EntityInfo> gSortedVehiclesAndPeds;
+
+int32 CRenderer::ms_nNoOfVisibleEntities;
+CEntity *CRenderer::ms_aVisibleEntityPtrs[NUMVISIBLEENTITIES];
+CEntity *CRenderer::ms_aInVisibleEntityPtrs[NUMINVISIBLEENTITIES];
+int32 CRenderer::ms_nNoOfInVisibleEntities;
+#ifdef NEW_RENDERER
+int32 CRenderer::ms_nNoOfVisibleVehicles;
+CEntity *CRenderer::ms_aVisibleVehiclePtrs[NUMVISIBLEENTITIES];
+int32 CRenderer::ms_nNoOfVisibleBuildings;
+CEntity *CRenderer::ms_aVisibleBuildingPtrs[NUMVISIBLEENTITIES];
+
+CLinkList<EntityInfo> gSortedBuildings;
+#endif
+
+CVector CRenderer::ms_vecCameraPosition;
+CVehicle *CRenderer::m_pFirstPersonVehicle;
+bool CRenderer::m_loadingPriority;
+float CRenderer::ms_lodDistScale = 1.2f;
+
+// unused
+BlockedRange CRenderer::aBlockedRanges[16];
+BlockedRange *CRenderer::pFullBlockedRanges;
+BlockedRange *CRenderer::pEmptyBlockedRanges;
+
+void
+CRenderer::Init(void)
+{
+ gSortedVehiclesAndPeds.Init(40);
+ SortBIGBuildings();
+#ifdef NEW_RENDERER
+ gSortedBuildings.Init(NUMVISIBLEENTITIES);
+#endif
+}
+
+void
+CRenderer::Shutdown(void)
+{
+ gSortedVehiclesAndPeds.Shutdown();
+#ifdef NEW_RENDERER
+ gSortedBuildings.Shutdown();
+#endif
+}
+
+void
+CRenderer::PreRender(void)
+{
+ int i;
+ CLink<CVisibilityPlugins::AlphaObjectInfo> *node;
+
+ for(i = 0; i < ms_nNoOfVisibleEntities; i++)
+ ms_aVisibleEntityPtrs[i]->PreRender();
+
+#ifdef NEW_RENDERER
+ if(gbNewRenderer){
+ for(i = 0; i < ms_nNoOfVisibleVehicles; i++)
+ ms_aVisibleVehiclePtrs[i]->PreRender();
+ // How is this done with cWorldStream?
+ //for(i = 0; i < ms_nNoOfVisibleBuildings; i++)
+ // ms_aVisibleBuildingPtrs[i]->PreRender();
+ for(CLink<EntityInfo> *node = gSortedBuildings.head.next;
+ node != &gSortedBuildings.tail;
+ node = node->next)
+ ((CEntity*)node->item.ent)->PreRender();
+ for(node = CVisibilityPlugins::m_alphaBuildingList.head.next;
+ node != &CVisibilityPlugins::m_alphaBuildingList.tail;
+ node = node->next)
+ ((CEntity*)node->item.entity)->PreRender();
+ }
+#endif
+
+ for (i = 0; i < ms_nNoOfInVisibleEntities; i++) {
+#ifdef SQUEEZE_PERFORMANCE
+ if (ms_aInVisibleEntityPtrs[i]->IsVehicle() && ((CVehicle*)ms_aInVisibleEntityPtrs[i])->IsHeli())
+#endif
+ ms_aInVisibleEntityPtrs[i]->PreRender();
+ }
+
+ for(node = CVisibilityPlugins::m_alphaEntityList.head.next;
+ node != &CVisibilityPlugins::m_alphaEntityList.tail;
+ node = node->next)
+ ((CEntity*)node->item.entity)->PreRender();
+
+ CHeli::SpecialHeliPreRender();
+ CShadows::RenderExtraPlayerShadows();
+}
+
+void
+CRenderer::RenderOneRoad(CEntity *e)
+{
+ if(gbDontRenderBuildings)
+ return;
+ if(gbShowCollisionPolys)
+ CCollision::DrawColModel_Coloured(e->GetMatrix(), *CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel(), e->GetModelIndex());
+ else{
+#ifdef EXTENDED_PIPELINES
+ CustomPipes::AttachGlossPipe(e->GetAtomic());
+#endif
+ PUSH_RENDERGROUP(CModelInfo::GetModelInfo(e->GetModelIndex())->GetModelName());
+
+#ifdef EXTRA_MODEL_FLAGS
+ if(!e->IsBuilding() || CModelInfo::GetModelInfo(e->GetModelIndex())->RenderDoubleSided()){
+ BACKFACE_CULLING_OFF;
+ e->Render();
+ BACKFACE_CULLING_ON;
+ }else
+#endif
+ e->Render();
+
+ POP_RENDERGROUP();
+ }
+}
+
+void
+CRenderer::RenderOneNonRoad(CEntity *e)
+{
+ CPed *ped;
+ CVehicle *veh;
+ int i;
+ bool resetLights;
+
+#ifndef MASTER
+ if(gbShowCollisionPolys){
+ if(!e->IsVehicle()){
+ CCollision::DrawColModel_Coloured(e->GetMatrix(), *CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel(), e->GetModelIndex());
+ return;
+ }
+ }else if(e->IsBuilding()){
+ if(e->bIsBIGBuilding){
+ if(gbDontRenderBigBuildings)
+ return;
+ }else{
+ if(gbDontRenderBuildings)
+ return;
+ }
+ }else
+#endif
+ if(e->IsPed()){
+#ifndef MASTER
+ if(gbDontRenderPeds)
+ return;
+#endif
+ ped = (CPed*)e;
+ if(ped->m_nPedState == PED_DRIVING)
+ return;
+ }
+#ifndef MASTER
+ else if(e->IsObject() || e->IsDummy()){
+ if(gbDontRenderObjects)
+ return;
+ }else if(e->IsVehicle()){
+ // re3 addition
+ if(gbDontRenderVehicles)
+ return;
+ }
+#endif
+
+ PUSH_RENDERGROUP(CModelInfo::GetModelInfo(e->GetModelIndex())->GetModelName());
+
+ resetLights = e->SetupLighting();
+
+ if(e->IsVehicle())
+ CVisibilityPlugins::InitAlphaAtomicList();
+
+ // Render Peds in vehicle before vehicle itself
+ if(e->IsVehicle()){
+ veh = (CVehicle*)e;
+ if(veh->pDriver && veh->pDriver->m_nPedState == PED_DRIVING)
+ veh->pDriver->Render();
+ for(i = 0; i < 8; i++)
+ if(veh->pPassengers[i] && veh->pPassengers[i]->m_nPedState == PED_DRIVING)
+ veh->pPassengers[i]->Render();
+ BACKFACE_CULLING_OFF;
+ }
+#ifdef EXTRA_MODEL_FLAGS
+ if(!e->IsBuilding() || CModelInfo::GetModelInfo(e->GetModelIndex())->RenderDoubleSided()){
+ BACKFACE_CULLING_OFF;
+ e->Render();
+ BACKFACE_CULLING_ON;
+ }else
+#endif
+ e->Render();
+
+ if(e->IsVehicle()){
+ BACKFACE_CULLING_OFF;
+ e->bImBeingRendered = true;
+ CVisibilityPlugins::RenderAlphaAtomics();
+ e->bImBeingRendered = false;
+ BACKFACE_CULLING_ON;
+ }
+
+ e->RemoveLighting(resetLights);
+
+ POP_RENDERGROUP();
+}
+
+void
+CRenderer::RenderFirstPersonVehicle(void)
+{
+ if(m_pFirstPersonVehicle == nil)
+ return;
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RenderOneNonRoad(m_pFirstPersonVehicle);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+}
+
+inline bool IsRoad(CEntity *e) { return e->IsBuilding() && ((CBuilding*)e)->GetIsATreadable(); }
+
+void
+CRenderer::RenderRoads(void)
+{
+ int i;
+ CTreadable *t;
+
+ PUSH_RENDERGROUP("CRenderer::RenderRoads");
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
+ BACKFACE_CULLING_ON;
+ DeActivateDirectional();
+ SetAmbientColours();
+
+ for(i = 0; i < ms_nNoOfVisibleEntities; i++){
+ t = (CTreadable*)ms_aVisibleEntityPtrs[i];
+ if(IsRoad(t)){
+#ifndef MASTER
+ if(gbShowCarRoadGroups || gbShowPedRoadGroups){
+ int ind = 0;
+ if(gbShowCarRoadGroups)
+ ind += ThePaths.m_pathNodes[t->m_nodeIndices[PATH_CAR][0]].group;
+ if(gbShowPedRoadGroups)
+ ind += ThePaths.m_pathNodes[t->m_nodeIndices[PATH_PED][0]].group;
+ SetAmbientColoursToIndicateRoadGroup(ind);
+ }
+#endif
+ RenderOneRoad(t);
+#ifndef MASTER
+ if(gbShowCarRoadGroups || gbShowPedRoadGroups)
+ ReSetAmbientAndDirectionalColours();
+#endif
+ }
+ }
+ POP_RENDERGROUP();
+}
+
+void
+CRenderer::RenderEverythingBarRoads(void)
+{
+ int i;
+ CEntity *e;
+ CVector dist;
+ EntityInfo ei;
+
+ PUSH_RENDERGROUP("CRenderer::RenderEverythingBarRoads");
+ BACKFACE_CULLING_ON;
+ gSortedVehiclesAndPeds.Clear();
+
+ for(i = 0; i < ms_nNoOfVisibleEntities; i++){
+ e = ms_aVisibleEntityPtrs[i];
+
+ if(IsRoad(e))
+ continue;
+
+#ifdef EXTENDED_PIPELINES
+ if(CustomPipes::bRenderingEnvMap && (e->IsPed() || e->IsVehicle()))
+ continue;
+#endif
+
+ if(e->IsVehicle() ||
+ e->IsPed() && CVisibilityPlugins::GetClumpAlpha((RpClump*)e->m_rwObject) != 255){
+ if(e->IsVehicle() && ((CVehicle*)e)->IsBoat()){
+ ei.ent = e;
+ dist = ms_vecCameraPosition - e->GetPosition();
+ ei.sort = dist.MagnitudeSqr();
+ gSortedVehiclesAndPeds.InsertSorted(ei);
+ }else{
+ dist = ms_vecCameraPosition - e->GetPosition();
+ if(!CVisibilityPlugins::InsertEntityIntoSortedList(e, dist.Magnitude())){
+ printf("Ran out of space in alpha entity list");
+ RenderOneNonRoad(e);
+ }
+ }
+ }else
+ RenderOneNonRoad(e);
+ }
+ POP_RENDERGROUP();
+}
+
+void
+CRenderer::RenderVehiclesButNotBoats(void)
+{
+ // This function doesn't do anything
+ // because only boats are inserted into the list
+ CLink<EntityInfo> *node;
+
+ for(node = gSortedVehiclesAndPeds.tail.prev;
+ node != &gSortedVehiclesAndPeds.head;
+ node = node->prev){
+ // only boats in this list
+ CVehicle *v = (CVehicle*)node->item.ent;
+ if(!v->IsBoat())
+ RenderOneNonRoad(v);
+ }
+}
+
+void
+CRenderer::RenderBoats(void)
+{
+ CLink<EntityInfo> *node;
+
+ PUSH_RENDERGROUP("CRenderer::RenderBoats");
+ BACKFACE_CULLING_ON;
+
+ for(node = gSortedVehiclesAndPeds.tail.prev;
+ node != &gSortedVehiclesAndPeds.head;
+ node = node->prev){
+ // only boats in this list
+ CVehicle *v = (CVehicle*)node->item.ent;
+ if(v->IsBoat())
+ RenderOneNonRoad(v);
+ }
+ POP_RENDERGROUP();
+}
+
+#ifdef NEW_RENDERER
+#ifndef LIBRW
+#error "Need librw for EXTENDED_PIPELINES"
+#endif
+#include "WaterLevel.h"
+
+enum {
+ // blend passes
+ PASS_NOZ, // no z-write
+ PASS_ADD, // additive
+ PASS_BLEND // normal blend
+};
+
+static RwRGBAReal black;
+
+static void
+SetStencilState(int state)
+{
+ switch(state){
+ // disable stencil
+ case 0:
+ rw::SetRenderState(rw::STENCILENABLE, FALSE);
+ break;
+ // test against stencil
+ case 1:
+ rw::SetRenderState(rw::STENCILENABLE, TRUE);
+ rw::SetRenderState(rw::STENCILFUNCTION, rw::STENCILNOTEQUAL);
+ rw::SetRenderState(rw::STENCILPASS, rw::STENCILKEEP);
+ rw::SetRenderState(rw::STENCILFAIL, rw::STENCILKEEP);
+ rw::SetRenderState(rw::STENCILZFAIL, rw::STENCILKEEP);
+ rw::SetRenderState(rw::STENCILFUNCTIONMASK, 0xFF);
+ rw::SetRenderState(rw::STENCILFUNCTIONREF, 0xFF);
+ break;
+ // write to stencil
+ case 2:
+ rw::SetRenderState(rw::STENCILENABLE, TRUE);
+ rw::SetRenderState(rw::STENCILFUNCTION, rw::STENCILALWAYS);
+ rw::SetRenderState(rw::STENCILPASS, rw::STENCILREPLACE);
+ rw::SetRenderState(rw::STENCILFUNCTIONREF, 0xFF);
+ break;
+ }
+}
+
+void
+CRenderer::RenderOneBuilding(CEntity *ent, float camdist)
+{
+ if(ent->m_rwObject == nil)
+ return;
+
+ ent->bImBeingRendered = true; // TODO: this seems wrong, but do we even need it?
+
+ assert(RwObjectGetType(ent->m_rwObject) == rpATOMIC);
+ RpAtomic *atomic = (RpAtomic*)ent->m_rwObject;
+ CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(ent->GetModelIndex());
+
+#ifdef EXTRA_MODEL_FLAGS
+ bool resetCull = false;
+ if(!ent->IsBuilding() || mi->RenderDoubleSided()){
+ resetCull = true;
+ BACKFACE_CULLING_OFF;
+ }
+#endif
+
+ int pass = PASS_BLEND;
+ if(mi->m_additive) // very questionable
+ pass = PASS_ADD;
+ if(mi->m_noZwrite)
+ pass = PASS_NOZ;
+
+ if(ent->bDistanceFade){
+ RpAtomic *lodatm;
+ float fadefactor;
+ uint32 alpha;
+
+ lodatm = mi->GetAtomicFromDistance(camdist - FADE_DISTANCE);
+ fadefactor = (mi->GetLargestLodDistance() - (camdist - FADE_DISTANCE))/FADE_DISTANCE;
+ if(fadefactor > 1.0f)
+ fadefactor = 1.0f;
+ alpha = mi->m_alpha * fadefactor;
+
+ if(alpha == 255)
+ WorldRender::AtomicFirstPass(atomic, pass);
+ else{
+ // not quite sure what this is about, do we have to do that?
+ RpGeometry *geo = RpAtomicGetGeometry(lodatm);
+ if(geo != RpAtomicGetGeometry(atomic))
+ RpAtomicSetGeometry(atomic, geo, rpATOMICSAMEBOUNDINGSPHERE);
+ WorldRender::AtomicFullyTransparent(atomic, pass, alpha);
+ }
+ }else
+ WorldRender::AtomicFirstPass(atomic, pass);
+
+#ifdef EXTRA_MODEL_FLAGS
+ if(resetCull)
+ BACKFACE_CULLING_ON;
+#endif
+
+ ent->bImBeingRendered = false; // TODO: this seems wrong, but do we even need it?
+}
+
+void
+CRenderer::RenderWorld(int pass)
+{
+ int i;
+ CEntity *e;
+ CLink<CVisibilityPlugins::AlphaObjectInfo> *node;
+
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
+ BACKFACE_CULLING_ON;
+ DeActivateDirectional();
+ SetAmbientColours();
+
+ // Temporary...have to figure out sorting better
+ switch(pass){
+ case 0:
+ // Roads
+ PUSH_RENDERGROUP("CRenderer::RenderWorld - Roads");
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+/*
+ for(i = 0; i < ms_nNoOfVisibleBuildings; i++){
+ e = ms_aVisibleBuildingPtrs[i];
+ if(e->bIsBIGBuilding || IsRoad(e))
+ RenderOneBuilding(e);
+ }
+*/
+ for(CLink<EntityInfo> *node = gSortedBuildings.tail.prev;
+ node != &gSortedBuildings.head;
+ node = node->prev){
+ e = node->item.ent;
+ if(e->bIsBIGBuilding || IsRoad(e))
+ RenderOneBuilding(e);
+ }
+ for(node = CVisibilityPlugins::m_alphaBuildingList.tail.prev;
+ node != &CVisibilityPlugins::m_alphaBuildingList.head;
+ node = node->prev){
+ e = node->item.entity;
+ if(e->bIsBIGBuilding || IsRoad(e))
+ RenderOneBuilding(e, node->item.sort);
+ }
+
+ // KLUDGE for road puddles which have to be rendered at road-time
+ // only very temporary, there are more rendering issues
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ WorldRender::RenderBlendPass(PASS_BLEND);
+ WorldRender::numBlendInsts[PASS_BLEND] = 0;
+ POP_RENDERGROUP();
+ break;
+ case 1:
+ // Opaque
+ PUSH_RENDERGROUP("CRenderer::RenderWorld - Opaque");
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+/*
+ for(i = 0; i < ms_nNoOfVisibleBuildings; i++){
+ e = ms_aVisibleBuildingPtrs[i];
+ if(!(e->bIsBIGBuilding || IsRoad(e)))
+ RenderOneBuilding(e);
+ }
+*/
+ for(CLink<EntityInfo> *node = gSortedBuildings.tail.prev;
+ node != &gSortedBuildings.head;
+ node = node->prev){
+ e = node->item.ent;
+ if(!(e->bIsBIGBuilding || IsRoad(e)))
+ RenderOneBuilding(e);
+ }
+ for(node = CVisibilityPlugins::m_alphaBuildingList.tail.prev;
+ node != &CVisibilityPlugins::m_alphaBuildingList.head;
+ node = node->prev){
+ e = node->item.entity;
+ if(!(e->bIsBIGBuilding || IsRoad(e)))
+ RenderOneBuilding(e, node->item.sort);
+ }
+ // Now we have iterated through all visible buildings (unsorted and sorted)
+ // and the transparency list is done.
+
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE);
+ WorldRender::RenderBlendPass(PASS_NOZ);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ POP_RENDERGROUP();
+ break;
+ case 2:
+ // Transparent
+ PUSH_RENDERGROUP("CRenderer::RenderWorld - Transparent");
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+ WorldRender::RenderBlendPass(PASS_ADD);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ WorldRender::RenderBlendPass(PASS_BLEND);
+ POP_RENDERGROUP();
+ break;
+ }
+}
+
+void
+CRenderer::RenderPeds(void)
+{
+ int i;
+ CEntity *e;
+
+ PUSH_RENDERGROUP("CRenderer::RenderPeds");
+ for(i = 0; i < ms_nNoOfVisibleVehicles; i++){
+ e = ms_aVisibleVehiclePtrs[i];
+ if(e->IsPed())
+ RenderOneNonRoad(e);
+ }
+ POP_RENDERGROUP();
+}
+
+void
+CRenderer::RenderVehicles(void)
+{
+ int i;
+ CEntity *e;
+ EntityInfo ei;
+ CLink<EntityInfo> *node;
+
+ PUSH_RENDERGROUP("CRenderer::RenderVehicles");
+ // not the real thing
+ for(i = 0; i < ms_nNoOfVisibleVehicles; i++){
+ e = ms_aVisibleVehiclePtrs[i];
+ if(!e->IsVehicle())
+ continue;
+// if(PutIntoSortedVehicleList((CVehicle*)e))
+// continue; // boats handled elsewhere
+ ei.ent = e;
+ ei.sort = (ms_vecCameraPosition - e->GetPosition()).MagnitudeSqr();
+ gSortedVehiclesAndPeds.InsertSorted(ei);
+ }
+
+ for(node = gSortedVehiclesAndPeds.tail.prev;
+ node != &gSortedVehiclesAndPeds.head;
+ node = node->prev)
+ RenderOneNonRoad(node->item.ent);
+ POP_RENDERGROUP();
+}
+
+void
+CRenderer::RenderWater(void)
+{
+ int i;
+ CEntity *e;
+
+ PUSH_RENDERGROUP("CRenderer::RenderWater");
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDZERO);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ SetStencilState(2);
+
+ for(i = 0; i < ms_nNoOfVisibleVehicles; i++){
+ e = ms_aVisibleVehiclePtrs[i];
+ if(e->IsVehicle() && ((CVehicle*)e)->IsBoat())
+ ((CBoat*)e)->RenderWaterOutPolys();
+ }
+
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ SetStencilState(1);
+
+ CWaterLevel::RenderWater();
+
+ SetStencilState(0);
+ POP_RENDERGROUP();
+}
+
+void
+CRenderer::ClearForFrame(void)
+{
+ ms_nNoOfVisibleEntities = 0;
+ ms_nNoOfVisibleVehicles = 0;
+ ms_nNoOfVisibleBuildings = 0;
+ ms_nNoOfInVisibleEntities = 0;
+ gSortedVehiclesAndPeds.Clear();
+ gSortedBuildings.Clear();
+
+ WorldRender::numBlendInsts[PASS_NOZ] = 0;
+ WorldRender::numBlendInsts[PASS_ADD] = 0;
+ WorldRender::numBlendInsts[PASS_BLEND] = 0;
+}
+#endif
+
+void
+CRenderer::RenderFadingInEntities(void)
+{
+ PUSH_RENDERGROUP("CRenderer::RenderFadingInEntities");
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
+ BACKFACE_CULLING_ON;
+ DeActivateDirectional();
+ SetAmbientColours();
+ CVisibilityPlugins::RenderFadingEntities();
+ POP_RENDERGROUP();
+}
+
+void
+CRenderer::RenderCollisionLines(void)
+{
+ int i;
+
+ // game doesn't draw fading in entities
+ // this should probably be fixed
+ for(i = 0; i < ms_nNoOfVisibleEntities; i++){
+ CEntity *e = ms_aVisibleEntityPtrs[i];
+ if(Abs(e->GetPosition().x - ms_vecCameraPosition.x) < 100.0f &&
+ Abs(e->GetPosition().y - ms_vecCameraPosition.y) < 100.0f)
+ CCollision::DrawColModel(e->GetMatrix(), *e->GetColModel());
+ }
+}
+
+// unused
+void
+CRenderer::RenderBlockBuildingLines(void)
+{
+ for(BlockedRange *br = pFullBlockedRanges; br; br = br->next)
+ printf("Blocked: %f %f\n", br->a, br->b);
+}
+
+enum Visbility
+{
+ VIS_INVISIBLE,
+ VIS_VISIBLE,
+ VIS_OFFSCREEN,
+ VIS_STREAMME
+};
+
+// Time Objects can be time culled if
+// other == -1 || CModelInfo::GetModelInfo(other)->GetRwObject()
+// i.e. we have to draw even at the wrong time if
+// other != -1 && CModelInfo::GetModelInfo(other)->GetRwObject() == nil
+
+#define OTHERUNAVAILABLE (other != -1 && CModelInfo::GetModelInfo(other)->GetRwObject() == nil)
+#define CANTIMECULL (!OTHERUNAVAILABLE)
+
+int32
+CRenderer::SetupEntityVisibility(CEntity *ent)
+{
+ CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(ent->m_modelIndex);
+ CTimeModelInfo *ti;
+ int32 other;
+ float dist;
+
+ bool request = true;
+ if (mi->GetModelType() == MITYPE_TIME) {
+ ti = (CTimeModelInfo*)mi;
+ other = ti->GetOtherTimeModel();
+ if(CClock::GetIsTimeInRange(ti->GetTimeOn(), ti->GetTimeOff())){
+ // don't fade in, or between time objects
+ if(CANTIMECULL)
+ ti->m_alpha = 255;
+ }else{
+ // Hide if possible
+ if(CANTIMECULL)
+ return VIS_INVISIBLE;
+ // can't cull, so we'll try to draw this one, but don't request
+ // it since what we really want is the other one.
+ request = false;
+ }
+ }else{
+ if (mi->GetModelType() != MITYPE_SIMPLE) {
+ if(FindPlayerVehicle() == ent &&
+ TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON){
+ // Player's vehicle in first person mode
+ if(TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking == LOOKING_FORWARD ||
+ ent->GetModelIndex() == MI_RHINO ||
+ ent->GetModelIndex() == MI_COACH ||
+ TheCamera.m_bInATunnelAndABigVehicle){
+ ent->bNoBrightHeadLights = true;
+ }else{
+ m_pFirstPersonVehicle = (CVehicle*)ent;
+ ent->bNoBrightHeadLights = false;
+ }
+ return VIS_OFFSCREEN;
+ }
+ // All sorts of Clumps
+ if(ent->m_rwObject == nil || !ent->bIsVisible)
+ return VIS_INVISIBLE;
+ if(!ent->GetIsOnScreen())
+ return VIS_OFFSCREEN;
+ if(ent->bDrawLast){
+ dist = (ent->GetPosition() - ms_vecCameraPosition).Magnitude();
+ CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist);
+ ent->bDistanceFade = false;
+ return VIS_INVISIBLE;
+ }
+ return VIS_VISIBLE;
+ }
+ if(ent->IsObject() &&
+ ((CObject*)ent)->ObjectCreatedBy == TEMP_OBJECT){
+ if(ent->m_rwObject == nil || !ent->bIsVisible)
+ return VIS_INVISIBLE;
+ return ent->GetIsOnScreen() ? VIS_VISIBLE : VIS_OFFSCREEN;
+ }
+ }
+
+ // Simple ModelInfo
+
+ dist = (ent->GetPosition() - ms_vecCameraPosition).Magnitude();
+
+ // This can only happen with multi-atomic models (e.g. railtracks)
+ // but why do we bump up the distance? can only be fading...
+ if(LOD_DISTANCE + STREAM_DISTANCE < dist && dist < mi->GetLargestLodDistance())
+ dist = mi->GetLargestLodDistance();
+
+ if(ent->IsObject() && ent->bRenderDamaged)
+ mi->m_isDamaged = true;
+
+ RpAtomic *a = mi->GetAtomicFromDistance(dist);
+ if(a){
+ mi->m_isDamaged = false;
+ if(ent->m_rwObject == nil)
+ ent->CreateRwObject();
+ assert(ent->m_rwObject);
+ RpAtomic *rwobj = (RpAtomic*)ent->m_rwObject;
+ // Make sure our atomic uses the right geometry and not
+ // that of an atomic for another draw distance.
+ if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj))
+ RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?)
+ mi->IncreaseAlpha();
+ if(ent->m_rwObject == nil || !ent->bIsVisible)
+ return VIS_INVISIBLE;
+
+ if(!ent->GetIsOnScreen()){
+ mi->m_alpha = 255;
+ return VIS_OFFSCREEN;
+ }
+
+ if(mi->m_alpha != 255){
+ CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist);
+ ent->bDistanceFade = true;
+ return VIS_INVISIBLE;
+ }
+
+ if(mi->m_drawLast || ent->bDrawLast){
+ CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist);
+ ent->bDistanceFade = false;
+ return VIS_INVISIBLE;
+ }
+ return VIS_VISIBLE;
+ }
+
+ // Object is not loaded, figure out what to do
+
+ if(mi->m_noFade){
+ mi->m_isDamaged = false;
+ // request model
+ if(dist - STREAM_DISTANCE < mi->GetLargestLodDistance() && request)
+ return VIS_STREAMME;
+ return VIS_INVISIBLE;
+ }
+
+ // We might be fading
+
+ a = mi->GetAtomicFromDistance(dist - FADE_DISTANCE);
+ mi->m_isDamaged = false;
+ if(a == nil){
+ // request model
+ if(dist - FADE_DISTANCE - STREAM_DISTANCE < mi->GetLargestLodDistance() && request)
+ return VIS_STREAMME;
+ return VIS_INVISIBLE;
+ }
+
+ if(ent->m_rwObject == nil)
+ ent->CreateRwObject();
+ assert(ent->m_rwObject);
+ RpAtomic *rwobj = (RpAtomic*)ent->m_rwObject;
+ if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj))
+ RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?)
+ mi->IncreaseAlpha();
+ if(ent->m_rwObject == nil || !ent->bIsVisible)
+ return VIS_INVISIBLE;
+
+ if(!ent->GetIsOnScreen()){
+ mi->m_alpha = 255;
+ return VIS_OFFSCREEN;
+ }else{
+ CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist);
+ ent->bDistanceFade = true;
+ return VIS_OFFSCREEN; // Why this?
+ }
+}
+
+int32
+CRenderer::SetupBigBuildingVisibility(CEntity *ent)
+{
+ CSimpleModelInfo *mi = (CSimpleModelInfo *)CModelInfo::GetModelInfo(ent->GetModelIndex());
+ CTimeModelInfo *ti;
+ int32 other;
+
+ if (mi->GetModelType() == MITYPE_TIME) {
+ ti = (CTimeModelInfo*)mi;
+ other = ti->GetOtherTimeModel();
+ // Hide objects not in time range if possible
+ if(CANTIMECULL)
+ if(!CClock::GetIsTimeInRange(ti->GetTimeOn(), ti->GetTimeOff()))
+ return VIS_INVISIBLE;
+ // Draw like normal
+ } else if (mi->GetModelType() == MITYPE_VEHICLE)
+ return ent->IsVisible() ? VIS_VISIBLE : VIS_INVISIBLE;
+
+ float dist = (ms_vecCameraPosition-ent->GetPosition()).Magnitude();
+ CSimpleModelInfo *nonLOD = mi->GetRelatedModel();
+
+ // Find out whether to draw below near distance.
+ // This is only the case if there is a non-LOD which is either not
+ // loaded or not completely faded in yet.
+ if(dist < mi->GetNearDistance() && dist < LOD_DISTANCE + STREAM_DISTANCE){
+ // No non-LOD or non-LOD is completely visible.
+ if(nonLOD == nil ||
+ nonLOD->GetRwObject() && nonLOD->m_alpha == 255)
+ return VIS_INVISIBLE;
+
+ // But if it is a time object, we'd rather draw the wrong
+ // non-LOD than the right LOD.
+ if (nonLOD->GetModelType() == MITYPE_TIME) {
+ ti = (CTimeModelInfo*)nonLOD;
+ other = ti->GetOtherTimeModel();
+ if(other != -1 && CModelInfo::GetModelInfo(other)->GetRwObject())
+ return VIS_INVISIBLE;
+ }
+ }
+
+ RpAtomic *a = mi->GetAtomicFromDistance(dist);
+ if(a){
+ if(ent->m_rwObject == nil)
+ ent->CreateRwObject();
+ assert(ent->m_rwObject);
+ RpAtomic *rwobj = (RpAtomic*)ent->m_rwObject;
+
+ // Make sure our atomic uses the right geometry and not
+ // that of an atomic for another draw distance.
+ if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj))
+ RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?)
+ if (!ent->IsVisible() || !ent->GetIsOnScreenComplex())
+ return VIS_INVISIBLE;
+ if(mi->m_drawLast){
+ CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist);
+ ent->bDistanceFade = false;
+ return VIS_INVISIBLE;
+ }
+ return VIS_VISIBLE;
+ }
+
+ if(mi->m_noFade){
+ ent->DeleteRwObject();
+ return VIS_INVISIBLE;
+ }
+
+
+ // get faded atomic
+ a = mi->GetAtomicFromDistance(dist - FADE_DISTANCE);
+ if(a == nil){
+ ent->DeleteRwObject();
+ return VIS_INVISIBLE;
+ }
+
+ // Fade...
+ if(ent->m_rwObject == nil)
+ ent->CreateRwObject();
+ assert(ent->m_rwObject);
+ RpAtomic *rwobj = (RpAtomic*)ent->m_rwObject;
+ if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj))
+ RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?)
+ if (ent->IsVisible() && ent->GetIsOnScreenComplex())
+ CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist);
+ return VIS_INVISIBLE;
+}
+
+void
+CRenderer::ConstructRenderList(void)
+{
+#ifdef NEW_RENDERER
+ if(!gbNewRenderer)
+#endif
+{
+ ms_nNoOfVisibleEntities = 0;
+ ms_nNoOfInVisibleEntities = 0;
+}
+ ms_vecCameraPosition = TheCamera.GetPosition();
+
+ // unused
+ pFullBlockedRanges = nil;
+ pEmptyBlockedRanges = aBlockedRanges;
+ for(int i = 0; i < 16; i++){
+ aBlockedRanges[i].prev = &aBlockedRanges[i-1];
+ aBlockedRanges[i].next = &aBlockedRanges[i+1];
+ }
+ aBlockedRanges[0].prev = nil;
+ aBlockedRanges[15].next = nil;
+
+ // unused
+ TestCloseThings = 0;
+ TestBigThings = 0;
+
+ ScanWorld();
+}
+
+void
+LimitFrustumVector(CVector &vec1, const CVector &vec2, float l)
+{
+ float f;
+ f = (l - vec2.z) / (vec1.z - vec2.z);
+ vec1.x = f*(vec1.x - vec2.x) + vec2.x;
+ vec1.y = f*(vec1.y - vec2.y) + vec2.y;
+ vec1.z = f*(vec1.z - vec2.z) + vec2.z;
+}
+
+enum Corners
+{
+ CORNER_CAM = 0,
+ CORNER_FAR_TOPLEFT,
+ CORNER_FAR_TOPRIGHT,
+ CORNER_FAR_BOTRIGHT,
+ CORNER_FAR_BOTLEFT,
+ CORNER_LOD_LEFT,
+ CORNER_LOD_RIGHT,
+ CORNER_PRIO_LEFT,
+ CORNER_PRIO_RIGHT,
+};
+
+void
+CRenderer::ScanWorld(void)
+{
+ float f = RwCameraGetFarClipPlane(TheCamera.m_pRwCamera);
+ RwV2d vw = *RwCameraGetViewWindow(TheCamera.m_pRwCamera);
+ CVector vectors[9];
+ RwMatrix *cammatrix;
+ RwV2d poly[3];
+
+#ifndef MASTER
+ // missing in game but has to be done somewhere
+ EntitiesRendered = 0;
+ EntitiesNotRendered = 0;
+ RenderedBigBuildings = 0;
+ RenderedBuildings = 0;
+ RenderedCars = 0;
+ RenderedPeds = 0;
+ RenderedObjects = 0;
+ RenderedDummies = 0;
+ TestedBigBuildings = 0;
+ TestedBuildings = 0;
+ TestedCars = 0;
+ TestedPeds = 0;
+ TestedObjects = 0;
+ TestedDummies = 0;
+#endif
+
+ memset(vectors, 0, sizeof(vectors));
+ vectors[CORNER_FAR_TOPLEFT].x = -vw.x * f;
+ vectors[CORNER_FAR_TOPLEFT].y = vw.y * f;
+ vectors[CORNER_FAR_TOPLEFT].z = f;
+ vectors[CORNER_FAR_TOPRIGHT].x = vw.x * f;
+ vectors[CORNER_FAR_TOPRIGHT].y = vw.y * f;
+ vectors[CORNER_FAR_TOPRIGHT].z = f;
+ vectors[CORNER_FAR_BOTRIGHT].x = vw.x * f;
+ vectors[CORNER_FAR_BOTRIGHT].y = -vw.y * f;
+ vectors[CORNER_FAR_BOTRIGHT].z = f;
+ vectors[CORNER_FAR_BOTLEFT].x = -vw.x * f;
+ vectors[CORNER_FAR_BOTLEFT].y = -vw.y * f;
+ vectors[CORNER_FAR_BOTLEFT].z = f;
+
+ cammatrix = RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera));
+
+ m_pFirstPersonVehicle = nil;
+ CVisibilityPlugins::InitAlphaEntityList();
+ CWorld::AdvanceCurrentScanCode();
+
+ if(cammatrix->at.z > 0.0f){
+ // looking up, bottom corners are further away
+ vectors[CORNER_LOD_LEFT] = vectors[CORNER_FAR_BOTLEFT] * LOD_DISTANCE/f;
+ vectors[CORNER_LOD_RIGHT] = vectors[CORNER_FAR_BOTRIGHT] * LOD_DISTANCE/f;
+ }else{
+ // looking down, top corners are further away
+ vectors[CORNER_LOD_LEFT] = vectors[CORNER_FAR_TOPLEFT] * LOD_DISTANCE/f;
+ vectors[CORNER_LOD_RIGHT] = vectors[CORNER_FAR_TOPRIGHT] * LOD_DISTANCE/f;
+ }
+ vectors[CORNER_PRIO_LEFT].x = vectors[CORNER_LOD_LEFT].x * 0.2f;
+ vectors[CORNER_PRIO_LEFT].y = vectors[CORNER_LOD_LEFT].y * 0.2f;
+ vectors[CORNER_PRIO_LEFT].z = vectors[CORNER_LOD_LEFT].z;
+ vectors[CORNER_PRIO_RIGHT].x = vectors[CORNER_LOD_RIGHT].x * 0.2f;
+ vectors[CORNER_PRIO_RIGHT].y = vectors[CORNER_LOD_RIGHT].y * 0.2f;
+ vectors[CORNER_PRIO_RIGHT].z = vectors[CORNER_LOD_RIGHT].z;
+ RwV3dTransformPoints(vectors, vectors, 9, cammatrix);
+
+ m_loadingPriority = false;
+ if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
+#ifdef FIX_BUGS
+ TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_GTACLASSIC ||
+#endif
+ TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){
+ CRect rect;
+ int x1, x2, y1, y2;
+ LimitFrustumVector(vectors[CORNER_FAR_TOPLEFT], vectors[CORNER_CAM], -100.0f);
+ rect.ContainPoint(vectors[CORNER_FAR_TOPLEFT]);
+ LimitFrustumVector(vectors[CORNER_FAR_TOPRIGHT], vectors[CORNER_CAM], -100.0f);
+ rect.ContainPoint(vectors[CORNER_FAR_TOPRIGHT]);
+ LimitFrustumVector(vectors[CORNER_FAR_BOTRIGHT], vectors[CORNER_CAM], -100.0f);
+ rect.ContainPoint(vectors[CORNER_FAR_BOTRIGHT]);
+ LimitFrustumVector(vectors[CORNER_FAR_BOTLEFT], vectors[CORNER_CAM], -100.0f);
+ rect.ContainPoint(vectors[CORNER_FAR_BOTLEFT]);
+ x1 = CWorld::GetSectorIndexX(rect.left);
+ if(x1 < 0) x1 = 0;
+ x2 = CWorld::GetSectorIndexX(rect.right);
+ if(x2 >= NUMSECTORS_X-1) x2 = NUMSECTORS_X-1;
+ y1 = CWorld::GetSectorIndexY(rect.top);
+ if(y1 < 0) y1 = 0;
+ y2 = CWorld::GetSectorIndexY(rect.bottom);
+ if(y2 >= NUMSECTORS_Y-1) y2 = NUMSECTORS_Y-1;
+ for(; x1 <= x2; x1++)
+ for(int y = y1; y <= y2; y++)
+ ScanSectorList(CWorld::GetSector(x1, y)->m_lists);
+ }else{
+ CVehicle *train = FindPlayerTrain();
+ if(train && train->GetPosition().z < 0.0f){
+ poly[0].x = CWorld::GetSectorX(vectors[CORNER_CAM].x);
+ poly[0].y = CWorld::GetSectorY(vectors[CORNER_CAM].y);
+ poly[1].x = CWorld::GetSectorX(vectors[CORNER_LOD_LEFT].x);
+ poly[1].y = CWorld::GetSectorY(vectors[CORNER_LOD_LEFT].y);
+ poly[2].x = CWorld::GetSectorX(vectors[CORNER_LOD_RIGHT].x);
+ poly[2].y = CWorld::GetSectorY(vectors[CORNER_LOD_RIGHT].y);
+ ScanSectorPoly(poly, 3, ScanSectorList_Subway);
+ }else{
+ if(f > LOD_DISTANCE){
+ // priority
+ poly[0].x = CWorld::GetSectorX(vectors[CORNER_CAM].x);
+ poly[0].y = CWorld::GetSectorY(vectors[CORNER_CAM].y);
+ poly[1].x = CWorld::GetSectorX(vectors[CORNER_PRIO_LEFT].x);
+ poly[1].y = CWorld::GetSectorY(vectors[CORNER_PRIO_LEFT].y);
+ poly[2].x = CWorld::GetSectorX(vectors[CORNER_PRIO_RIGHT].x);
+ poly[2].y = CWorld::GetSectorY(vectors[CORNER_PRIO_RIGHT].y);
+ ScanSectorPoly(poly, 3, ScanSectorList_Priority);
+
+ // below LOD
+ poly[0].x = CWorld::GetSectorX(vectors[CORNER_CAM].x);
+ poly[0].y = CWorld::GetSectorY(vectors[CORNER_CAM].y);
+ poly[1].x = CWorld::GetSectorX(vectors[CORNER_LOD_LEFT].x);
+ poly[1].y = CWorld::GetSectorY(vectors[CORNER_LOD_LEFT].y);
+ poly[2].x = CWorld::GetSectorX(vectors[CORNER_LOD_RIGHT].x);
+ poly[2].y = CWorld::GetSectorY(vectors[CORNER_LOD_RIGHT].y);
+ ScanSectorPoly(poly, 3, ScanSectorList);
+ }else{
+ poly[0].x = CWorld::GetSectorX(vectors[CORNER_CAM].x);
+ poly[0].y = CWorld::GetSectorY(vectors[CORNER_CAM].y);
+ poly[1].x = CWorld::GetSectorX(vectors[CORNER_FAR_TOPLEFT].x);
+ poly[1].y = CWorld::GetSectorY(vectors[CORNER_FAR_TOPLEFT].y);
+ poly[2].x = CWorld::GetSectorX(vectors[CORNER_FAR_TOPRIGHT].x);
+ poly[2].y = CWorld::GetSectorY(vectors[CORNER_FAR_TOPRIGHT].y);
+ ScanSectorPoly(poly, 3, ScanSectorList);
+ }
+#ifdef NO_ISLAND_LOADING
+ if (CMenuManager::m_PrefsIslandLoading == CMenuManager::ISLAND_LOADING_HIGH) {
+ ScanBigBuildingList(CWorld::GetBigBuildingList(LEVEL_INDUSTRIAL));
+ ScanBigBuildingList(CWorld::GetBigBuildingList(LEVEL_COMMERCIAL));
+ ScanBigBuildingList(CWorld::GetBigBuildingList(LEVEL_SUBURBAN));
+ } else
+#endif
+ {
+ #ifdef FIX_BUGS
+ if (CCollision::ms_collisionInMemory != LEVEL_GENERIC)
+ #endif
+ ScanBigBuildingList(CWorld::GetBigBuildingList(CCollision::ms_collisionInMemory));
+ }
+ ScanBigBuildingList(CWorld::GetBigBuildingList(LEVEL_GENERIC));
+ }
+ }
+
+#ifndef MASTER
+ if(gbShowCullZoneDebugStuff){
+ sprintf(gString, "Rejected: %d/%d.", EntitiesNotRendered, EntitiesNotRendered + EntitiesRendered);
+ CDebug::PrintAt(gString, 10, 10);
+ sprintf(gString, "Tested:BBuild:%d Build:%d Peds:%d Cars:%d Obj:%d Dummies:%d",
+ TestedBigBuildings, TestedBuildings, TestedPeds, TestedCars, TestedObjects, TestedDummies);
+ CDebug::PrintAt(gString, 10, 11);
+ sprintf(gString, "Rendered:BBuild:%d Build:%d Peds:%d Cars:%d Obj:%d Dummies:%d",
+ RenderedBigBuildings, RenderedBuildings, RenderedPeds, RenderedCars, RenderedObjects, RenderedDummies);
+ CDebug::PrintAt(gString, 10, 12);
+ }
+#endif
+}
+
+void
+CRenderer::RequestObjectsInFrustum(void)
+{
+ float f = RwCameraGetFarClipPlane(TheCamera.m_pRwCamera);
+ RwV2d vw = *RwCameraGetViewWindow(TheCamera.m_pRwCamera);
+ CVector vectors[9];
+ RwMatrix *cammatrix;
+ RwV2d poly[3];
+
+ memset(vectors, 0, sizeof(vectors));
+ vectors[CORNER_FAR_TOPLEFT].x = -vw.x * f;
+ vectors[CORNER_FAR_TOPLEFT].y = vw.y * f;
+ vectors[CORNER_FAR_TOPLEFT].z = f;
+ vectors[CORNER_FAR_TOPRIGHT].x = vw.x * f;
+ vectors[CORNER_FAR_TOPRIGHT].y = vw.y * f;
+ vectors[CORNER_FAR_TOPRIGHT].z = f;
+ vectors[CORNER_FAR_BOTRIGHT].x = vw.x * f;
+ vectors[CORNER_FAR_BOTRIGHT].y = -vw.y * f;
+ vectors[CORNER_FAR_BOTRIGHT].z = f;
+ vectors[CORNER_FAR_BOTLEFT].x = -vw.x * f;
+ vectors[CORNER_FAR_BOTLEFT].y = -vw.y * f;
+ vectors[CORNER_FAR_BOTLEFT].z = f;
+
+ cammatrix = RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera));
+
+ CWorld::AdvanceCurrentScanCode();
+
+ if(cammatrix->at.z > 0.0f){
+ // looking up, bottom corners are further away
+ vectors[CORNER_LOD_LEFT] = vectors[CORNER_FAR_BOTLEFT] * LOD_DISTANCE/f;
+ vectors[CORNER_LOD_RIGHT] = vectors[CORNER_FAR_BOTRIGHT] * LOD_DISTANCE/f;
+ }else{
+ // looking down, top corners are further away
+ vectors[CORNER_LOD_LEFT] = vectors[CORNER_FAR_TOPLEFT] * LOD_DISTANCE/f;
+ vectors[CORNER_LOD_RIGHT] = vectors[CORNER_FAR_TOPRIGHT] * LOD_DISTANCE/f;
+ }
+ vectors[CORNER_PRIO_LEFT].x = vectors[CORNER_LOD_LEFT].x * 0.2f;
+ vectors[CORNER_PRIO_LEFT].y = vectors[CORNER_LOD_LEFT].y * 0.2f;
+ vectors[CORNER_PRIO_LEFT].z = vectors[CORNER_LOD_LEFT].z;
+ vectors[CORNER_PRIO_RIGHT].x = vectors[CORNER_LOD_RIGHT].x * 0.2f;
+ vectors[CORNER_PRIO_RIGHT].y = vectors[CORNER_LOD_RIGHT].y * 0.2f;
+ vectors[CORNER_PRIO_RIGHT].z = vectors[CORNER_LOD_RIGHT].z;
+ RwV3dTransformPoints(vectors, vectors, 9, cammatrix);
+
+ if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
+#ifdef FIX_BUGS
+ TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_GTACLASSIC ||
+#endif
+ TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){
+ CRect rect;
+ int x1, x2, y1, y2;
+ LimitFrustumVector(vectors[CORNER_FAR_TOPLEFT], vectors[CORNER_CAM], -100.0f);
+ rect.ContainPoint(vectors[CORNER_FAR_TOPLEFT]);
+ LimitFrustumVector(vectors[CORNER_FAR_TOPRIGHT], vectors[CORNER_CAM], -100.0f);
+ rect.ContainPoint(vectors[CORNER_FAR_TOPRIGHT]);
+ LimitFrustumVector(vectors[CORNER_FAR_BOTRIGHT], vectors[CORNER_CAM], -100.0f);
+ rect.ContainPoint(vectors[CORNER_FAR_BOTRIGHT]);
+ LimitFrustumVector(vectors[CORNER_FAR_BOTLEFT], vectors[CORNER_CAM], -100.0f);
+ rect.ContainPoint(vectors[CORNER_FAR_BOTLEFT]);
+ x1 = CWorld::GetSectorIndexX(rect.left);
+ if(x1 < 0) x1 = 0;
+ x2 = CWorld::GetSectorIndexX(rect.right);
+ if(x2 >= NUMSECTORS_X-1) x2 = NUMSECTORS_X-1;
+ y1 = CWorld::GetSectorIndexY(rect.top);
+ if(y1 < 0) y1 = 0;
+ y2 = CWorld::GetSectorIndexY(rect.bottom);
+ if(y2 >= NUMSECTORS_Y-1) y2 = NUMSECTORS_Y-1;
+ for(; x1 <= x2; x1++)
+ for(int y = y1; y <= y2; y++)
+ ScanSectorList_RequestModels(CWorld::GetSector(x1, y)->m_lists);
+ }else{
+ poly[0].x = CWorld::GetSectorX(vectors[CORNER_CAM].x);
+ poly[0].y = CWorld::GetSectorY(vectors[CORNER_CAM].y);
+ poly[1].x = CWorld::GetSectorX(vectors[CORNER_LOD_LEFT].x);
+ poly[1].y = CWorld::GetSectorY(vectors[CORNER_LOD_LEFT].y);
+ poly[2].x = CWorld::GetSectorX(vectors[CORNER_LOD_RIGHT].x);
+ poly[2].y = CWorld::GetSectorY(vectors[CORNER_LOD_RIGHT].y);
+ ScanSectorPoly(poly, 3, ScanSectorList_RequestModels);
+ }
+}
+
+bool
+CEntity::SetupLighting(void)
+{
+ DeActivateDirectional();
+ SetAmbientColours();
+ return false;
+}
+
+void
+CEntity::RemoveLighting(bool)
+{
+}
+
+bool
+CPed::SetupLighting(void)
+{
+ ActivateDirectional();
+ SetAmbientColoursForPedsCarsAndObjects();
+
+#ifndef MASTER
+ // Originally this was being called through iteration of Sectors, but putting it here is better.
+ if (GetDebugDisplay() != 0 && !IsPlayer())
+ DebugRenderOnePedText();
+#endif
+
+ if (bRenderScorched) {
+ WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f);
+ } else {
+ // Note that this lightMult is only affected by LIGHT_DARKEN. If there's no LIGHT_DARKEN, it will be 1.0.
+ float lightMult = CPointLights::GenerateLightsAffectingObject(&GetPosition());
+ if (!bHasBlip && lightMult != 1.0f) {
+ SetAmbientAndDirectionalColours(lightMult);
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+CPed::RemoveLighting(bool reset)
+{
+ CRenderer::RemoveVehiclePedLights(this, reset);
+}
+
+float
+CalcNewDelta(RwV2d *a, RwV2d *b)
+{
+ return (b->x - a->x) / (b->y - a->y);
+}
+
+#ifdef FIX_BUGS
+#define TOINT(x) ((int)Floor(x))
+#else
+#define TOINT(x) ((int)(x))
+#endif
+
+void
+CRenderer::ScanSectorPoly(RwV2d *poly, int32 numVertices, void (*scanfunc)(CPtrList *))
+{
+ float miny, maxy;
+ int y, yend;
+ int x, xstart, xend;
+ int i;
+ int a1, a2, b1, b2;
+ float deltaA, deltaB;
+ float xA, xB;
+
+ miny = poly[0].y;
+ maxy = poly[0].y;
+ a2 = 0;
+ xstart = 9999;
+ xend = -9999;
+
+ for(i = 1; i < numVertices; i++){
+ if(poly[i].y > maxy)
+ maxy = poly[i].y;
+ if(poly[i].y < miny){
+ miny = poly[i].y;
+ a2 = i;
+ }
+ }
+ y = TOINT(miny);
+ yend = TOINT(maxy);
+
+ // Go left in poly to find first edge b
+ b2 = a2;
+ for(i = 0; i < numVertices; i++){
+ b1 = b2--;
+ if(b2 < 0) b2 = numVertices-1;
+ if(poly[b1].x < xstart)
+ xstart = TOINT(poly[b1].x);
+ if(TOINT(poly[b1].y) != TOINT(poly[b2].y))
+ break;
+ }
+ // Go right to find first edge a
+ for(i = 0; i < numVertices; i++){
+ a1 = a2++;
+ if(a2 == numVertices) a2 = 0;
+ if(poly[a1].x > xend)
+ xend = TOINT(poly[a1].x);
+ if(TOINT(poly[a1].y) != TOINT(poly[a2].y))
+ break;
+ }
+
+ // prestep x1 and x2 to next integer y
+ deltaA = CalcNewDelta(&poly[a1], &poly[a2]);
+ xA = deltaA * (Ceil(poly[a1].y) - poly[a1].y) + poly[a1].x;
+ deltaB = CalcNewDelta(&poly[b1], &poly[b2]);
+ xB = deltaB * (Ceil(poly[b1].y) - poly[b1].y) + poly[b1].x;
+
+ if(y != yend){
+ if(deltaB < 0.0f && TOINT(xB) < xstart)
+ xstart = TOINT(xB);
+ if(deltaA >= 0.0f && TOINT(xA) > xend)
+ xend = TOINT(xA);
+ }
+
+ while(y <= yend && y < NUMSECTORS_Y){
+ // scan one x-line
+ if(y >= 0 && xstart < NUMSECTORS_X)
+ for(x = xstart; x <= xend && x != NUMSECTORS_X; x++)
+ if(x >= 0)
+ scanfunc(CWorld::GetSector(x, y)->m_lists);
+
+ // advance one scan line
+ y++;
+ xA += deltaA;
+ xB += deltaB;
+
+ // update left side
+ if(y == TOINT(poly[b2].y)){
+ // reached end of edge
+ if(y == yend){
+ if(deltaB < 0.0f){
+ do{
+ xstart = TOINT(poly[b2--].x);
+ if(b2 < 0) b2 = numVertices-1;
+ }while(xstart > TOINT(poly[b2].x));
+ }else
+ xstart = TOINT(xB - deltaB);
+ }else{
+ // switch edges
+ if(deltaB < 0.0f)
+ xstart = TOINT(poly[b2].x);
+ else
+ xstart = TOINT(xB - deltaB);
+ do{
+ b1 = b2--;
+ if(b2 < 0) b2 = numVertices-1;
+ if(TOINT(poly[b1].x) < xstart)
+ xstart = TOINT(poly[b1].x);
+ }while(y == TOINT(poly[b2].y));
+ deltaB = CalcNewDelta(&poly[b1], &poly[b2]);
+ xB = deltaB * (Ceil(poly[b1].y) - poly[b1].y) + poly[b1].x;
+ if(deltaB < 0.0f && TOINT(xB) < xstart)
+ xstart = TOINT(xB);
+ }
+ }else{
+ if(deltaB < 0.0f)
+ xstart = TOINT(xB);
+ else
+ xstart = TOINT(xB - deltaB);
+ }
+
+ // update right side
+ if(y == TOINT(poly[a2].y)){
+ // reached end of edge
+ if(y == yend){
+ if(deltaA < 0.0f)
+ xend = TOINT(xA - deltaA);
+ else{
+ do{
+ xend = TOINT(poly[a2++].x);
+ if(a2 == numVertices) a2 = 0;
+ }while(xend < TOINT(poly[a2].x));
+ }
+ }else{
+ // switch edges
+ if(deltaA < 0.0f)
+ xend = TOINT(xA - deltaA);
+ else
+ xend = TOINT(poly[a2].x);
+ do{
+ a1 = a2++;
+ if(a2 == numVertices) a2 = 0;
+ if(TOINT(poly[a1].x) > xend)
+ xend = TOINT(poly[a1].x);
+ }while(y == TOINT(poly[a2].y));
+ deltaA = CalcNewDelta(&poly[a1], &poly[a2]);
+ xA = deltaA * (Ceil(poly[a1].y) - poly[a1].y) + poly[a1].x;
+ if(deltaA >= 0.0f && TOINT(xA) > xend)
+ xend = TOINT(xA);
+ }
+ }else{
+ if(deltaA < 0.0f)
+ xend = TOINT(xA - deltaA);
+ else
+ xend = TOINT(xA);
+ }
+ }
+}
+
+void
+CRenderer::InsertEntityIntoList(CEntity *ent)
+{
+#ifdef FIX_BUGS
+ if (!ent->m_rwObject) return;
+#endif
+
+#ifdef NEW_RENDERER
+ // TODO: there are more flags being checked here
+ if(gbNewRenderer && (ent->IsVehicle() || ent->IsPed()))
+ ms_aVisibleVehiclePtrs[ms_nNoOfVisibleVehicles++] = ent;
+ else if(gbNewRenderer && ent->IsBuilding()){
+ EntityInfo info;
+ info.ent = ent;
+ info.sort = -(ent->GetPosition() - ms_vecCameraPosition).MagnitudeSqr();
+ gSortedBuildings.InsertSorted(info);
+// ms_aVisibleBuildingPtrs[ms_nNoOfVisibleBuildings++] = ent;
+ }else
+#endif
+ ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent;
+}
+
+void
+CRenderer::ScanBigBuildingList(CPtrList &list)
+{
+ CPtrNode *node;
+ CEntity *ent;
+
+ for(node = list.first; node; node = node->next){
+ ent = (CEntity*)node->item;
+#ifndef MASTER
+ // all missing from game actually
+ TestedBigBuildings++;
+#endif
+ if(!ent->bZoneCulled || gbDisableZoneCull){
+ if(SetupBigBuildingVisibility(ent) == VIS_VISIBLE)
+ InsertEntityIntoList(ent);
+#ifndef MASTER
+ EntitiesRendered++;
+ RenderedBigBuildings++;
+ }else{
+ EntitiesNotRendered++;
+#endif
+ }
+ }
+}
+
+void
+CRenderer::ScanSectorList(CPtrList *lists)
+{
+ CPtrNode *node;
+ CPtrList *list;
+ CEntity *ent;
+ int i;
+ float dx, dy;
+
+ for(i = 0; i < NUMSECTORENTITYLISTS; i++){
+ list = &lists[i];
+ for(node = list->first; node; node = node->next){
+ ent = (CEntity*)node->item;
+ if(ent->m_scanCode == CWorld::GetCurrentScanCode())
+ continue; // already seen
+ ent->m_scanCode = CWorld::GetCurrentScanCode();
+
+ if(IsEntityCullZoneVisible(ent)){
+ switch(SetupEntityVisibility(ent)){
+ case VIS_VISIBLE:
+ InsertEntityIntoList(ent);
+ break;
+ case VIS_INVISIBLE:
+ if(!IsGlass(ent->GetModelIndex()))
+ break;
+ // fall through
+ case VIS_OFFSCREEN:
+ dx = ms_vecCameraPosition.x - ent->GetPosition().x;
+ dy = ms_vecCameraPosition.y - ent->GetPosition().y;
+ if(dx > -65.0f && dx < 65.0f &&
+ dy > -65.0f && dy < 65.0f &&
+ ms_nNoOfInVisibleEntities < NUMINVISIBLEENTITIES - 1)
+ ms_aInVisibleEntityPtrs[ms_nNoOfInVisibleEntities++] = ent;
+ break;
+ case VIS_STREAMME:
+ if(!CStreaming::ms_disableStreaming)
+ if(!m_loadingPriority || CStreaming::ms_numModelsRequested < 10)
+ CStreaming::RequestModel(ent->GetModelIndex(), 0);
+ break;
+ }
+#ifndef MASTER
+ EntitiesRendered++;
+ switch(ent->GetType()){
+ case ENTITY_TYPE_BUILDING:
+ if(ent->bIsBIGBuilding)
+ RenderedBigBuildings++;
+ else
+ RenderedBuildings++;
+ break;
+ case ENTITY_TYPE_VEHICLE:
+ RenderedCars++;
+ break;
+ case ENTITY_TYPE_PED:
+ RenderedPeds++;
+ break;
+ case ENTITY_TYPE_OBJECT:
+ RenderedObjects++;
+ break;
+ case ENTITY_TYPE_DUMMY:
+ RenderedDummies++;
+ break;
+ }
+#endif
+ }else if(IsRoad(ent) && !CStreaming::ms_disableStreaming){
+ if(SetupEntityVisibility(ent) == VIS_STREAMME)
+ if(!m_loadingPriority || CStreaming::ms_numModelsRequested < 10)
+ CStreaming::RequestModel(ent->GetModelIndex(), 0);
+ }else{
+#ifndef MASTER
+ EntitiesNotRendered++;
+#endif
+ }
+ }
+ }
+}
+
+void
+CRenderer::ScanSectorList_Priority(CPtrList *lists)
+{
+ CPtrNode *node;
+ CPtrList *list;
+ CEntity *ent;
+ int i;
+ float dx, dy;
+
+ for(i = 0; i < NUMSECTORENTITYLISTS; i++){
+ list = &lists[i];
+ for(node = list->first; node; node = node->next){
+ ent = (CEntity*)node->item;
+ if(ent->m_scanCode == CWorld::GetCurrentScanCode())
+ continue; // already seen
+ ent->m_scanCode = CWorld::GetCurrentScanCode();
+
+ if(IsEntityCullZoneVisible(ent)){
+ switch(SetupEntityVisibility(ent)){
+ case VIS_VISIBLE:
+ InsertEntityIntoList(ent);
+ break;
+ case VIS_INVISIBLE:
+ if(!IsGlass(ent->GetModelIndex()))
+ break;
+ // fall through
+ case VIS_OFFSCREEN:
+ dx = ms_vecCameraPosition.x - ent->GetPosition().x;
+ dy = ms_vecCameraPosition.y - ent->GetPosition().y;
+ if(dx > -65.0f && dx < 65.0f &&
+ dy > -65.0f && dy < 65.0f &&
+ ms_nNoOfInVisibleEntities < NUMINVISIBLEENTITIES - 1)
+ ms_aInVisibleEntityPtrs[ms_nNoOfInVisibleEntities++] = ent;
+ break;
+ case VIS_STREAMME:
+ if(!CStreaming::ms_disableStreaming){
+ CStreaming::RequestModel(ent->GetModelIndex(), 0);
+ if(CStreaming::ms_aInfoForModel[ent->GetModelIndex()].m_loadState != STREAMSTATE_LOADED)
+ m_loadingPriority = true;
+ }
+ break;
+ }
+#ifndef MASTER
+ // actually missing in game
+ EntitiesRendered++;
+ switch(ent->GetType()){
+ case ENTITY_TYPE_BUILDING:
+ if(ent->bIsBIGBuilding)
+ RenderedBigBuildings++;
+ else
+ RenderedBuildings++;
+ break;
+ case ENTITY_TYPE_VEHICLE:
+ RenderedCars++;
+ break;
+ case ENTITY_TYPE_PED:
+ RenderedPeds++;
+ break;
+ case ENTITY_TYPE_OBJECT:
+ RenderedObjects++;
+ break;
+ case ENTITY_TYPE_DUMMY:
+ RenderedDummies++;
+ break;
+ }
+#endif
+ }else if(IsRoad(ent) && !CStreaming::ms_disableStreaming){
+ if(SetupEntityVisibility(ent) == VIS_STREAMME)
+ CStreaming::RequestModel(ent->GetModelIndex(), 0);
+ }else{
+#ifndef MASTER
+ // actually missing in game
+ EntitiesNotRendered++;
+#endif
+ }
+ }
+ }
+}
+
+void
+CRenderer::ScanSectorList_Subway(CPtrList *lists)
+{
+ CPtrNode *node;
+ CPtrList *list;
+ CEntity *ent;
+ int i;
+ float dx, dy;
+
+ for(i = 0; i < NUMSECTORENTITYLISTS; i++){
+ list = &lists[i];
+ for(node = list->first; node; node = node->next){
+ ent = (CEntity*)node->item;
+ if(ent->m_scanCode == CWorld::GetCurrentScanCode())
+ continue; // already seen
+ ent->m_scanCode = CWorld::GetCurrentScanCode();
+ switch(SetupEntityVisibility(ent)){
+ case VIS_VISIBLE:
+ InsertEntityIntoList(ent);
+ break;
+ case VIS_OFFSCREEN:
+ dx = ms_vecCameraPosition.x - ent->GetPosition().x;
+ dy = ms_vecCameraPosition.y - ent->GetPosition().y;
+ if(dx > -65.0f && dx < 65.0f &&
+ dy > -65.0f && dy < 65.0f &&
+ ms_nNoOfInVisibleEntities < NUMINVISIBLEENTITIES - 1)
+ ms_aInVisibleEntityPtrs[ms_nNoOfInVisibleEntities++] = ent;
+ break;
+ }
+ }
+ }
+}
+
+void
+CRenderer::ScanSectorList_RequestModels(CPtrList *lists)
+{
+ CPtrNode *node;
+ CPtrList *list;
+ CEntity *ent;
+ int i;
+
+ for(i = 0; i < NUMSECTORENTITYLISTS; i++){
+ list = &lists[i];
+ for(node = list->first; node; node = node->next){
+ ent = (CEntity*)node->item;
+ if(ent->m_scanCode == CWorld::GetCurrentScanCode())
+ continue; // already seen
+ ent->m_scanCode = CWorld::GetCurrentScanCode();
+ if(IsEntityCullZoneVisible(ent))
+ if(ShouldModelBeStreamed(ent))
+ CStreaming::RequestModel(ent->GetModelIndex(), 0);
+ }
+ }
+}
+
+// Put big buildings in front
+// This seems pointless because the sector lists shouldn't have big buildings in the first place
+void
+CRenderer::SortBIGBuildings(void)
+{
+ int x, y;
+ for(y = 0; y < NUMSECTORS_Y; y++)
+ for(x = 0; x < NUMSECTORS_X; x++){
+ SortBIGBuildingsForSectorList(&CWorld::GetSector(x, y)->m_lists[ENTITYLIST_BUILDINGS]);
+ SortBIGBuildingsForSectorList(&CWorld::GetSector(x, y)->m_lists[ENTITYLIST_BUILDINGS_OVERLAP]);
+ }
+}
+
+void
+CRenderer::SortBIGBuildingsForSectorList(CPtrList *list)
+{
+ CPtrNode *node;
+ CEntity *ent;
+
+ for(node = list->first; node; node = node->next){
+ ent = (CEntity*)node->item;
+ if(ent->bIsBIGBuilding){
+ list->RemoveNode(node);
+ list->InsertNode(node);
+ }
+ }
+}
+
+bool
+CRenderer::ShouldModelBeStreamed(CEntity *ent)
+{
+ CSimpleModelInfo *mi = (CSimpleModelInfo *)CModelInfo::GetModelInfo(ent->GetModelIndex());
+ float dist = (ent->GetPosition() - ms_vecCameraPosition).Magnitude();
+ if(mi->m_noFade)
+ return dist - STREAM_DISTANCE < mi->GetLargestLodDistance();
+ else
+ return dist - FADE_DISTANCE - STREAM_DISTANCE < mi->GetLargestLodDistance();
+}
+
+bool
+CRenderer::IsEntityCullZoneVisible(CEntity *ent)
+{
+ CPed *ped;
+ CObject *obj;
+
+ if(gbDisableZoneCull) return true;
+
+#ifndef MASTER
+ switch(ent->GetType()){
+ case ENTITY_TYPE_BUILDING:
+ if(ent->bIsBIGBuilding)
+ TestedBigBuildings++;
+ else
+ TestedBuildings++;
+ break;
+ case ENTITY_TYPE_VEHICLE:
+ TestedCars++;
+ break;
+ case ENTITY_TYPE_PED:
+ TestedPeds++;
+ break;
+ case ENTITY_TYPE_OBJECT:
+ TestedObjects++;
+ break;
+ case ENTITY_TYPE_DUMMY:
+ TestedDummies++;
+ break;
+ }
+#endif
+ if(ent->bZoneCulled)
+ return false;
+
+
+ switch(ent->GetType()){
+ case ENTITY_TYPE_VEHICLE:
+ return IsVehicleCullZoneVisible(ent);
+ case ENTITY_TYPE_PED:
+ ped = (CPed*)ent;
+ if (ped->bInVehicle) {
+ if (ped->m_pMyVehicle)
+ return IsVehicleCullZoneVisible(ped->m_pMyVehicle);
+ else
+ return true;
+ }
+ return !(ped->m_pCurSurface && ped->m_pCurSurface->bZoneCulled2);
+ case ENTITY_TYPE_OBJECT:
+ obj = (CObject*)ent;
+ if(!obj->GetIsStatic())
+ return true;
+ return !(obj->m_pCurSurface && obj->m_pCurSurface->bZoneCulled2);
+ default: break;
+ }
+ return true;
+}
+
+bool
+CRenderer::IsVehicleCullZoneVisible(CEntity *ent)
+{
+ CVehicle *v = (CVehicle*)ent;
+ switch(v->GetStatus()) {
+ case STATUS_SIMPLE:
+ case STATUS_PHYSICS:
+ case STATUS_ABANDONED:
+ case STATUS_WRECKED:
+ return !(v->m_pCurGroundEntity && v->m_pCurGroundEntity->bZoneCulled2);
+ default: break;
+ }
+ return true;
+}
+
+void
+CRenderer::RemoveVehiclePedLights(CEntity *ent, bool reset)
+{
+ if(ent->bRenderScorched){
+ WorldReplaceScorchedLightsWithNormal(Scene.world);
+ return;
+ }
+ CPointLights::RemoveLightsAffectingObject();
+ if(reset)
+ ReSetAmbientAndDirectionalColours();
+}