(uint32)ms_streamingBufferSize) {
+ if (i + 1 == ARRAY_SIZE(ms_pStreamingBuffer))
+ continue;
+ else if (!first && streamIds[i+1] != -1)
+ continue;
+ } else {
+ if (i != 0 && streamIds[i-1] != -1 && streamSizes[i-1] > (uint32)ms_streamingBufferSize)
+ continue;
+ }
+ ms_aInfoForModel[streamId].RemoveFromList();
+ DecrementRef(streamId);
+
+ streamIds[i] = streamId;
+ streamSizes[i] = size;
+ streamPoses[i] = posn;
+ CdStreamRead(i, ms_pStreamingBuffer[i], imgOffset+posn, size);
+ processI = i;
+ } else {
+ ms_aInfoForModel[streamId].RemoveFromList();
+ DecrementRef(streamId);
+
+ ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED;
+ streamIds[i] = -1;
+ }
+ } else
+ streamIds[i] = -1;
+ }
+
+ first = false;
+
+ // Now process
+ if (streamIds[processI] == -1)
+ break;
+
+ // Try again on error
+ while (CdStreamSync(processI) != STREAM_NONE) {
+ CdStreamRead(processI, ms_pStreamingBuffer[processI], imgOffset+streamPoses[processI], streamSizes[processI]);
+ }
+ ms_aInfoForModel[streamIds[processI]].m_loadState = STREAMSTATE_READING;
+
+ MakeSpaceFor(streamSizes[processI] * CDSTREAM_SECTOR_SIZE);
+ ConvertBufferToObject(ms_pStreamingBuffer[processI], streamIds[processI]);
+ if(ms_aInfoForModel[streamIds[processI]].m_loadState == STREAMSTATE_STARTED)
+ FinishLoadingLargeFile(ms_pStreamingBuffer[processI], streamIds[processI]);
+
+ if(streamIds[processI] < STREAM_OFFSET_TXD){
+ CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(streamIds[processI]);
+ if(mi->IsSimple())
+ mi->m_alpha = 255;
+ }
+ streamIds[processI] = -1;
+ }
+
+ ms_bLoadingBigModel = false;
+ for(i = 0; i < 4; i++){
+ ms_channel[1].streamIds[i] = -1;
+ ms_channel[1].offsets[i] = -1;
+ }
+ ms_channel[1].state = CHANNELSTATE_IDLE;
+ bInsideLoadAll = false;
+}
+#else
void
CStreaming::LoadAllRequestedModels(bool priority)
{
@@ -1887,6 +2082,7 @@ CStreaming::LoadAllRequestedModels(bool priority)
ms_channel[1].state = CHANNELSTATE_IDLE;
bInsideLoadAll = false;
}
+#endif
void
CStreaming::FlushChannels(void)
@@ -1918,6 +2114,14 @@ CStreaming::FlushRequestList(void)
next = si->m_next;
RemoveModel(si - ms_aInfoForModel);
}
+#ifndef _WIN32
+ if(ms_channel[0].state == CHANNELSTATE_READING) {
+ flushStream[0] = 1;
+ }
+ if(ms_channel[1].state == CHANNELSTATE_READING) {
+ flushStream[1] = 1;
+ }
+#endif
FlushChannels();
}
@@ -1925,19 +2129,25 @@ CStreaming::FlushRequestList(void)
void
CStreaming::ImGonnaUseStreamingMemory(void)
{
- // empty
+ PUSH_MEMID(MEMID_STREAM);
}
void
CStreaming::IHaveUsedStreamingMemory(void)
{
+ POP_MEMID();
UpdateMemoryUsed();
}
void
CStreaming::UpdateMemoryUsed(void)
{
- // empty
+#ifdef USE_CUSTOM_ALLOCATOR
+ ms_memoryUsed =
+ gMainHeap.GetMemoryUsed(MEMID_STREAM) +
+ gMainHeap.GetMemoryUsed(MEMID_STREAM_MODELS) +
+ gMainHeap.GetMemoryUsed(MEMID_STREAM_TEXUTRES);
+#endif
}
#define STREAM_DIST 80.0f
@@ -2440,12 +2650,17 @@ CStreaming::DeleteRwObjectsNotInFrustumInSectorList(CPtrList &list, size_t mem)
void
CStreaming::MakeSpaceFor(int32 size)
{
- // BUG: ms_memoryAvailable can be uninitialized
- // the code still happens to work in that case because ms_memoryAvailable is unsigned
- // but it's not nice....
-
+#ifdef FIX_BUGS
+#define MB (1024 * 1024)
+ if(ms_memoryAvailable == 0) {
+ extern size_t _dwMemAvailPhys;
+ ms_memoryAvailable = (_dwMemAvailPhys - 10 * MB) / 2;
+ if(ms_memoryAvailable < 50 * MB) ms_memoryAvailable = 50 * MB;
+ }
+#undef MB
+#endif
while(ms_memoryUsed >= ms_memoryAvailable - size)
- if(!RemoveLeastUsedModel()){
+ if(!RemoveLeastUsedModel()) {
DeleteRwObjectsBehindCamera(ms_memoryAvailable - size);
return;
}
@@ -2512,3 +2727,71 @@ CStreaming::UpdateForAnimViewer(void)
CStreaming::RetryLoadFile(CStreaming::ms_channelError);
}
}
+
+
+void
+CStreaming::PrintStreamingBufferState()
+{
+ char str[128];
+ wchar wstr[128];
+ uint32 offset, size;
+
+ CTimer::Stop();
+ int i = 0;
+ while (i < NUMSTREAMINFO) {
+ while (true) {
+ int j = 0;
+ DoRWStuffStartOfFrame(50, 50, 50, 0, 0, 0, 255);
+ CPad::UpdatePads();
+ CSprite2d::InitPerFrame();
+ CFont::InitPerFrame();
+ DefinedState();
+
+ CRect unusedRect(0, 0, RsGlobal.maximumWidth, RsGlobal.maximumHeight);
+ CRGBA unusedColor(255, 255, 255, 255);
+ CFont::SetFontStyle(FONT_BANK);
+ CFont::SetBackgroundOff();
+ CFont::SetWrapx(DEFAULT_SCREEN_WIDTH);
+ CFont::SetScale(0.5f, 0.75f);
+ CFont::SetCentreOff();
+ CFont::SetCentreSize(DEFAULT_SCREEN_WIDTH);
+ CFont::SetJustifyOff();
+ CFont::SetColor(CRGBA(200, 200, 200, 200));
+ CFont::SetBackGroundOnlyTextOff();
+ int modelIndex = i;
+ if (modelIndex < NUMSTREAMINFO) {
+ int y = 24;
+ for ( ; j < 34 && modelIndex < NUMSTREAMINFO; modelIndex++) {
+ CStreamingInfo *streamingInfo = &ms_aInfoForModel[modelIndex];
+ CBaseModelInfo *modelInfo = CModelInfo::GetModelInfo(modelIndex);
+ if (streamingInfo->m_loadState != STREAMSTATE_LOADED || !streamingInfo->GetCdPosnAndSize(offset, size))
+ continue;
+
+ if (modelIndex >= STREAM_OFFSET_TXD)
+ sprintf(str, "txd %s, refs %d, size %dK, flags 0x%x", CTxdStore::GetTxdName(modelIndex - STREAM_OFFSET_TXD),
+ CTxdStore::GetNumRefs(modelIndex - STREAM_OFFSET_TXD), 2 * size, streamingInfo->m_flags);
+ else
+ sprintf(str, "model %d,%s, refs%d, size%dK, flags%x", modelIndex, modelInfo->GetName(), modelInfo->GetNumRefs(), 2 * size,
+ streamingInfo->m_flags);
+ AsciiToUnicode(str, wstr);
+ CFont::PrintString(24.0f, y, wstr);
+ y += 12;
+ j++;
+ }
+ }
+
+ if (CPad::GetPad(1)->GetCrossJustDown())
+ i = modelIndex;
+
+ if (!CPad::GetPad(1)->GetTriangleJustDown())
+ break;
+
+ i = 0;
+ CFont::DrawFonts();
+ DoRWStuffEndOfFrame();
+ }
+ CFont::DrawFonts();
+ DoRWStuffEndOfFrame();
+ }
+ CTimer::Update();
+}
\ No newline at end of file
diff --git a/src/core/Streaming.h b/src/core/Streaming.h
index 0b2ff124..ee9183a5 100644
--- a/src/core/Streaming.h
+++ b/src/core/Streaming.h
@@ -188,4 +188,6 @@ public:
static void MemoryCardLoad(uint8 *buffer, uint32 length);
static void UpdateForAnimViewer(void);
+
+ static void PrintStreamingBufferState();
};
diff --git a/src/core/World.cpp b/src/core/World.cpp
index 7f8d8994..b2c1696c 100644
--- a/src/core/World.cpp
+++ b/src/core/World.cpp
@@ -33,7 +33,7 @@
CColPoint gaTempSphereColPoints[MAX_COLLISION_POINTS];
-CPtrList CWorld::ms_bigBuildingsList[4];
+CPtrList CWorld::ms_bigBuildingsList[NUM_LEVELS];
CPtrList CWorld::ms_listMovingEntityPtrs;
CSector CWorld::ms_aSectors[NUMSECTORS_Y][NUMSECTORS_X];
uint16 CWorld::ms_nCurrentScanCode;
@@ -53,6 +53,9 @@ bool CWorld::bIncludeCarTyres;
void
CWorld::Initialise()
{
+#if GTA_VERSION <= GTA3_PS2_160
+ CPools::Initialise();
+#endif
pIgnoreEntity = nil;
bDoingCarCollisions = false;
bSecondShift = false;
@@ -75,7 +78,7 @@ CWorld::Add(CEntity *ent)
if(ent->IsBuilding() || ent->IsDummy()) return;
- if(!ent->IsStatic()) ((CPhysical *)ent)->AddToMovingList();
+ if(!ent->GetIsStatic()) ((CPhysical *)ent)->AddToMovingList();
}
void
@@ -90,7 +93,7 @@ CWorld::Remove(CEntity *ent)
if(ent->IsBuilding() || ent->IsDummy()) return;
- if(!ent->IsStatic()) ((CPhysical *)ent)->RemoveFromMovingList();
+ if(!ent->GetIsStatic()) ((CPhysical *)ent)->RemoveFromMovingList();
}
void
@@ -919,24 +922,24 @@ CEntity *
CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float radius, CEntity *entityToIgnore,
bool ignoreSomeObjects)
{
- static CColModel sphereCol;
+ static CColModel OurColModel;
- sphereCol.boundingSphere.center.x = 0.0f;
- sphereCol.boundingSphere.center.y = 0.0f;
- sphereCol.boundingSphere.center.z = 0.0f;
- sphereCol.boundingSphere.radius = radius;
- sphereCol.boundingBox.min.x = -radius;
- sphereCol.boundingBox.min.y = -radius;
- sphereCol.boundingBox.min.z = -radius;
- sphereCol.boundingBox.max.x = radius;
- sphereCol.boundingBox.max.y = radius;
- sphereCol.boundingBox.max.z = radius;
- sphereCol.numSpheres = 1;
- sphereCol.spheres = &sphereCol.boundingSphere;
- sphereCol.numLines = 0;
- sphereCol.numBoxes = 0;
- sphereCol.numTriangles = 0;
- sphereCol.ownsCollisionVolumes = false;
+ OurColModel.boundingSphere.center.x = 0.0f;
+ OurColModel.boundingSphere.center.y = 0.0f;
+ OurColModel.boundingSphere.center.z = 0.0f;
+ OurColModel.boundingSphere.radius = radius;
+ OurColModel.boundingBox.min.x = -radius;
+ OurColModel.boundingBox.min.y = -radius;
+ OurColModel.boundingBox.min.z = -radius;
+ OurColModel.boundingBox.max.x = radius;
+ OurColModel.boundingBox.max.y = radius;
+ OurColModel.boundingBox.max.z = radius;
+ OurColModel.numSpheres = 1;
+ OurColModel.spheres = &OurColModel.boundingSphere;
+ OurColModel.numLines = 0;
+ OurColModel.numBoxes = 0;
+ OurColModel.numTriangles = 0;
+ OurColModel.ownsCollisionVolumes = false;
CMatrix sphereMat;
sphereMat.SetTranslate(spherePos);
@@ -959,7 +962,7 @@ CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float rad
if(e->GetBoundRadius() + radius > distance) {
CColModel *eCol = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel();
int collidedSpheres =
- CCollision::ProcessColModels(sphereMat, sphereCol, e->GetMatrix(), *eCol,
+ CCollision::ProcessColModels(sphereMat, OurColModel, e->GetMatrix(), *eCol,
gaTempSphereColPoints, nil, nil);
if(collidedSpheres != 0 ||
@@ -1358,102 +1361,6 @@ CWorld::FindMissionEntitiesIntersectingCubeSectorList(CPtrList &list, const CVec
}
}
-CPlayerPed *
-FindPlayerPed(void)
-{
- return CWorld::Players[CWorld::PlayerInFocus].m_pPed;
-}
-
-CVehicle *
-FindPlayerVehicle(void)
-{
- CPlayerPed *ped = FindPlayerPed();
- if(ped && ped->InVehicle()) return ped->m_pMyVehicle;
- return nil;
-}
-
-CVehicle *
-FindPlayerTrain(void)
-{
- if(FindPlayerVehicle() && FindPlayerVehicle()->IsTrain())
- return FindPlayerVehicle();
- else
- return nil;
-}
-
-CEntity *
-FindPlayerEntity(void)
-{
- CPlayerPed *ped = FindPlayerPed();
- if(ped->InVehicle())
- return ped->m_pMyVehicle;
- else
- return ped;
-}
-
-CVector
-FindPlayerCoors(void)
-{
-#ifdef FIX_BUGS
- if (CReplay::IsPlayingBack())
- return TheCamera.GetPosition();
-#endif
- CPlayerPed *ped = FindPlayerPed();
- if(ped->InVehicle())
- return ped->m_pMyVehicle->GetPosition();
- else
- return ped->GetPosition();
-}
-
-CVector &
-FindPlayerSpeed(void)
-{
-#ifdef FIX_BUGS
- static CVector vecTmpVector(0.0f, 0.0f, 0.0f);
- if (CReplay::IsPlayingBack())
- return vecTmpVector;
-#endif
- CPlayerPed *ped = FindPlayerPed();
- if(ped->InVehicle())
- return ped->m_pMyVehicle->m_vecMoveSpeed;
- else
- return ped->m_vecMoveSpeed;
-}
-
-const CVector &
-FindPlayerCentreOfWorld(int32 player)
-{
-#ifdef FIX_BUGS
- if(CReplay::IsPlayingBack()) return TheCamera.GetPosition();
-#endif
- if(CCarCtrl::bCarsGeneratedAroundCamera) return TheCamera.GetPosition();
- if(CWorld::Players[player].m_pRemoteVehicle) return CWorld::Players[player].m_pRemoteVehicle->GetPosition();
- if(FindPlayerVehicle()) return FindPlayerVehicle()->GetPosition();
- return CWorld::Players[player].m_pPed->GetPosition();
-}
-
-const CVector &
-FindPlayerCentreOfWorld_NoSniperShift(void)
-{
-#ifdef FIX_BUGS
- if (CReplay::IsPlayingBack()) return TheCamera.GetPosition();
-#endif
- if(CCarCtrl::bCarsGeneratedAroundCamera) return TheCamera.GetPosition();
- if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle)
- return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetPosition();
- if(FindPlayerVehicle()) return FindPlayerVehicle()->GetPosition();
- return FindPlayerPed()->GetPosition();
-}
-
-float
-FindPlayerHeading(void)
-{
- if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle)
- return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetForward().Heading();
- if(FindPlayerVehicle()) return FindPlayerVehicle()->GetForward().Heading();
- return FindPlayerPed()->GetForward().Heading();
-}
-
void
CWorld::ClearCarsFromArea(float x1, float y1, float z1, float x2, float y2, float z2)
{
@@ -1534,7 +1441,7 @@ CWorld::CallOffChaseForAreaSectorListVehicles(CPtrList &list, float x1, float y1
if(pVehicle->m_scanCode != GetCurrentScanCode()) {
pVehicle->m_scanCode = GetCurrentScanCode();
const CVector &vehiclePos = pVehicle->GetPosition();
- eCarMission carMission = pVehicle->AutoPilot.m_nCarMission;
+ uint8 carMission = pVehicle->AutoPilot.m_nCarMission;
if(pVehicle != FindPlayerVehicle() && vehiclePos.x > fStartX && vehiclePos.x < fEndX &&
vehiclePos.y > fStartY && vehiclePos.y < fEndY && pVehicle->bIsLawEnforcer &&
(carMission == MISSION_RAMPLAYER_FARAWAY || carMission == MISSION_RAMPLAYER_CLOSE ||
@@ -1735,21 +1642,29 @@ CWorld::ShutDown(void)
CWorld::Remove(pEntity);
delete pEntity;
}
+#ifndef FIX_BUGS
pSector->m_lists[ENTITYLIST_BUILDINGS].Flush();
pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].Flush();
pSector->m_lists[ENTITYLIST_DUMMIES].Flush();
pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP].Flush();
+#endif
}
- for(int32 i = 0; i < 4; i++) {
- for(CPtrNode *pNode = GetBigBuildingList((eLevelName)i).first; pNode; pNode = pNode->next) {
+ for(int32 i = 0; i < NUM_LEVELS; i++) {
+ for(CPtrNode *pNode = ms_bigBuildingsList[i].first; pNode; pNode = pNode->next) {
CEntity *pEntity = (CEntity *)pNode->item;
// Maybe remove from world here?
delete pEntity;
}
- GetBigBuildingList((eLevelName)i).Flush();
+ ms_bigBuildingsList[i].Flush();
}
for(int i = 0; i < NUMSECTORS_X * NUMSECTORS_Y; i++) {
CSector *pSector = GetSector(i % NUMSECTORS_X, i / NUMSECTORS_Y);
+#ifdef FIX_BUGS
+ pSector->m_lists[ENTITYLIST_BUILDINGS].Flush();
+ pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].Flush();
+ pSector->m_lists[ENTITYLIST_DUMMIES].Flush();
+ pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP].Flush();
+#endif
if(pSector->m_lists[ENTITYLIST_BUILDINGS].first) {
sprintf(gString, "Building list %d,%d not empty\n", i % NUMSECTORS_X, i / NUMSECTORS_Y);
pSector->m_lists[ENTITYLIST_BUILDINGS].Flush();
@@ -1780,6 +1695,9 @@ CWorld::ShutDown(void)
}
}
ms_listMovingEntityPtrs.Flush();
+#if GTA_VERSION <= GTA3_PS2_160
+ CPools::Shutdown();
+#endif
}
void
@@ -1941,12 +1859,11 @@ CWorld::Process(void)
} else {
for(CPtrNode *node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CEntity *movingEnt = (CEntity *)node->item;
-#ifdef SQUEEZE_PERFORMANCE
- if (movingEnt->bRemoveFromWorld) {
- RemoveEntityInsteadOfProcessingIt(movingEnt);
- } else
-#endif
+#ifdef FIX_BUGS // from VC
+ if(!movingEnt->bRemoveFromWorld && movingEnt->m_rwObject && RwObjectGetType(movingEnt->m_rwObject) == rpCLUMP &&
+#else
if(movingEnt->m_rwObject && RwObjectGetType(movingEnt->m_rwObject) == rpCLUMP &&
+#endif
RpAnimBlendClumpGetFirstAssociation(movingEnt->GetClump())) {
RpAnimBlendClumpUpdateAnimations(movingEnt->GetClump(),
0.02f * (movingEnt->IsObject()
@@ -1960,7 +1877,7 @@ CWorld::Process(void)
RemoveEntityInsteadOfProcessingIt(movingEnt);
} else {
movingEnt->ProcessControl();
- if(movingEnt->IsStatic()) { movingEnt->RemoveFromMovingList(); }
+ if(movingEnt->GetIsStatic()) { movingEnt->RemoveFromMovingList(); }
}
}
bForceProcessControl = true;
@@ -1971,7 +1888,7 @@ CWorld::Process(void)
RemoveEntityInsteadOfProcessingIt(movingEnt);
} else {
movingEnt->ProcessControl();
- if(movingEnt->IsStatic()) { movingEnt->RemoveFromMovingList(); }
+ if(movingEnt->GetIsStatic()) { movingEnt->RemoveFromMovingList(); }
}
}
}
@@ -2124,13 +2041,13 @@ CWorld::TriggerExplosionSectorList(CPtrList &list, const CVector &position, floa
CObject *pObject = (CObject *)pEntity;
CVehicle *pVehicle = (CVehicle *)pEntity;
if(!pEntity->bExplosionProof && (!pEntity->IsPed() || !pPed->bInVehicle)) {
- if(pEntity->IsStatic()) {
+ if(pEntity->GetIsStatic()) {
if(pEntity->IsObject()) {
if (fPower > pObject->m_fUprootLimit || IsFence(pObject->GetModelIndex())) {
if (IsGlass(pObject->GetModelIndex())) {
CGlass::WindowRespondsToExplosion(pObject, position);
} else {
- pObject->bIsStatic = false;
+ pObject->SetIsStatic(false);
pObject->AddToMovingList();
int16 modelId = pEntity->GetModelIndex();
if(modelId != MI_FIRE_HYDRANT ||
@@ -2148,18 +2065,18 @@ CWorld::TriggerExplosionSectorList(CPtrList &list, const CVector &position, floa
}
}
}
- if(pEntity->IsStatic()) {
+ if(pEntity->GetIsStatic()) {
float fDamageMultiplier =
(fRadius - fMagnitude) * 2.0f / fRadius;
float fDamage = 300.0f * Min(fDamageMultiplier, 1.0f);
pObject->ObjectDamage(fDamage);
}
} else {
- pEntity->bIsStatic = false;
+ pEntity->SetIsStatic(false);
pEntity->AddToMovingList();
}
}
- if(!pEntity->IsStatic()) {
+ if(!pEntity->GetIsStatic()) {
float fDamageMultiplier = Min((fRadius - fMagnitude) * 2.0f / fRadius, 1.0f);
CVector vecForceDir =
vecDistance * (fPower * pEntity->m_fMass * 0.00071429f * fDamageMultiplier /
diff --git a/src/core/World.h b/src/core/World.h
index 9465a914..9d62e79b 100644
--- a/src/core/World.h
+++ b/src/core/World.h
@@ -55,7 +55,7 @@ struct CStoredCollPoly;
class CWorld
{
- static CPtrList ms_bigBuildingsList[4];
+ static CPtrList ms_bigBuildingsList[NUM_LEVELS];
static CPtrList ms_listMovingEntityPtrs;
static CSector ms_aSectors[NUMSECTORS_Y][NUMSECTORS_X];
static uint16 ms_nCurrentScanCode;
@@ -157,14 +157,3 @@ public:
extern CColPoint gaTempSphereColPoints[MAX_COLLISION_POINTS];
-class CPlayerPed;
-class CVehicle;
-CPlayerPed *FindPlayerPed(void);
-CVehicle *FindPlayerVehicle(void);
-CVehicle *FindPlayerTrain(void);
-CEntity *FindPlayerEntity(void);
-CVector FindPlayerCoors(void);
-CVector &FindPlayerSpeed(void);
-const CVector &FindPlayerCentreOfWorld(int32 player);
-const CVector &FindPlayerCentreOfWorld_NoSniperShift(void);
-float FindPlayerHeading(void);
diff --git a/src/core/ZoneCull.cpp b/src/core/ZoneCull.cpp
index f2ae8dba..4b03ba90 100644
--- a/src/core/ZoneCull.cpp
+++ b/src/core/ZoneCull.cpp
@@ -1,5 +1,6 @@
#include "common.h"
+#include "General.h"
#include "Building.h"
#include "Treadable.h"
#include "Train.h"
@@ -11,6 +12,9 @@
#include "ZoneCull.h"
#include "Zones.h"
+#include "Debug.h"
+#include "Renderer.h"
+
int32 CCullZones::NumCullZones;
CCullZone CCullZones::aZones[NUMCULLZONES];
int32 CCullZones::NumAttributeZones;
@@ -27,6 +31,8 @@ int32 CCullZones::EntityIndicesUsed;
bool CCullZones::bCurrentSubwayIsInvisible;
bool CCullZones::bCullZonesDisabled;
+#define NUMUNCOMPRESSED (6000)
+#define NUMTEMPINDICES (140000)
void
CCullZones::Init(void)
@@ -48,26 +54,6 @@ CCullZones::Init(void)
aPointersToBigBuildingsForTreadables[i] = -1;
}
-bool CCullZone::TestLine(CVector vec1, CVector vec2)
-{
- CColPoint colPoint;
- CEntity *entity;
-
- if (CWorld::ProcessLineOfSight(vec1, vec2, colPoint, entity, true, false, false, false, false, true, false))
- return true;
- if (CWorld::ProcessLineOfSight(CVector(vec1.x + 0.05f, vec1.y, vec1.z), CVector(vec2.x + 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false))
- return true;
- if (CWorld::ProcessLineOfSight(CVector(vec1.x - 0.05f, vec1.y, vec1.z), CVector(vec2.x - 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false))
- return true;
- if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y + 0.05f, vec1.z), CVector(vec2.x, vec2.y + 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false))
- return true;
- if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y - 0.05f, vec1.z), CVector(vec2.x, vec2.y - 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false))
- return true;
- if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z + 0.05f), CVector(vec2.x, vec2.y, vec2.z + 0.05f), colPoint, entity, true, false, false, false, false, true, false))
- return true;
- return CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z - 0.05f), CVector(vec2.x, vec2.y, vec2.z - 0.05f), colPoint, entity, true, false, false, false, false, true, false);
-}
-
uint16* pTempArrayIndices;
int TempEntityIndicesUsed;
@@ -131,19 +117,25 @@ CCullZones::ResolveVisibilities(void)
aPointersToBigBuildingsForTreadables[i] = BSWAP16(aPointersToBigBuildingsForTreadables[i]);
#endif
}else{
-#if 0
- // TODO: implement code from mobile to generate data here
+#ifndef MASTER
EntityIndicesUsed = 0;
BuildListForBigBuildings();
- pTempArrayIndices = new uint16[140000];
+ pTempArrayIndices = new uint16[NUMTEMPINDICES];
TempEntityIndicesUsed = 0;
- for (int i = 0; i < NumCullZones; i++) {
- DoVisibilityTestCullZone(i, true);
+// if(!LoadTempFile()) // not in final game
+ {
+ for (int i = 0; i < NumCullZones; i++) {
+//printf("testing zone %d (%d indices)\n", i, TempEntityIndicesUsed);
+ DoVisibilityTestCullZone(i, true);
+ }
+
+// SaveTempFile(); // not in final game
}
CompressIndicesArray();
delete[] pTempArrayIndices;
+ pTempArrayIndices = nil;
fd = CFileMgr::OpenFileForWriting("data\\cullzone.dat");
if (fd != 0) {
@@ -160,16 +152,53 @@ CCullZones::ResolveVisibilities(void)
}
}
+bool
+CCullZones::LoadTempFile(void)
+{
+ int fd = CFileMgr::OpenFile("cullzone.tmp");
+ if (fd != 0) {
+ CFileMgr::Read(fd, (char*)&NumCullZones, sizeof(NumCullZones));
+ CFileMgr::Read(fd, (char*)aZones, sizeof(aZones));
+ CFileMgr::Read(fd, (char*)&NumAttributeZones, sizeof(NumAttributeZones));
+ CFileMgr::Read(fd, (char*)&aAttributeZones, sizeof(aAttributeZones));
+ CFileMgr::Read(fd, (char*)pTempArrayIndices, NUMTEMPINDICES*sizeof(uint16));
+ CFileMgr::Read(fd, (char*)&TempEntityIndicesUsed, sizeof(TempEntityIndicesUsed));
+ CFileMgr::Read(fd, (char*)&aPointersToBigBuildingsForBuildings, sizeof(aPointersToBigBuildingsForBuildings));
+ CFileMgr::Read(fd, (char*)&aPointersToBigBuildingsForTreadables, sizeof(aPointersToBigBuildingsForTreadables));
+ CFileMgr::CloseFile(fd);
+ return true;
+ }
+ return false;
+}
+
+void
+CCullZones::SaveTempFile(void)
+{
+ int fd = CFileMgr::OpenFileForWriting("cullzone.tmp");
+ if (fd != 0) {
+ CFileMgr::Write(fd, (char*)&NumCullZones, sizeof(NumCullZones));
+ CFileMgr::Write(fd, (char*)aZones, sizeof(aZones));
+ CFileMgr::Write(fd, (char*)&NumAttributeZones, sizeof(NumAttributeZones));
+ CFileMgr::Write(fd, (char*)&aAttributeZones, sizeof(aAttributeZones));
+ CFileMgr::Write(fd, (char*)pTempArrayIndices, NUMTEMPINDICES*sizeof(uint16));
+ CFileMgr::Write(fd, (char*)&TempEntityIndicesUsed, sizeof(TempEntityIndicesUsed));
+ CFileMgr::Write(fd, (char*)&aPointersToBigBuildingsForBuildings, sizeof(aPointersToBigBuildingsForBuildings));
+ CFileMgr::Write(fd, (char*)&aPointersToBigBuildingsForTreadables, sizeof(aPointersToBigBuildingsForTreadables));
+ CFileMgr::CloseFile(fd);
+ }
+}
+
+
void
CCullZones::BuildListForBigBuildings()
{
for (int i = CPools::GetBuildingPool()->GetSize()-1; i >= 0; i--) {
CBuilding *building = CPools::GetBuildingPool()->GetSlot(i);
if (building == nil || !building->bIsBIGBuilding) continue;
- CSimpleModelInfo *nonlod = (CSimpleModelInfo*)((CSimpleModelInfo *)CModelInfo::GetModelInfo(building->GetModelIndex()))->m_atomics[2];
+ CSimpleModelInfo *nonlod = ((CSimpleModelInfo *)CModelInfo::GetModelInfo(building->GetModelIndex()))->GetRelatedModel();
if (nonlod == nil) continue;
- for (int j = i; j >= 0; j--) {
+ for (int j = CPools::GetBuildingPool()->GetSize()-1; j >= 0; j--) {
CBuilding *building2 = CPools::GetBuildingPool()->GetSlot(j);
if (building2 == nil || building2->bIsBIGBuilding) continue;
if (CModelInfo::GetModelInfo(building2->GetModelIndex()) == nonlod) {
@@ -192,7 +221,7 @@ CCullZones::BuildListForBigBuildings()
}
void
-CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt)
+CCullZones::DoVisibilityTestCullZone(int zoneId, bool findIndices)
{
aZones[zoneId].m_groupIndexCount[0] = 0;
aZones[zoneId].m_groupIndexCount[1] = 0;
@@ -200,16 +229,17 @@ CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt)
aZones[zoneId].m_indexStart = TempEntityIndicesUsed;
aZones[zoneId].FindTestPoints();
- if (!doIt) return;
+ if (!findIndices) return;
for (int i = CPools::GetBuildingPool()->GetSize() - 1; i >= 0; i--) {
CBuilding *building = CPools::GetBuildingPool()->GetSlot(i);
if (building != nil && !building->bIsBIGBuilding && aZones[zoneId].IsEntityCloseEnoughToZone(building, aPointersToBigBuildingsForBuildings[i] != -1)) {
- CBuilding *building2 = nil;
+ CBuilding *LODbuilding = nil;
if (aPointersToBigBuildingsForBuildings[i] != -1)
- building2 = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForBuildings[i]);
+ LODbuilding = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForBuildings[i]);
- if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, building2)) {
+ if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, LODbuilding)) {
+ assert(TempEntityIndicesUsed < NUMTEMPINDICES);
pTempArrayIndices[TempEntityIndicesUsed++] = i;
aZones[zoneId].m_groupIndexCount[0]++;
}
@@ -217,13 +247,14 @@ CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt)
}
for (int i = CPools::GetTreadablePool()->GetSize() - 1; i >= 0; i--) {
- CTreadable* building = CPools::GetTreadablePool()->GetSlot(i);
+ CBuilding* building = CPools::GetTreadablePool()->GetSlot(i);
if (building != nil && aZones[zoneId].IsEntityCloseEnoughToZone(building, aPointersToBigBuildingsForTreadables[i] != -1)) {
- CTreadable* building2 = nil;
+ CBuilding *LODbuilding = nil;
if (aPointersToBigBuildingsForTreadables[i] != -1)
- building2 = CPools::GetTreadablePool()->GetSlot(aPointersToBigBuildingsForTreadables[i]);
+ LODbuilding = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForTreadables[i]);
- if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 10.0f, building2)) {
+ if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 10.0f, LODbuilding)) {
+ assert(TempEntityIndicesUsed < NUMTEMPINDICES);
pTempArrayIndices[TempEntityIndicesUsed++] = i;
aZones[zoneId].m_groupIndexCount[1]++;
}
@@ -231,23 +262,28 @@ CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt)
}
for (int i = CPools::GetTreadablePool()->GetSize() - 1; i >= 0; i--) {
- CTreadable *building = CPools::GetTreadablePool()->GetSlot(i);
- if (building != nil && aZones[zoneId].CalcDistToCullZoneSquared(building->GetPosition().x, building->GetPosition().y) < 40000.0f) {
+ CBuilding *building = CPools::GetTreadablePool()->GetSlot(i);
+ if (building != nil && aZones[zoneId].CalcDistToCullZoneSquared(building->GetPosition().x, building->GetPosition().y) < SQR(200.0f)) {
int start = aZones[zoneId].m_groupIndexCount[0] + aZones[zoneId].m_indexStart;
int end = aZones[zoneId].m_groupIndexCount[1] + start;
bool alreadyAdded = false;
for (int k = start; k < end; k++) {
+#ifdef FIX_BUGS
+ if (pTempArrayIndices[k] == i)
+#else
if (aIndices[k] == i)
+#endif
alreadyAdded = true;
}
if (!alreadyAdded) {
- CBuilding *building2 = nil;
+ CBuilding *LODbuilding = nil;
if (aPointersToBigBuildingsForTreadables[i] != -1)
- building2 = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForTreadables[i]);
- if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, building2)) {
+ LODbuilding = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForTreadables[i]);
+ if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, LODbuilding)) {
+ assert(TempEntityIndicesUsed < NUMTEMPINDICES);
pTempArrayIndices[TempEntityIndicesUsed++] = i;
aZones[zoneId].m_groupIndexCount[2]++;
}
@@ -395,7 +431,9 @@ CCullZones::AddCullZone(CVector const &position,
if((flag & ATTRZONE_NOTCULLZONE) == 0){
cull = &aZones[NumCullZones++];
v = position;
- // WTF is this?
+ // reposition start point to the start/end of the
+ // alley next to the big building in the industrial district.
+ // probably isn't analyzed correctly otherwise?s
if((v-CVector(1032.14f, -624.255f, 24.93f)).Magnitude() < 1.0f)
v = CVector(1061.7f, -613.0f, 19.0f);
if((v-CVector(1029.48f, -495.757f, 21.98f)).Magnitude() < 1.0f)
@@ -427,6 +465,208 @@ CCullZones::AddCullZone(CVector const &position,
}
}
+uint16 *pExtraArrayIndices;
+
+void
+CCullZones::CompressIndicesArray()
+{
+ uint16 set[3];
+
+ // These are used to hold the compressed groups in sets of 3
+ int numExtraIndices = 0;
+ pExtraArrayIndices = new uint16[NUMTEMPINDICES];
+
+ for(int numOccurrences = 6; numOccurrences > 1; numOccurrences--){
+ if(NumCullZones == 0)
+ break;
+
+//printf("checking occurrences %d\n", numOccurrences);
+ int attempt = 0;
+ while(attempt < 10000){
+ for(;;){
+ attempt++;
+
+ int zone = CGeneral::GetRandomNumber() % NumCullZones;
+ int group = CGeneral::GetRandomNumber() % 3;
+ if(!PickRandomSetForGroup(zone, group, set))
+ break;
+ if(!DoWeHaveMoreThanXOccurencesOfSet(numOccurrences, set))
+ break;
+
+ // add this set
+ attempt = 1;
+ int setId = numExtraIndices + NUMUNCOMPRESSED;
+ pExtraArrayIndices[numExtraIndices++] = set[0];
+ pExtraArrayIndices[numExtraIndices++] = set[1];
+ pExtraArrayIndices[numExtraIndices++] = set[2];
+ ReplaceSetForAllGroups(set, setId);
+ }
+ }
+ }
+
+ TidyUpAndMergeLists(pExtraArrayIndices, numExtraIndices);
+
+ delete[] pExtraArrayIndices;
+}
+
+// Get three random indices for this group of a zone
+bool
+CCullZones::PickRandomSetForGroup(int32 zone, int32 group, uint16 *set)
+{
+ int32 start;
+ int32 size;
+
+ aZones[zone].GetGroupStartAndSize(group, start, size);
+ if(size <= 0)
+ return false;
+
+ int numIndices = 0;
+ for(int i = 0; i < size; i++)
+ if(pTempArrayIndices[start + i] != 0xFFFF)
+ numIndices++;
+ if(numIndices < 3)
+ return false;
+
+ int first = CGeneral::GetRandomNumber() % (numIndices-2);
+
+ numIndices = 0;
+ int n = 0;
+ for(int i = 0; i < size; i++)
+ if(pTempArrayIndices[start + i] != 0xFFFF){
+ if(n++ < first) continue;
+
+ set[numIndices++] = pTempArrayIndices[start + i];
+ if(numIndices == 3)
+ break;
+ }
+ return true;
+}
+
+bool
+CCullZones::DoWeHaveMoreThanXOccurencesOfSet(int32 count, uint16 *set)
+{
+ int32 curCount;
+ int32 start;
+ int32 size;
+
+ curCount = 0;
+ for (int i = 0; i < NumCullZones; i++) {
+ for (int group = 0; group < 3; group++) {
+ aZones[i].GetGroupStartAndSize(group, start, size);
+ if(size <= 0) continue;
+
+ // check if the set is a subset of the group
+ int n = 0;
+ for (int j = 0; j < size; j++) {
+ for (int k = 0; k < 3; k++) {
+ if (pTempArrayIndices[start+j] == set[k])
+ n++;
+ }
+ }
+ // yes it is
+ if(n == 3){
+ curCount++;
+ // check if we have seen this set often enough
+ if(curCount >= count)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void
+CCullZones::ReplaceSetForAllGroups(uint16 *set, uint16 setid)
+{
+ int32 start;
+ int32 size;
+
+ for(int i = 0; i < NumCullZones; i++)
+ for(int group = 0; group < 3; group++){
+ aZones[i].GetGroupStartAndSize(group, start, size);
+ if(size <= 0) continue;
+
+ // check if the set is a subset of the group
+ int n = 0;
+ for(int j = 0; j < size; j++){
+ for(int k = 0; k < 3; k++){
+ if(pTempArrayIndices[start+j] == set[k])
+ n++;
+ }
+ }
+
+ // yes it is, so replace it
+ if(n == 3){
+ bool insertedSet = false;
+ for(int j = 0; j < size; j++){
+ for(int k = 0; k < 3; k++){
+ // replace first element by set, invalidate others
+ if(pTempArrayIndices[start+j] == set[k]){
+ if(!insertedSet)
+ pTempArrayIndices[start+j] = setid;
+ else
+ pTempArrayIndices[start+j] = 0xFFFF;
+ insertedSet = true;
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+CCullZones::TidyUpAndMergeLists(uint16 *extraIndices, int32 numExtraIndices)
+{
+ int numTempIndices = 0;
+ for(int i = 0; i < TempEntityIndicesUsed; i++)
+ if(pTempArrayIndices[i] != 0xFFFF)
+ numTempIndices++;
+
+ // Fix up zone ranges such that there are no holes
+ for(int i = 0; i < NumCullZones; i++){
+ int j;
+ int start = 0;
+ for(j = 0; j < aZones[i].m_indexStart; j++)
+ if(pTempArrayIndices[j] != 0xFFFF)
+ start++;
+
+ aZones[i].m_indexStart = start;
+ aZones[i].m_numBuildings = 0;
+ aZones[i].m_numTreadablesPlus10m = 0;
+ aZones[i].m_numTreadables = 0;
+
+ for(int k = 0; k < aZones[i].m_groupIndexCount[0]; k++)
+ if(pTempArrayIndices[j++] != 0xFFFF)
+ aZones[i].m_numBuildings++;
+ for(int k = 0; k < aZones[i].m_groupIndexCount[1]; k++)
+ if(pTempArrayIndices[j++] != 0xFFFF)
+ aZones[i].m_numTreadablesPlus10m++;
+ for(int k = 0; k < aZones[i].m_groupIndexCount[2]; k++)
+ if(pTempArrayIndices[j++] != 0xFFFF)
+ aZones[i].m_numTreadables++;
+ }
+
+ // Now copy the actually used indices
+ EntityIndicesUsed = 0;
+ for(int i = 0; i < TempEntityIndicesUsed; i++)
+ if(pTempArrayIndices[i] != 0xFFFF){
+ assert(EntityIndicesUsed < NUMZONEINDICES);
+ if(pTempArrayIndices[i] < NUMUNCOMPRESSED)
+ aIndices[EntityIndicesUsed++] = pTempArrayIndices[i];
+ else
+ aIndices[EntityIndicesUsed++] = pTempArrayIndices[i] + numTempIndices;
+ }
+ for(int i = 0; i < numExtraIndices; i++)
+ if(extraIndices[i] != 0xFFFF){
+ assert(EntityIndicesUsed < NUMZONEINDICES);
+ if(extraIndices[i] < NUMUNCOMPRESSED)
+ aIndices[EntityIndicesUsed++] = extraIndices[i];
+ else
+ aIndices[EntityIndicesUsed++] = extraIndices[i] + numTempIndices;
+ }
+}
+
+
void
CCullZone::DoStuffLeavingZone(void)
@@ -445,13 +685,14 @@ CCullZone::DoStuffLeavingZone_OneBuilding(uint16 i)
int16 bb;
int j;
- if(i < 6000){
+
+ if(i < NUMUNCOMPRESSED){
CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = false;
bb = CCullZones::aPointersToBigBuildingsForBuildings[i];
if(bb != -1)
CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false;
}else{
- i -= 6000;
+ i -= NUMUNCOMPRESSED;
for(j = 0; j < 3; j++)
DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]);
}
@@ -463,14 +704,14 @@ CCullZone::DoStuffLeavingZone_OneTreadableBoth(uint16 i)
int16 bb;
int j;
- if(i < 6000){
+ if(i < NUMUNCOMPRESSED){
CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = false;
CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = false;
bb = CCullZones::aPointersToBigBuildingsForTreadables[i];
if(bb != -1)
CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false;
}else{
- i -= 6000;
+ i -= NUMUNCOMPRESSED;
for(j = 0; j < 3; j++)
DoStuffLeavingZone_OneTreadableBoth(CCullZones::aIndices[i+j]);
}
@@ -495,13 +736,13 @@ CCullZone::DoStuffEnteringZone_OneBuilding(uint16 i)
int16 bb;
int j;
- if(i < 6000){
+ if(i < NUMUNCOMPRESSED){
CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = true;
bb = CCullZones::aPointersToBigBuildingsForBuildings[i];
if(bb != -1)
CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true;
}else{
- i -= 6000;
+ i -= NUMUNCOMPRESSED;
for(j = 0; j < 3; j++)
DoStuffEnteringZone_OneBuilding(CCullZones::aIndices[i+j]);
}
@@ -513,14 +754,14 @@ CCullZone::DoStuffEnteringZone_OneTreadablePlus10m(uint16 i)
int16 bb;
int j;
- if(i < 6000){
+ if(i < NUMUNCOMPRESSED){
CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true;
CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = true;
bb = CCullZones::aPointersToBigBuildingsForTreadables[i];
if(bb != -1)
CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true;
}else{
- i -= 6000;
+ i -= NUMUNCOMPRESSED;
for(j = 0; j < 3; j++)
DoStuffEnteringZone_OneTreadablePlus10m(CCullZones::aIndices[i+j]);
}
@@ -532,13 +773,13 @@ CCullZone::DoStuffEnteringZone_OneTreadable(uint16 i)
int16 bb;
int j;
- if(i < 6000){
+ if(i < NUMUNCOMPRESSED){
CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true;
bb = CCullZones::aPointersToBigBuildingsForTreadables[i];
if(bb != -1)
CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true;
}else{
- i -= 6000;
+ i -= NUMUNCOMPRESSED;
for(j = 0; j < 3; j++)
DoStuffEnteringZone_OneTreadable(CCullZones::aIndices[i+j]);
}
@@ -560,6 +801,68 @@ CCullZone::CalcDistToCullZoneSquared(float x, float y)
return rx + ry;
}
+bool
+CCullZone::TestLine(CVector vec1, CVector vec2)
+{
+ CColPoint colPoint;
+ CEntity *entity;
+
+ if (CWorld::ProcessLineOfSight(vec1, vec2, colPoint, entity, true, false, false, false, false, true, false))
+ return true;
+ if (CWorld::ProcessLineOfSight(CVector(vec1.x + 0.05f, vec1.y, vec1.z), CVector(vec2.x + 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false))
+ return true;
+ if (CWorld::ProcessLineOfSight(CVector(vec1.x - 0.05f, vec1.y, vec1.z), CVector(vec2.x - 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false))
+ return true;
+ if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y + 0.05f, vec1.z), CVector(vec2.x, vec2.y + 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false))
+ return true;
+ if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y - 0.05f, vec1.z), CVector(vec2.x, vec2.y - 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false))
+ return true;
+ if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z + 0.05f), CVector(vec2.x, vec2.y, vec2.z + 0.05f), colPoint, entity, true, false, false, false, false, true, false))
+ return true;
+ return CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z - 0.05f), CVector(vec2.x, vec2.y, vec2.z - 0.05f), colPoint, entity, true, false, false, false, false, true, false);
+}
+
+bool
+CCullZone::DoThoroughLineTest(CVector start, CVector end, CEntity *testEntity)
+{
+ CColPoint colPoint;
+ CEntity *entity;
+
+ if(CWorld::ProcessLineOfSight(start, end, colPoint, entity, true, false, false, false, false, true, false) &&
+ testEntity != entity)
+ return false;
+
+ CVector side;
+#ifdef FIX_BUGS
+ if(start.x != end.x || start.y != end.y)
+#else
+ if(start.x != end.x && start.y != end.y)
+#endif
+ side = CVector(0.0f, 0.0f, 1.0f);
+ else
+ side = CVector(1.0f, 0.0f, 0.0f);
+ CVector up = CrossProduct(side, end - start);
+ side = CrossProduct(up, end - start);
+ side.Normalise();
+ up.Normalise();
+ side *= 0.1f;
+ up *= 0.1f;
+
+ if(CWorld::ProcessLineOfSight(start+side, end+side, colPoint, entity, true, false, false, false, false, true, false) &&
+ testEntity != entity)
+ return false;
+ if(CWorld::ProcessLineOfSight(start-side, end-side, colPoint, entity, true, false, false, false, false, true, false) &&
+ testEntity != entity)
+ return false;
+ if(CWorld::ProcessLineOfSight(start+up, end+up, colPoint, entity, true, false, false, false, false, true, false) &&
+ testEntity != entity)
+ return false;
+ if(CWorld::ProcessLineOfSight(start-up, end-up, colPoint, entity, true, false, false, false, false, true, false) &&
+ testEntity != entity)
+ return false;
+ return true;
+}
+
bool
CCullZone::IsEntityCloseEnoughToZone(CEntity *entity, bool checkLevel)
{
@@ -568,10 +871,10 @@ CCullZone::IsEntityCloseEnoughToZone(CEntity *entity, bool checkLevel)
CSimpleModelInfo *minfo = (CSimpleModelInfo*)CModelInfo::GetModelInfo(entity->GetModelIndex());
float distToZone = CalcDistToCullZone(pos.x, pos.y);
float lodDist;
- if (minfo->m_isSubway)
- lodDist = minfo->GetLargestLodDistance() + 30.0f;
+ if (minfo->m_noFade)
+ lodDist = minfo->GetLargestLodDistance() + STREAM_DISTANCE;
else
- lodDist = minfo->GetLargestLodDistance() + 50.0f;
+ lodDist = minfo->GetLargestLodDistance() + STREAM_DISTANCE + FADE_DISTANCE;
if (lodDist > distToZone) return true;
if (!checkLevel) return false;
@@ -580,27 +883,749 @@ CCullZone::IsEntityCloseEnoughToZone(CEntity *entity, bool checkLevel)
}
bool
-CCullZones::DoWeHaveMoreThanXOccurencesOfSet(int32 count, uint16 *set)
+CCullZone::PointFallsWithinZone(CVector pos, float radius)
{
- int32 curCount;
- int32 start;
- int32 size;
+ if(minx - radius > pos.x ||
+ maxx + radius < pos.x ||
+ miny - radius > pos.y ||
+ maxy + radius < pos.y ||
+ minz - radius > pos.z ||
+ maxz + radius < pos.z)
+ return false;
+ return true;
+}
- for (int i = 0; i < NumCullZones; i++) {
- curCount = 0;
- for (int group = 0; group < 3; group++) {
- aZones[i].GetGroupStartAndSize(group, start, size);
- int unk = 0; // TODO: figure out
- for (int j = 0; j < size; j++) {
- for (int k = 0; k < 3; k++) {
- if (set[k] == pTempArrayIndices[start+j])
- unk++;
+CVector ExtraFudgePointsCoors[] = {
+ CVector(978.0, -394.0, 18.0),
+ CVector(1189.7, -414.6, 27.0),
+ CVector(978.8, -391.0, 19.0),
+ CVector(1199.0, -502.3, 28.0),
+ CVector(1037.0, -391.9, 18.4),
+ CVector(1140.0, -608.7, 16.0),
+ CVector(1051.0, -26.0, 11.0),
+ CVector(951.5, -345.1, 12.0),
+ CVector(958.2, -394.6, 16.0),
+ CVector(1036.5, -390.0, 15.2),
+ CVector(960.6, -390.5, 20.9),
+ CVector(1061.0, -640.6, 16.3),
+ CVector(1034.5, -388.96, 14.78),
+ CVector(1038.4, -13.98, 12.2),
+ CVector(1047.2, -16.7, 10.6),
+ CVector(1257.9, -333.3, 40.0),
+ CVector(885.6, -424.9, 17.0),
+ CVector(1127.5, -795.8, 17.7),
+ CVector(1133.0, -716.0, 19.0),
+ CVector(1125.0, -694.0, 18.5),
+ CVector(1125.0, -670.0, 16.3),
+ CVector(1051.6, 36.3, 17.9),
+ CVector(1054.6, -11.4, 15.0),
+ CVector(1058.9, -278.0, 15.0),
+ CVector(1059.4, -261.0, 10.9),
+ CVector(1051.5, -638.5, 16.5),
+ CVector(1058.2, -643.4, 15.5),
+ CVector(1058.2, -643.4, 18.0),
+ CVector(826.0, -260.0, 7.0),
+ CVector(826.0, -260.0, 11.0),
+ CVector(833.0, -603.6, 16.4),
+ CVector(833.0, -603.6, 20.0),
+ CVector(1002.0, -318.5, 10.5),
+ CVector(998.0, -318.0, 9.8),
+ CVector(1127.0, -183.0, 18.1),
+ CVector(1123.0, -331.5, 23.8),
+ CVector(1123.8, -429.0, 24.0),
+ CVector(1197.0, -30.0, 13.7),
+ CVector(1117.5, -230.0, 17.3),
+ CVector(1117.5, -230.0, 20.0),
+ CVector(1120.0, -281.6, 21.5),
+ CVector(1120.0, -281.6, 24.0),
+ CVector(1084.5, -1022.7, 17.0),
+ CVector(1071.5, 5.4, 4.6),
+ CVector(1177.2, -215.7, 27.6),
+ CVector(841.6, -460.0, 19.7),
+ CVector(874.8, -456.6, 16.6),
+ CVector(918.3, -451.8, 17.8),
+ CVector(844.0, -495.7, 16.7),
+ CVector(842.0, -493.4, 21.0),
+ CVector(1433.5, -774.4, 16.9),
+ CVector(1051.0, -205.0, 7.5),
+ CVector(885.5, -425.6, 15.6),
+ CVector(182.6, -470.4, 27.8),
+ CVector(132.5, -930.2, 29.0),
+ CVector(124.7, -904.0, 28.0),
+ CVector(-50.0, -686.0, 22.0),
+ CVector(-49.1, -694.5, 22.5),
+ CVector(1063.8, -404.45, 16.2),
+ CVector(1062.2, -405.5, 17.0)
+};
+int32 NumTestPoints;
+int32 aTestPointsX[100];
+int32 aTestPointsY[100];
+int32 aTestPointsZ[100];
+CVector aTestPoints[100];
+int32 ElementsX, ElementsY, ElementsZ;
+float StepX, StepY, StepZ;
+int32 Memsize;
+uint8 *pMem;
+#define MEM(x, y, z) pMem[((x)*ElementsY + (y))*ElementsZ + (z)]
+#define FLAG_FREE 1
+#define FLAG_PROCESSED 2
+
+int32 MinValX, MaxValX;
+int32 MinValY, MaxValY;
+int32 MinValZ, MaxValZ;
+int32 Point1, Point2;
+int32 NewPointX, NewPointY, NewPointZ;
+
+
+void
+CCullZone::FindTestPoints()
+{
+ static int CZNumber;
+
+ NumTestPoints = 0;
+ ElementsX = (maxx-minx) < 1.0f ? 2 : (maxx-minx)+1.0f;
+ ElementsY = (maxy-miny) < 1.0f ? 2 : (maxy-miny)+1.0f;
+ ElementsZ = (maxz-minz) < 1.0f ? 2 : (maxz-minz)+1.0f;
+ if(ElementsX > 32) ElementsX = 32;
+ if(ElementsY > 32) ElementsY = 32;
+ if(ElementsZ > 32) ElementsZ = 32;
+ Memsize = ElementsX * ElementsY * ElementsZ;
+ StepX = (maxx-minx)/(ElementsX-1);
+ StepY = (maxy-miny)/(ElementsY-1);
+ StepZ = (maxz-minz)/(ElementsZ-1);
+
+ pMem = new uint8[Memsize];
+ memset(pMem, 0, Memsize);
+
+ // indices of center
+ int x = ElementsX * (position.x-minx)/(maxx-minx);
+ x = clamp(x, 0, ElementsX-1);
+ int y = ElementsY * (position.y-miny)/(maxy-miny);
+ y = clamp(y, 0, ElementsY-1);
+ int z = ElementsZ * (position.z-minz)/(maxz-minz);
+ z = clamp(z, 0, ElementsZ-1);
+
+ // Mark which test points inside the zone are not occupied by buildings.
+ // To do this, mark the start point as free and do a food fill.
+
+ // NB: we just assume the start position is free here!
+ MEM(x, y, z) |= FLAG_FREE;
+ aTestPointsX[NumTestPoints] = x;
+ aTestPointsY[NumTestPoints] = y;
+ aTestPointsZ[NumTestPoints] = z;
+ NumTestPoints++;
+
+ bool notDoneYet;
+ do{
+ notDoneYet = false;
+ for(x = 0; x < ElementsX; x++){
+ for(y = 0; y < ElementsY; y++){
+ for(z = 0; z < ElementsZ; z++){
+ if(!(MEM(x, y, z) & FLAG_FREE) || MEM(x, y, z) & FLAG_PROCESSED)
+ continue;
+
+ float pX = x*StepX + minx;
+ float pY = y*StepY + miny;
+ float pZ = z*StepZ + minz;
+
+ if(x > 0 && !(MEM(x-1, y, z) & (FLAG_FREE | FLAG_PROCESSED)) &&
+ !TestLine(CVector(pX, pY, pZ), CVector(pX-StepX, pY, pZ)))
+ MEM(x-1, y, z) |= FLAG_FREE;
+ if(x < ElementsX-1 && !(MEM(x+1, y, z) & (FLAG_FREE | FLAG_PROCESSED)) &&
+ !TestLine(CVector(pX, pY, pZ), CVector(pX+StepX, pY, pZ)))
+ MEM(x+1, y, z) |= FLAG_FREE;
+
+ if(y > 0 && !(MEM(x, y-1, z) & (FLAG_FREE | FLAG_PROCESSED)) &&
+ !TestLine(CVector(pX, pY, pZ), CVector(pX, pY-StepY, pZ)))
+ MEM(x, y-1, z) |= FLAG_FREE;
+ if(y < ElementsY-1 && !(MEM(x, y+1, z) & (FLAG_FREE | FLAG_PROCESSED)) &&
+ !TestLine(CVector(pX, pY, pZ), CVector(pX, pY+StepY, pZ)))
+ MEM(x, y+1, z) |= FLAG_FREE;
+
+ if(z > 0 && !(MEM(x, y, z-1) & (FLAG_FREE | FLAG_PROCESSED)) &&
+ !TestLine(CVector(pX, pY, pZ), CVector(pX, pY, pZ-StepZ)))
+ MEM(x, y, z-1) |= FLAG_FREE;
+ if(z < ElementsZ-1 && !(MEM(x, y, z+1) & (FLAG_FREE | FLAG_PROCESSED)) &&
+ !TestLine(CVector(pX, pY, pZ), CVector(pX, pY, pZ+StepZ)))
+ MEM(x, y, z+1) |= FLAG_FREE;
+
+ notDoneYet = true;
+ MEM(x, y, z) |= FLAG_PROCESSED;
}
}
- if (unk == 3 && ++curCount >= count)
- return true;
+ }
+ }while(notDoneYet);
+
+ bool done;
+
+ // Find bound planes of free space
+
+ // increase x, bounds in y and z
+ x = 0;
+ do{
+ done = false;
+ int minA = 10000;
+ int minB = 10000;
+ int maxA = -10000;
+ int maxB = -10000;
+ for(y = 0; y < ElementsY; y++)
+ for(z = 0; z < ElementsZ; z++)
+ if(MEM(x, y, z) & FLAG_FREE){
+ if(y + z < minA){
+ minA = y + z;
+ aTestPointsX[NumTestPoints] = x;
+ aTestPointsY[NumTestPoints] = y;
+ aTestPointsZ[NumTestPoints] = z;
+ }
+ if(y + z > maxA){
+ maxA = y + z;
+ aTestPointsX[NumTestPoints+1] = x;
+ aTestPointsY[NumTestPoints+1] = y;
+ aTestPointsZ[NumTestPoints+1] = z;
+ }
+ if(y - z < minB){
+ minB = y - z;
+ aTestPointsX[NumTestPoints+2] = x;
+ aTestPointsY[NumTestPoints+2] = y;
+ aTestPointsZ[NumTestPoints+2] = z;
+ }
+ if(y - z > maxB){
+ maxB = y - z;
+ aTestPointsX[NumTestPoints+3] = x;
+ aTestPointsY[NumTestPoints+3] = y;
+ aTestPointsZ[NumTestPoints+3] = z;
+ }
+ done = true;
+ }
+ x++;
+ }while(!done);
+ NumTestPoints += 4;
+
+ // decrease x, bounds in y and z
+ x = ElementsX-1;
+ do{
+ done = false;
+ int minA = 10000;
+ int minB = 10000;
+ int maxA = -10000;
+ int maxB = -10000;
+ for(y = 0; y < ElementsY; y++)
+ for(z = 0; z < ElementsZ; z++)
+ if(MEM(x, y, z) & FLAG_FREE){
+ if(y + z < minA){
+ minA = y + z;
+ aTestPointsX[NumTestPoints] = x;
+ aTestPointsY[NumTestPoints] = y;
+ aTestPointsZ[NumTestPoints] = z;
+ }
+ if(y + z > maxA){
+ maxA = y + z;
+ aTestPointsX[NumTestPoints+1] = x;
+ aTestPointsY[NumTestPoints+1] = y;
+ aTestPointsZ[NumTestPoints+1] = z;
+ }
+ if(y - z < minB){
+ minB = y - z;
+ aTestPointsX[NumTestPoints+2] = x;
+ aTestPointsY[NumTestPoints+2] = y;
+ aTestPointsZ[NumTestPoints+2] = z;
+ }
+ if(y - z > maxB){
+ maxB = y - z;
+ aTestPointsX[NumTestPoints+3] = x;
+ aTestPointsY[NumTestPoints+3] = y;
+ aTestPointsZ[NumTestPoints+3] = z;
+ }
+ done = true;
+ }
+ x--;
+ }while(!done);
+ NumTestPoints += 4;
+
+ // increase y, bounds in x and z
+ y = 0;
+ do{
+ done = false;
+ int minA = 10000;
+ int minB = 10000;
+ int maxA = -10000;
+ int maxB = -10000;
+ for(x = 0; x < ElementsX; x++)
+ for(z = 0; z < ElementsZ; z++)
+ if(MEM(x, y, z) & FLAG_FREE){
+ if(x + z < minA){
+ minA = x + z;
+ aTestPointsX[NumTestPoints] = x;
+ aTestPointsY[NumTestPoints] = y;
+ aTestPointsZ[NumTestPoints] = z;
+ }
+ if(x + z > maxA){
+ maxA = x + z;
+ aTestPointsX[NumTestPoints+1] = x;
+ aTestPointsY[NumTestPoints+1] = y;
+ aTestPointsZ[NumTestPoints+1] = z;
+ }
+ if(x - z < minB){
+ minB = x - z;
+ aTestPointsX[NumTestPoints+2] = x;
+ aTestPointsY[NumTestPoints+2] = y;
+ aTestPointsZ[NumTestPoints+2] = z;
+ }
+ if(x - z > maxB){
+ maxB = x - z;
+ aTestPointsX[NumTestPoints+3] = x;
+ aTestPointsY[NumTestPoints+3] = y;
+ aTestPointsZ[NumTestPoints+3] = z;
+ }
+ done = true;
+ }
+ y++;
+ }while(!done);
+ NumTestPoints += 4;
+
+ // decrease y, bounds in x and z
+ y = ElementsY-1;
+ do{
+ done = false;
+ int minA = 10000;
+ int minB = 10000;
+ int maxA = -10000;
+ int maxB = -10000;
+ for(x = 0; x < ElementsX; x++)
+ for(z = 0; z < ElementsZ; z++)
+ if(MEM(x, y, z) & FLAG_FREE){
+ if(x + z < minA){
+ minA = x + z;
+ aTestPointsX[NumTestPoints] = x;
+ aTestPointsY[NumTestPoints] = y;
+ aTestPointsZ[NumTestPoints] = z;
+ }
+ if(x + z > maxA){
+ maxA = x + z;
+ aTestPointsX[NumTestPoints+1] = x;
+ aTestPointsY[NumTestPoints+1] = y;
+ aTestPointsZ[NumTestPoints+1] = z;
+ }
+ if(x - z < minB){
+ minB = x - z;
+ aTestPointsX[NumTestPoints+2] = x;
+ aTestPointsY[NumTestPoints+2] = y;
+ aTestPointsZ[NumTestPoints+2] = z;
+ }
+ if(x - z > maxB){
+ maxB = x - z;
+ aTestPointsX[NumTestPoints+3] = x;
+ aTestPointsY[NumTestPoints+3] = y;
+ aTestPointsZ[NumTestPoints+3] = z;
+ }
+ done = true;
+ }
+ y--;
+ }while(!done);
+ NumTestPoints += 4;
+
+ // increase z, bounds in x and y
+ z = 0;
+ do{
+ done = false;
+ int minA = 10000;
+ int minB = 10000;
+ int maxA = -10000;
+ int maxB = -10000;
+ for(x = 0; x < ElementsX; x++)
+ for(y = 0; y < ElementsY; y++)
+ if(MEM(x, y, z) & FLAG_FREE){
+ if(x + y < minA){
+ minA = x + y;
+ aTestPointsX[NumTestPoints] = x;
+ aTestPointsY[NumTestPoints] = y;
+ aTestPointsZ[NumTestPoints] = z;
+ }
+ if(x + y > maxA){
+ maxA = x + y;
+ aTestPointsX[NumTestPoints+1] = x;
+ aTestPointsY[NumTestPoints+1] = y;
+ aTestPointsZ[NumTestPoints+1] = z;
+ }
+ if(x - y < minB){
+ minB = x - y;
+ aTestPointsX[NumTestPoints+2] = x;
+ aTestPointsY[NumTestPoints+2] = y;
+ aTestPointsZ[NumTestPoints+2] = z;
+ }
+ if(x - y > maxB){
+ maxB = x - y;
+ aTestPointsX[NumTestPoints+3] = x;
+ aTestPointsY[NumTestPoints+3] = y;
+ aTestPointsZ[NumTestPoints+3] = z;
+ }
+ done = true;
+ }
+ z++;
+ }while(!done);
+ NumTestPoints += 4;
+
+ // decrease z, bounds in x and y
+ z = ElementsZ-1;
+ do{
+ done = false;
+ int minA = 10000;
+ int minB = 10000;
+ int maxA = -10000;
+ int maxB = -10000;
+ for(x = 0; x < ElementsX; x++)
+ for(y = 0; y < ElementsY; y++)
+ if(MEM(x, y, z) & FLAG_FREE){
+ if(x + y < minA){
+ minA = x + y;
+ aTestPointsX[NumTestPoints] = x;
+ aTestPointsY[NumTestPoints] = y;
+ aTestPointsZ[NumTestPoints] = z;
+ }
+ if(x + y > maxA){
+ maxA = x + y;
+ aTestPointsX[NumTestPoints+1] = x;
+ aTestPointsY[NumTestPoints+1] = y;
+ aTestPointsZ[NumTestPoints+1] = z;
+ }
+ if(x - y < minB){
+ minB = x - y;
+ aTestPointsX[NumTestPoints+2] = x;
+ aTestPointsY[NumTestPoints+2] = y;
+ aTestPointsZ[NumTestPoints+2] = z;
+ }
+ if(x - y > maxB){
+ maxB = x - y;
+ aTestPointsX[NumTestPoints+3] = x;
+ aTestPointsY[NumTestPoints+3] = y;
+ aTestPointsZ[NumTestPoints+3] = z;
+ }
+ done = true;
+ }
+ z--;
+ }while(!done);
+ NumTestPoints += 4;
+
+ // divide the axis aligned bounding planes into 4 and place some test points
+
+ // x = 0 plane
+ MinValY = 999999;
+ MinValZ = 999999;
+ MaxValY = 0;
+ MaxValZ = 0;
+ for(y = 0; y < ElementsY; y++)
+ for(z = 0; z < ElementsZ; z++)
+ if(MEM(0, y, z) & FLAG_FREE){
+ if(y < MinValY) MinValY = y;
+ if(z < MinValZ) MinValZ = z;
+ if(y > MaxValY) MaxValY = y;
+ if(z > MaxValZ) MaxValZ = z;
+ }
+ // pick 4 points in the found bounds and add new test points
+ if(MaxValY != 0 && MaxValZ != 0)
+ for(Point1 = 0; Point1 < 2; Point1++)
+ for(Point2 = 0; Point2 < 2; Point2++){
+ NewPointY = (Point1 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY;
+ NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ;
+ if(MEM(0, NewPointY, NewPointZ) & FLAG_FREE){
+ aTestPointsX[NumTestPoints] = 0;
+ aTestPointsY[NumTestPoints] = NewPointY;
+ aTestPointsZ[NumTestPoints] = NewPointZ;
+ NumTestPoints++;
+ }
+ }
+
+ // x = ElementsX-1 plane
+ MinValY = 999999;
+ MinValZ = 999999;
+ MaxValY = 0;
+ MaxValZ = 0;
+ for(y = 0; y < ElementsY; y++)
+ for(z = 0; z < ElementsZ; z++)
+ if(MEM(ElementsX-1, y, z) & FLAG_FREE){
+ if(y < MinValY) MinValY = y;
+ if(z < MinValZ) MinValZ = z;
+ if(y > MaxValY) MaxValY = y;
+ if(z > MaxValZ) MaxValZ = z;
+ }
+ // pick 4 points in the found bounds and add new test points
+ if(MaxValY != 0 && MaxValZ != 0)
+ for(Point1 = 0; Point1 < 2; Point1++)
+ for(Point2 = 0; Point2 < 2; Point2++){
+ NewPointY = (Point1 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY;
+ NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ;
+ if(MEM(ElementsX-1, NewPointY, NewPointZ) & FLAG_FREE){
+ aTestPointsX[NumTestPoints] = ElementsX-1;
+ aTestPointsY[NumTestPoints] = NewPointY;
+ aTestPointsZ[NumTestPoints] = NewPointZ;
+ NumTestPoints++;
+ }
+ }
+
+ // y = 0 plane
+ MinValX = 999999;
+ MinValZ = 999999;
+ MaxValX = 0;
+ MaxValZ = 0;
+ for(x = 0; x < ElementsX; x++)
+ for(z = 0; z < ElementsZ; z++)
+ if(MEM(x, 0, z) & FLAG_FREE){
+ if(x < MinValX) MinValX = x;
+ if(z < MinValZ) MinValZ = z;
+ if(x > MaxValX) MaxValX = x;
+ if(z > MaxValZ) MaxValZ = z;
+ }
+ // pick 4 points in the found bounds and add new test points
+ if(MaxValX != 0 && MaxValZ != 0)
+ for(Point1 = 0; Point1 < 2; Point1++)
+ for(Point2 = 0; Point2 < 2; Point2++){
+ NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX;
+ NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ;
+ if(MEM(NewPointX, 0, NewPointZ) & FLAG_FREE){
+ aTestPointsX[NumTestPoints] = NewPointX;
+ aTestPointsY[NumTestPoints] = 0;
+ aTestPointsZ[NumTestPoints] = NewPointZ;
+ NumTestPoints++;
+ }
+ }
+
+ // y = ElementsY-1 plane
+ MinValX = 999999;
+ MinValZ = 999999;
+ MaxValX = 0;
+ MaxValZ = 0;
+ for(x = 0; x < ElementsX; x++)
+ for(z = 0; z < ElementsZ; z++)
+ if(MEM(x, ElementsY-1, z) & FLAG_FREE){
+ if(x < MinValX) MinValX = x;
+ if(z < MinValZ) MinValZ = z;
+ if(x > MaxValX) MaxValX = x;
+ if(z > MaxValZ) MaxValZ = z;
+ }
+ // pick 4 points in the found bounds and add new test points
+ if(MaxValX != 0 && MaxValZ != 0)
+ for(Point1 = 0; Point1 < 2; Point1++)
+ for(Point2 = 0; Point2 < 2; Point2++){
+ NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX;
+ NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ;
+ if(MEM(NewPointX, ElementsY-1, NewPointZ) & FLAG_FREE){
+ aTestPointsX[NumTestPoints] = NewPointX;
+ aTestPointsY[NumTestPoints] = ElementsY-1;
+ aTestPointsZ[NumTestPoints] = NewPointZ;
+ NumTestPoints++;
+ }
+ }
+
+ // z = 0 plane
+ MinValX = 999999;
+ MinValY = 999999;
+ MaxValX = 0;
+ MaxValY = 0;
+ for(x = 0; x < ElementsX; x++)
+ for(y = 0; y < ElementsY; y++)
+ if(MEM(x, y, 0) & FLAG_FREE){
+ if(x < MinValX) MinValX = x;
+ if(y < MinValY) MinValY = y;
+ if(x > MaxValX) MaxValX = x;
+ if(y > MaxValY) MaxValY = y;
+ }
+ // pick 4 points in the found bounds and add new test points
+ if(MaxValX != 0 && MaxValY != 0)
+ for(Point1 = 0; Point1 < 2; Point1++)
+ for(Point2 = 0; Point2 < 2; Point2++){
+ NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX;
+ NewPointY = (Point2 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY;
+ if(MEM(NewPointX, NewPointY, 0) & FLAG_FREE){
+ aTestPointsX[NumTestPoints] = NewPointX;
+ aTestPointsY[NumTestPoints] = NewPointY;
+ aTestPointsZ[NumTestPoints] = 0;
+ NumTestPoints++;
+ }
+ }
+
+ // z = ElementsZ-1 plane
+ MinValX = 999999;
+ MinValY = 999999;
+ MaxValX = 0;
+ MaxValY = 0;
+ for(x = 0; x < ElementsX; x++)
+ for(y = 0; y < ElementsY; y++)
+ if(MEM(x, y, ElementsZ-1) & FLAG_FREE){
+ if(x < MinValX) MinValX = x;
+ if(y < MinValY) MinValY = y;
+ if(x > MaxValX) MaxValX = x;
+ if(y > MaxValY) MaxValY = y;
+ }
+ // pick 4 points in the found bounds and add new test points
+ if(MaxValX != 0 && MaxValY != 0)
+ for(Point1 = 0; Point1 < 2; Point1++)
+ for(Point2 = 0; Point2 < 2; Point2++){
+ NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX;
+ NewPointY = (Point2 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY;
+ if(MEM(NewPointX, NewPointY, ElementsZ-1) & FLAG_FREE){
+ aTestPointsX[NumTestPoints] = NewPointX;
+ aTestPointsY[NumTestPoints] = NewPointY;
+ aTestPointsZ[NumTestPoints] = ElementsZ-1;
+ NumTestPoints++;
+ }
+ }
+
+ // add some hardcoded test points
+ for(int i = 0; i < ARRAY_SIZE(ExtraFudgePointsCoors); i++)
+ if(PointFallsWithinZone(ExtraFudgePointsCoors[i], 0.0f)){
+ x = ElementsX * (ExtraFudgePointsCoors[i].x-minx)/(maxx-minx);
+ y = ElementsY * (ExtraFudgePointsCoors[i].y-miny)/(maxy-miny);
+ z = ElementsZ * (ExtraFudgePointsCoors[i].z-minz)/(maxz-minz);
+ if(MEM(x, y, z) & FLAG_FREE){
+ aTestPointsX[NumTestPoints] = x;
+ aTestPointsY[NumTestPoints] = y;
+ aTestPointsZ[NumTestPoints] = z;
+ NumTestPoints++;
+ }
+ }
+
+ // remove duplicate points
+ for(int i = 0; i < NumTestPoints; i++)
+ for(int j = i+1; j < NumTestPoints; j++)
+ if(aTestPointsX[j] == aTestPointsX[i] &&
+ aTestPointsY[j] == aTestPointsY[i] &&
+ aTestPointsZ[j] == aTestPointsZ[i]){
+ // get rid of [j]
+ for(int k = j; k < NumTestPoints-1; k++){
+ aTestPointsX[k] = aTestPointsX[k+1];
+ aTestPointsY[k] = aTestPointsY[k+1];
+ aTestPointsZ[k] = aTestPointsZ[k+1];
+ }
+ NumTestPoints--;
+ }
+
+ // convert points to floating point
+ for(int i = 0; i < NumTestPoints; i++){
+ aTestPoints[i].x = aTestPointsX[i]*StepX + minx;
+ aTestPoints[i].y = aTestPointsY[i]*StepY + miny;
+ aTestPoints[i].z = aTestPointsZ[i]*StepZ + minz;
+ }
+
+ CZNumber++;
+
+ delete[] pMem;
+ pMem = nil;
+}
+
+bool
+CCullZone::TestEntityVisibilityFromCullZone(CEntity *entity, float extraDist, CEntity *LODentity)
+{
+ CColModel *colmodel = entity->GetColModel();
+ float boundMaxX = colmodel->boundingBox.max.x;
+ float boundMaxY = colmodel->boundingBox.max.y;
+ float boundMaxZ = colmodel->boundingBox.max.z;
+ float boundMinX = colmodel->boundingBox.min.x;
+ float boundMinY = colmodel->boundingBox.min.y;
+ float boundMinZ = colmodel->boundingBox.min.z;
+ if(LODentity){
+ colmodel = LODentity->GetColModel();
+ boundMaxX = Max(boundMaxX, colmodel->boundingBox.max.x);
+ boundMaxY = Max(boundMaxY, colmodel->boundingBox.max.y);
+ boundMaxZ = Max(boundMaxZ, colmodel->boundingBox.max.z);
+ boundMinX = Min(boundMinX, colmodel->boundingBox.min.x);
+ boundMinY = Min(boundMinY, colmodel->boundingBox.min.y);
+ boundMinZ = Min(boundMinZ, colmodel->boundingBox.min.z);
+ }
+
+ if(boundMaxZ-boundMinZ + extraDist < 0.5f)
+ boundMaxZ = boundMinZ + 0.5f;
+ else
+ boundMaxZ += extraDist;
+
+ CVector vecMin = entity->GetMatrix() * CVector(boundMinX, boundMinY, boundMinZ);
+ CVector vecMaxX = entity->GetMatrix() * CVector(boundMaxX, boundMinY, boundMinZ);
+ CVector vecMaxY = entity->GetMatrix() * CVector(boundMinX, boundMaxY, boundMinZ);
+ CVector vecMaxZ = entity->GetMatrix() * CVector(boundMinX, boundMinY, boundMaxZ);
+ CVector dirx = vecMaxX - vecMin;
+ CVector diry = vecMaxY - vecMin;
+ CVector dirz = vecMaxZ - vecMin;
+
+ // If building intersects zone at all, it's visible
+ int x, y, z;
+ for(x = 0; x < 9; x++){
+ CVector posX = vecMin + x/8.0f*dirx;
+ for(y = 0; y < 9; y++){
+ CVector posY = posX + y/8.0f*diry;
+ for(z = 0; z < 9; z++){
+ CVector posZ = posY + z/8.0f*dirz;
+ if(PointFallsWithinZone(posZ, 2.0f))
+ return true;
+ }
}
}
+
+ float distToZone = CalcDistToCullZone(entity->GetPosition().x, entity->GetPosition().y)/15.0f;
+ distToZone = Max(distToZone, 7.0f);
+ int numX = (boundMaxX - boundMinX)/distToZone + 2.0f;
+ int numY = (boundMaxY - boundMinY)/distToZone + 2.0f;
+ int numZ = (boundMaxZ - boundMinZ)/distToZone + 2.0f;
+
+ float stepX = 1.0f/(numX-1);
+ float stepY = 1.0f/(numY-1);
+ float stepZ = 1.0f/(numZ-1);
+ float midX = (boundMaxX + boundMinX)/2.0f;
+ float midY = (boundMaxY + boundMinY)/2.0f;
+ float midZ = (boundMaxZ + boundMinZ)/2.0f;
+
+ // check both xy planes
+ for(int i = 0; i < NumTestPoints; i++){
+ CVector testPoint = aTestPoints[i];
+ CVector mid = entity->GetMatrix() * CVector(midX, midY, midZ);
+ mid.z += 0.1f;
+ if(DoThoroughLineTest(testPoint, mid, entity))
+ return true;
+
+ CVector ray = entity->GetPosition() - testPoint;
+
+ float dotX = DotProduct(ray, dirx);
+ float dotY = DotProduct(ray, diry);
+ float dotZ = DotProduct(ray, dirz);
+
+ for(x = 0; x < numX; x++){
+ CVector pMinZ = vecMin + x*stepX*dirx;
+ CVector pMaxZ = vecMin + x*stepX*dirx + dirz;
+ for(y = 0; y < numY; y++)
+ if(dotZ > 0.0f){
+ if(DoThoroughLineTest(testPoint, pMinZ + y*stepY*diry, entity))
+ return true;
+ }else{
+ if(DoThoroughLineTest(testPoint, pMaxZ + y*stepY*diry, entity))
+ return true;
+ }
+ }
+
+ for(x = 0; x < numX; x++){
+ CVector pMinY = vecMin + x*stepX*dirx;
+ CVector pMaxY = vecMin + x*stepX*dirx + diry;
+ for(z = 1; z < numZ-1; z++) // edge cases already handled
+ if(dotY > 0.0f){
+ if(DoThoroughLineTest(testPoint, pMinY + z*stepZ*dirz, entity))
+ return true;
+ }else{
+ if(DoThoroughLineTest(testPoint, pMaxY + z*stepZ*dirz, entity))
+ return true;
+ }
+ }
+
+ for(y = 1; y < numY-1; y++){ // edge cases already handled
+ CVector pMinX = vecMin + y*stepY*diry;
+ CVector pMaxX = vecMin + y*stepY*diry + dirx;
+ for(z = 1; z < numZ-1; z++) // edge cases already handled
+ if(dotX > 0.0f){
+ if(DoThoroughLineTest(testPoint, pMinX + z*stepZ*dirz, entity))
+ return true;
+ }else{
+ if(DoThoroughLineTest(testPoint, pMaxX + z*stepZ*dirz, entity))
+ return true;
+ }
+ }
+ }
+
return false;
}
diff --git a/src/core/ZoneCull.h b/src/core/ZoneCull.h
index 9bc07b8c..10742ffb 100644
--- a/src/core/ZoneCull.h
+++ b/src/core/ZoneCull.h
@@ -12,7 +12,7 @@ public:
float maxz;
int32 m_indexStart;
- int16 m_groupIndexCount[3];
+ int16 m_groupIndexCount[3]; // only useful during resolution stage
int16 m_numBuildings;
int16 m_numTreadablesPlus10m;
int16 m_numTreadables;
@@ -26,30 +26,35 @@ public:
static void DoStuffEnteringZone_OneTreadable(uint16 i);
- static bool TestLine(CVector a1, CVector a2);
+ static bool TestLine(CVector vec1, CVector vec2);
+ static bool DoThoroughLineTest(CVector vec1, CVector vec2, CEntity *testEntity);
float CalcDistToCullZoneSquared(float x, float y);
float CalcDistToCullZone(float x, float y) { return Sqrt(CalcDistToCullZoneSquared(x, y)); };
bool IsEntityCloseEnoughToZone(CEntity* entity, bool checkLevel);
+ bool PointFallsWithinZone(CVector pos, float radius);
+ bool TestEntityVisibilityFromCullZone(CEntity *entity, float extraDist, CEntity *LODentity);
+ void FindTestPoints();
void GetGroupStartAndSize(int32 groupid, int32 &start, int32 &size) {
switch (groupid) {
+ case 0:
+ default:
+ // buildings
+ start = m_indexStart;
+ size = m_groupIndexCount[0];
+ break;
case 1:
+ // treadables + 10m
start = m_groupIndexCount[0] + m_indexStart;
size = m_groupIndexCount[1];
break;
case 2:
+ // treadables
start = m_groupIndexCount[0] + m_groupIndexCount[1] + m_indexStart;
size = m_groupIndexCount[2];
break;
- default:
- start = m_indexStart;
- size = m_groupIndexCount[0];
- break;
}
}
-
- void FindTestPoints() {}; // todo
- bool TestEntityVisibilityFromCullZone(CEntity*, float, CEntity*) { return false; }; // todo
};
enum eZoneAttribs
@@ -121,5 +126,12 @@ public:
static void DoVisibilityTestCullZone(int zoneId, bool doIt);
static bool DoWeHaveMoreThanXOccurencesOfSet(int32 count, uint16 *set);
- static void CompressIndicesArray() {};// todo
+ static void CompressIndicesArray();
+ static bool PickRandomSetForGroup(int32 zone, int32 group, uint16 *set);
+ static void ReplaceSetForAllGroups(uint16 *set, uint16 setid);
+ static void TidyUpAndMergeLists(uint16 *extraIndices, int32 numExtraIndices);
+
+ // debug
+ static bool LoadTempFile(void);
+ static void SaveTempFile(void);
};
diff --git a/src/core/common.h b/src/core/common.h
index ff1e3b90..59aad4db 100644
--- a/src/core/common.h
+++ b/src/core/common.h
@@ -139,7 +139,7 @@ inline float _floatswap32(float f)
inline uint32 dpb(uint32 b, uint32 p, uint32 s, uint32 w)
{
uint32 m = MASK(p,s);
- return w & ~m | b<(high) ? (high) : (v))
inline float sq(float x) { return x*x; }
@@ -279,8 +307,14 @@ void re3_usererror(const char *format, ...);
#define DEBUGBREAK() __debugbreak();
-#define debug(f, ...) re3_debug("[DBG]: " f, ## __VA_ARGS__)
+// Switch to enable development messages.
+#if 1
+#define DEV(f, ...)
+#else
#define DEV(f, ...) re3_debug("[DEV]: " f, ## __VA_ARGS__)
+#endif
+
+#define debug(f, ...) re3_debug("[DBG]: " f, ## __VA_ARGS__)
#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f, ## __VA_ARGS__)
#define Error(f, ...) re3_debug("[ERROR]: " f, ## __VA_ARGS__)
#define USERERROR(f, ...) re3_usererror(f, ## __VA_ARGS__)
@@ -479,4 +513,4 @@ inline T *WriteSaveBuf(uint8 *&buf, const T &value)
assert(ReadSaveBuf(buf) == size);
-void cprintf(char*, ...);
\ No newline at end of file
+void cprintf(char*, ...);
diff --git a/src/core/config.h b/src/core/config.h
index 91fb67eb..e5a97049 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -1,27 +1,27 @@
#pragma once
enum Config {
- NUMPLAYERS = 1,
+ NUMPLAYERS = 1, // 4 on PS2
NUMCDIMAGES = 12, // gta3.img duplicates (not used on PC)
MAX_CDIMAGES = 8, // additional cdimages
MAX_CDCHANNELS = 5,
- MODELINFOSIZE = 5500,
+ MODELINFOSIZE = 5500, // 3150 on PS2
// TXDSTORESIZE = 850,
TXDSTORESIZE = 1024, // for Xbox map
EXTRADIRSIZE = 128,
CUTSCENEDIRSIZE = 512,
- SIMPLEMODELSIZE = 5000,
+ SIMPLEMODELSIZE = 5000, // 2910 on PS2
MLOMODELSIZE = 1,
MLOINSTANCESIZE = 1,
TIMEMODELSIZE = 30,
CLUMPMODELSIZE = 5,
PEDMODELSIZE = 90,
- VEHICLEMODELSIZE = 120,
+ VEHICLEMODELSIZE = 120, // 70 on PS2
XTRACOMPSMODELSIZE = 2,
- TWODFXSIZE = 2000,
+ TWODFXSIZE = 2000, // 1210 on PS2
MAXVEHICLESLOADED = 50, // 70 on mobile
@@ -135,10 +135,6 @@ enum Config {
NUM_EXPLOSIONS = 48,
};
-// We'll use this once we're ready to become independent of the game
-// Use it to mark bugs in the code that will prevent the game from working then
-//#define STANDALONE
-
// We don't expect to compile for PS2 or Xbox
// but it might be interesting for documentation purposes
#define GTA_PC
@@ -156,30 +152,69 @@ enum Config {
// any debug stuff that is only left in mobile, is not in MASTER
//#define MASTER
+// once and for all:
+// pc: FINAL & MASTER
+// mobile: FINAL
+
+// MASTER builds must be FINAL
+#ifdef MASTER
+#define FINAL
+#endif
+
+// Version defines
+#define GTA3_PS2_140 300
+#define GTA3_PS2_160 301
+#define GTA3_PC_10 310
+#define GTA3_PC_11 311
+#define GTA3_PC_STEAM 312
+// TODO? maybe something for xbox or android?
+
+#define GTA_VERSION GTA3_PC_11
+
+// quality of life fixes that should also be in FINAL
+#define NASTY_GAME // nasty game for all languages
+#define NO_CDCHECK
+
+// those infamous texts
+#define DRAW_GAME_VERSION_TEXT
+#define DRAW_MENU_VERSION_TEXT
+
+// Memory allocation and compression
+// #define USE_CUSTOM_ALLOCATOR // use CMemoryHeap for allocation. use with care, not finished yet
+//#define COMPRESSED_COL_VECTORS // use compressed vectors for collision vertices
+//#define ANIM_COMPRESSION // only keep most recently used anims uncompressed
+
#if defined GTA_PS2
# define GTA_PS2_STUFF
# define RANDOMSPLASH
+# define USE_CUSTOM_ALLOCATOR
# define VU_COLLISION
+# define ANIM_COMPRESSION
#elif defined GTA_PC
-# define GTA3_1_1_PATCH
-//# define GTA3_STEAM_PATCH
# ifdef GTA_PS2_STUFF
# define USE_PS2_RAND
# define RANDOMSPLASH // use random splash as on PS2
# define PS2_MATFX
# endif
+# define PC_PLAYER_CONTROLS // mouse player/cam mode
+# define GTA_REPLAY
+# define GTA_SCENE_EDIT
#elif defined GTA_XBOX
#endif
#ifdef VU_COLLISION
-#define COMPRESSED_COL_VECTORS // current need compressed vectors in this code
+#define COMPRESSED_COL_VECTORS // currently need compressed vectors in this code
#endif
#ifdef MASTER
// only in master builds
+ #undef DRAW_GAME_VERSION_TEXT
#else
// not in master builds
#define VALIDATE_SAVE_SIZE
+
+ #define NO_MOVIES // disable intro videos
+ #define DEBUGMENU
#endif
#ifdef FINAL
@@ -187,35 +222,43 @@ enum Config {
# define USE_MY_DOCUMENTS // use my documents directory for user files
#else
// not in any game
-# define NASTY_GAME // nasty game for all languages
-# define NO_MOVIES // disable intro videos
-# define NO_CDCHECK
# define CHATTYSPLASH // print what the game is loading
-# define DEBUGMENU
# define TIMEBARS // print debug timers
#endif
-#define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more
+#define FIX_BUGS // fixes bugs that we've came across during reversing
#define MORE_LANGUAGES // Add more translations to the game
#define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible
+#define LOAD_INI_SETTINGS // as the name suggests. fundamental for CUSTOM_FRONTEND_OPTIONS
+
+// Just debug menu entries
+#ifdef DEBUGMENU
+#define MISSION_SWITCHER // from debug menu
+#endif
// Rendering/display
+//#define EXTRA_MODEL_FLAGS // from mobile to optimize rendering
+//# define HARDCODED_MODEL_FLAGS // sets the flags enabled above from hardcoded model names.
+ // NB: keep this enabled unless your map IDEs have these flags baked in
#define ASPECT_RATIO_SCALE // Not just makes everything scale with aspect ratio, also adds support for all aspect ratios
#define DEFAULT_NATIVE_RESOLUTION // Set default video mode to your native resolution (fixes Windows 10 launch)
#define USE_TXD_CDIMAGE // generate and load textures from txd.img
#define PS2_ALPHA_TEST // emulate ps2 alpha test
#define IMPROVED_VIDEOMODE // save and load videomode parameters instead of a magic number
#define DISABLE_LOADING_SCREEN // disable the loading screen which vastly improves the loading time
-#define NO_ISLAND_LOADING // disable loadscreen between islands via loading all island data at once, consumes more memory and CPU
+#define DISABLE_VSYNC_ON_TEXTURE_CONVERSION // make texture conversion work faster by disabling vsync
//#define USE_TEXTURE_POOL
-#define CUTSCENE_BORDERS_SWITCH
+#ifdef LIBRW
//#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur)
//#define EXTENDED_PIPELINES // custom render pipelines (includes Neo)
-#define MULTISAMPLING // adds MSAA option
+//#define SCREEN_DROPLETS // neo water droplets
+#endif
-#ifdef LIBRW
-// these are not supported with librw yet
-# undef MULTISAMPLING
+#ifndef EXTENDED_COLOURFILTER
+#undef SCREEN_DROPLETS // we need the backbuffer for this effect
+#endif
+#ifndef EXTENDED_PIPELINES
+#undef SCREEN_DROPLETS // we need neo.txd
#endif
// Particle
@@ -226,17 +269,24 @@ enum Config {
#if !defined(RW_GL3) && defined(_WIN32)
#define XINPUT
#endif
+#if !defined(_WIN32) && !defined(__SWITCH__)
+#define DONT_TRUST_RECOGNIZED_JOYSTICKS // Then we'll only rely on GLFW gamepad DB, and expect user to enter Controller->Detect joysticks if his joystick isn't on that list.
+#endif
#define DETECT_PAD_INPUT_SWITCH // Adds automatic switch of pad related stuff between controller and kb/m
#define KANGAROO_CHEAT
#define ALLCARSHELI_CHEAT
#define ALT_DODO_CHEAT
#define REGISTER_START_BUTTON
//#define BIND_VEHICLE_FIREWEAPON // Adds ability to rebind fire key for 'in vehicle' controls
+#define BUTTON_ICONS // use textures to show controller buttons
// Hud, frontend and radar
+//#define PS2_HUD
#define HUD_ENHANCEMENTS // Adjusts some aspects to make the HUD look/behave a little bit better.
// #define BETA_SLIDING_TEXT
#define TRIANGULAR_BLIPS // height indicating triangular radar blips, as in VC
+// #define XBOX_SUBTITLES // the infamous outlines
+#define RADIO_OFF_TEXT
#define PC_MENU
#ifndef PC_MENU
@@ -250,7 +300,14 @@ enum Config {
//# define PS2_LIKE_MENU // An effort to recreate PS2 menu, cycling through tabs, different bg etc.
//# define PS2_SAVE_DIALOG // PS2 style save dialog with transparent black box
# define CUSTOM_FRONTEND_OPTIONS
-# define GRAPHICS_MENU_OPTIONS // otherwise Advanced Options menu will appear if Display is full
+
+# ifdef CUSTOM_FRONTEND_OPTIONS
+# define GRAPHICS_MENU_OPTIONS // otherwise Display settings will be scrollable
+# define NO_ISLAND_LOADING // disable loadscreen between islands via loading all island data at once, consumes more memory and CPU
+# define CUTSCENE_BORDERS_SWITCH
+# define MULTISAMPLING // adds MSAA option
+# define INVERT_LOOK_FOR_PAD // add bInvertLook4Pad from VC
+# endif
#endif
// Script
@@ -294,11 +351,14 @@ enum Config {
#define FREE_CAM // Rotating cam
// Audio
+#define RADIO_SCROLL_TO_PREV_STATION
#ifndef AUDIO_OAL // is not working yet for openal
#define AUDIO_CACHE // cache sound lengths to speed up the cold boot
#endif
//#define PS2_AUDIO // changes audio paths for cutscenes and radio to PS2 paths, needs vbdec to support VB with MSS
+// IMG
+#define BIG_IMG // allows to read larger img files
//#define SQUEEZE_PERFORMANCE
#ifdef SQUEEZE_PERFORMANCE
@@ -306,4 +366,8 @@ enum Config {
#undef NO_ISLAND_LOADING
#define PC_PARTICLE
#define VC_PED_PORTS // To not process collisions always. But should be tested if that's really beneficial
-#endif
\ No newline at end of file
+#endif
+
+#ifdef LIBRW
+// these are not supported with librw yet
+#endif
diff --git a/src/core/main.cpp b/src/core/main.cpp
index 5fea9c4b..3a855e20 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -63,7 +63,11 @@
#include "SceneEdit.h"
#include "debugmenu.h"
#include "Clock.h"
+#include "postfx.h"
#include "custompipes.h"
+#include "screendroplets.h"
+#include "frontendoption.h"
+#include "MemoryHeap.h"
GlobalScene Scene;
@@ -81,14 +85,18 @@ bool gbModelViewer;
bool gbShowTimebars;
#endif
-int32 frameCount;
+volatile int32 frameCount;
RwRGBA gColourTop;
bool gameAlreadyInitialised;
float NumberOfChunksLoaded;
+#ifdef GTA_PS2
+#define TOTALNUMCHUNKS 48.0f
+#else
#define TOTALNUMCHUNKS 73.0f
+#endif
bool g_SlowMode = false;
char version_name[64];
@@ -102,6 +110,18 @@ void TheGame(void);
void DebugMenuPopulate(void);
#endif
+#ifndef FINAL
+bool gbPrintMemoryUsage;
+#endif
+
+#ifdef PS2_MENU
+#define WANT_TO_LOAD TheMemoryCard.m_bWantToLoad
+#define FOUND_GAME_TO_LOAD TheMemoryCard.b_FoundRecentSavedGameWantToLoad
+#else
+#define WANT_TO_LOAD FrontEndMenuManager.m_bWantToLoad
+#define FOUND_GAME_TO_LOAD b_FoundRecentSavedGameWantToLoad
+#endif
+
void
ValidateVersion()
{
@@ -395,6 +415,63 @@ PluginAttach(void)
return TRUE;
}
+#ifdef GTA_PS2
+#define NUM_PREALLOC_ATOMICS 3245
+#define NUM_PREALLOC_CLUMPS 101
+#define NUM_PREALLOC_FRAMES 2821
+#define NUM_PREALLOC_GEOMETRIES 1404
+#define NUM_PREALLOC_TEXDICTS 106
+#define NUM_PREALLOC_TEXTURES 1900
+#define NUM_PREALLOC_MATERIALS 3300
+bool preAlloc;
+
+void
+PreAllocateRwObjects(void)
+{
+ int i;
+ void **tmp = new void*[0x8000];
+ preAlloc = true;
+
+ for(i = 0; i < NUM_PREALLOC_ATOMICS; i++)
+ tmp[i] = RpAtomicCreate();
+ for(i = 0; i < NUM_PREALLOC_ATOMICS; i++)
+ RpAtomicDestroy((RpAtomic*)tmp[i]);
+
+ for(i = 0; i < NUM_PREALLOC_CLUMPS; i++)
+ tmp[i] = RpClumpCreate();
+ for(i = 0; i < NUM_PREALLOC_CLUMPS; i++)
+ RpClumpDestroy((RpClump*)tmp[i]);
+
+ for(i = 0; i < NUM_PREALLOC_FRAMES; i++)
+ tmp[i] = RwFrameCreate();
+ for(i = 0; i < NUM_PREALLOC_FRAMES; i++)
+ RwFrameDestroy((RwFrame*)tmp[i]);
+
+ for(i = 0; i < NUM_PREALLOC_GEOMETRIES; i++)
+ tmp[i] = RpGeometryCreate(0, 0, 0);
+ for(i = 0; i < NUM_PREALLOC_GEOMETRIES; i++)
+ RpGeometryDestroy((RpGeometry*)tmp[i]);
+
+ for(i = 0; i < NUM_PREALLOC_TEXDICTS; i++)
+ tmp[i] = RwTexDictionaryCreate();
+ for(i = 0; i < NUM_PREALLOC_TEXDICTS; i++)
+ RwTexDictionaryDestroy((RwTexDictionary*)tmp[i]);
+
+ for(i = 0; i < NUM_PREALLOC_TEXTURES; i++)
+ tmp[i] = RwTextureCreate(RwRasterCreate(0, 0, 0, 0));
+ for(i = 0; i < NUM_PREALLOC_TEXDICTS; i++)
+ RwTextureDestroy((RwTexture*)tmp[i]);
+
+ for(i = 0; i < NUM_PREALLOC_MATERIALS; i++)
+ tmp[i] = RpMaterialCreate();
+ for(i = 0; i < NUM_PREALLOC_MATERIALS; i++)
+ RpMaterialDestroy((RpMaterial*)tmp[i]);
+
+ delete[] tmp;
+ preAlloc = false;
+}
+#endif
+
static RwBool
Initialise3D(void *param)
{
@@ -404,9 +481,19 @@ Initialise3D(void *param)
DebugMenuInit();
DebugMenuPopulate();
#endif // !DEBUGMENU
+#ifdef CUSTOM_FRONTEND_OPTIONS
+ // Apparently this func. can be run multiple times at the start.
+ if (numCustomFrontendOptions == 0 && numCustomFrontendScreens == 0) {
+ // needs stored language and TheText to be loaded, and last TheText reload is at the start of here
+ CustomFrontendOptionsPopulate();
+ }
+#endif
bool ret = CGame::InitialiseRenderWare();
#ifdef EXTENDED_PIPELINES
CustomPipes::CustomPipeInit(); // need Scene.world for this
+#endif
+#ifdef SCREEN_DROPLETS
+ ScreenDroplets::InitDraw();
#endif
return ret;
}
@@ -417,6 +504,9 @@ Initialise3D(void *param)
static void
Terminate3D(void)
{
+#ifdef SCREEN_DROPLETS
+ ScreenDroplets::Shutdown();
+#endif
#ifdef EXTENDED_PIPELINES
CustomPipes::CustomPipeShutdown();
#endif
@@ -544,7 +634,12 @@ LoadingScreen(const char *str1, const char *str2, const char *splashscreen)
return;
#endif
- if(DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255)){
+#ifndef GTA_PS2
+ if(DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255))
+#else
+ DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255);
+#endif
+ {
CSprite2d::SetRecipNearClip();
CSprite2d::InitPerFrame();
CFont::InitPerFrame();
@@ -583,8 +678,10 @@ LoadingScreen(const char *str1, const char *str2, const char *splashscreen)
AsciiToUnicode(str1, tmpstr);
CFont::PrintString(hpos, vpos, tmpstr);
vpos += 22*yscale;
- AsciiToUnicode(str2, tmpstr);
- CFont::PrintString(hpos, vpos, tmpstr);
+ if (str2) {
+ AsciiToUnicode(str2, tmpstr);
+ CFont::PrintString(hpos, vpos, tmpstr);
+ }
#endif
}
@@ -604,8 +701,13 @@ LoadingIslandScreen(const char *levelName)
splash = LoadSplash(nil);
name = TheText.Get(levelName);
+
+#ifndef GTA_PS2
if(!DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255))
return;
+#else
+ DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255);
+#endif
CSprite2d::SetRecipNearClip();
CSprite2d::InitPerFrame();
@@ -614,23 +716,61 @@ LoadingIslandScreen(const char *levelName)
col = CRGBA(255, 255, 255, 255);
splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), col, col, col, col);
CFont::SetBackgroundOff();
+#ifdef FIX_BUGS
+ CFont::SetScale(SCREEN_SCALE_X(1.5f), SCREEN_SCALE_Y(1.5f));
+#else
CFont::SetScale(1.5f, 1.5f);
+#endif
CFont::SetPropOn();
CFont::SetRightJustifyOn();
+#ifdef FIX_BUGS
+ CFont::SetRightJustifyWrap(SCREEN_SCALE_X(150.0f));
+#else
CFont::SetRightJustifyWrap(150.0f);
+#endif
CFont::SetFontStyle(FONT_HEADING);
sprintf(str, "WELCOME TO");
AsciiToUnicode(str, wstr);
CFont::SetDropColor(CRGBA(0, 0, 0, 255));
CFont::SetDropShadowPosition(3);
CFont::SetColor(CRGBA(243, 237, 71, 255));
- CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f));
- CFont::PrintString(SCREEN_WIDTH - 20, SCREEN_STRETCH_FROM_BOTTOM(110.0f), TheText.Get("WELCOME"));
+#if !defined(PS2_HUD) && defined(GTA_PC)
+ CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.2f));
+#endif
+
+#ifdef PS2_HUD
+ #ifdef FIX_BUGS
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(140.0f), TheText.Get("WELCOME"));
+ #else
+ CFont::PrintString(SCREEN_WIDTH - 20, SCREEN_HEIGHT - 140, TheText.Get("WELCOME"));
+ #endif
+#else
+ #ifdef FIX_BUGS
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(110.0f), TheText.Get("WELCOME"));
+ #else
+ CFont::PrintString(SCREEN_WIDTH - 20, SCREEN_SCALE_FROM_BOTTOM(110.0f), TheText.Get("WELCOME"));
+ #endif
+#endif
TextCopy(wstr, name);
TheText.UpperCase(wstr);
CFont::SetColor(CRGBA(243, 237, 71, 255));
- CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f));
- CFont::PrintString(SCREEN_WIDTH-20, SCREEN_STRETCH_FROM_BOTTOM(80.0f), wstr);
+#if !defined(PS2_HUD) && defined(GTA_PC)
+ CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.2f));
+#endif
+
+#ifdef PS2_HUD
+ #ifdef FIX_BUGS
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(110.0f), wstr);
+ #else
+ CFont::PrintString(SCREEN_WIDTH-20, SCREEN_HEIGHT - 110, wstr);
+ #endif
+#else
+ #ifdef FIX_BUGS
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(80.0f), wstr);
+ #else
+ CFont::PrintString(SCREEN_WIDTH-20, SCREEN_SCALE_FROM_BOTTOM(80.0f), wstr);
+ #endif
+#endif
CFont::DrawFonts();
DoRWStuffEndOfFrame();
}
@@ -752,6 +892,170 @@ tZonePrint ZonePrint[] =
};
#ifndef MASTER
+
+void
+PrintMemoryUsage(void)
+{
+// little hack
+if(CPools::GetPtrNodePool() == nil)
+return;
+
+ // Style taken from LCS, modified for III
+// CFont::SetFontStyle(FONT_PAGER);
+ CFont::SetFontStyle(FONT_BANK);
+ CFont::SetBackgroundOff();
+ CFont::SetWrapx(640.0f);
+// CFont::SetScale(0.5f, 0.75f);
+ CFont::SetScale(0.4f, 0.75f);
+ CFont::SetCentreOff();
+ CFont::SetCentreSize(640.0f);
+ CFont::SetJustifyOff();
+ CFont::SetPropOn();
+ CFont::SetColor(CRGBA(200, 200, 200, 200));
+ CFont::SetBackGroundOnlyTextOff();
+ CFont::SetDropShadowPosition(0);
+
+ float y;
+
+#ifdef USE_CUSTOM_ALLOCATOR
+ y = 24.0f;
+ sprintf(gString, "Total: %d blocks, %d bytes", gMainHeap.m_totalBlocksUsed, gMainHeap.m_totalMemUsed);
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Game: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_GAME), gMainHeap.GetMemoryUsed(MEMID_GAME));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "World: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_WORLD), gMainHeap.GetMemoryUsed(MEMID_WORLD));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Render: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_RENDER), gMainHeap.GetMemoryUsed(MEMID_RENDER));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Render List: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_RENDERLIST), gMainHeap.GetMemoryUsed(MEMID_RENDERLIST));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Default Models: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_DEF_MODELS), gMainHeap.GetMemoryUsed(MEMID_DEF_MODELS));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Textures: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_TEXTURES), gMainHeap.GetMemoryUsed(MEMID_TEXTURES));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Streaming: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_STREAM), gMainHeap.GetMemoryUsed(MEMID_STREAM));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Streamed Models: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_STREAM_MODELS), gMainHeap.GetMemoryUsed(MEMID_STREAM_MODELS));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Streamed Textures: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_STREAM_TEXUTRES), gMainHeap.GetMemoryUsed(MEMID_STREAM_TEXUTRES));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Animation: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_ANIMATION), gMainHeap.GetMemoryUsed(MEMID_ANIMATION));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Pools: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_POOLS), gMainHeap.GetMemoryUsed(MEMID_POOLS));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Collision: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_COLLISION), gMainHeap.GetMemoryUsed(MEMID_COLLISION));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Game Process: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_GAME_PROCESS), gMainHeap.GetMemoryUsed(MEMID_GAME_PROCESS));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Script: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_SCRIPT), gMainHeap.GetMemoryUsed(MEMID_SCRIPT));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Cars: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_CARS), gMainHeap.GetMemoryUsed(MEMID_CARS));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Frontend: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_FRONTEND), gMainHeap.GetMemoryUsed(MEMID_FRONTEND));
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(24.0f, y, gUString);
+ y += 12.0f;
+#endif
+
+ y = 132.0f;
+ AsciiToUnicode("Pools usage:", gUString);
+ CFont::PrintString(400.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "PtrNode: %d/%d", CPools::GetPtrNodePool()->GetNoOfUsedSpaces(), CPools::GetPtrNodePool()->GetSize());
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(400.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "EntryInfoNode: %d/%d", CPools::GetEntryInfoNodePool()->GetNoOfUsedSpaces(), CPools::GetEntryInfoNodePool()->GetSize());
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(400.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Ped: %d/%d", CPools::GetPedPool()->GetNoOfUsedSpaces(), CPools::GetPedPool()->GetSize());
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(400.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Vehicle: %d/%d", CPools::GetVehiclePool()->GetNoOfUsedSpaces(), CPools::GetVehiclePool()->GetSize());
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(400.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Building: %d/%d", CPools::GetBuildingPool()->GetNoOfUsedSpaces(), CPools::GetBuildingPool()->GetSize());
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(400.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Treadable: %d/%d", CPools::GetTreadablePool()->GetNoOfUsedSpaces(), CPools::GetTreadablePool()->GetSize());
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(400.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Object: %d/%d", CPools::GetObjectPool()->GetNoOfUsedSpaces(), CPools::GetObjectPool()->GetSize());
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(400.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "Dummy: %d/%d", CPools::GetDummyPool()->GetNoOfUsedSpaces(), CPools::GetDummyPool()->GetSize());
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(400.0f, y, gUString);
+ y += 12.0f;
+
+ sprintf(gString, "AudioScriptObjects: %d/%d", CPools::GetAudioScriptObjectPool()->GetNoOfUsedSpaces(), CPools::GetAudioScriptObjectPool()->GetSize());
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(400.0f, y, gUString);
+ y += 12.0f;
+}
+
void
DisplayGameDebugText()
{
@@ -763,11 +1067,15 @@ DisplayGameDebugText()
TWEAKBOOL(bDisplayPosn);
TWEAKBOOL(bDisplayRate);
}
-#endif
+ if(gbPrintMemoryUsage)
+ PrintMemoryUsage();
+#endif
char str[200];
wchar ustr[200];
+
+#ifdef DRAW_GAME_VERSION_TEXT
wchar ver[200];
AsciiToUnicode(version_name, ver);
@@ -782,7 +1090,12 @@ DisplayGameDebugText()
CFont::SetJustifyOff();
CFont::SetBackGroundOnlyTextOff();
CFont::SetColor(CRGBA(255, 108, 0, 255));
+#ifdef FIX_BUGS
CFont::PrintString(SCREEN_SCALE_X(10.0f), SCREEN_SCALE_Y(10.0f), ver);
+#else
+ CFont::PrintString(10.0f, 10.0f, ver);
+#endif
+#endif // #ifdef DRAW_GAME_VERSION_TEXT
FrameSamples++;
FramesPerSecondCounter += 1000.0f / (CTimer::GetTimeStepNonClippedInSeconds() * 1000.0f);
@@ -833,22 +1146,37 @@ DisplayGameDebugText()
AsciiToUnicode(str, ustr);
- // Let's not scale those numbers, they look better that way :eyes:
CFont::SetPropOff();
CFont::SetBackgroundOff();
+#ifdef FIX_BUGS
+ CFont::SetScale(SCREEN_SCALE_X(0.7f), SCREEN_SCALE_Y(1.5f));
+#else
CFont::SetScale(0.7f, 1.5f);
+#endif
CFont::SetCentreOff();
CFont::SetRightJustifyOff();
CFont::SetJustifyOff();
CFont::SetBackGroundOnlyTextOff();
- CFont::SetWrapx(640.0f);
+#ifdef FIX_BUGS
+ CFont::SetWrapx(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH));
+#else
+ CFont::SetWrapx(DEFAULT_SCREEN_WIDTH);
+#endif
CFont::SetFontStyle(FONT_HEADING);
CFont::SetColor(CRGBA(0, 0, 0, 255));
- CFont::PrintString(42.0f, 42.0f, ustr);
+#ifdef FIX_BUGS
+ CFont::PrintString(SCREEN_SCALE_X(40.0f+2.0f), SCREEN_SCALE_Y(40.0f+2.0f), ustr);
+#else
+ CFont::PrintString(40.0f+2.0f, 40.0f+2.0f, ustr);
+#endif
CFont::SetColor(CRGBA(255, 108, 0, 255));
+#ifdef FIX_BUGS
+ CFont::PrintString(SCREEN_SCALE_X(40.0f), SCREEN_SCALE_Y(40.0f), ustr);
+#else
CFont::PrintString(40.0f, 40.0f, ustr);
+#endif
}
}
#endif
@@ -957,9 +1285,11 @@ Render2dStuff(void)
MusicManager.DisplayRadioStationName();
TheConsole.Display();
+#ifdef GTA_SCENE_EDIT
if(CSceneEdit::m_bEditOn)
CSceneEdit::Draw();
else
+#endif
CHud::Draw();
CUserDisplay::OnscnTimer.ProcessForDisplay();
CMessages::Display();
@@ -978,13 +1308,9 @@ RenderMenus(void)
{
if (FrontEndMenuManager.m_bMenuActive)
{
-#ifdef PS2
- gMainHeap.PushMemId(_TODOCONST(17));
-#endif
+ PUSH_MEMID(MEMID_FRONTEND);
FrontEndMenuManager.DrawFrontEnd();
-#ifdef PS2
- gMainHeap.PopMemId();
-#endif
+ POP_MEMID();
}
}
@@ -1008,9 +1334,7 @@ Idle(void *arg)
CTimer::Update();
-#ifdef TIMEBARS
tbInit();
-#endif
CSprite2d::InitPerFrame();
CFont::InitPerFrame();
@@ -1025,58 +1349,42 @@ Idle(void *arg)
CPad::UpdatePads();
FrontEndMenuManager.Process();
} else {
+ PUSH_MEMID(MEMID_GAME_PROCESS);
CPointLights::InitPerFrame();
-#ifdef TIMEBARS
tbStartTimer(0, "CGame::Process");
-#endif
CGame::Process();
-#ifdef TIMEBARS
tbEndTimer("CGame::Process");
- tbStartTimer(0, "DMAudio.Service");
-#endif
- DMAudio.Service();
+ POP_MEMID();
-#ifdef TIMEBARS
+ tbStartTimer(0, "DMAudio.Service");
+ DMAudio.Service();
tbEndTimer("DMAudio.Service");
-#endif
}
if (RsGlobal.quit)
return;
#else
+
+ PUSH_MEMID(MEMID_GAME_PROCESS);
CPointLights::InitPerFrame();
-#ifdef TIMEBARS
+
tbStartTimer(0, "CGame::Process");
-#endif
CGame::Process();
-#ifdef TIMEBARS
tbEndTimer("CGame::Process");
+ POP_MEMID();
+
tbStartTimer(0, "DMAudio.Service");
-#endif
-
DMAudio.Service();
-
-#ifdef TIMEBARS
tbEndTimer("DMAudio.Service");
-#endif
#endif
if(CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing()){
-#ifdef PS2_MENU
- TheMemoryCard.m_bWantToLoad = false;
+ WANT_TO_LOAD = false;
FrontEndMenuManager.m_bWantToRestart = true;
-#else
- FrontEndMenuManager.m_bWantToRestart = true;
- FrontEndMenuManager.m_bWantToLoad = false;
-#endif
return;
}
-#ifdef PS2_MENU
- if ( FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad )
-#else
- if(FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad)
-#endif
+ if(FrontEndMenuManager.m_bWantToRestart || FOUND_GAME_TO_LOAD)
{
return;
}
@@ -1086,30 +1394,30 @@ Idle(void *arg)
if(arg == nil)
return;
+ PUSH_MEMID(MEMID_RENDER);
+
if((!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bRenderGameInMenu) &&
TheCamera.GetScreenFadeStatus() != FADE_2)
{
-#ifdef GTA_PC
+#if defined(GTA_PC) && !defined(RW_GL3) && defined(FIX_BUGS)
+ // This is from SA, but it's nice for windowed mode
if (!FrontEndMenuManager.m_bRenderGameInMenu) {
- // This is from SA, but it's nice for windowed mode
RwV2d pos;
pos.x = SCREEN_WIDTH / 2.0f;
pos.y = SCREEN_HEIGHT / 2.0f;
RsMouseSetPos(&pos);
}
#endif
-#ifdef TIMEBARS
+
+ PUSH_MEMID(MEMID_RENDERLIST);
tbStartTimer(0, "CnstrRenderList");
-#endif
CRenderer::ConstructRenderList();
-#ifdef TIMEBARS
tbEndTimer("CnstrRenderList");
+
tbStartTimer(0, "PreRender");
-#endif
CRenderer::PreRender();
-#ifdef TIMEBARS
tbEndTimer("PreRender");
-#endif
+ POP_MEMID();
#ifdef FIX_BUGS
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE); // TODO: temp? this fixes OpenGL render but there should be a better place for this
@@ -1120,12 +1428,12 @@ Idle(void *arg)
if(CWeather::LightningFlash && !CCullZones::CamNoRain()){
if(!DoRWStuffStartOfFrame_Horizon(255, 255, 255, 255, 255, 255, 255))
- return;
+ goto popret;
}else{
if(!DoRWStuffStartOfFrame_Horizon(CTimeCycle::GetSkyTopRed(), CTimeCycle::GetSkyTopGreen(), CTimeCycle::GetSkyTopBlue(),
CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(),
255))
- return;
+ goto popret;
}
DefinedState();
@@ -1135,13 +1443,9 @@ Idle(void *arg)
RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart());
#endif
-#ifdef TIMEBARS
tbStartTimer(0, "RenderScene");
-#endif
RenderScene();
-#ifdef TIMEBARS
tbEndTimer("RenderScene");
-#endif
#ifdef EXTENDED_PIPELINES
CustomPipes::EnvMapRender();
@@ -1150,21 +1454,23 @@ Idle(void *arg)
RenderDebugShit();
RenderEffects();
-#ifdef TIMEBARS
- tbStartTimer(0, "RenderMotionBlur");
-#endif
if((TheCamera.m_BlurType == MOTION_BLUR_NONE || TheCamera.m_BlurType == MOTION_BLUR_LIGHT_SCENE) &&
TheCamera.m_ScreenReductionPercentage > 0.0f)
TheCamera.SetMotionBlurAlpha(150);
+
+#ifdef SCREEN_DROPLETS
+ CPostFX::GetBackBuffer(Scene.camera);
+ ScreenDroplets::Process();
+ ScreenDroplets::Render();
+#endif
+
+ tbStartTimer(0, "RenderMotionBlur");
TheCamera.RenderMotionBlur();
-#ifdef TIMEBARS
tbEndTimer("RenderMotionBlur");
+
tbStartTimer(0, "Render2dStuff");
-#endif
Render2dStuff();
-#ifdef TIMEBARS
tbEndTimer("Render2dStuff");
-#endif
}else{
#ifdef ASPECT_RATIO_SCALE
CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO);
@@ -1174,47 +1480,45 @@ Idle(void *arg)
CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
if(!RsCameraBeginUpdate(Scene.camera))
- return;
+ goto popret;
}
#ifdef PS2_SAVE_DIALOG
if (FrontEndMenuManager.m_bMenuActive)
DefinedState();
#endif
-#ifdef TIMEBARS
tbStartTimer(0, "RenderMenus");
-#endif
RenderMenus();
-#ifdef TIMEBARS
tbEndTimer("RenderMenus");
- tbStartTimer(0, "DoFade");
-#endif
#ifdef PS2_MENU
if ( TheMemoryCard.m_bWantToLoad )
- return;
+ goto popret;
#endif
+
+ tbStartTimer(0, "DoFade");
DoFade();
-#ifdef TIMEBARS
tbEndTimer("DoFade");
+
tbStartTimer(0, "Render2dStuff-Fade");
-#endif
Render2dStuffAfterFade();
-#ifdef TIMEBARS
tbEndTimer("Render2dStuff-Fade");
-#endif
+
CCredits::Render();
-#ifdef TIMEBARS
if (gbShowTimebars)
tbDisplay();
-#endif
DoRWStuffEndOfFrame();
+ POP_MEMID(); // MEMID_RENDER
+
if(g_SlowMode)
ProcessSlowMode();
+ return;
+
+popret: POP_MEMID(); // MEMID_RENDER
}
void
@@ -1335,15 +1639,6 @@ AppEventHandler(RsEvent event, void *param)
return rsEVENTPROCESSED;
}
-#ifndef MASTER
- case rsANIMVIEWER:
- {
- TheModelViewer();
-
- return rsEVENTPROCESSED;
- }
-#endif
-
default:
{
return rsEVENTNOTPROCESSED;
@@ -1358,8 +1653,11 @@ TheModelViewer(void)
#if (defined(GTA_PS2) || defined(GTA_XBOX))
//TODO
#else
+ // This is III Mobile code. III Xbox code run it like main function, which is impossible to implement on PC's state machine implementation.
+ // Also we want 2D things initialized in here to print animation ids etc., our additions for that marked with X
+
#ifdef ASPECT_RATIO_SCALE
- CDraw::SetAspectRatio(CDraw::FindAspectRatio());
+ CDraw::SetAspectRatio(CDraw::FindAspectRatio()); // X
#endif
CAnimViewer::Update();
CTimer::Update();
@@ -1369,29 +1667,28 @@ TheModelViewer(void)
CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(),
255);
- CSprite2d::InitPerFrame();
- CFont::InitPerFrame();
+ CSprite2d::InitPerFrame(); // X
+ CFont::InitPerFrame(); // X
DefinedState();
CVisibilityPlugins::InitAlphaEntityList();
CAnimViewer::Render();
- Render2dStuff();
+ Render2dStuff(); // X
DoRWStuffEndOfFrame();
#endif
}
#endif
-#ifdef PS2
+
+#ifdef GTA_PS2
void TheGame(void)
{
printf("Into TheGame!!!\n");
-#ifdef GTA_PS2
- gMainHeap.PushMemId(_TODOCONST(1));
-#endif
+ PUSH_MEMID(MEMID_GAME); // NB: not popped
CTimer::Initialise();
-#ifdef GTA_PS2
+#if GTA_VERSION <= GTA3_PS2_160
CGame::Initialise();
#else
CGame::Initialise("DATA\\GTA3.DAT");
@@ -1425,76 +1722,54 @@ void TheGame(void)
while (true)
{
-#ifdef PS2
- if (TheMemoryCard.m_bWantToLoad)
-#else
- if (FrontEndMenuManager.m_bWantToLoad)
-#endif
+ if (WANT_TO_LOAD)
{
Const char *splash1 = GetLevelSplashScreen(CGame::currLevel);
LoadSplash(splash1);
}
-#ifdef PS2
- TheMemoryCard.m_bWantToLoad = false;
-#else
- FrontEndMenuManager.m_bWantToLoad = false;
-#endif
+ WANT_TO_LOAD = false;
CTimer::Update();
-#ifdef PS2
- while (!(FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad))
-#else
- while (!(FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad))
-#endif
+ while (!(FrontEndMenuManager.m_bWantToRestart || FOUND_GAME_TO_LOAD))
{
CSprite2d::InitPerFrame();
CFont::InitPerFrame();
-#ifdef GTA_PS2
- gMainHeap.PushMemId(_TODOCONST(12));
-#endif
- CPointLights::NumLights = 0;
+ PUSH_MEMID(MEMID_GAME_PROCESS)
+ CPointLights::InitPerFrame();
CGame::Process();
-#ifdef GTA_PS2
- gMainHeap.PopMemId();
-#endif
+ POP_MEMID();
DMAudio.Service();
if (CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing())
{
-#ifdef PS2
- TheMemoryCard.m_bWantToLoad = false;
-#else
- FrontEndMenuManager.m_bWantToLoad = false;
-#endif
+ WANT_TO_LOAD = false;
FrontEndMenuManager.m_bWantToRestart = true;
break;
}
-#ifdef PS2
- if (FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad)
-#else
- if (FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad)
-#endif
+ if (FrontEndMenuManager.m_bWantToRestart || FOUND_GAME_TO_LOAD)
break;
SetLightsWithTimeOfDayColour(Scene.world);
-#ifdef GTA_PS2
- gMainHeap.PushMemId(_TODOCONST(15));
-#endif
- if (!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bRenderGameInMenu == true && TheCamera.GetScreenFadeStatus() != FADE_2 )
+ PUSH_MEMID(MEMID_RENDER);
+
+ if ((!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bRenderGameInMenu == true) && TheCamera.GetScreenFadeStatus() != FADE_2 )
{
-#ifdef GTA_PS2
- gMainHeap.PushMemId(_TODOCONST(11));
-#endif
+
+ PUSH_MEMID(MEMID_RENDERLIST);
CRenderer::ConstructRenderList();
CRenderer::PreRender();
-#ifdef GTA_PS2
- gMainHeap.PopMemId();
+ POP_MEMID();
+
+#ifdef FIX_BUGS
+ // This has to be done BEFORE RwCameraBeginUpdate
+ RwCameraSetFarClipPlane(Scene.camera, CTimeCycle::GetFarClip());
+ RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart());
#endif
if (CWeather::LightningFlash && !CCullZones::CamNoRain())
@@ -1503,8 +1778,10 @@ void TheGame(void)
DoRWStuffStartOfFrame_Horizon(CTimeCycle::GetSkyTopRed(), CTimeCycle::GetSkyTopGreen(), CTimeCycle::GetSkyTopBlue(), CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(), 255);
DefinedState();
+#ifndef FIX_BUGS
RwCameraSetFarClipPlane(Scene.camera, CTimeCycle::GetFarClip());
RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart());
+#endif
RenderScene();
RenderDebugShit();
@@ -1518,24 +1795,21 @@ void TheGame(void)
}
else
{
- CameraSize(Scene.camera, NULL, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO);
+#ifdef ASPECT_RATIO_SCALE
+ CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO);
+#else
+ CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, DEFAULT_ASPECT_RATIO);
+#endif
CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
- if (!RsCameraBeginUpdate(Scene.camera))
- break;
+ RsCameraBeginUpdate(Scene.camera);
}
RenderMenus();
-#ifdef PS2
- if (TheMemoryCard.m_bWantToLoad)
-#else
- if (FrontEndMenuManager.m_bWantToLoad)
-#endif
+ if (WANT_TO_LOAD)
{
-#ifdef GTA_PS2
- gMainHeap.PopMemId();
-#endif
+ POP_MEMID(); // MEMID_RENDER
break;
}
@@ -1552,9 +1826,7 @@ void TheGame(void)
CTimer::Update();
-#ifdef GTA_PS2
- gMainHeap.PopMemId();
-#endif
+ POP_MEMID(): // MEMID_RENDER
if (g_SlowMode)
ProcessSlowMode();
@@ -1566,24 +1838,12 @@ void TheGame(void)
CGame::ShutDownForRestart();
CTimer::Stop();
-#ifdef PS2
- if (FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad)
-#else
- if (FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad)
-#endif
+ if (FrontEndMenuManager.m_bWantToRestart || FOUND_GAME_TO_LOAD)
{
-#ifdef PS2
- if (TheMemoryCard.b_FoundRecentSavedGameWantToLoad)
-#else
- if (b_FoundRecentSavedGameWantToLoad)
-#endif
+ if (FOUND_GAME_TO_LOAD)
{
FrontEndMenuManager.m_bWantToRestart = true;
-#ifdef PS2
- TheMemoryCard.m_bWantToLoad = true;
-#else
- FrontEndMenuManager.m_bWantToLoad = true;
-#endif
+ WANT_TO_LOAD = true;
}
CGame::InitialiseWhenRestarting();
@@ -1606,7 +1866,7 @@ void SystemInit()
mwInit();
#endif
-#ifdef GTA_PS2
+#ifdef USE_CUSTOM_ALLOCATOR
InitMemoryMgr();
#endif
@@ -1636,7 +1896,7 @@ void SystemInit()
#ifdef GTA_PS2
CFileMgr::InitCd();
- Char modulepath[256];
+ char modulepath[256];
strcpy(modulepath, "cdrom0:\\");
strcat(modulepath, "SYSTEM\\");
@@ -1723,11 +1983,25 @@ void SystemInit()
//
#endif
-#ifdef PS2
+#ifdef GTA_PS2
TheMemoryCard.Init();
#endif
}
+int VBlankCounter(int ca)
+{
+ frameCount++;
+ ExitHandler();
+ return 0;
+}
+
+// linked against by RW!
+extern "C" void WaitVBlank(void)
+{
+ int32 startFrame = frameCount;
+ while(startFrame == frameCount);
+}
+
void GameInit()
{
if ( !gameAlreadyInitialised )
@@ -1752,7 +2026,7 @@ void GameInit()
#endif
CdStreamInit(MAX_CDCHANNELS);
-#ifdef PS2
+#ifdef GTA_PS2
Initialise3D(); //no params
#else
//TODO
@@ -1771,11 +2045,16 @@ void GameInit()
"\\MODELS\\MISC.TXD;1",
"\\MODELS\\GENERIC.TXD;1",
"\\MODELS\\GTA3.DIR;1",
+ // TODO: japanese?
+#ifdef GTA_PAL
"\\TEXT\\ENGLISH.GXT;1",
"\\TEXT\\FRENCH.GXT;1",
"\\TEXT\\GERMAN.GXT;1",
"\\TEXT\\ITALIAN.GXT;1",
"\\TEXT\\SPANISH.GXT;1",
+#else
+ "\\TEXT\\AMERICAN.GXT;1",
+#endif
"\\TXD\\LOADSC0.TXD;1",
"\\TXD\\LOADSC1.TXD;1",
"\\TXD\\LOADSC2.TXD;1",
@@ -1859,21 +2138,18 @@ void GameInit()
CreateDebugFont();
#ifdef GTA_PS2
- AddIntcHandler(_TODOCONST(2), VBlankCounter, 0);
+ AddIntcHandler(INTC_VBLANK_S, VBlankCounter, 0);
#endif
CameraSize(Scene.camera, NULL, DEFAULT_VIEWWINDOW, DEFAULT_ASPECT_RATIO);
CSprite2d::SetRecipNearClip();
CTxdStore::Initialise();
-#ifdef GTA_PS2
- gMainHeap.PushMemId(_TODOCONST(9));
-#endif
+
+ PUSH_MEMID(MEMID_TEXTURES);
CFont::Initialise();
CHud::Initialise();
-#ifdef GTA_PS2
- gMainHeap.PopMemId();
-#endif
+ POP_MEMID();
ValidateVersion();
@@ -1892,6 +2168,36 @@ void GameInit()
}
}
+void PlayIntroMPEGs()
+{
+#ifdef GTA_PS2
+ if (gameAlreadyInitialised)
+ RpSkySuspend();
+
+ InitMPEGPlayer();
+
+#ifdef GTA_PAL
+ PlayMPEG("cdrom0:\\MOVIES\\DMAPAL.PSS;1", false);
+
+ if (CGame::frenchGame || CGame::germanGame)
+ PlayMPEG("cdrom0:\\MOVIES\\INTROPAF.PSS;1", true);
+ else
+ PlayMPEG("cdrom0:\\MOVIES\\INTROPAL.PSS;1", true);
+#else
+ PlayMPEG("cdrom0:\\MOVIES\\DMANTSC.PSS;1", false);
+
+ PlayMPEG("cdrom0:\\MOVIES\\INTRNTSC.PSS;1", true);
+#endif
+
+ ShutdownMPEGPlayer();
+
+ if ( gameAlreadyInitialised )
+ RpSkyResume();
+#else
+ //TODO
+#endif
+}
+
int
main(int argc, char *argv[])
{
@@ -1901,11 +2207,10 @@ main(int argc, char *argv[])
SystemInit();
-#ifdef PS2
+#ifdef GTA_PS2
int32 r = TheMemoryCard.CheckCardStateAtGameStartUp(CARD_ONE);
- if ( r == CMemoryCard::ERR_DIRNOENTRY || r == CMemoryCard::ERR_NOFORMAT
- && r != CMemoryCard::ERR_OPENNOENTRY && r != CMemoryCard::ERR_NONE )
+ if ( r == CMemoryCard::ERR_DIRNOENTRY || r == CMemoryCard::ERR_NOFORMAT )
{
GameInit();
@@ -1915,31 +2220,12 @@ main(int argc, char *argv[])
CFont::Initialise();
FrontEndMenuManager.DrawMemoryCardStartUpMenus();
+ }else if(r == CMemoryCard::ERR_OPENNOENTRY || r == CMemoryCard::ERR_NONE){
+ // eh?
}
#endif
-
-#ifdef GTA_PS2
- {
- if (gameAlreadyInitialised)
- RpSkySuspend();
- InitMPEGPlayer();
-
- PlayMPEG("cdrom0:\\MOVIES\\DMAPAL.PSS;1", false);
-
- if (CGame::frenchGame || CGame::germanGame)
- PlayMPEG("cdrom0:\\MOVIES\\INTROPAF.PSS;1", true);
- else
- PlayMPEG("cdrom0:\\MOVIES\\INTROPAL.PSS;1", true);
-
- ShutdownMPEGPlayer();
-
- if ( gameAlreadyInitialised )
- RpSkyResume();
- }
-#else
- //TODO
-#endif
+ PlayIntroMPEGs();
GameInit();
diff --git a/src/core/main.h b/src/core/main.h
index 96fbef05..149c0878 100644
--- a/src/core/main.h
+++ b/src/core/main.h
@@ -16,6 +16,12 @@ extern bool gbPrintShite;
extern bool gbModelViewer;
#ifdef TIMEBARS
extern bool gbShowTimebars;
+#else
+#define gbShowTimebars false
+#endif
+
+#ifndef FINAL
+extern bool gbPrintMemoryUsage;
#endif
class CSprite2d;
@@ -23,6 +29,7 @@ class CSprite2d;
bool DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
bool DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
void DoRWStuffEndOfFrame(void);
+void PreAllocateRwObjects(void);
void InitialiseGame(void);
void LoadingScreen(const char *str1, const char *str2, const char *splashscreen);
void LoadingIslandScreen(const char *levelName);
@@ -36,3 +43,8 @@ void ResetLoadingScreenBar(void);
#ifndef MASTER
void TheModelViewer(void);
#endif
+
+#ifdef LOAD_INI_SETTINGS
+void LoadINISettings();
+void SaveINISettings();
+#endif
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 71bbe0ae..82c084b1 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -15,8 +15,6 @@
#include "Boat.h"
#include "Heli.h"
#include "Automobile.h"
-#include "Ped.h"
-#include "Particle.h"
#include "Console.h"
#include "Debug.h"
#include "Hud.h"
@@ -26,19 +24,23 @@
#include "Radar.h"
#include "debugmenu.h"
#include "Frontend.h"
-#include "Text.h"
#include "WaterLevel.h"
#include "main.h"
-#include "MBlur.h"
+#include "Script.h"
#include "postfx.h"
#include "custompipes.h"
+#include "MemoryHeap.h"
+
+#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
+#include "FileMgr.h"
+#include "ControllerConfig.h"
+#endif
#ifndef _WIN32
#include "assert.h"
#include
#endif
-#ifdef __WIIU__
#include
#include
#endif
@@ -46,8 +48,6 @@
#include
#ifdef RWLIBS
-extern "C" int vsprintf(char* const _Buffer, char const* const _Format, va_list _ArgList);
-#endif
#ifdef USE_PS2_RAND
@@ -78,325 +78,168 @@ mysrand(unsigned int seed)
#ifdef CUSTOM_FRONTEND_OPTIONS
#include "frontendoption.h"
-#include "platform.h"
-#include "Font.h"
-void ReloadFrontendOptions(void)
-{
- CustomFrontendOptionsPopulate();
-}
-
-void RestoreDefGraphics(int8 action) {
- if (action != FEOPTION_ACTION_SELECT)
- return;
-
- #ifdef PS2_ALPHA_TEST
- gPS2alphaTest = false;
- #endif
- #ifdef MULTISAMPLING
- FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel = 0;
- #endif
- #ifdef GRAPHICS_MENU_OPTIONS // otherwise Frontend will handle those
- CMenuManager::m_PrefsFrameLimiter = true;
- CMenuManager::m_PrefsVsyncDisp = true;
- CMenuManager::m_PrefsVsync = true;
- CMenuManager::m_PrefsUseWideScreen = false;
- FrontEndMenuManager.m_nDisplayVideoMode = FrontEndMenuManager.m_nPrefsVideoMode;
- #ifdef GTA3_1_1_PATCH
- if (_dwOperatingSystemVersion == OS_WIN98) {
- CMBlur::BlurOn = false;
- CMBlur::MotionBlurClose();
- } else {
- CMBlur::BlurOn = true;
- CMBlur::MotionBlurOpen(Scene.camera);
- }
- #else
- CMBlur::BlurOn = true;
- #endif
- FrontEndMenuManager.SaveSettings();
- #endif
-}
-
-void RestoreDefDisplay(int8 action) {
- if (action != FEOPTION_ACTION_SELECT)
- return;
-
- #ifdef CUTSCENE_BORDERS_SWITCH
- CMenuManager::m_PrefsCutsceneBorders = true;
- #endif
- #ifdef FREE_CAM
- TheCamera.bFreeCam = false;
- #endif
- #ifdef GRAPHICS_MENU_OPTIONS // otherwise Frontend will handle those
- CMenuManager::m_PrefsBrightness = 256;
- CMenuManager::m_PrefsLOD = 1.2f;
- CRenderer::ms_lodDistScale = 1.2f;
- CMenuManager::m_PrefsShowSubtitles = true;
- FrontEndMenuManager.SaveSettings();
- #endif
-}
-
-#ifdef MULTISAMPLING
-void MultiSamplingGoBack() {
- FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel;
-}
-
-void MultiSamplingButtonPress(int8 action) {
- if (action == FEOPTION_ACTION_SELECT) {
- if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) {
- FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel;
- _psSelectScreenVM(FrontEndMenuManager.m_nPrefsVideoMode);
- FrontEndMenuManager.SetHelperText(0);
- FrontEndMenuManager.SaveSettings();
- }
- } else if (action == FEOPTION_ACTION_LEFT || action == FEOPTION_ACTION_RIGHT) {
- if (FrontEndMenuManager.m_bGameNotLoaded) {
- FrontEndMenuManager.m_nDisplayMSAALevel += (action == FEOPTION_ACTION_RIGHT ? 1 : -1);
-
- int i = 0;
- int maxAA = RwD3D8EngineGetMaxMultiSamplingLevels();
- while (maxAA != 1) {
- i++;
- maxAA >>= 1;
- }
-
- if (FrontEndMenuManager.m_nDisplayMSAALevel < 0)
- FrontEndMenuManager.m_nDisplayMSAALevel = i;
- else if (FrontEndMenuManager.m_nDisplayMSAALevel > i)
- FrontEndMenuManager.m_nDisplayMSAALevel = 0;
- }
- } else if (action == FEOPTION_ACTION_FOCUSLOSS) {
- if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) {
- FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel;
- FrontEndMenuManager.SetHelperText(3);
- }
- }
-}
-
-wchar* MultiSamplingDraw(bool *disabled, bool userHovering) {
- static wchar unicodeTemp[64];
- if (userHovering) {
- if (FrontEndMenuManager.m_nDisplayMSAALevel == FrontEndMenuManager.m_nPrefsMSAALevel) {
- if (FrontEndMenuManager.m_nHelperTextMsgId == 1) // Press enter to apply
- FrontEndMenuManager.ResetHelperText();
- } else {
- FrontEndMenuManager.SetHelperText(1);
- }
- } else {
- if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) {
- FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel;
- }
- }
-
- if (!FrontEndMenuManager.m_bGameNotLoaded)
- *disabled = true;
-
- switch (FrontEndMenuManager.m_nDisplayMSAALevel) {
- case 0:
- return TheText.Get("FEM_OFF");
- default:
- sprintf(gString, "%iX", 1 << (FrontEndMenuManager.m_nDisplayMSAALevel));
- AsciiToUnicode(gString, unicodeTemp);
- return unicodeTemp;
- }
-}
-#endif
-
-#ifdef MORE_LANGUAGES
-void LangPolSelect(int8 action)
-{
- if (action == FEOPTION_ACTION_SELECT) {
- FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_POLISH;
- FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true;
- FrontEndMenuManager.InitialiseChangedLanguageSettings();
- FrontEndMenuManager.SaveSettings();
- }
-}
-
-void LangRusSelect(int8 action)
-{
- if (action == FEOPTION_ACTION_SELECT) {
- FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_RUSSIAN;
- FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true;
- FrontEndMenuManager.InitialiseChangedLanguageSettings();
- FrontEndMenuManager.SaveSettings();
- }
-}
-
-void LangJapSelect(int8 action)
-{
- if (action == FEOPTION_ACTION_SELECT) {
- FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_JAPANESE;
- FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true;
- FrontEndMenuManager.InitialiseChangedLanguageSettings();
- FrontEndMenuManager.SaveSettings();
- }
-}
-#endif
-
-#ifdef IMPROVED_VIDEOMODE
-void ScreenModeChange(int8 displayedValue)
-{
- if (displayedValue != FrontEndMenuManager.m_nPrefsWindowed) {
- FrontEndMenuManager.m_nPrefsWindowed = displayedValue;
- _psSelectScreenVM(FrontEndMenuManager.m_nPrefsVideoMode); // apply same resolution
- FrontEndMenuManager.SetHelperText(0);
- FrontEndMenuManager.SaveSettings();
- }
-}
-#endif
-
-#ifdef FREE_CAM
-void FreeCamChange(int8 displayedValue)
-{
- TheCamera.bFreeCam = !!displayedValue;
- FrontEndMenuManager.SaveSettings();
-}
-#endif
-
-#ifdef CUTSCENE_BORDERS_SWITCH
-void BorderModeChange(int8 displayedValue)
-{
- CMenuManager::m_PrefsCutsceneBorders = !!displayedValue;
- FrontEndMenuManager.SaveSettings();
-}
-#endif
-
-#ifdef PS2_ALPHA_TEST
-void PS2AlphaTestChange(int8 displayedValue)
-{
- gPS2alphaTest = !!displayedValue;
- FrontEndMenuManager.SaveSettings();
-}
-#endif
-
-
-// Important: Make sure to read the warnings/informations in frontendoption.h!!
-// For texts: Either use TheText.Get, or use wcsdup(wchar version of strdup)
void
CustomFrontendOptionsPopulate(void)
{
- RemoveCustomFrontendOptions(); // if exist
-
- // -- Graphics/display seperation preperation starts - don't add options in here!
-#ifdef GRAPHICS_MENU_OPTIONS
- int graphicsMenu = FrontendScreenAdd("FET_GRA", MENUSPRITE_MAINMENU, MENUPAGE_OPTIONS, 50, 0, 20,
- FONT_HEADING, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, true);
-
- int newDisplayMenu = FrontendScreenAdd("FET_DIS", MENUSPRITE_MAINMENU, MENUPAGE_OPTIONS, 50, 0, 20,
- FONT_HEADING, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, true);
-
- FrontendOptionSetCursor(MENUPAGE_OPTIONS, 2, true);
- FrontendOptionAddRedirect(TheText.Get("FET_DIS"), newDisplayMenu, 0);
- FrontendOptionSetCursor(MENUPAGE_OPTIONS, 3);
- FrontendOptionAddRedirect(TheText.Get("FET_GRA"), graphicsMenu, 0);
-
-#define SWITCH_TO_GRAPHICS_MENU FrontendOptionSetCursor(graphicsMenu, -1);
-#define SWITCH_TO_DISPLAY_MENU FrontendOptionSetCursor(newDisplayMenu, -1);
-#define CLONE_OPTION(a, b, c, d) FrontendOptionAddBuiltinAction(a, b, c, d);
-#define ADD_BACK FrontendOptionAddBackButton(TheText.Get("FEDS_TB"));
-#define ADD_RESTORE_DEFAULTS(a) FrontendOptionAddDynamic(TheText.Get("FET_DEF"), nil, nil, a, nil);
-#else
- int advancedDisplayMenu = FrontendScreenAdd("FET_ADV", MENUSPRITE_MAINMENU, MENUPAGE_DISPLAY_SETTINGS, 50, 0, 20,
- FONT_HEADING, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, true);
- bool movedToAdvMenu = false;
-
-#define SWITCH_TO_GRAPHICS_MENU \
- if (GetNumberOfMenuOptions(MENUPAGE_DISPLAY_SETTINGS) >= 12) { \
- FrontendOptionSetCursor(advancedDisplayMenu, -1); \
- movedToAdvMenu = true; \
- } else { \
- FrontendOptionSetCursor(MENUPAGE_DISPLAY_SETTINGS, -3); \
- }
-
-#define SWITCH_TO_DISPLAY_MENU SWITCH_TO_GRAPHICS_MENU
-#define CLONE_OPTION(a, b, c, d)
-#define ADD_BACK
-#define ADD_RESTORE_DEFAULTS(a)
-#endif
- // -- Graphics/display seperation preperation end
-
- const wchar* off_on[] = { TheText.Get("FEM_OFF"), TheText.Get("FEM_ON") };
-
-#ifdef MORE_LANGUAGES
- FrontendOptionSetCursor(MENUPAGE_LANGUAGE_SETTINGS, -2);
- FrontendOptionAddDynamic(TheText.Get("FEL_POL"), nil, nil, LangPolSelect, nil);
- FrontendOptionAddDynamic(TheText.Get("FEL_RUS"), nil, nil, LangRusSelect, nil);
- FrontendOptionAddDynamic(TheText.Get("FEL_JAP"), nil, nil, LangJapSelect, nil);
-#endif
-
-#ifdef MENU_MAP
- FrontendOptionSetCursor(MENUPAGE_PAUSE_MENU, 2);
- FrontendOptionAddRedirect(TheText.Get("FEG_MAP"), MENUPAGE_MAP);
-#endif
-
- // -- Start of graphics menu - add options in display order!
-
- SWITCH_TO_GRAPHICS_MENU
- CLONE_OPTION(TheText.Get("FED_RES"), MENUACTION_SCREENRES, nil, nil);
- CLONE_OPTION(TheText.Get("FED_WIS"), MENUACTION_WIDESCREEN, nil, nil)
-
-#ifdef IMPROVED_VIDEOMODE
- const wchar* screenModes[] = { TheText.Get("FED_FLS"), TheText.Get("FED_WND") };
- // Storing isn't enabled because it's handled in Frontend
- FrontendOptionAddSelect(TheText.Get("FEM_SCF"), screenModes, 2, (int8*)&FrontEndMenuManager.m_nPrefsWindowed, true, ScreenModeChange, nil);
-#endif
-
- CLONE_OPTION(TheText.Get("FEM_VSC"), MENUACTION_FRAMESYNC, nil, nil);
- CLONE_OPTION(TheText.Get("FEM_FRM"), MENUACTION_FRAMELIMIT, nil, nil);
-
-#ifdef MULTISAMPLING
- SWITCH_TO_GRAPHICS_MENU
- FrontendOptionAddDynamic(TheText.Get("FED_AAS"), MultiSamplingDraw, (int8*)&FrontEndMenuManager.m_nPrefsMSAALevel, MultiSamplingButtonPress, MultiSamplingGoBack, true);
-#endif
-
- CLONE_OPTION(TheText.Get("FED_TRA"), MENUACTION_TRAILS, nil, nil);
-
-#ifdef PS2_ALPHA_TEST
- SWITCH_TO_GRAPHICS_MENU
- FrontendOptionAddSelect(TheText.Get("FEM_2PR"), off_on, 2, (int8*)&gPS2alphaTest, false, PS2AlphaTestChange, nil, true);
-#endif
-
- ADD_RESTORE_DEFAULTS(RestoreDefGraphics)
- ADD_BACK
-
- // ---- End of Graphics Menu ----
-
- // -- Start of Display menu - add options in display order!
-
- SWITCH_TO_DISPLAY_MENU
- CLONE_OPTION(TheText.Get("FED_BRI"), MENUACTION_BRIGHTNESS, nil, nil);
- CLONE_OPTION(TheText.Get("FEM_LOD"), MENUACTION_DRAWDIST, nil, nil);
-
-#ifdef CUTSCENE_BORDERS_SWITCH
- SWITCH_TO_DISPLAY_MENU
- FrontendOptionAddSelect(TheText.Get("FEM_CSB"), off_on, 2, (int8 *)&CMenuManager::m_PrefsCutsceneBorders, false, BorderModeChange, nil, true);
-#endif
-
-#ifdef FREE_CAM
- SWITCH_TO_DISPLAY_MENU
- static const wchar* text = (wchar*)wcsdup(L"FREE CAM");
- FrontendOptionAddSelect(text, off_on, 2, (int8*)&TheCamera.bFreeCam, false, FreeCamChange, nil, true);
-#endif
-
- CLONE_OPTION(TheText.Get("FED_SUB"), MENUACTION_SUBTITLES, nil, nil);
-
- // Add link to advanced graphics menu if it's filled.
-#ifndef GRAPHICS_MENU_OPTIONS
- if (movedToAdvMenu) {
- FrontendOptionSetCursor(MENUPAGE_DISPLAY_SETTINGS, -3);
- FrontendOptionAddRedirect(TheText.Get("FET_ADV"), advancedDisplayMenu, 0);
-
- FrontendOptionSetCursor(advancedDisplayMenu, -1);
- FrontendOptionAddBackButton(TheText.Get("FEDS_TB"));
- }
-#endif
-
- ADD_RESTORE_DEFAULTS(RestoreDefDisplay)
- ADD_BACK
+ // Moved to an array in MenuScreensCustom.cpp, but APIs are still available. see frontendoption.h
}
#endif
+#ifdef LOAD_INI_SETTINGS
+#include "ini_parser.hpp"
+
+linb::ini cfg;
+int CheckAndReadIniInt(const char *cat, const char *key, int original)
+{
+ std::string strval = cfg.get(cat, key, "");
+ const char *value = strval.c_str();
+ if (value && value[0] != '\0')
+ return atoi(value);
+
+ return original;
+}
+
+float CheckAndReadIniFloat(const char *cat, const char *key, float original)
+{
+ std::string strval = cfg.get(cat, key, "");
+ const char *value = strval.c_str();
+ if (value && value[0] != '\0')
+ return atof(value);
+
+ return original;
+}
+
+void CheckAndSaveIniInt(const char *cat, const char *key, int val, bool &changed)
+{
+ char temp[10];
+ if (atoi(cfg.get(cat, key, "xxx").c_str()) != val) { // if .ini doesn't have our key, compare with xxx and forcefully add it
+ changed = true;
+ sprintf(temp, "%u", val);
+ cfg.set(cat, key, temp);
+ }
+}
+
+void CheckAndSaveIniFloat(const char *cat, const char *key, float val, bool &changed)
+{
+ char temp[10];
+ if (atof(cfg.get(cat, key, "xxx").c_str()) != val) { // if .ini doesn't have our key, compare with xxx and forcefully add it
+ changed = true;
+ sprintf(temp, "%f", val);
+ cfg.set(cat, key, temp);
+ }
+}
+
+void LoadINISettings()
+{
+ cfg.load_file("re3.ini");
+
+#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
+ // Written by assuming the codes below will run after _InputInitialiseJoys().
+ strcpy(gSelectedJoystickName, cfg.get("DetectJoystick", "JoystickName", "").c_str());
+
+ if(gSelectedJoystickName[0] != '\0') {
+ for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) {
+ if (glfwJoystickPresent(i) && strncmp(gSelectedJoystickName, glfwGetJoystickName(i), strlen(gSelectedJoystickName)) == 0) {
+ if (PSGLOBAL(joy1id) != -1) {
+ PSGLOBAL(joy2id) = PSGLOBAL(joy1id);
+ }
+ PSGLOBAL(joy1id) = i;
+ int count;
+ glfwGetJoystickButtons(PSGLOBAL(joy1id), &count);
+
+ // We need to init and reload bindings, because;
+ // 1-joypad button number may differ with saved/prvly connected one
+ // 2-bindings are not init'ed if there is no joypad at the start
+ ControlsManager.InitDefaultControlConfigJoyPad(count);
+ CFileMgr::SetDirMyDocuments();
+ int32 gta3set = CFileMgr::OpenFile("gta3.set", "r");
+ if (gta3set) {
+ ControlsManager.LoadSettings(gta3set);
+ CFileMgr::CloseFile(gta3set);
+ }
+ CFileMgr::SetDir("");
+ break;
+ }
+ }
+ }
+#endif
+
+#ifdef CUSTOM_FRONTEND_OPTIONS
+ for (int i = 0; i < MENUPAGES; i++) {
+ for (int j = 0; j < NUM_MENUROWS; j++) {
+ CMenuScreenCustom::CMenuEntry &option = aScreens[i].m_aEntries[j];
+ if (option.m_Action == MENUACTION_NOTHING)
+ break;
+
+ // CFO check
+ if (option.m_Action < MENUACTION_NOTHING && option.m_CFO->save) {
+ // CFO only supports saving uint8 right now
+ *option.m_CFO->value = CheckAndReadIniInt("FrontendOptions", option.m_CFO->save, *option.m_CFO->value);
+ if (option.m_Action == MENUACTION_CFO_SELECT) {
+ option.m_CFOSelect->lastSavedValue = option.m_CFOSelect->displayedValue = *option.m_CFO->value;
+ }
+ }
+ }
+ }
+#endif
+
+#ifdef EXTENDED_COLOURFILTER
+ CPostFX::Intensity = CheckAndReadIniFloat("CustomPipesValues", "PostFXIntensity", CPostFX::Intensity);
+#endif
+#ifdef EXTENDED_PIPELINES
+ CustomPipes::VehicleShininess = CheckAndReadIniFloat("CustomPipesValues", "NeoVehicleShininess", CustomPipes::VehicleShininess);
+ CustomPipes::VehicleSpecularity = CheckAndReadIniFloat("CustomPipesValues", "NeoVehicleSpecularity", CustomPipes::VehicleSpecularity);
+ CustomPipes::RimlightMult = CheckAndReadIniFloat("CustomPipesValues", "RimlightMult", CustomPipes::RimlightMult);
+ CustomPipes::LightmapMult = CheckAndReadIniFloat("CustomPipesValues", "LightmapMult", CustomPipes::LightmapMult);
+ CustomPipes::GlossMult = CheckAndReadIniFloat("CustomPipesValues", "GlossMult", CustomPipes::GlossMult);
+#endif
+}
+
+void SaveINISettings()
+{
+ bool changed = false;
+ char temp[4];
+
+#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
+ if (strncmp(cfg.get("DetectJoystick", "JoystickName", "").c_str(), gSelectedJoystickName, strlen(gSelectedJoystickName)) != 0) {
+ changed = true;
+ cfg.set("DetectJoystick", "JoystickName", gSelectedJoystickName);
+ }
+#endif
+#ifdef CUSTOM_FRONTEND_OPTIONS
+ for (int i = 0; i < MENUPAGES; i++) {
+ for (int j = 0; j < NUM_MENUROWS; j++) {
+ CMenuScreenCustom::CMenuEntry &option = aScreens[i].m_aEntries[j];
+ if (option.m_Action == MENUACTION_NOTHING)
+ break;
+
+ if (option.m_Action < MENUACTION_NOTHING && option.m_CFO->save) {
+ // Beware: CFO only supports saving uint8 right now
+ CheckAndSaveIniInt("FrontendOptions", option.m_CFO->save, *option.m_CFO->value, changed);
+ }
+ }
+ }
+#endif
+
+#ifdef EXTENDED_COLOURFILTER
+ CheckAndSaveIniFloat("CustomPipesValues", "PostFXIntensity", CPostFX::Intensity, changed);
+#endif
+#ifdef EXTENDED_PIPELINES
+ CheckAndSaveIniFloat("CustomPipesValues", "NeoVehicleShininess", CustomPipes::VehicleShininess, changed);
+ CheckAndSaveIniFloat("CustomPipesValues", "NeoVehicleSpecularity", CustomPipes::VehicleSpecularity, changed);
+ CheckAndSaveIniFloat("CustomPipesValues", "RimlightMult", CustomPipes::RimlightMult, changed);
+ CheckAndSaveIniFloat("CustomPipesValues", "LightmapMult", CustomPipes::LightmapMult, changed);
+ CheckAndSaveIniFloat("CustomPipesValues", "GlossMult", CustomPipes::GlossMult, changed);
+#endif
+
+ if (changed)
+ cfg.write_file("re3.ini");
+}
+
+#endif
+
+
#ifdef DEBUGMENU
void WeaponCheat();
void HealthCheat();
@@ -536,6 +379,19 @@ ResetCamStatics(void)
TheCamera.Cams[TheCamera.ActiveCam].ResetStatics = true;
}
+#ifdef MISSION_SWITCHER
+int8 nextMissionToSwitch = 0;
+static void
+SwitchToMission(void)
+{
+ CTheScripts::SwitchToMission(nextMissionToSwitch);
+}
+#endif
+
+#ifdef USE_CUSTOM_ALLOCATOR
+static void ParseHeap(void) { gMainHeap.ParseHeap(); }
+#endif
+
static const char *carnames[] = {
"landstal", "idaho", "stinger", "linerun", "peren", "sentinel", "patriot", "firetruk", "trash", "stretch", "manana", "infernus", "blista", "pony",
"mule", "cheetah", "ambulan", "fbicar", "moonbeam", "esperant", "taxi", "kuruma", "bobcat", "mrwhoop", "bfinject", "corpse", "police", "enforcer",
@@ -544,6 +400,8 @@ static const char *carnames[] = {
"yankee", "escape", "borgnine", "toyz", "ghost",
};
+//#include
+
static CTweakVar** TweakVarsList;
static int TweakVarsListSize = -1;
static bool bAddTweakVarsNow = false;
@@ -556,7 +414,7 @@ void CTweakVars::Add(CTweakVar *var)
TweakVarsListSize = 0;
}
if(TweakVarsListSize > 63)
- TweakVarsList = (CTweakVar**) realloc(TweakVarsList, (TweakVarsListSize + 1) * sizeof(var));
+ TweakVarsList = (CTweakVar**) realloc(TweakVarsList, (TweakVarsListSize + 1) * sizeof(*var));
TweakVarsList[TweakVarsListSize++] = var;
// TweakVarsList.push_back(var);
@@ -695,9 +553,12 @@ DebugMenuPopulate(void)
DebugMenuEntrySetWrap(e, true);
DebugMenuAddVar("Render", "Neo Vehicle Shininess", &CustomPipes::VehicleShininess, nil, 0.1f, 0, 1.0f);
DebugMenuAddVar("Render", "Neo Vehicle Specularity", &CustomPipes::VehicleSpecularity, nil, 0.1f, 0, 1.0f);
- DebugMenuAddVar("Render", "Neo Ped Rim light", &CustomPipes::RimlightMult, nil, 0.1f, 0, 1.0f);
- DebugMenuAddVar("Render", "Neo World Lightmaps", &CustomPipes::LightmapMult, nil, 0.1f, 0, 1.0f);
- DebugMenuAddVar("Render", "Neo Road Gloss", &CustomPipes::GlossMult, nil, 0.1f, 0, 1.0f);
+ DebugMenuAddVarBool8("Render", "Neo Ped Rim light enable", &CustomPipes::RimlightEnable, nil);
+ DebugMenuAddVar("Render", "Mult", &CustomPipes::RimlightMult, nil, 0.1f, 0, 1.0f);
+ DebugMenuAddVarBool8("Render", "Neo World Lightmaps enable", &CustomPipes::LightmapEnable, nil);
+ DebugMenuAddVar("Render", "Mult", &CustomPipes::LightmapMult, nil, 0.1f, 0, 1.0f);
+ DebugMenuAddVarBool8("Render", "Neo Road Gloss enable", &CustomPipes::GlossEnable, nil);
+ DebugMenuAddVar("Render", "Mult", &CustomPipes::GlossMult, nil, 0.1f, 0, 1.0f);
#endif
DebugMenuAddVarBool8("Render", "Show Ped Paths", &gbShowPedPaths, nil);
DebugMenuAddVarBool8("Render", "Show Car Paths", &gbShowCarPaths, nil);
@@ -713,8 +574,19 @@ DebugMenuPopulate(void)
DebugMenuAddVarBool8("Render", "Don't render Objects", &gbDontRenderObjects, nil);
DebugMenuAddVarBool8("Render", "Don't Render Water", &gbDontRenderWater, nil);
+#ifndef FINAL
+ DebugMenuAddVarBool8("Debug", "Print Memory Usage", &gbPrintMemoryUsage, nil);
+#ifdef USE_CUSTOM_ALLOCATOR
+ DebugMenuAddCmd("Debug", "Parse Heap", ParseHeap);
+#endif
+#endif
+ DebugMenuAddVarBool8("Debug", "Show cullzone debug stuff", &gbShowCullZoneDebugStuff, nil);
+ DebugMenuAddVarBool8("Debug", "Disable zone cull", &gbDisableZoneCull, nil);
+
DebugMenuAddVarBool8("Debug", "pad 1 -> pad 2", &CPad::m_bMapPadOneToPadTwo, nil);
+#ifdef GTA_SCENE_EDIT
DebugMenuAddVarBool8("Debug", "Edit on", &CSceneEdit::m_bEditOn, nil);
+#endif
#ifdef MENU_MAP
DebugMenuAddCmd("Debug", "Teleport to map waypoint", TeleportToWaypoint);
#endif
@@ -731,9 +603,6 @@ DebugMenuPopulate(void)
DebugMenuAddCmd("Debug", "Catalina Fly Away", CHeli::MakeCatalinaHeliFlyAway);
DebugMenuAddVarBool8("Debug", "Script Heli On", &CHeli::ScriptHeliOn, nil);
-#ifdef CUSTOM_FRONTEND_OPTIONS
- DebugMenuAddCmd("Debug", "Reload custom frontend options", ReloadFrontendOptions);
-#endif
DebugMenuAddVarBool8("Debug", "Toggle popping heads on headshot", &CPed::bPopHeadsOnHeadshot, nil);
DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start);
DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop);
@@ -742,6 +611,29 @@ DebugMenuPopulate(void)
#ifdef TIMEBARS
DebugMenuAddVarBool8("Debug", "Show Timebars", &gbShowTimebars, nil);
#endif
+#ifdef MISSION_SWITCHER
+ DebugMenuEntry *missionEntry;
+ static const char* missions[] = {
+ "Intro Movie", "Hospital Info Scene", "Police Station Info Scene",
+ "RC Diablo Destruction", "RC Mafia Massacre", "RC Rumpo Rampage", "RC Casino Calamity",
+ "Patriot Playground", "A Ride In The Park", "Gripped!", "Multistorey Mayhem",
+ "Paramedic", "Firefighter", "Vigilante", "Taxi Driver",
+ "The Crook", "The Thieves", "The Wife", "Her Lover",
+ "Give Me Liberty and Luigi's Girls", "Don't Spank My Bitch Up", "Drive Misty For Me", "Pump-Action Pimp", "The Fuzz Ball",
+ "Mike Lips Last Lunch", "Farewell 'Chunky' Lee Chong", "Van Heist", "Cipriani's Chauffeur", "Dead Skunk In The Trunk", "The Getaway",
+ "Taking Out The Laundry", "The Pick-Up", "Salvatore's Called A Meeting", "Triads And Tribulations", "Blow Fish", "Chaperone", "Cutting The Grass",
+ "Bomb Da Base: Act I", "Bomb Da Base: Act II", "Last Requests", "Turismo", "I Scream, You Scream", "Trial By Fire", "Big'N'Veiny", "Sayonara Salvatore",
+ "Under Surveillance", "Paparazzi Purge", "Payday For Ray", "Two-Faced Tanner", "Kanbu Bust-Out", "Grand Theft Auto", "Deal Steal", "Shima", "Smack Down",
+ "Silence The Sneak", "Arms Shortage", "Evidence Dash", "Gone Fishing", "Plaster Blaster", "Marked Man",
+ "Liberator", "Waka-Gashira Wipeout!", "A Drop In The Ocean", "Bling-Bling Scramble", "Uzi Rider", "Gangcar Round-Up", "Kingdom Come",
+ "Grand Theft Aero", "Escort Service", "Decoy", "Love's Disappearance", "Bait", "Espresso-2-Go!", "S.A.M.",
+ "Uzi Money", "Toyminator", "Rigged To Blow", "Bullion Run", "Rumble", "The Exchange"
+ };
+
+ missionEntry = DebugMenuAddVar("Debug", "Select mission", &nextMissionToSwitch, nil, 1, 0, 79, missions);
+ DebugMenuEntrySetWrap(missionEntry, true);
+ DebugMenuAddCmd("Debug", "Start selected mission ", SwitchToMission);
+#endif
extern bool PrintDebugCode;
extern int16 DebugCamMode;
diff --git a/src/core/templates.h b/src/core/templates.h
index e074f22c..d7980e6e 100644
--- a/src/core/templates.h
+++ b/src/core/templates.h
@@ -1,31 +1,31 @@
#pragma once
-template
+template
class CStore
{
public:
- int allocPtr;
+ int32 allocPtr;
T store[n];
- T *alloc(void){
- if(this->allocPtr >= n){
+ T *Alloc(void){
+ if(allocPtr >= n){
printf("Size of this thing:%d needs increasing\n", n);
assert(0);
}
- return &this->store[this->allocPtr++];
+ return &store[allocPtr++];
}
- void clear(void){
- this->allocPtr = 0;
+ void Clear(void){
+ allocPtr = 0;
}
- int getIndex(T *item){
- assert(item >= &this->store[0]);
- assert(item < &this->store[n]);
- return item - this->store;
+ int32 GetIndex(T *item){
+ assert(item >= &store[0]);
+ assert(item < &store[n]);
+ return item - store;
}
- T *getItem(int index){
+ T *GetItem(int32 index){
assert(index >= 0);
assert(index < n);
- return &this->store[index];
+ return &store[index];
}
};
@@ -46,14 +46,13 @@ class CPool
};
uint8 u;
} *m_flags;
- int m_size;
- int m_allocPtr;
+ int32 m_size;
+ int32 m_allocPtr;
public:
- CPool(int size){
- // TODO: use new here
- m_entries = (U*)malloc(sizeof(U)*size);
- m_flags = (Flags*)malloc(sizeof(Flags)*size);
+ CPool(int32 size){
+ m_entries = (U*)new uint8[sizeof(U)*size];
+ m_flags = (Flags*)new uint8[sizeof(Flags)*size];
m_size = size;
m_allocPtr = 0;
for(int i = 0; i < size; i++){
@@ -67,15 +66,15 @@ public:
}
void Flush() {
if (m_size > 0) {
- free(m_entries);
- free(m_flags);
+ delete[] (uint8*)m_entries;
+ delete[] (uint8*)m_flags;
m_entries = nil;
m_flags = nil;
m_size = 0;
m_allocPtr = 0;
}
}
- int GetSize(void) const { return m_size; }
+ int32 GetSize(void) const { return m_size; }
T *New(void){
bool wrapped = false;
do
@@ -99,12 +98,12 @@ public:
m_flags[m_allocPtr].id++;
return (T*)&m_entries[m_allocPtr];
}
- T *New(int handle){
+ T *New(int32 handle){
T *entry = (T*)&m_entries[handle>>8];
SetNotFreeAt(handle);
return entry;
}
- void SetNotFreeAt(int handle){
+ void SetNotFreeAt(int32 handle){
int idx = handle>>8;
m_flags[idx].free = 0;
m_flags[idx].id = handle & 0x7F;
@@ -129,15 +128,21 @@ public:
return m_flags[handle>>8].u == (handle & 0xFF) ?
(T*)&m_entries[handle >> 8] : nil;
}
- int GetIndex(T *entry){
- int i = GetJustIndex(entry);
+ int32 GetIndex(T *entry){
+ int i = GetJustIndex_NoFreeAssert(entry);
return m_flags[i].u + (i<<8);
}
- int GetJustIndex(T *entry){
- // TODO: the cast is unsafe
- return (int)((U*)entry - m_entries);
+ int32 GetJustIndex(T *entry){
+ int index = GetJustIndex_NoFreeAssert(entry);
+ assert(!IsFreeSlot(index));
+ return index;
}
- int GetNoOfUsedSpaces(void) const{
+ int32 GetJustIndex_NoFreeAssert(T* entry){
+ int index = ((U*)entry - m_entries);
+ assert((U*)entry == (U*)&m_entries[index]); // cast is unsafe - check required
+ return index;
+ }
+ int32 GetNoOfUsedSpaces(void) const{
int i;
int n = 0;
for(i = 0; i < m_size; i++)
@@ -147,8 +152,8 @@ public:
}
bool IsFreeSlot(int i) { return !!m_flags[i].free; }
void ClearStorage(uint8 *&flags, U *&entries){
- free(flags);
- free(entries);
+ delete[] (uint8*)flags;
+ delete[] (uint8*)entries;
flags = nil;
entries = nil;
}
@@ -162,8 +167,8 @@ public:
debug("CopyBack:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */
}
void Store(uint8 *&flags, U *&entries){
- flags = (uint8*)malloc(sizeof(uint8)*m_size);
- entries = (U*)malloc(sizeof(U)*m_size);
+ flags = (uint8*)new uint8[sizeof(uint8)*m_size];
+ entries = (U*)new uint8[sizeof(U)*m_size];
memcpy(flags, m_flags, sizeof(uint8)*m_size);
memcpy(entries, m_entries, sizeof(U)*m_size);
debug("Stored:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */
@@ -241,7 +246,7 @@ public:
link->Remove(); // remove from list
freeHead.Insert(link); // insert into free list
}
- int Count(void){
+ int32 Count(void){
int n = 0;
CLink *lnk;
for(lnk = head.next; lnk != &tail; lnk = lnk->next)
diff --git a/src/core/timebars.cpp b/src/core/timebars.cpp
index 5ac5565d..94051b25 100644
--- a/src/core/timebars.cpp
+++ b/src/core/timebars.cpp
@@ -89,7 +89,7 @@ void tbDisplay()
CFont::SetScale(0.48f, 1.12f);
CFont::SetCentreOff();
CFont::SetJustifyOff();
- CFont::SetWrapx(640.0f);
+ CFont::SetWrapx(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH));
CFont::SetRightJustifyOff();
CFont::SetPropOn();
CFont::SetFontStyle(FONT_BANK);
diff --git a/src/core/timebars.h b/src/core/timebars.h
index 3871b61c..c4939802 100644
--- a/src/core/timebars.h
+++ b/src/core/timebars.h
@@ -1,6 +1,13 @@
#pragma once
+#ifdef TIMEBARS
void tbInit();
void tbStartTimer(int32, Const char*);
void tbEndTimer(Const char*);
-void tbDisplay();
\ No newline at end of file
+void tbDisplay();
+#else
+#define tbInit()
+#define tbStartTimer(a, b)
+#define tbEndTimer(a)
+#define tbDisplay()
+#endif
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 5e3204b2..476439fa 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -28,6 +28,7 @@
#include "Bones.h"
#include "Debug.h"
#include "Renderer.h"
+#include "MemoryHeap.h"
int gBuildings;
@@ -274,7 +275,11 @@ CEntity::CreateRwObject(void)
CBaseModelInfo *mi;
mi = CModelInfo::GetModelInfo(m_modelIndex);
+
+ PUSH_MEMID(MEMID_WORLD);
m_rwObject = mi->CreateInstance();
+ POP_MEMID();
+
if(m_rwObject){
if(IsBuilding())
gBuildings++;
diff --git a/src/entities/Entity.h b/src/entities/Entity.h
index eca462cd..9372c85d 100644
--- a/src/entities/Entity.h
+++ b/src/entities/Entity.h
@@ -6,7 +6,7 @@
struct CReference;
class CPtrList;
-enum eEntityType : uint8
+enum eEntityType
{
ENTITY_TYPE_NOTHING = 0,
ENTITY_TYPE_BUILDING,
@@ -16,7 +16,7 @@ enum eEntityType : uint8
ENTITY_TYPE_DUMMY,
};
-enum eEntityStatus : uint8
+enum eEntityStatus
{
STATUS_PLAYER,
STATUS_PLAYER_PLAYBACKFROMBUFFER,
@@ -92,12 +92,13 @@ public:
CReference *m_pFirstReference;
public:
- eEntityType GetType() const { return (eEntityType)m_type; }
- void SetType(eEntityType type) { m_type = type; }
- eEntityStatus GetStatus() const { return (eEntityStatus)m_status; }
- void SetStatus(eEntityStatus status) { m_status = status; }
+ uint8 GetType() const { return m_type; }
+ void SetType(uint8 type) { m_type = type; }
+ uint8 GetStatus() const { return m_status; }
+ void SetStatus(uint8 status) { m_status = status; }
CColModel *GetColModel(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); }
- bool IsStatic(void) { return bIsStatic; }
+ bool GetIsStatic(void) const { return bIsStatic; }
+ void SetIsStatic(bool state) { bIsStatic = state; }
#ifdef COMPATIBLE_SAVES
void SaveEntityFlags(uint8*& buf);
void LoadEntityFlags(uint8*& buf);
diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp
index 49060fe7..04cec96b 100644
--- a/src/entities/Physical.cpp
+++ b/src/entities/Physical.cpp
@@ -341,7 +341,7 @@ CPhysical::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
AddCollisionRecord(ent);
if(!ent->IsBuilding()) // Can't this catch dummies too?
((CPhysical*)ent)->AddCollisionRecord(this);
- if(ent->IsBuilding() || ent->IsStatic())
+ if(ent->IsBuilding() || ent->GetIsStatic())
this->bHasHitWall = true;
}
return numSpheres;
@@ -377,7 +377,7 @@ CPhysical::ProcessControl(void)
m_nStaticFrames++;
if(m_nStaticFrames > 10){
m_nStaticFrames = 10;
- bIsStatic = true;
+ SetIsStatic(true);
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
m_vecMoveFriction = m_vecMoveSpeed;
@@ -556,7 +556,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
massFactorB = B->bIsHeavy ? 2.0f : 1.0f;
float speedA, speedB;
- if(B->IsStatic()){
+ if(B->GetIsStatic()){
if(A->bPedPhysics){
speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
if(speedA < 0.0f){
@@ -567,16 +567,16 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
if(IsGlass(B->GetModelIndex()))
CGlass::WindowRespondsToCollision(B, impulseA, A->m_vecMoveSpeed, colpoint.point, false);
else if(!B->bInfiniteMass)
- B->bIsStatic = false;
+ B->SetIsStatic(false);
}else{
if(IsGlass(B->GetModelIndex()))
CGlass::WindowRespondsToSoftCollision(B, impulseA);
if(!A->bInfiniteMass)
- A->ApplyMoveForce(colpoint.normal*(1.0f + A->m_fElasticity)*impulseA);
+ A->ApplyMoveForce(colpoint.GetNormal() * (1.0f + A->m_fElasticity) * impulseA);
return true;
}
}else if(!B->bInfiniteMass)
- B->bIsStatic = false;
+ B->SetIsStatic(false);
if(B->bInfiniteMass){
impulseA = -speedA * A->m_fMass;
@@ -614,7 +614,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
if(IsGlass(B->GetModelIndex()))
CGlass::WindowRespondsToCollision(B, impulseA, A->m_vecMoveSpeed, colpoint.point, false);
else
- B->bIsStatic = false;
+ B->SetIsStatic(false);
int16 model = B->GetModelIndex();
if(model == MI_FIRE_HYDRANT && !Bobj->bHasBeenDamaged){
CParticleObject::AddObject(POBJECT_FIRE_HYDRANT, B->GetPosition() - CVector(0.0f, 0.0f, 0.5f), true);
@@ -624,7 +624,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
}else{
if(IsGlass(B->GetModelIndex()))
CGlass::WindowRespondsToSoftCollision(B, impulseA);
- CVector f = colpoint.normal * impulseA;
+ CVector f = colpoint.GetNormal() * impulseA;
if(A->IsVehicle() && colpoint.normal.z < 0.7f)
f.z *= 0.3f;
if(!A->bInfiniteMass){
@@ -635,11 +635,11 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
return true;
}
}else if(!B->bInfiniteMass)
- B->bIsStatic = false;
+ B->SetIsStatic(false);
}
}
- if(B->IsStatic())
+ if(B->GetIsStatic())
return false;
if(!B->bInfiniteMass)
B->AddToMovingList();
@@ -824,7 +824,7 @@ CPhysical::ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CV
normalSpeed = DotProduct(speed, colpoint.normal);
if(normalSpeed < 0.0f){
float minspeed = 1.3f*GRAVITY * CTimer::GetTimeStep();
-#ifdef GTA3_1_1_PATCH
+#if GTA_VERSION >= GTA3_PC_11
if ((IsObject() || IsVehicle() && (GetUp().z < -0.3f || ((CVehicle*)this)->IsBike() && (GetStatus() == STATUS_ABANDONED || GetStatus() == STATUS_WRECKED))) &&
#else
if((IsObject() || IsVehicle() && GetUp().z < -0.3f) &&
@@ -1074,7 +1074,7 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists)
canshift = true;
else
canshift = A->IsPed() &&
- B->IsObject() && B->bIsStatic && !Bobj->bHasBeenDamaged;
+ B->IsObject() && B->GetIsStatic() && !Bobj->bHasBeenDamaged;
if(B == A ||
B->m_scanCode == CWorld::GetCurrentScanCode() ||
!B->bUsesCollision ||
@@ -1098,7 +1098,7 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists)
CObject *Aobj = (CObject*)A;
if(Aobj->ObjectCreatedBy != TEMP_OBJECT &&
!Aobj->bHasBeenDamaged &&
- Aobj->IsStatic()){
+ Aobj->GetIsStatic()){
if(Aobj->m_pCollidingEntity == B)
Aobj->m_pCollidingEntity = nil;
}else if(Aobj->m_pCollidingEntity != B){
@@ -1115,7 +1115,7 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists)
CObject *Bobj = (CObject*)B;
if(Bobj->ObjectCreatedBy != TEMP_OBJECT &&
!Bobj->bHasBeenDamaged &&
- Bobj->IsStatic()){
+ Bobj->GetIsStatic()){
if(Bobj->m_pCollidingEntity == A)
Bobj->m_pCollidingEntity = nil;
}else if(Bobj->m_pCollidingEntity != A){
@@ -1146,43 +1146,43 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists)
mostColliding = 0;
for(j = 1; j < numCollisions; j++)
- if(colpoints[j].depth > colpoints[mostColliding].depth)
+ if (colpoints[j].GetDepth() > colpoints[mostColliding].GetDepth())
mostColliding = j;
if(CWorld::bSecondShift)
for(j = 0; j < numCollisions; j++)
- shift += colpoints[j].normal * colpoints[j].depth * 1.5f/numCollisions;
+ shift += colpoints[j].GetNormal() * colpoints[j].GetDepth() * 1.5f / numCollisions;
else
for(j = 0; j < numCollisions; j++)
- shift += colpoints[j].normal * colpoints[j].depth * 1.2f/numCollisions;
+ shift += colpoints[j].GetNormal() * colpoints[j].GetDepth() * 1.2f / numCollisions;
if(A->IsVehicle() && B->IsVehicle()){
CVector dir = A->GetPosition() - B->GetPosition();
dir.Normalise();
if(dir.z < 0.0f && dir.z < A->GetForward().z && dir.z < A->GetRight().z)
dir.z = Min(0.0f, Min(A->GetForward().z, A->GetRight().z));
- shift += dir * colpoints[mostColliding].depth * 0.5f;
+ shift += dir * colpoints[mostColliding].GetDepth() * 0.5f;
}else if(A->IsPed() && B->IsVehicle() && ((CVehicle*)B)->IsBoat()){
- CVector dir = colpoints[mostColliding].normal;
+ CVector dir = colpoints[mostColliding].GetNormal();
float f = Min(Abs(dir.z), 0.9f);
dir.z = 0.0f;
dir.Normalise();
- shift += dir * colpoints[mostColliding].depth / (1.0f - f);
+ shift += dir * colpoints[mostColliding].GetDepth() / (1.0f - f);
boat = B;
}else if(B->IsPed() && A->IsVehicle() && ((CVehicle*)A)->IsBoat()){
- CVector dir = colpoints[mostColliding].normal * -1.0f;
+ CVector dir = colpoints[mostColliding].GetNormal() * -1.0f;
float f = Min(Abs(dir.z), 0.9f);
dir.z = 0.0f;
dir.Normalise();
- B->GetMatrix().Translate(dir * colpoints[mostColliding].depth / (1.0f - f));
+ B->GetMatrix().Translate(dir * colpoints[mostColliding].GetDepth() / (1.0f - f));
// BUG? how can that ever happen? A is a Ped
if(B->IsVehicle())
B->ProcessEntityCollision(A, colpoints);
}else{
if(CWorld::bSecondShift)
- shift += colpoints[mostColliding].normal * colpoints[mostColliding].depth * 0.4f;
+ shift += colpoints[mostColliding].GetNormal() * colpoints[mostColliding].GetDepth() * 0.4f;
else
- shift += colpoints[mostColliding].normal * colpoints[mostColliding].depth * 0.2f;
+ shift += colpoints[mostColliding].GetNormal() * colpoints[mostColliding].GetDepth() * 0.2f;
}
doShift = true;
@@ -1433,7 +1433,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
skipCollision = true;
else if(Aobj->ObjectCreatedBy == TEMP_OBJECT ||
Aobj->bHasBeenDamaged ||
- !Aobj->IsStatic()){
+ !Aobj->GetIsStatic()){
if(Aobj->m_pCollidingEntity == B)
skipCollision = true;
else{
@@ -1452,7 +1452,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
skipCollision = true;
else if(Bobj->ObjectCreatedBy == TEMP_OBJECT ||
Bobj->bHasBeenDamaged ||
- !Bobj->IsStatic()){
+ !Bobj->GetIsStatic()){
if(Bobj->m_pCollidingEntity == A)
skipCollision = true;
else{
diff --git a/src/extras/custompipes.cpp b/src/extras/custompipes.cpp
index 79254eb4..bb3ebd2e 100644
--- a/src/extras/custompipes.cpp
+++ b/src/extras/custompipes.cpp
@@ -44,7 +44,7 @@ CustomMatCopy(void *dst, void *src, int32, int32)
-static rw::TexDictionary *neoTxd;
+rw::TexDictionary *neoTxd;
bool bRenderingEnvMap;
int32 EnvMapSize = 128;
@@ -337,7 +337,7 @@ ReadTweakValueTable(char *fp, InterpolatedValue &interp)
* Neo Vehicle pipe
*/
-int32 VehiclePipeSwitch = VEHICLEPIPE_NEO;
+int32 VehiclePipeSwitch = VEHICLEPIPE_MATFX;
float VehicleShininess = 0.7f; // the default is a bit extreme
float VehicleSpecularity = 1.0f;
InterpolatedFloat Fresnel(0.4f);
@@ -365,6 +365,7 @@ AttachVehiclePipe(rw::Clump *clump)
* Neo World pipe
*/
+bool LightmapEnable;
float LightmapMult = 1.0f;
InterpolatedFloat WorldLightmapBlend(1.0f);
rw::ObjPipeline *worldPipe;
@@ -389,6 +390,7 @@ AttachWorldPipe(rw::Clump *clump)
* Neo Gloss pipe
*/
+bool GlossEnable;
float GlossMult = 1.0f;
rw::ObjPipeline *glossPipe;
@@ -427,6 +429,7 @@ AttachGlossPipe(rw::Clump *clump)
* Neo Rim pipes
*/
+bool RimlightEnable;
float RimlightMult = 1.0f;
InterpolatedColor RampStart(Color(0.0f, 0.0f, 0.0f, 1.0f));
InterpolatedColor RampEnd(Color(1.0f, 1.0f, 1.0f, 1.0f));
diff --git a/src/extras/custompipes.h b/src/extras/custompipes.h
index 4ebe586f..ca3f0fb4 100644
--- a/src/extras/custompipes.h
+++ b/src/extras/custompipes.h
@@ -6,6 +6,7 @@
namespace CustomPipes {
+extern rw::TexDictionary *neoTxd;
struct CustomMatExt
{
@@ -98,6 +99,7 @@ void DestroyVehiclePipe(void);
void AttachVehiclePipe(rw::Atomic *atomic);
void AttachVehiclePipe(rw::Clump *clump);
+extern bool LightmapEnable;
extern float LightmapMult;
extern InterpolatedFloat WorldLightmapBlend;
extern rw::ObjPipeline *worldPipe;
@@ -106,6 +108,7 @@ void DestroyWorldPipe(void);
void AttachWorldPipe(rw::Atomic *atomic);
void AttachWorldPipe(rw::Clump *clump);
+extern bool GlossEnable;
extern float GlossMult;
extern rw::ObjPipeline *glossPipe;
void CreateGlossPipe(void);
@@ -114,6 +117,7 @@ void AttachGlossPipe(rw::Atomic *atomic);
void AttachGlossPipe(rw::Clump *clump);
rw::Texture *GetGlossTex(rw::Material *mat);
+extern bool RimlightEnable;
extern float RimlightMult;
extern InterpolatedColor RampStart;
extern InterpolatedColor RampEnd;
diff --git a/src/extras/custompipes_d3d9.cpp b/src/extras/custompipes_d3d9.cpp
index bfc744a3..b39efd47 100644
--- a/src/extras/custompipes_d3d9.cpp
+++ b/src/extras/custompipes_d3d9.cpp
@@ -131,6 +131,7 @@ vehicleRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
drawInst(header, inst);
inst++;
}
+ d3d::setTexture(1, nil);
SetRenderState(SRCBLEND, BLENDSRCALPHA);
}
@@ -190,6 +191,11 @@ worldRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
using namespace rw::d3d;
using namespace rw::d3d9;
+ if(!LightmapEnable){
+ defaultRenderCB_Shader(atomic, header);
+ return;
+ }
+
int vsBits;
setStreamSource(0, header->vertexStream[0].vertexBuffer, 0, header->vertexStream[0].stride);
setIndices(header->indexBuffer);
@@ -297,6 +303,9 @@ glossRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
using namespace rw::d3d;
using namespace rw::d3d9;
+ if(!GlossEnable)
+ return;
+
setVertexShader(neoGloss_VS);
setPixelShader(neoGloss_PS);
@@ -395,6 +404,11 @@ rimRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
using namespace rw::d3d;
using namespace rw::d3d9;
+ if(!RimlightEnable){
+ defaultRenderCB_Shader(atomic, header);
+ return;
+ }
+
int vsBits;
setStreamSource(0, header->vertexStream[0].vertexBuffer, 0, header->vertexStream[0].stride);
setIndices(header->indexBuffer);
@@ -433,6 +447,11 @@ rimSkinRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
using namespace rw::d3d;
using namespace rw::d3d9;
+ if(!RimlightEnable){
+ skinRenderCB(atomic, header);
+ return;
+ }
+
int vsBits;
setStreamSource(0, (IDirect3DVertexBuffer9*)header->vertexStream[0].vertexBuffer,
diff --git a/src/extras/custompipes_gl.cpp b/src/extras/custompipes_gl.cpp
index 5717c83b..861a831e 100644
--- a/src/extras/custompipes_gl.cpp
+++ b/src/extras/custompipes_gl.cpp
@@ -134,6 +134,7 @@ vehicleRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
}
SetRenderState(SRCBLEND, BLENDSRCALPHA);
+ setTexture(1, nil);
#ifndef RW_GL_USE_VAOS
disableAttribPointers(header->attribDesc, header->numAttribs);
@@ -158,13 +159,8 @@ CreateVehiclePipe(void)
{
-#ifdef RW_GLES2
-#include "gl2_shaders/neoVehicle_fs_gl2.inc"
-#include "gl2_shaders/neoVehicle_vs_gl2.inc"
-#else
-#include "shaders/neoVehicle_fs_gl3.inc"
-#include "shaders/neoVehicle_vs_gl3.inc"
-#endif
+#include "shaders/neoVehicle_fs_gl.inc"
+#include "shaders/neoVehicle_vs_gl.inc"
const char *vs[] = { shaderDecl, header_vert_src, neoVehicle_vert_src, nil };
const char *fs[] = { shaderDecl, header_frag_src, neoVehicle_frag_src, nil };
neoVehicleShader = Shader::create(vs, fs);
@@ -203,6 +199,11 @@ worldRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
using namespace rw;
using namespace rw::gl3;
+ if(!LightmapEnable){
+ gl3::defaultRenderCB(atomic, header);
+ return;
+ }
+
Material *m;
setWorldMatrix(atomic->getFrame()->getLTM());
@@ -251,6 +252,7 @@ worldRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
drawInst(header, inst);
inst++;
}
+ setTexture(1, nil);
#ifndef RW_GL_USE_VAOS
disableAttribPointers(header->attribDesc, header->numAttribs);
#endif
@@ -268,13 +270,8 @@ CreateWorldPipe(void)
ReadTweakValueTable((char*)work_buff, WorldLightmapBlend);
{
-#ifdef RW_GLES2
-#include "gl2_shaders/neoWorldIII_fs_gl2.inc"
-#include "gl2_shaders/default_UV2_gl2.inc"
-#else
-#include "shaders/neoWorldIII_fs_gl3.inc"
-#include "shaders/default_UV2_gl3.inc"
-#endif
+#include "shaders/neoWorldIII_fs_gl.inc"
+#include "shaders/default_UV2_gl.inc"
const char *vs[] = { shaderDecl, header_vert_src, default_UV2_vert_src, nil };
const char *fs[] = { shaderDecl, header_frag_src, neoWorldIII_frag_src, nil };
neoWorldShader = Shader::create(vs, fs);
@@ -315,6 +312,8 @@ glossRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
using namespace rw::gl3;
worldRenderCB(atomic, header);
+ if(!GlossEnable)
+ return;
Material *m;
@@ -374,13 +373,8 @@ CreateGlossPipe(void)
using namespace rw::gl3;
{
-#ifdef RW_GLES2
-#include "gl2_shaders/neoGloss_fs_gl2.inc"
-#include "gl2_shaders/neoGloss_vs_gl2.inc"
-#else
-#include "shaders/neoGloss_fs_gl3.inc"
-#include "shaders/neoGloss_vs_gl3.inc"
-#endif
+#include "shaders/neoGloss_fs_gl.inc"
+#include "shaders/neoGloss_vs_gl.inc"
const char *vs[] = { shaderDecl, header_vert_src, neoGloss_vert_src, nil };
const char *fs[] = { shaderDecl, header_frag_src, neoGloss_frag_src, nil };
neoGlossShader = Shader::create(vs, fs);
@@ -442,6 +436,11 @@ rimSkinRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
using namespace rw;
using namespace rw::gl3;
+ if(!RimlightEnable){
+ gl3::skinRenderCB(atomic, header);
+ return;
+ }
+
Material *m;
setWorldMatrix(atomic->getFrame()->getLTM());
@@ -487,6 +486,11 @@ rimRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
using namespace rw;
using namespace rw::gl3;
+ if(!RimlightEnable){
+ gl3::defaultRenderCB(atomic, header);
+ return;
+ }
+
Material *m;
setWorldMatrix(atomic->getFrame()->getLTM());
@@ -541,13 +545,8 @@ CreateRimLightPipes(void)
}
{
-#ifdef RW_GLES2
-#include "gl2_shaders/simple_fs_gl2.inc"
-#include "gl2_shaders/neoRimSkin_gl2.inc"
-#else
-#include "shaders/simple_fs_gl3.inc"
-#include "shaders/neoRimSkin_gl3.inc"
-#endif
+#include "shaders/simple_fs_gl.inc"
+#include "shaders/neoRimSkin_gl.inc"
const char *vs[] = { shaderDecl, header_vert_src, neoRimSkin_vert_src, nil };
const char *fs[] = { shaderDecl, header_frag_src, simple_frag_src, nil };
neoRimSkinShader = Shader::create(vs, fs);
@@ -555,13 +554,8 @@ CreateRimLightPipes(void)
}
{
-#ifdef RW_GLES2
-#include "gl2_shaders/simple_fs_gl2.inc"
-#include "gl2_shaders/neoRim_gl2.inc"
-#else
-#include "shaders/simple_fs_gl3.inc"
-#include "shaders/neoRim_gl3.inc"
-#endif
+#include "shaders/simple_fs_gl.inc"
+#include "shaders/neoRim_gl.inc"
const char *vs[] = { shaderDecl, header_vert_src, neoRim_vert_src, nil };
const char *fs[] = { shaderDecl, header_frag_src, simple_frag_src, nil };
neoRimShader = Shader::create(vs, fs);
diff --git a/src/extras/debugmenu.cpp b/src/extras/debugmenu.cpp
index 3a4c4175..533b97f5 100644
--- a/src/extras/debugmenu.cpp
+++ b/src/extras/debugmenu.cpp
@@ -5,7 +5,7 @@
#include "ControllerConfig.h"
#include "Timer.h"
#include "rtcharse.h"
-#include "inttypes.h"
+#include "re3_inttypes.h"
#include "debugmenu.h"
#include
diff --git a/src/extras/debugmenu.h b/src/extras/debugmenu.h
index eb56c8f9..c2198aca 100644
--- a/src/extras/debugmenu.h
+++ b/src/extras/debugmenu.h
@@ -15,7 +15,7 @@ struct MenuEntry
Menu *menu;
MenuEntry(const char *name);
- virtual ~MenuEntry(void) {}
+ virtual ~MenuEntry(void) { free((void*)name); }
};
typedef MenuEntry DebugMenuEntry;
diff --git a/src/extras/frontendoption.cpp b/src/extras/frontendoption.cpp
index b365a3fe..a3c4b9e3 100644
--- a/src/extras/frontendoption.cpp
+++ b/src/extras/frontendoption.cpp
@@ -1,20 +1,14 @@
#include "common.h"
#ifdef CUSTOM_FRONTEND_OPTIONS
-#include "frontendoption.h"
+#include "Frontend.h"
#include "Text.h"
-int numCustomFrontendOptions = 0;
-FrontendOption *customFrontendOptions;
-
-int numCustomFrontendScreens = 0;
-FrontendScreen* customFrontendScreens;
-
-int numFrontendOptionReplacements = 0;
-CMenuScreen::CMenuEntry* frontendOptionReplacements;
-
int lastOgScreen = MENUPAGES; // means no new pages
+int numCustomFrontendOptions = 0;
+int numCustomFrontendScreens = 0;
+
int optionCursor = -2;
int currentMenu;
bool optionOverwrite = false;
@@ -32,8 +26,7 @@ void GoBack(bool fadeIn)
{
int screen = !FrontEndMenuManager.m_bGameNotLoaded ?
aScreens[FrontEndMenuManager.m_nCurrScreen].m_PreviousPage[1] : aScreens[FrontEndMenuManager.m_nCurrScreen].m_PreviousPage[0];
- int option = !FrontEndMenuManager.m_bGameNotLoaded ?
- aScreens[FrontEndMenuManager.m_nCurrScreen].m_ParentEntry[1] : aScreens[FrontEndMenuManager.m_nCurrScreen].m_ParentEntry[0];
+ int option = FrontEndMenuManager.GetPreviousPageOption();
FrontEndMenuManager.ThingsToDoBeforeGoingBack();
@@ -56,9 +49,9 @@ GetNumberOfMenuOptions(int screen)
uint8
GetLastMenuScreen()
{
- uint8 page = -1;
+ int8 page = -1;
for (int i = 0; i < MENUPAGES; i++) {
- if (strcmp(aScreens[i].m_ScreenName, "") == 0 && aScreens[i].unk == 0)
+ if (strcmp(aScreens[i].m_ScreenName, "") == 0 && aScreens[i].m_PreviousPage[0] == MENUPAGE_NONE)
break;
++page;
@@ -66,89 +59,23 @@ GetLastMenuScreen()
return page;
}
-// Used before populating options, but effective in InitialiseChangedLanguageSettings and debugmenu
-void
-RemoveCustomFrontendOptions()
-{
- if (numCustomFrontendOptions != 0) {
-
- for (int i = 0; i < MENUPAGES; i++) {
- for (int j = 0; j < NUM_MENUROWS; j++) {
- if (aScreens[i].m_aEntries[j].m_SaveSlot == SAVESLOT_CFO) {
- int ogOptionId = customFrontendOptions[aScreens[i].m_aEntries[j].m_TargetMenu].ogOptionId;
-
- if (customFrontendOptions[aScreens[i].m_aEntries[j].m_TargetMenu].type == FEOPTION_SELECT)
- free(customFrontendOptions[aScreens[i].m_aEntries[j].m_TargetMenu].rightTexts);
-
- if (ogOptionId == -1) {
- int k;
- for (k = j; k < NUM_MENUROWS - 1; k++) {
- memcpy(&aScreens[i].m_aEntries[k], &aScreens[i].m_aEntries[k + 1], sizeof(CMenuScreen::CMenuEntry));
- }
- aScreens[i].m_aEntries[k].m_Action = MENUACTION_NOTHING;
- aScreens[i].m_aEntries[k].m_SaveSlot = SAVESLOT_NONE;
- aScreens[i].m_aEntries[k].m_EntryName[0] = '\0';
- j--;
- } else {
- memcpy(&aScreens[i].m_aEntries[j], &frontendOptionReplacements[ogOptionId], sizeof(CMenuScreen::CMenuEntry));
- }
- }
- }
- }
- free(customFrontendOptions);
- numCustomFrontendOptions = 0;
-
- if (numFrontendOptionReplacements != 0) {
- free(frontendOptionReplacements);
- numFrontendOptionReplacements = 0;
- }
- }
-
- if (numCustomFrontendScreens == 0)
- return;
-
- for (int i = 0; i < MENUPAGES; i++) {
- if (i > lastOgScreen) {
- aScreens[i].m_ScreenName[0] = '\0';
- aScreens[i].unk = 0;
- }
- }
- free(customFrontendScreens);
- numCustomFrontendScreens = 0;
- lastOgScreen = MENUPAGES;
-}
-
-int8 RegisterNewScreen(const char *name, int prevPage)
+int8 RegisterNewScreen(const char *name, int prevPage, ReturnPrevPageFunc returnPrevPageFunc)
{
if (lastOgScreen == MENUPAGES)
lastOgScreen = GetLastMenuScreen();
numCustomFrontendScreens++;
- if (numCustomFrontendScreens == 1)
- customFrontendScreens = (FrontendScreen*)malloc(5 * sizeof(FrontendScreen));
- else if (numCustomFrontendScreens % 5 == 1)
- customFrontendScreens = (FrontendScreen*)realloc(customFrontendScreens, (numCustomFrontendScreens + 4) * sizeof(FrontendScreen));
-
- assert(customFrontendScreens != nil && "Custom frontend screens can't be allocated");
-
int id = lastOgScreen + numCustomFrontendScreens;
assert(id < MENUPAGES && "No room for new custom frontend screens! Increase MENUPAGES");
strncpy(aScreens[id].m_ScreenName, name, 8);
aScreens[id].m_PreviousPage[0] = aScreens[id].m_PreviousPage[1] = prevPage;
- aScreens[id].unk = 1;
+ aScreens[id].returnPrevPageFunc = returnPrevPageFunc;
return id;
}
int8 RegisterNewOption()
{
numCustomFrontendOptions++;
- if (numCustomFrontendOptions == 1)
- customFrontendOptions = (FrontendOption*)malloc(5 * sizeof(FrontendOption));
- else if (numCustomFrontendOptions % 5 == 1)
- customFrontendOptions = (FrontendOption*)realloc(customFrontendOptions, (numCustomFrontendOptions + 4) * sizeof(FrontendOption));
-
- assert(customFrontendOptions != nil && "Custom frontend options can't be allocated");
-
uint8 numOptions = GetNumberOfMenuOptions(currentMenu);
uint8 curIdx;
if (optionCursor < 0) {
@@ -159,30 +86,11 @@ int8 RegisterNewOption()
if (!optionOverwrite) {
if (aScreens[currentMenu].m_aEntries[curIdx].m_Action != MENUACTION_NOTHING) {
for (int i = numOptions - 1; i >= curIdx; i--) {
- memcpy(&aScreens[currentMenu].m_aEntries[i + 1], &aScreens[currentMenu].m_aEntries[i], sizeof(CMenuScreen::CMenuEntry));
+ memcpy(&aScreens[currentMenu].m_aEntries[i + 1], &aScreens[currentMenu].m_aEntries[i], sizeof(CMenuScreenCustom::CMenuEntry));
}
}
}
optionCursor++;
-
- if (optionOverwrite) {
- numFrontendOptionReplacements++;
- if (numFrontendOptionReplacements == 1)
- frontendOptionReplacements = (CMenuScreen::CMenuEntry*)malloc(5 * sizeof(CMenuScreen::CMenuEntry));
- else if (numFrontendOptionReplacements % 5 == 1)
- frontendOptionReplacements = (CMenuScreen::CMenuEntry*)realloc(frontendOptionReplacements, (numFrontendOptionReplacements + 4) * sizeof(CMenuScreen::CMenuEntry));
-
- memcpy(&frontendOptionReplacements[numFrontendOptionReplacements - 1], &aScreens[currentMenu].m_aEntries[curIdx], sizeof(CMenuScreen::CMenuEntry));
- customFrontendOptions[numCustomFrontendOptions - 1].ogOptionId = numFrontendOptionReplacements - 1;
- } else {
- customFrontendOptions[numCustomFrontendOptions - 1].ogOptionId = -1;
- }
- customFrontendOptions[numCustomFrontendOptions - 1].screen = currentMenu;
-
- aScreens[currentMenu].m_aEntries[curIdx].m_Action = MENUACTION_TRIGGERFUNC;
- aScreens[currentMenu].m_aEntries[curIdx].m_SaveSlot = SAVESLOT_CFO;
- aScreens[currentMenu].m_aEntries[curIdx].m_TargetMenu = numCustomFrontendOptions - 1;
- aScreens[currentMenu].m_aEntries[curIdx].m_EntryName[0] = 1; // just something to fool it
return curIdx;
}
@@ -193,111 +101,79 @@ void FrontendOptionSetCursor(int screen, int8 option, bool overwrite)
optionOverwrite = overwrite;
}
-void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc) {
+void FrontendOptionAddBuiltinAction(const char* gxtKey, int action, int targetMenu, int saveSlot) {
int8 screenOptionOrder = RegisterNewOption();
- FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1];
+ CMenuScreenCustom::CMenuEntry &option = aScreens[currentMenu].m_aEntries[screenOptionOrder];
- // To fool the Frontend, we will still display the text passed via first param.
+ // We can't use custom text on those :shrug:
switch (action) {
case MENUACTION_SCREENRES:
- strcpy(aScreens[currentMenu].m_aEntries[screenOptionOrder].m_EntryName, "FED_RES");
+ strcpy(option.m_EntryName, "FED_RES");
break;
case MENUACTION_AUDIOHW:
- strcpy(aScreens[currentMenu].m_aEntries[screenOptionOrder].m_EntryName, "FEA_3DH");
+ strcpy(option.m_EntryName, "FEA_3DH");
+ break;
+ default:
+ strncpy(option.m_EntryName, gxtKey, 8);
break;
}
- aScreens[currentMenu].m_aEntries[screenOptionOrder].m_Action = action;
- option.type = FEOPTION_BUILTIN_ACTION;
- option.buttonPressFunc = buttonPressFunc;
- TextCopy(option.leftText, leftText);
- option.screenOptionOrder = screenOptionOrder;
- option.returnPrevPageFunc = returnPrevPageFunc;
- option.save = false;
+ option.m_Action = action;
+ option.m_SaveSlot = saveSlot;
+ option.m_TargetMenu = targetMenu;
}
-void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save)
+void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName)
+{
+ int8 screenOptionOrder = RegisterNewOption();
+
+ CMenuScreenCustom::CMenuEntry &option = aScreens[currentMenu].m_aEntries[screenOptionOrder];
+ option.m_Action = MENUACTION_CFO_SELECT;
+ strncpy(option.m_EntryName, gxtKey, 8);
+ option.m_CFOSelect = new CCFOSelect();
+ option.m_CFOSelect->rightTexts = (char**)malloc(numRightTexts * sizeof(char*));
+ memcpy(option.m_CFOSelect->rightTexts, rightTexts, numRightTexts * sizeof(char*));
+ option.m_CFOSelect->numRightTexts = numRightTexts;
+ option.m_CFOSelect->value = var;
+ if (var) {
+ option.m_CFOSelect->displayedValue = *var;
+ option.m_CFOSelect->lastSavedValue = *var;
+ }
+ option.m_CFOSelect->save = saveName;
+ option.m_CFOSelect->onlyApplyOnEnter = onlyApplyOnEnter;
+ option.m_CFOSelect->changeFunc = changeFunc;
+}
+
+void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveName)
{
int8 screenOptionOrder = RegisterNewOption();
- FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1];
- option.type = FEOPTION_SELECT;
- TextCopy(option.leftText, leftText);
- option.rightTexts = (wchar**)malloc(numRightTexts * sizeof(wchar*));
- memcpy(option.rightTexts, rightTexts, numRightTexts * sizeof(wchar*));
- option.numRightTexts = numRightTexts;
- option.value = var;
- option.displayedValue = *var;
- option.lastSavedValue = *var;
- option.save = save;
- option.onlyApplyOnEnter = onlyApplyOnEnter;
- option.changeFunc = changeFunc;
- option.screenOptionOrder = screenOptionOrder;
- option.returnPrevPageFunc = returnPrevPageFunc;
-}
-
-void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save)
-{
- int8 screenOptionOrder = RegisterNewOption();
-
- FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1];
- option.type = FEOPTION_DYNAMIC;
- option.drawFunc = drawFunc;
- option.buttonPressFunc = buttonPressFunc;
- TextCopy(option.leftText, leftText);
- option.value = var;
- option.save = save;
- option.screenOptionOrder = screenOptionOrder;
- option.returnPrevPageFunc = returnPrevPageFunc;
-}
-
-void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption, bool fadeIn)
-{
- int8 screenOptionOrder = RegisterNewOption();
-
- FrontendOption &option = customFrontendOptions[numCustomFrontendOptions - 1];
- option.type = FEOPTION_REDIRECT;
- option.to = to;
- option.option = selectedOption;
- option.fadeIn = fadeIn;
- TextCopy(option.leftText, text);
- option.screenOptionOrder = screenOptionOrder;
- option.returnPrevPageFunc = nil;
- option.save = false;
-}
-
-void FrontendOptionAddBackButton(const wchar* text, bool fadeIn)
-{
- int8 screenOptionOrder = RegisterNewOption();
-
- FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1];
- option.type = FEOPTION_GOBACK;
- option.fadeIn = fadeIn;
- TextCopy(option.leftText, text);
- option.screenOptionOrder = screenOptionOrder;
- option.returnPrevPageFunc = nil;
- option.save = false;
+ CMenuScreenCustom::CMenuEntry &option = aScreens[currentMenu].m_aEntries[screenOptionOrder];
+ option.m_Action = MENUACTION_CFO_DYNAMIC;
+ strncpy(option.m_EntryName, gxtKey, 8);
+ option.m_CFODynamic = new CCFODynamic();
+ option.m_CFODynamic->drawFunc = drawFunc;
+ option.m_CFODynamic->buttonPressFunc = buttonPressFunc;
+ option.m_CFODynamic->value = var;
+ option.m_CFODynamic->save = saveName;
}
uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight,
int8 font, float fontScaleX, float fontScaleY, int8 alignment, bool showLeftRightHelper, ReturnPrevPageFunc returnPrevPageFunc) {
- uint8 screenOrder = RegisterNewScreen(gxtKey, prevPage);
+ uint8 screenOrder = RegisterNewScreen(gxtKey, prevPage, returnPrevPageFunc);
- FrontendScreen &screen = customFrontendScreens[numCustomFrontendScreens - 1];
- screen.id = screenOrder;
- screen.sprite = sprite;
- screen.prevPage = prevPage;
- strncpy(screen.name, gxtKey, 8);
- screen.columnWidth = columnWidth;
- screen.headerHeight = headerHeight;
- screen.lineHeight = lineHeight;
- screen.font = font;
- screen.fontScaleX = fontScaleX;
- screen.fontScaleY = fontScaleY;
- screen.alignment = alignment;
- screen.returnPrevPageFunc = returnPrevPageFunc;
+ CCustomScreenLayout *screen = new CCustomScreenLayout();
+ aScreens[screenOrder].layout = screen;
+ screen->sprite = sprite;
+ screen->columnWidth = columnWidth;
+ screen->headerHeight = headerHeight;
+ screen->lineHeight = lineHeight;
+ screen->font = font;
+ screen->fontScaleX = fontScaleX;
+ screen->fontScaleY = fontScaleY;
+ screen->alignment = alignment;
return screenOrder;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/extras/frontendoption.h b/src/extras/frontendoption.h
index b2bfbf5e..19340b20 100644
--- a/src/extras/frontendoption.h
+++ b/src/extras/frontendoption.h
@@ -2,47 +2,23 @@
#include "common.h"
#ifdef CUSTOM_FRONTEND_OPTIONS
-#include "Frontend.h"
-
-// Warning:
-// All of the code relies on that you won't use more then NUM_MENUROWS(18) options on one page.
-// Also congrats if you can make 18 options visible at once.
-
-// About texts:
-// All text parameters accept wchar(including hardcoded wchar* and TheText.Get)
-// except FrontendScreenAdd(it's char[8] by the design of Frontend).
-// All texts reload if custom options reloaded too, which includes language changes and via live reload feature in debug menu!
-
-// Execute direction:
-// All of the calls below eventually manipulate the aScreens array, so keep in mind to add/replace options in order,
-// i.e. don't set cursor to 8 first and then 3.
-
-// Live reload:
-// You can add/change/undo the new options in-game if you use VS. Change what you want, build the changed bits via "Edit and Continue",
-// and hit the "Reload custom frontend options" from debug menu. Or call CustomFrontendOptionsPopulate() from somewhere else.
+// ! There are 2 ways to use CFO,
+// 1st; by adding a new option to the array in MenuScreensCustom.cpp and passing attributes/CBs to it
+// 2nd; by calling the functions listed at the bottom of this file.
// -- Option types
//
// Static/select: You allocate the variable, pass it to function and game sets it from user input among the strings given to function,
-// then you can handle ChangeFunc(only called on enter if onlyApplyOnEnter set, or set immediately)
-// and ReturnPrevPageFunc optionally. You can store the option in gta3.set if you pass true to corresponding parameter.
+// optionally you can add post-change event via ChangeFunc(only called on enter if onlyApplyOnEnter set, or set immediately)
+// You can store the option in an INI file if you pass the key(as a char array) to corresponding parameter.
//
// Dynamic: Passing variable to function is only needed if you want to store it, otherwise you should do
// all the operations with ButtonPressFunc, this includes allocating the variable.
// Left-side text is passed while creating and static, but ofc right-side text is dynamic -
-// you should return it in DrawFunc, which is called on every draw. ReturnPrevPageFunc is also here if needed.
-//
-// Redirect: Redirection to another screen. selectedOption parameter is the highlighted option user will see after the redirection.
+// you should return it in DrawFunc, which is called on every draw.
//
// Built-in action: As the name suggests, any action that game has built-in. But as an extra you can set the option text,
-// and can be informed on button press/focus loss via buttonPressFunc. ReturnPrevPageFunc is also here.
-
-#define FEOPTION_SELECT 0
-#define FEOPTION_DYNAMIC 1
-#define FEOPTION_REDIRECT 2
-#define FEOPTION_GOBACK 3
-#define FEOPTION_BUILTIN_ACTION 4
// -- Returned via ButtonPressFunc() action param.
#define FEOPTION_ACTION_LEFT 0
@@ -61,7 +37,7 @@
typedef void (*ReturnPrevPageFunc)();
// for static options
-typedef void (*ChangeFunc)(int8 displayedValue); // called before updating the value.
+typedef void (*ChangeFunc)(int8 before, int8 after); // called after updating the value.
// only called on enter if onlyApplyOnEnter set, otherwise called on every value change
// for dynamic options
@@ -69,71 +45,11 @@ typedef wchar* (*DrawFunc)(bool* disabled, bool userHovering); // you must retur
// you can also set *disabled if you want to gray it out.
typedef void (*ButtonPressFunc)(int8 action); // see FEOPTION_ACTIONs above
-struct FrontendScreen
-{
- int id;
- char name[8];
- eMenuSprites sprite;
- int prevPage;
- int columnWidth;
- int headerHeight;
- int lineHeight;
- int8 font;
- float fontScaleX;
- float fontScaleY;
- int8 alignment;
- bool showLeftRightHelper;
- ReturnPrevPageFunc returnPrevPageFunc;
-};
-
-struct FrontendOption
-{
- int8 type;
- int8 screenOptionOrder;
- int32 screen;
- wchar leftText[64];
- ReturnPrevPageFunc returnPrevPageFunc;
- int8* value;
- int8 displayedValue; // only if onlyApplyOnEnter enabled for now
- bool save;
- int32 ogOptionId; // for replacements, see overwrite parameter of SetCursor
-
- union {
- // Only for dynamic / built-in action
- struct {
- DrawFunc drawFunc;
- ButtonPressFunc buttonPressFunc;
- };
-
- // Only for static/select
- struct {
- wchar** rightTexts;
- int8 numRightTexts;
- bool onlyApplyOnEnter;
- ChangeFunc changeFunc;
- int8 lastSavedValue; // only if onlyApplyOnEnter enabled
- };
-
- // Only for redirect
- struct {
- int to;
- int8 option;
- bool fadeIn;
- };
- };
-};
-
// -- Internal things
-void RemoveCustomFrontendOptions();
void CustomFrontendOptionsPopulate();
-
extern int lastOgScreen; // for reloading
-
extern int numCustomFrontendOptions;
-extern FrontendOption* customFrontendOptions;
-
extern int numCustomFrontendScreens;
-extern FrontendScreen* customFrontendScreens;
// -- To be used in ButtonPressFunc / ChangeFunc(this one would be weird):
void ChangeScreen(int screen, int option = 0, bool fadeIn = true);
@@ -141,6 +57,21 @@ void GoBack(bool fadeIn = true);
uint8 GetNumberOfMenuOptions(int screen);
+// !!! We're now moved to MenuScreensCustom.cpp, which houses an array that keeps all original+custom options.
+// But you can still use the APIs below, and manipulate aScreens while in game.
+
+// Limits:
+// The code relies on that you won't use more then NUM_MENUROWS(18) options on one page, and won't exceed the MENUPAGES of pages.
+// Also congrats if you can make 18 options visible at once.
+
+// Texts:
+// All text parameters accept char[8] GXT key.
+
+// Execute direction:
+// All of the calls below eventually manipulate the aScreens array, so keep in mind to add/replace options in order,
+// i.e. don't set cursor to 8 first and then 3.
+
+
// -- Placing the cursor to append/overwrite option
//
// Done via FrontendOptionSetCursor(screen, position, overwrite = false), parameters explained below:
@@ -151,12 +82,10 @@ uint8 GetNumberOfMenuOptions(int screen);
void FrontendOptionSetCursor(int screen, int8 option, bool overwrite = false);
-// var is optional in AddDynamic, you can enable save parameter if you pass one, otherwise pass nil/0
-void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc);
-void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save = false);
-void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save = false);
-void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption = 0, bool fadeIn = true);
-void FrontendOptionAddBackButton(const wchar* text, bool fadeIn = true);
+// var is optional in AddDynamic, enables you to save them in an INI file(also needs passing char array to saveName param. obv), otherwise pass nil/0
+void FrontendOptionAddBuiltinAction(const char* gxtKey, int action, int targetMenu = MENUPAGE_NONE, int saveSlot = SAVESLOT_NONE);
+void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName = nil);
+void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveName = nil);
uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight, int8 font, float fontScaleX, float fontScaleY, int8 alignment, bool showLeftRightHelper, ReturnPrevPageFunc returnPrevPageFunc = nil);
-#endif
\ No newline at end of file
+#endif
diff --git a/src/extras/ini_parser.hpp b/src/extras/ini_parser.hpp
new file mode 100644
index 00000000..99acf1ee
--- /dev/null
+++ b/src/extras/ini_parser.hpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2013-2015 Denilson das Mercês Amorim
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ */
+#ifndef LINB_INI_PARSER_HPP
+#define LINB_INI_PARSER_HPP
+
+/*
+ * STL-like INI Container
+ */
+
+#include // for std::string
+#include