#include "common.h"
#include "RwHelper.h"
#include "templates.h"
#include "main.h"
#include "Entity.h"
#include "ModelInfo.h"
#include "Lights.h"
#include "RwHelper.h"
#include "Renderer.h"
#include "Camera.h"
#include "VisibilityPlugins.h"
#include "World.h"
#include "custompipes.h"
#include "MemoryHeap.h"
//--LCS: file done
// LCS: no transparent water in LCS so no need for alpha boat and alpha underwater lists
CLinkList<CVisibilityPlugins::AlphaObjectInfo> CVisibilityPlugins::m_alphaList;
//CLinkList<CVisibilityPlugins::AlphaObjectInfo> CVisibilityPlugins::m_alphaBoatAtomicList;
CLinkList<CVisibilityPlugins::AlphaObjectInfo> CVisibilityPlugins::m_alphaEntityList;
//CLinkList<CVisibilityPlugins::AlphaObjectInfo> CVisibilityPlugins::m_alphaUnderwaterEntityList;
#ifdef NEW_RENDERER
CLinkList<CVisibilityPlugins::AlphaObjectInfo> CVisibilityPlugins::m_alphaBuildingList;
#endif
int32 CVisibilityPlugins::ms_atomicPluginOffset = -1;
int32 CVisibilityPlugins::ms_framePluginOffset = -1;
int32 CVisibilityPlugins::ms_clumpPluginOffset = -1;
RwCamera *CVisibilityPlugins::ms_pCamera;
RwV3d *CVisibilityPlugins::ms_pCameraPosn;
float CVisibilityPlugins::ms_cullCompsDist;
float CVisibilityPlugins::ms_vehicleLod0Dist;
float CVisibilityPlugins::ms_vehicleLod1Dist;
float CVisibilityPlugins::ms_vehicleFadeDist;
float CVisibilityPlugins::ms_bigVehicleLod0Dist;
float CVisibilityPlugins::ms_bigVehicleLod1Dist;
float CVisibilityPlugins::ms_pedLodDist;
float CVisibilityPlugins::ms_pedFadeDist;
#define RENDERCALLBACK AtomicDefaultRenderCallBack
void
CVisibilityPlugins::Initialise(void)
{
m_alphaList.Init(NUMALPHALIST);
m_alphaList.head.item.sort = 0.0f;
m_alphaList.tail.item.sort = 100000000.0f;
// m_alphaBoatAtomicList.Init(NUMBOATALPHALIST);
// m_alphaBoatAtomicList.head.item.sort = 0.0f;
// m_alphaBoatAtomicList.tail.item.sort = 100000000.0f;
#ifdef ASPECT_RATIO_SCALE
// default 150 is not enough for bigger FOVs
m_alphaEntityList.Init(NUMALPHAENTITYLIST * 3);
#else
m_alphaEntityList.Init(NUMALPHAENTITYLIST);
#endif // ASPECT_RATIO_SCALE
m_alphaEntityList.head.item.sort = 0.0f;
m_alphaEntityList.tail.item.sort = 100000000.0f;
// m_alphaUnderwaterEntityList.Init(NUMALPHAUNTERWATERENTITYLIST);
// m_alphaUnderwaterEntityList.head.item.sort = 0.0f;
// m_alphaUnderwaterEntityList.tail.item.sort = 100000000.0f;
#ifdef NEW_RENDERER
m_alphaBuildingList.Init(NUMALPHAENTITYLIST);
m_alphaBuildingList.head.item.sort = 0.0f;
m_alphaBuildingList.tail.item.sort = 100000000.0f;
#endif
base::RegisterRelocatableChunkFunc((void*)RENDERCALLBACK);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleReallyLowDetailCB);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleHiDetailCB);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleHiDetailAlphaCB);
base::RegisterRelocatableChunkFunc((void*)RenderTrainHiDetailCB);
base::RegisterRelocatableChunkFunc((void*)RenderTrainHiDetailAlphaCB);
base::RegisterRelocatableChunkFunc((void*)RenderWheelAtomicCB);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleRotorAlphaCB);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleTailRotorAlphaCB);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleReallyLowDetailCB_BigVehicle);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleLowDetailCB_BigVehicle);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleHiDetailCB_BigVehicle);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleLowDetailAlphaCB_BigVehicle);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleHiDetailAlphaCB_BigVehicle);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleHiDetailCB_Boat);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleLoDetailCB_Boat);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleHiDetailCB_Boat_Far);
base::RegisterRelocatableChunkFunc((void*)RenderVehicleLoDetailCB_Boat_Far);
base::RegisterRelocatableChunkFunc((void*)RenderPedCB);
}
void
CVisibilityPlugins::Shutdown(void)
{
m_alphaList.Shutdown();
// m_alphaBoatAtomicList.Shutdown();
m_alphaEntityList.Shutdown();
// m_alphaUnderwaterEntityList.Shutdown();
#ifdef NEW_RENDERER
m_alphaBuildingList.Shutdown();
#endif
}
void
CVisibilityPlugins::InitAlphaEntityList(void)
{
m_alphaEntityList.Clear();
// m_alphaBoatAtomicList.Clear();
// m_alphaUnderwaterEntityList.Clear();
#ifdef NEW_RENDERER
m_alphaBuildingList.Clear();
#endif
}
bool
CVisibilityPlugins::InsertEntityIntoSortedList(CEntity *e, float dist)
{
#ifdef FIX_BUGS
if (!e->m_rwObject) return true;
#endif
AlphaObjectInfo item;
item.entity = e;
item.sort = dist;
#ifdef NEW_RENDERER
if(!gbPreviewCity && e->IsBuilding())
return !!m_alphaBuildingList.InsertSorted(item);
#endif
// if(e->bUnderwater && m_alphaUnderwaterEntityList.InsertSorted(item))
// return true;
return !!m_alphaEntityList.InsertSorted(item);
}
void
CVisibilityPlugins::InitAlphaAtomicList(void)
{
m_alphaList.Clear();
}
bool
CVisibilityPlugins::InsertAtomicIntoSortedList(RpAtomic *a, float dist)
{
AlphaObjectInfo item;
item.atomic = a;
item.sort = dist;
return !!m_alphaList.InsertSorted(item);
}
/*
bool
CVisibilityPlugins::InsertAtomicIntoBoatSortedList(RpAtomic *a, float dist)
{
AlphaObjectInfo item;
item.atomic = a;
item.sort = dist;
return !!m_alphaBoatAtomicList.InsertSorted(item);
}
*/
// can't increase this yet unfortunately...
// probably have to fix fading for this so material alpha isn't overwritten
// LCS: VIS_DISTANCE_ALPHA will probably take care of this
#define VEHICLE_LODDIST_MULTIPLIER (TheCamera.GenerationDistMultiplier)
void
CVisibilityPlugins::SetRenderWareCamera(RwCamera *camera)
{
ms_pCamera = camera;
ms_pCameraPosn = RwMatrixGetPos(RwFrameGetMatrix(RwCameraGetFrame(camera)));
if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED)
ms_cullCompsDist = 1000000.0f;
else
ms_cullCompsDist = sq(TheCamera.LODDistMultiplier * 20.0f);
ms_vehicleLod0Dist = sq(70.0f * VEHICLE_LODDIST_MULTIPLIER);
ms_vehicleLod1Dist = sq(90.0f * VEHICLE_LODDIST_MULTIPLIER);
ms_vehicleFadeDist = sq(100.0f * VEHICLE_LODDIST_MULTIPLIER);
ms_bigVehicleLod0Dist = sq(60.0f * VEHICLE_LODDIST_MULTIPLIER);
ms_bigVehicleLod1Dist = sq(150.0f * VEHICLE_LODDIST_MULTIPLIER);
ms_pedLodDist = sq(70.0f * TheCamera.LODDistMultiplier);
ms_pedFadeDist = sq(70.0f * TheCamera.LODDistMultiplier);
}
static float DistToCameraSq;
static float PitchToCamera;
void
CVisibilityPlugins::SetupVehicleVariables(RpClump *vehicle)
{
if (RwObjectGetType((RwObject*)vehicle) != rpCLUMP)
return;
DistToCameraSq = GetDistanceSquaredFromCamera(RpClumpGetFrame(vehicle));
RwV3d distToCam;
RwV3dSub(&distToCam, ms_pCameraPosn, &RwFrameGetMatrix(RpClumpGetFrame(vehicle))->pos);
float dist2d = Sqrt(SQR(distToCam.x) + SQR(distToCam.y));
if(distToCam.z == 0.0f && dist2d == 0.0f)
PitchToCamera = 0.0f;
else
PitchToCamera = Atan2(distToCam.z, dist2d);
}
RpMaterial*
SetAlphaCB(RpMaterial *material, void *data)
{
((RwRGBA*)RpMaterialGetColor(material))->alpha = (uint8)(uintptr)data;
return material;
}
RpMaterial*
SetTextureCB(RpMaterial *material, void *data)
{
RpMaterialSetTexture(material, (RwTexture*)data);
return material;
}
void
CVisibilityPlugins::RenderAtomicList(CLinkList<AlphaObjectInfo> &list)
{
CLink<AlphaObjectInfo> *node;
for(node = list.tail.prev; node != &list.head; node = node->prev)
RENDERCALLBACK(node->item.atomic);
}
void
CVisibilityPlugins::RenderAlphaAtomics(void)
{
RenderAtomicList(m_alphaList);
}
/*
//LCS: removed
void
CVisibilityPlugins::RenderBoatAlphaAtomics(void)
{
SetCullMode(rwCULLMODECULLNONE);
RenderAtomicList(m_alphaBoatAtomicList);
SetCullMode(rwCULLMODECULLBACK);
}
*/
void
CVisibilityPlugins::RenderFadingEntities(CLinkList<AlphaObjectInfo> &list)
{
CLink<AlphaObjectInfo> *node;
CSimpleModelInfo *mi;
for(node = list.tail.prev; node != &list.head; node = node->prev){
CEntity *e = node->item.entity;
if(e->m_rwObject == nil)
continue;
#ifdef EXTENDED_PIPELINES
if(CustomPipes::bRenderingEnvMap && (e->IsPed() || e->IsVehicle()))
continue;
#endif
mi = (CSimpleModelInfo *)CModelInfo::GetModelInfo(e->GetModelIndex());
if(mi->GetModelType() == MITYPE_SIMPLE && mi->m_noZwrite)
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE);
#if defined(FIX_BUGS) && !defined(VIS_DISTANCE_ALPHA)
//LCS: removed, but that's dumb cause it breaks distance fading
if(e->bDistanceFade){
DeActivateDirectional();
SetAmbientColours();
e->bImBeingRendered = true;
PUSH_RENDERGROUP(mi->GetModelName());
RenderFadingAtomic((RpAtomic*)e->m_rwObject, node->item.sort);
POP_RENDERGROUP();
e->bImBeingRendered = false;
}else
#endif
{
#ifdef VIS_DISTANCE_ALPHA
// BUG: we don't even know if this is a clump
if(GetClumpAlpha((RpClump*)e->m_rwObject) != 255 ||
GetObjectDistanceAlpha(e->m_rwObject) != 255)
; // set blend render states
else
; // set default render states
#endif
CRenderer::RenderOneNonRoad(e);
}
if(mi->GetModelType() == MITYPE_SIMPLE && mi->m_noZwrite)
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
}
}
void
CVisibilityPlugins::RenderFadingEntities(void)
{
RenderFadingEntities(m_alphaEntityList);
// RenderBoatAlphaAtomics();
}
void
CVisibilityPlugins::RenderFadingUnderwaterEntities(void)
{
// RenderFadingEntities(m_alphaUnderwaterEntityList);
}
RpAtomic*
CVisibilityPlugins::RenderWheelAtomicCB(RpAtomic *atomic)
{
RpAtomic *lodatm;
float len;
CSimpleModelInfo *mi;
mi = GetAtomicModelInfo(atomic);
len = Sqrt(DistToCameraSq);
#ifdef FIX_BUGS
len *= 0.5f; // HACK HACK, LOD wheels look shite
lodatm = mi->GetAtomicFromDistance(len * TheCamera.LODDistMultiplier / VEHICLE_LODDIST_MULTIPLIER);
#else
lodatm = mi->GetAtomicFromDistance(len);
#endif
if(lodatm){
if(RpAtomicGetGeometry(lodatm) != RpAtomicGetGeometry(atomic))
RpAtomicSetGeometry(atomic, RpAtomicGetGeometry(lodatm), rpATOMICSAMEBOUNDINGSPHERE);
RENDERCALLBACK(atomic);
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderObjNormalAtomic(RpAtomic *atomic)
{
RwMatrix *m;
RwV3d view;
float len;
m = RwFrameGetLTM(RpAtomicGetFrame(atomic));
RwV3dSub(&view, RwMatrixGetPos(m), ms_pCameraPosn);
len = RwV3dLength(&view);
if(RwV3dDotProduct(&view, RwMatrixGetUp(m)) < -0.3f*len && len > 8.0f)
return atomic;
RENDERCALLBACK(atomic);
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderAlphaAtomic(RpAtomic *atomic, int alpha)
{
RpGeometry *geo;
uint32 flags;
geo = RpAtomicGetGeometry(atomic);
flags = RpGeometryGetFlags(geo);
RpGeometrySetFlags(geo, flags | rpGEOMETRYMODULATEMATERIALCOLOR);
RpGeometryForAllMaterials(geo, SetAlphaCB, (void*)alpha);
RENDERCALLBACK(atomic);
RpGeometryForAllMaterials(geo, SetAlphaCB, (void*)255);
RpGeometrySetFlags(geo, flags);
return atomic;
}
/*
//LCS: removed
RpAtomic*
CVisibilityPlugins::RenderWeaponCB(RpAtomic *atomic)
{
RwMatrix *m;
RwV3d view;
float maxdist, distsq;
CSimpleModelInfo *mi;
mi = GetAtomicModelInfo(atomic);
m = RwFrameGetLTM(RpAtomicGetFrame(atomic));
RwV3dSub(&view, RwMatrixGetPos(m), ms_pCameraPosn);
maxdist = mi->GetLodDistance(0);
distsq = RwV3dDotProduct(&view, &view);
if(distsq < maxdist*maxdist)
RENDERCALLBACK(atomic);
return atomic;
}
*/
//LCS: removed, but we want it
RpAtomic*
CVisibilityPlugins::RenderFadingAtomic(RpAtomic *atomic, float camdist)
{
RpAtomic *lodatm;
float fadefactor;
uint32 alpha;
CSimpleModelInfo *mi;
mi = GetAtomicModelInfo(atomic);
lodatm = mi->GetAtomicFromDistance(camdist - FADE_DISTANCE);
if(mi->m_additive)
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
fadefactor = (mi->GetLargestLodDistance() - (camdist - FADE_DISTANCE))/FADE_DISTANCE;
if(fadefactor > 1.0f)
fadefactor = 1.0f;
alpha = mi->m_alpha * fadefactor;
if(alpha == 255)
RENDERCALLBACK(atomic);
else{
RpGeometry *geo = RpAtomicGetGeometry(lodatm);
uint32 flags = RpGeometryGetFlags(geo);
RpGeometrySetFlags(geo, flags | rpGEOMETRYMODULATEMATERIALCOLOR);
RpGeometryForAllMaterials(geo, SetAlphaCB, (void*)alpha);
if(geo != RpAtomicGetGeometry(atomic))
RpAtomicSetGeometry(atomic, geo, rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?)
RENDERCALLBACK(atomic);
RpGeometryForAllMaterials(geo, SetAlphaCB, (void*)255);
RpGeometrySetFlags(geo, flags);
}
if(mi->m_additive)
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleHiDetailCB(RpAtomic *atomic)
{
RwFrame *clumpframe;
float dot;
uint32 flags;
clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic));
if(DistToCameraSq < ms_vehicleLod0Dist){
flags = GetAtomicId(atomic);
if(DistToCameraSq > ms_cullCompsDist && (flags & ATOMIC_FLAG_NOCULL) == 0 && PitchToCamera < 0.2f){
dot = GetDotProductWithCameraVector(RwFrameGetLTM(RpAtomicGetFrame(atomic)),
RwFrameGetLTM(clumpframe), flags);
if(dot > 0.0f && ((flags & ATOMIC_FLAG_ANGLECULL) || 0.1f*DistToCameraSq < dot*dot))
return atomic;
}
#ifdef VIS_DISTANCE_ALPHA
if(GetObjectDistanceAlpha((RwObject*)RpAtomicGetClump(atomic)) == 255 ||
!InsertAtomicIntoSortedList(atomic, DistToCameraSq))
#endif
RENDERCALLBACK(atomic);
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleHiDetailAlphaCB(RpAtomic *atomic)
{
RwFrame *clumpframe;
float dot;
uint32 flags;
clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic));
if(DistToCameraSq < ms_vehicleLod0Dist){
flags = GetAtomicId(atomic);
dot = GetDotProductWithCameraVector(RwFrameGetLTM(RpAtomicGetFrame(atomic)),
RwFrameGetLTM(clumpframe), flags);
if(DistToCameraSq > ms_cullCompsDist && (flags & ATOMIC_FLAG_NOCULL) == 0 && PitchToCamera < 0.2f)
if(dot > 0.0f && ((flags & ATOMIC_FLAG_ANGLECULL) || 0.1f*DistToCameraSq < dot*dot))
return atomic;
if(flags & ATOMIC_FLAG_DRAWLAST){
// sort before clump
if(!InsertAtomicIntoSortedList(atomic, DistToCameraSq - 0.0001f))
RENDERCALLBACK(atomic);
}else{
if(!InsertAtomicIntoSortedList(atomic, DistToCameraSq + dot))
RENDERCALLBACK(atomic);
}
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleHiDetailCB_BigVehicle(RpAtomic *atomic)
{
RwFrame *clumpframe;
float dot;
uint32 flags;
clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic));
if(DistToCameraSq < ms_bigVehicleLod0Dist){
flags = GetAtomicId(atomic);
if(DistToCameraSq > ms_cullCompsDist && (flags & ATOMIC_FLAG_NOCULL) == 0 && PitchToCamera < 0.2f){
dot = GetDotProductWithCameraVector(RwFrameGetLTM(RpAtomicGetFrame(atomic)),
RwFrameGetLTM(clumpframe), flags);
if(dot > 0.0f)
return atomic;
}
RENDERCALLBACK(atomic);
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleHiDetailAlphaCB_BigVehicle(RpAtomic *atomic)
{
RwFrame *clumpframe;
float dot;
uint32 flags;
clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic));
if(DistToCameraSq < ms_bigVehicleLod0Dist){
flags = GetAtomicId(atomic);
dot = GetDotProductWithCameraVector(RwFrameGetLTM(RpAtomicGetFrame(atomic)),
RwFrameGetLTM(clumpframe), flags);
if(DistToCameraSq > ms_cullCompsDist && (flags & ATOMIC_FLAG_NOCULL) == 0 && PitchToCamera < 0.2f)
if(dot > 0.0f && ((flags & ATOMIC_FLAG_ANGLECULL) || 0.1f*DistToCameraSq < dot*dot))
return atomic;
if(!InsertAtomicIntoSortedList(atomic, DistToCameraSq + dot))
RENDERCALLBACK(atomic);
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleHiDetailCB_Boat(RpAtomic *atomic)
{
if(DistToCameraSq < ms_vehicleLod0Dist)
RENDERCALLBACK(atomic);
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleHiDetailCB_Boat_Far(RpAtomic *atomic)
{
if(DistToCameraSq < ms_bigVehicleLod1Dist)
RENDERCALLBACK(atomic);
return atomic;
}
/*
//LCS: removed
RpAtomic*
CVisibilityPlugins::RenderVehicleHiDetailAlphaCB_Boat(RpAtomic *atomic)
{
if(DistToCameraSq < ms_vehicleLod0Dist){
if(GetAtomicId(atomic) & ATOMIC_FLAG_DRAWLAST){
if(!InsertAtomicIntoBoatSortedList(atomic, DistToCameraSq))
RENDERCALLBACK(atomic);
}else
RENDERCALLBACK(atomic);
}
return atomic;
}
*/
RpAtomic*
CVisibilityPlugins::RenderVehicleLoDetailCB_Boat(RpAtomic *atomic)
{
RpClump *clump;
int32 alpha;
clump = RpAtomicGetClump(atomic);
if(DistToCameraSq >= ms_vehicleLod0Dist){
alpha = GetClumpAlpha(clump);
// if(alpha == 255)
// RENDERCALLBACK(atomic);
// else
RenderAlphaAtomic(atomic, alpha);
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleLoDetailCB_Boat_Far(RpAtomic *atomic)
{
RpClump *clump;
int32 alpha;
clump = RpAtomicGetClump(atomic);
if(DistToCameraSq >= ms_bigVehicleLod1Dist){
alpha = GetClumpAlpha(clump);
// if(alpha == 255)
// RENDERCALLBACK(atomic);
// else
RenderAlphaAtomic(atomic, alpha);
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleLowDetailCB_BigVehicle(RpAtomic *atomic)
{
RwFrame *clumpframe;
float dot;
uint32 flags;
clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic));
if(DistToCameraSq >= ms_bigVehicleLod0Dist &&
DistToCameraSq < ms_bigVehicleLod1Dist){
flags = GetAtomicId(atomic);
if(DistToCameraSq > ms_cullCompsDist && (flags & ATOMIC_FLAG_NOCULL) == 0 && PitchToCamera < 0.2f){
dot = GetDotProductWithCameraVector(RwFrameGetLTM(RpAtomicGetFrame(atomic)),
RwFrameGetLTM(clumpframe), flags);
if(dot > 0.0f)
return atomic;
}
RENDERCALLBACK(atomic);
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleLowDetailAlphaCB_BigVehicle(RpAtomic *atomic)
{
RwFrame *clumpframe;
float dot;
uint32 flags;
clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic));
if(DistToCameraSq >= ms_bigVehicleLod0Dist &&
DistToCameraSq < ms_bigVehicleLod1Dist){
flags = GetAtomicId(atomic);
dot = GetDotProductWithCameraVector(RwFrameGetLTM(RpAtomicGetFrame(atomic)),
RwFrameGetLTM(clumpframe), flags);
if(dot > 0.0f)
if(DistToCameraSq > ms_cullCompsDist && (flags & ATOMIC_FLAG_NOCULL) == 0 && PitchToCamera < 0.2f)
return atomic;
if(!InsertAtomicIntoSortedList(atomic, DistToCameraSq + dot))
RENDERCALLBACK(atomic);
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleReallyLowDetailCB(RpAtomic *atomic)
{
RpClump *clump;
int32 alpha;
clump = RpAtomicGetClump(atomic);
if(DistToCameraSq >= ms_vehicleLod0Dist){
alpha = GetClumpAlpha(clump);
// if(alpha == 255)
// RENDERCALLBACK(atomic);
// else
RenderAlphaAtomic(atomic, alpha);
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle(RpAtomic *atomic)
{
if(DistToCameraSq >= ms_bigVehicleLod1Dist)
RENDERCALLBACK(atomic);
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderTrainHiDetailCB(RpAtomic *atomic)
{
RwFrame *clumpframe;
float dot;
uint32 flags;
clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic));
if(DistToCameraSq < ms_bigVehicleLod1Dist){
flags = GetAtomicId(atomic);
if(DistToCameraSq > ms_cullCompsDist && (flags & ATOMIC_FLAG_NOCULL) == 0 && PitchToCamera < 0.2f){
dot = GetDotProductWithCameraVector(RwFrameGetLTM(RpAtomicGetFrame(atomic)),
RwFrameGetLTM(clumpframe), flags);
if(dot > 0.0f && ((flags & ATOMIC_FLAG_ANGLECULL) || 0.1f*DistToCameraSq < dot*dot))
return atomic;
}
RENDERCALLBACK(atomic);
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderTrainHiDetailAlphaCB(RpAtomic *atomic)
{
RwFrame *clumpframe;
float dot;
uint32 flags;
clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic));
if(DistToCameraSq < ms_bigVehicleLod1Dist){
flags = GetAtomicId(atomic);
dot = GetDotProductWithCameraVector(RwFrameGetLTM(RpAtomicGetFrame(atomic)),
RwFrameGetLTM(clumpframe), flags);
if(DistToCameraSq > ms_cullCompsDist && (flags & ATOMIC_FLAG_NOCULL) == 0 && PitchToCamera < 0.2f)
if(dot > 0.0f && ((flags & ATOMIC_FLAG_ANGLECULL) || 0.1f*DistToCameraSq < dot*dot))
return atomic;
if(flags & ATOMIC_FLAG_DRAWLAST){
if(!InsertAtomicIntoSortedList(atomic, DistToCameraSq))
RENDERCALLBACK(atomic);
}else{
if(!InsertAtomicIntoSortedList(atomic, DistToCameraSq + dot))
RENDERCALLBACK(atomic);
}
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleRotorAlphaCB(RpAtomic *atomic)
{
RwFrame *clumpframe;
float dot;
RwV3d cam2atm;
clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic));
if(DistToCameraSq < ms_bigVehicleLod1Dist){
RwV3dSub(&cam2atm, &RwFrameGetLTM(RpAtomicGetFrame(atomic))->pos, ms_pCameraPosn);
dot = RwV3dDotProduct(&cam2atm, &RwFrameGetLTM(clumpframe)->at);
if(!InsertAtomicIntoSortedList(atomic, DistToCameraSq + dot*20.0f))
RENDERCALLBACK(atomic);
}
return atomic;
}
RpAtomic*
CVisibilityPlugins::RenderVehicleTailRotorAlphaCB(RpAtomic *atomic)
{
RwMatrix *clumpMat, *atmMat;
float dot;
RwV3d cam2atm;
if(DistToCameraSq < ms_bigVehicleLod0Dist){
atmMat = RwFrameGetLTM(RpAtomicGetFrame(atomic));
clumpMat = RwFrameGetLTM(RpClumpGetFrame(RpAtomicGetClump(atomic)));
RwV3dSub(&cam2atm, &atmMat->pos, ms_pCameraPosn);
dot = RwV3dDotProduct(&cam2atm, &clumpMat->up) + RwV3dDotProduct(&cam2atm, &clumpMat->right);
if(!InsertAtomicIntoSortedList(atomic, DistToCameraSq - dot))
RENDERCALLBACK(atomic);
}
return atomic;
}
/*
RpAtomic*
CVisibilityPlugins::RenderPlayerCB(RpAtomic *atomic)
{
if(CWorld::Players[0].m_pSkinTexture)
RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), SetTextureCB, CWorld::Players[0].m_pSkinTexture);
RENDERCALLBACK(atomic);
return atomic;
}
*/
RpAtomic*
CVisibilityPlugins::RenderPedCB(RpAtomic *atomic)
{
RpClump *clump;
float dist;
int32 alpha;
clump = RpAtomicGetClump(atomic);
dist = GetDistanceSquaredFromCamera(RpClumpGetFrame(clump));
if(dist < ms_pedLodDist){
alpha = GetClumpAlpha(clump);
// if(alpha == 255)
// RENDERCALLBACK(atomic);
// else
RenderAlphaAtomic(atomic, alpha);
}
return atomic;
}
float
CVisibilityPlugins::GetDistanceSquaredFromCamera(RwV3d *pos)
{
RwV3d dist;
RwV3dSub(&dist, pos, ms_pCameraPosn);
return RwV3dDotProduct(&dist, &dist);
}
float
CVisibilityPlugins::GetDistanceSquaredFromCamera(RwFrame *frame)
{
RwMatrix *m;
RwV3d dist;
m = RwFrameGetLTM(frame);
RwV3dSub(&dist, RwMatrixGetPos(m), ms_pCameraPosn);
return RwV3dDotProduct(&dist, &dist);
}
float
CVisibilityPlugins::GetDotProductWithCameraVector(RwMatrix *atomicMat, RwMatrix *clumpMat, uint32 flags)
{
RwV3d dist;
float dot, dotdoor;
// Vehicle forward is the y axis (RwMatrix.up)
// Vehicle right is the x axis (RwMatrix.right)
RwV3dSub(&dist, RwMatrixGetPos(atomicMat), ms_pCameraPosn);
// forward/backward facing
if(flags & (ATOMIC_FLAG_FRONT | ATOMIC_FLAG_REAR))
dot = RwV3dDotProduct(&dist, RwMatrixGetUp(clumpMat));
// left/right facing
else if(flags & (ATOMIC_FLAG_LEFT | ATOMIC_FLAG_RIGHT))
dot = RwV3dDotProduct(&dist, RwMatrixGetRight(clumpMat));
else
dot = 0.0f;
if(flags & (ATOMIC_FLAG_LEFT | ATOMIC_FLAG_REAR))
dot = -dot;
if(flags & (ATOMIC_FLAG_REARDOOR | ATOMIC_FLAG_FRONTDOOR)){
if(flags & ATOMIC_FLAG_REARDOOR)
dotdoor = -RwV3dDotProduct(&dist, RwMatrixGetUp(clumpMat));
else if(flags & ATOMIC_FLAG_FRONTDOOR)
dotdoor = RwV3dDotProduct(&dist, RwMatrixGetUp(clumpMat));
else
dotdoor = 0.0f;
if(dot < 0.0f && dotdoor < 0.0f)
dot += dotdoor;
if(dot > 0.0f && dotdoor > 0.0f)
dot += dotdoor;
}
return dot;
}
/* These are all unused */
bool
CVisibilityPlugins::DefaultVisibilityCB(RpClump *clump)
{
return true;
}
bool
CVisibilityPlugins::FrustumSphereCB(RpClump *clump)
{
return true;
}
bool
CVisibilityPlugins::MloVisibilityCB(RpClump *clump)
{
RwFrame *frame = RpClumpGetFrame(clump);
CMloModelInfo *modelInfo = (CMloModelInfo*)GetFrameHierarchyId(frame);
if (SQR(modelInfo->drawDist) < GetDistanceSquaredFromCamera(frame))
return false;
return CVisibilityPlugins::FrustumSphereCB(clump);
}
bool
CVisibilityPlugins::VehicleVisibilityCB(RpClump *clump)
{
RwFrame *frame = RpClumpGetFrame(clump);
if (ms_vehicleLod1Dist < GetDistanceSquaredFromCamera(frame))
return false;
return FrustumSphereCB(clump);
}
bool
CVisibilityPlugins::VehicleVisibilityCB_BigVehicle(RpClump *clump)
{
return FrustumSphereCB(clump);
}
//
// RW Plugins
//
enum
{
ID_VISIBILITYATOMIC = MAKECHUNKID(rwVENDORID_ROCKSTAR, 0x00),
ID_VISIBILITYCLUMP = MAKECHUNKID(rwVENDORID_ROCKSTAR, 0x01),
ID_VISIBILITYFRAME = MAKECHUNKID(rwVENDORID_ROCKSTAR, 0x02),
};
bool
CVisibilityPlugins::PluginAttach(void)
{
ms_atomicPluginOffset = RpAtomicRegisterPlugin(sizeof(AtomicExt),
ID_VISIBILITYATOMIC,
AtomicConstructor, AtomicDestructor, AtomicCopyConstructor);
ms_framePluginOffset = RwFrameRegisterPlugin(sizeof(FrameExt),
ID_VISIBILITYFRAME,
FrameConstructor, FrameDestructor, FrameCopyConstructor);
ms_clumpPluginOffset = RpClumpRegisterPlugin(sizeof(ClumpExt),
ID_VISIBILITYCLUMP,
ClumpConstructor, ClumpDestructor, ClumpCopyConstructor);
return ms_atomicPluginOffset != -1 && ms_clumpPluginOffset != -1;
}
#define ATOMICEXT(o) (RWPLUGINOFFSET(CVisibilityPlugins::AtomicExt, o, CVisibilityPlugins::ms_atomicPluginOffset))
#define FRAMEEXT(o) (RWPLUGINOFFSET(CVisibilityPlugins::FrameExt, o, CVisibilityPlugins::ms_framePluginOffset))
#define CLUMPEXT(o) (RWPLUGINOFFSET(CVisibilityPlugins::ClumpExt, o, CVisibilityPlugins::ms_clumpPluginOffset))
//
// Atomic
//
void*
CVisibilityPlugins::AtomicConstructor(void *object, int32, int32)
{
ATOMICEXT(object)->modelId = -1;
ATOMICEXT(object)->flags = 0;
#ifdef VIS_DISTANCE_ALPHA
// This seems strange, want to start out invisible before fading in
// but maybe it's set elsewhere?
ATOMICEXT(object)->distanceAlpha = 255;
#endif
return object;
}
void*
CVisibilityPlugins::AtomicDestructor(void *object, int32, int32)
{
return object;
}
void*
CVisibilityPlugins::AtomicCopyConstructor(void *dst, const void *src, int32, int32)
{
*ATOMICEXT(dst) = *ATOMICEXT(src);
return dst;
}
void
CVisibilityPlugins::SetAtomicModelInfo(RpAtomic *atomic,
CSimpleModelInfo *modelInfo)
{
int id;
for(id = 0; id < MODELINFOSIZE; id++)
if(CModelInfo::GetModelInfo(id) == modelInfo){
ATOMICEXT(atomic)->modelId = id;
return;
}
ATOMICEXT(atomic)->modelId = -1;
}
void
CVisibilityPlugins::SetAtomicModelIndex(RpAtomic *atomic, int modelId)
{
ATOMICEXT(atomic)->modelId = modelId;
}
CSimpleModelInfo*
CVisibilityPlugins::GetAtomicModelInfo(RpAtomic *atomic)
{
int id = ATOMICEXT(atomic)->modelId;
if(id == -1)
return nil;
return (CSimpleModelInfo*)CModelInfo::GetModelInfo(id);
}
void
CVisibilityPlugins::SetAtomicFlag(RpAtomic *atomic, int f)
{
ATOMICEXT(atomic)->flags |= f;
}
void
CVisibilityPlugins::ClearAtomicFlag(RpAtomic *atomic, int f)
{
ATOMICEXT(atomic)->flags &= ~f;
}
void
CVisibilityPlugins::SetAtomicId(RpAtomic *atomic, int id)
{
ATOMICEXT(atomic)->flags = id;
}
int
CVisibilityPlugins::GetAtomicId(RpAtomic *atomic)
{
return ATOMICEXT(atomic)->flags;
}
void
CVisibilityPlugins::SetAtomicRenderCallback(RpAtomic *atomic, RpAtomicCallBackRender cb)
{
if(cb == nil)
cb = RENDERCALLBACK; // not necessary
RpAtomicSetRenderCallBack(atomic, cb);
}
//
// Frame
//
void*
CVisibilityPlugins::FrameConstructor(void *object, int32, int32)
{
FRAMEEXT(object)->id = 0;
return object;
}
void*
CVisibilityPlugins::FrameDestructor(void *object, int32, int32)
{
return object;
}
void*
CVisibilityPlugins::FrameCopyConstructor(void *dst, const void *src, int32, int32)
{
*FRAMEEXT(dst) = *FRAMEEXT(src);
return dst;
}
void
CVisibilityPlugins::SetFrameHierarchyId(RwFrame *frame, intptr id)
{
FRAMEEXT(frame)->id = id;
}
intptr
CVisibilityPlugins::GetFrameHierarchyId(RwFrame *frame)
{
return FRAMEEXT(frame)->id;
}
//
// Clump
//
void*
CVisibilityPlugins::ClumpConstructor(void *object, int32, int32)
{
ClumpExt *ext = CLUMPEXT(object);
ext->visibilityCB = DefaultVisibilityCB;
ext->alpha = 0xFF;
return object;
}
void*
CVisibilityPlugins::ClumpDestructor(void *object, int32, int32)
{
return object;
}
void*
CVisibilityPlugins::ClumpCopyConstructor(void *dst, const void *src, int32, int32)
{
CLUMPEXT(dst)->visibilityCB = CLUMPEXT(src)->visibilityCB;
return dst;
}
void
CVisibilityPlugins::SetClumpModelInfo(RpClump *clump, CClumpModelInfo *modelInfo)
{
CVehicleModelInfo *vmi;
SetFrameHierarchyId(RpClumpGetFrame(clump), (intptr)modelInfo);
// Unused
switch (modelInfo->GetModelType()) {
case MITYPE_MLO:
CLUMPEXT(clump)->visibilityCB = MloVisibilityCB;
break;
case MITYPE_VEHICLE:
vmi = (CVehicleModelInfo*)modelInfo;
if(vmi->m_vehicleType == VEHICLE_TYPE_TRAIN ||
vmi->m_vehicleType == VEHICLE_TYPE_HELI ||
vmi->m_vehicleType == VEHICLE_TYPE_PLANE)
CLUMPEXT(clump)->visibilityCB = VehicleVisibilityCB_BigVehicle;
else
CLUMPEXT(clump)->visibilityCB = VehicleVisibilityCB;
break;
default: break;
}
}
CClumpModelInfo*
CVisibilityPlugins::GetClumpModelInfo(RpClump *clump)
{
return (CClumpModelInfo*)GetFrameHierarchyId(RpClumpGetFrame(clump));
}
void
CVisibilityPlugins::SetClumpAlpha(RpClump *clump, int alpha)
{
CLUMPEXT(clump)->alpha = alpha;
}
int
CVisibilityPlugins::GetClumpAlpha(RpClump *clump)
{
return CLUMPEXT(clump)->alpha;
}
bool
CVisibilityPlugins::IsClumpVisible(RpClump *clump)
{
return CLUMPEXT(clump)->visibilityCB(clump);
}
#ifdef VIS_DISTANCE_ALPHA
// LCS walks the atomic list manually but we want to be compatible with both RW and librw,
// so this code isn't quite original and uses callbacks instead.
static RpAtomic*
SetAtomicDistanceAlphaCB(RpAtomic *atomic, void *data)
{
ATOMICEXT(atomic)->distanceAlpha = *(int*)data;
return atomic;
}
void
CVisibilityPlugins::SetClumpDistanceAlpha(RpClump *clump, int alpha)
{
RpClumpForAllAtomics(clump, SetAtomicDistanceAlphaCB, &alpha);
}
static RpAtomic*
GetAtomicDistanceAlphaCB(RpAtomic *atomic, void *data)
{
*(int*)data = ATOMICEXT(atomic)->distanceAlpha;
return atomic;
}
int
CVisibilityPlugins::GetClumpDistanceAlpha(RpClump *clump)
{
int alpha = 255;
RpClumpForAllAtomics(clump, GetAtomicDistanceAlphaCB, &alpha);
return alpha;
}
void
CVisibilityPlugins::SetObjectDistanceAlpha(RwObject *object, int alpha)
{
if(object == nil)
return;
if(RwObjectGetType(object) == rpATOMIC)
ATOMICEXT(object)->distanceAlpha = alpha;
else
SetClumpDistanceAlpha((RpClump*)object, alpha);
}
int
CVisibilityPlugins::GetObjectDistanceAlpha(RwObject *object)
{
if(object == nil)
return 255;
if(RwObjectGetType(object) == rpATOMIC)
return ATOMICEXT(object)->distanceAlpha;
else
return GetClumpDistanceAlpha((RpClump*)object);
}
#endif