From b1a431a740c9bde92e9169c041909cebfa705ae5 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sat, 28 Nov 2020 17:57:10 +0100 Subject: [PATCH 01/11] add -console cmdline arg instead of #if 0/1 --- src/skel/glfw/glfw.cpp | 14 ++++++++------ src/skel/win/win.cpp | 18 ++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 617fee18..c4a3cad1 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -1453,12 +1453,14 @@ WinMain(HINSTANCE instance, RwChar** argv; SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil, SPIF_SENDCHANGE); -#if 0 - // TODO: make this an option somewhere - AllocConsole(); - freopen("CONIN$", "r", stdin); - freopen("CONOUT$", "w", stdout); - freopen("CONOUT$", "w", stderr); +#ifndef MASTER + if (strstr(cmdLine, "-console")) + { + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + } #endif #else diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index b4897d67..4dc8c3f0 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -2011,16 +2011,18 @@ WinMain(HINSTANCE instance, RwChar **argv; SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil, SPIF_SENDCHANGE); -#ifdef USE_CUSTOM_ALLOCATOR - InitMemoryMgr(); +#ifndef MASTER + if (strstr(cmdLine, "-console")) + { + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + } #endif -#if 1 - // TODO: make this an option somewhere - AllocConsole(); - freopen("CONIN$", "r", stdin); - freopen("CONOUT$", "w", stdout); - freopen("CONOUT$", "w", stderr); +#ifdef USE_CUSTOM_ALLOCATOR + InitMemoryMgr(); #endif /* From 2c59e1c8945a5c6de6415611d4f1dbc720790d73 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 00:22:57 +0100 Subject: [PATCH 02/11] some more GTA_VERSION --- src/core/FileLoader.cpp | 6 +++ src/core/Game.cpp | 101 +++++++++++++++++++++++++++++----------- src/core/World.cpp | 5 +- 3 files changed, 85 insertions(+), 27 deletions(-) diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index aeaede56..b9d475b8 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -59,7 +59,13 @@ CFileLoader::LoadLevel(const char *filename) savedTxd = RwTexDictionaryCreate(); RwTexDictionarySetCurrent(savedTxd); } +#if GTA_VERSION <= GTA3_PS2_160 + CFileMgr::ChangeDir("\\DATA\\"); fd = CFileMgr::OpenFile(filename, "r"); + CFileMgr::ChangeDir("\\"); +#else + fd = CFileMgr::OpenFile(filename, "r"); +#endif assert(fd > 0); for(line = LoadLine(fd); line; line = LoadLine(fd)){ diff --git a/src/core/Game.cpp b/src/core/Game.cpp index d22a7184..7043a5b2 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -265,16 +265,19 @@ void CGame::ShutdownRenderWare(void) #endif } +// missing altogether on PS2 bool CGame::InitialiseOnceAfterRW(void) { +#if GTA_VERSION > GTA3_PS2_160 TheText.Load(); - DMAudio.Initialise(); + DMAudio.Initialise(); // before TheGame() on PS2 CTimer::Initialise(); CTempColModels::Initialise(); mod_HandlingManager.Initialise(); CSurfaceTable::Initialise("DATA\\SURFACE.DAT"); CPedStats::Initialise(); CTimeCycle::Initialise(); +#endif if ( DMAudio.GetNum3DProvidersAvailable() == 0 ) FrontEndMenuManager.m_nPrefsAudio3DProviderIndex = -1; @@ -330,10 +333,15 @@ bool CGame::Initialise(const char* datFile) { #ifdef GTA_PS2 // TODO: upload VU0 collision code here -#else +#endif + +#if GTA_VERSION > GTA3_PS2_160 ResetLoadingScreenBar(); strcpy(aDatFile, datFile); CPools::Initialise(); // done in CWorld on PS2 +#endif + +#ifndef GTA_PS2 CIniFile::LoadIniFile(); #endif @@ -367,13 +375,15 @@ bool CGame::Initialise(const char* datFile) CWeather::Init(); CCullZones::Init(); CCollision::Init(); -#ifdef PS2_MENU +#ifdef PS2_MENU // TODO: is this the right define? TheText.Load(); #endif CTheZones::Init(); CUserDisplay::Init(); CMessages::Init(); +#if GTA_VERSION > GTA3_PS2_160 CMessages::ClearAllMessagesDisplayedByGame(); +#endif CRecordDataForGame::Init(); CRestart::Initialise(); @@ -381,11 +391,17 @@ bool CGame::Initialise(const char* datFile) CWorld::Initialise(); POP_MEMID(); +#if GTA_VERSION <= GTA3_PS2_160 + mod_HandlingManager.Initialise(); + CSurfaceTable::Initialise("DATA\\SURFACE.DAT"); + CTempColModels::Initialise(); +#endif + PUSH_MEMID(MEMID_TEXTURES); CParticle::Initialise(); POP_MEMID(); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 gStartX = -180.0f; gStartY = 180.0f; gStartZ = 14.0f; @@ -400,20 +416,31 @@ bool CGame::Initialise(const char* datFile) CCarCtrl::Init(); POP_MEMID(); -#ifndef GTA_PS2 +#if GTA_VERSION > GTA3_PS2_160 InitModelIndices(); #endif PUSH_MEMID(MEMID_DEF_MODELS); CModelInfo::Initialise(); -#ifndef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 + CPedStats::Initialise(); // InitialiseOnceAfterRW +#else // probably moved before LoadLevel for multiplayer maps? CPickups::Init(); CTheCarGenerators::Init(); #endif + +#ifndef GTA_PS2 // or GTA_VERSION? CdStreamAddImage("MODELS\\GTA3.IMG"); +#endif + +#if GTA_VERSION > GTA3_PS2_160 CFileLoader::LoadLevel("DATA\\DEFAULT.DAT"); CFileLoader::LoadLevel(datFile); +#else + CFileLoader::LoadLevel("GTA3.DAT"); +#endif + #ifdef EXTENDED_PIPELINES // for generic fallback CustomPipes::SetTxdFindCallback(); @@ -424,18 +451,25 @@ bool CGame::Initialise(const char* datFile) CTheZones::PostZoneCreation(); POP_MEMID(); +#if GTA_VERSION <= GTA3_PS2_160 + TestModelIndices(); +#endif LoadingScreen("Loading the Game", "Setup paths", GetRandomSplashScreen()); ThePaths.PreparePathData(); - // done elsewhere on PS2 +#if GTA_VERSION > GTA3_PS2_160 for (int i = 0; i < NUMPLAYERS; i++) CWorld::Players[i].Clear(); CWorld::Players[0].LoadPlayerSkin(); TestModelIndices(); - // +#endif LoadingScreen("Loading the Game", "Setup water", nil); CWaterLevel::Initialise("DATA\\WATER.DAT"); +#if GTA_VERSION <= GTA3_PS2_160 + CTimeCycle::Initialise(); // InitialiseOnceAfterRW +#else TheConsole.Init(); +#endif CDraw::SetFOV(120.0f); CDraw::ms_fLODDistance = 500.0f; @@ -472,6 +506,11 @@ bool CGame::Initialise(const char* datFile) LoadingScreen("Loading the Game", "Setup game variables", nil); CPopulation::Initialise(); +#if GTA_VERSION <= GTA3_PS2_160 + for (int i = 0; i < NUMPLAYERS; i++) + CWorld::Players[i].Clear(); +// CWorld::Players[0].LoadPlayerSkin(); // TODO: use a define for this +#endif CWorld::PlayerInFocus = 0; CCoronas::Init(); CShadows::Init(); @@ -480,7 +519,7 @@ bool CGame::Initialise(const char* datFile) CAntennas::Init(); CGlass::Init(); gPhoneInfo.Initialise(); -#ifndef GTA_PS2 +#ifndef GTA_PS2 // TODO: define for this CSceneEdit::Initialise(); #endif @@ -491,11 +530,11 @@ bool CGame::Initialise(const char* datFile) POP_MEMID(); LoadingScreen("Loading the Game", "Setup game variables", nil); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CTimer::Initialise(); #endif CClock::Initialise(1000); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CTheCarGenerators::Init(); #endif CHeli::InitHelis(); @@ -503,44 +542,52 @@ bool CGame::Initialise(const char* datFile) CMovingThings::Init(); CDarkel::Init(); CStats::Init(); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CPickups::Init(); #endif CPacManPickups::Init(); - // CGarages::Init(); here on PS2 instead +#if GTA_VERSION <= GTA3_PS2_160 + CGarages::Init(); +#endif CRubbish::Init(); CClouds::Init(); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CRemote::Init(); #endif CSpecialFX::Init(); CWaterCannons::Init(); CBridge::Init(); +#if GTA_VERSION > GTA3_PS2_160 CGarages::Init(); +#endif LoadingScreen("Loading the Game", "Position dynamic objects", nil); CWorld::RepositionCertainDynamicObjects(); - // CCullZones::ResolveVisibilities(); on PS2 here instead +#if GTA_VERSION <= GTA3_PS2_160 + CCullZones::ResolveVisibilities(); +#endif LoadingScreen("Loading the Game", "Initialise vehicle paths", nil); +#if GTA_VERSION > GTA3_PS2_160 CCullZones::ResolveVisibilities(); +#endif CTrain::InitTrains(); CPlane::InitPlanes(); CCredits::Init(); CRecordDataForChase::Init(); +#ifndef GTA_PS2 // TODO: define for that CReplay::Init(); +#endif #ifdef PS2_MENU if ( !TheMemoryCard.m_bWantToLoad ) +#endif { -#endif - LoadingScreen("Loading the Game", "Start script", nil); - CTheScripts::StartTestScript(); - CTheScripts::Process(); - TheCamera.Process(); -#ifdef PS2_MENU + LoadingScreen("Loading the Game", "Start script", nil); + CTheScripts::StartTestScript(); + CTheScripts::Process(); + TheCamera.Process(); } -#endif LoadingScreen("Loading the Game", "Load scene", nil); CModelInfo::RemoveColModelsFromOtherLevels(currLevel); @@ -556,7 +603,7 @@ bool CGame::ShutDown(void) CPlane::Shutdown(); CTrain::Shutdown(); CSpecialFX::Shutdown(); -#ifndef PS2 +#if GTA_VERSION > GTA3_PS2_160 CGarages::Shutdown(); #endif CMovingThings::Shutdown(); @@ -597,7 +644,9 @@ bool CGame::ShutDown(void) CSkidmarks::Shutdown(); CWeaponEffects::Shutdown(); CParticle::Shutdown(); +#if GTA_VERSION > GTA3_PS2_160 CPools::ShutDown(); +#endif CTxdStore::RemoveTxdSlot(gameTxdSlot); CdStreamRemoveImages(); return true; @@ -623,7 +672,7 @@ void CGame::ReInitGameObjectVariables(void) CWorld::bDoingCarCollisions = false; CHud::ReInitialise(); CRadar::Initialise(); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 gStartX = -180.0f; gStartY = 180.0f; gStartZ = 14.0f; @@ -646,7 +695,7 @@ void CGame::ReInitGameObjectVariables(void) CWorld::Players[i].Clear(); CWorld::PlayerInFocus = 0; -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CWeaponEffects::Init(); CSkidmarks::Init(); #endif @@ -669,7 +718,7 @@ void CGame::ReInitGameObjectVariables(void) CPickups::Init(); CPacManPickups::Init(); CGarages::Init(); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CClouds::Init(); CRemote::Init(); #endif diff --git a/src/core/World.cpp b/src/core/World.cpp index 33c2f1c1..62d8d002 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -53,7 +53,7 @@ bool CWorld::bIncludeCarTyres; void CWorld::Initialise() { -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CPools::Initialise(); #endif pIgnoreEntity = nil; @@ -1783,6 +1783,9 @@ CWorld::ShutDown(void) } } ms_listMovingEntityPtrs.Flush(); +#if GTA_VERSION <= GTA3_PS2_160 + CPools::Shutdown(); +#endif } void From 6eb0fd52d7f36623ca78d6717fcbd64fd3e7ecd9 Mon Sep 17 00:00:00 2001 From: Zach Charo Date: Mon, 30 Nov 2020 19:08:15 -0600 Subject: [PATCH 03/11] Update Camera.cpp camdist multiplier is consitently between 1 and 1.4 on 16:9 aspect ratio On ultrawide, the cam dist multiplier jumps to anywhere between 2 and 3 The preferred distance generator for car objects is the cam dist multiplier * 120. Which puts cars that it's trying to generate outside of the allowed gen/draw distance for new car objects when on ultrawide. This means no new cars can spawn. This change caps the scaling for the generation distance a bit above what it would be for 16:9 and does not affect the LOD multiplier. --- src/core/Camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 1e1aa722..9281a20a 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -720,7 +720,7 @@ CCamera::Process(void) else LODDistMultiplier = 1.0f; // missing on PS2 - GenerationDistMultiplier = LODDistMultiplier; + GenerationDistMultiplier = 70.0f/CDraw::GetFOV() * fmin(CDraw::GetAspectRatio(),1.82f)/(4.0f/3.0f); LODDistMultiplier *= CRenderer::ms_lodDistScale; // From d6fab1bc53627d55391d10a557a9e0cbcd11ac6d Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 10:12:42 +0100 Subject: [PATCH 04/11] cam stuff --- src/core/Camera.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 9281a20a..cd748f09 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -94,9 +94,9 @@ CCamera::Init(void) #endif #ifdef PS2_MENU - if ( !TheMemoryCard.m_bWantToLoad && !FrontEndMenuManager.m_bWantToRestart ) { + if ( !TheMemoryCard.m_bWantToLoad && !FrontEndMenuManager.m_bWantToRestart ) #endif - + { #ifdef FIX_BUGS static const CCamera DummyCamera = CCamera(0.f); *this = DummyCamera; @@ -110,9 +110,7 @@ CCamera::Init(void) #endif m_pRwCamera = nil; -#ifdef PS2_MENU } -#endif m_1rstPersonRunCloseToAWall = false; m_fPositionAlongSpline = 0.0f; @@ -719,10 +717,14 @@ CCamera::Process(void) LODDistMultiplier = 70.0f/CDraw::GetFOV() * CDraw::GetAspectRatio()/(4.0f/3.0f); else LODDistMultiplier = 1.0f; - // missing on PS2 - GenerationDistMultiplier = 70.0f/CDraw::GetFOV() * fmin(CDraw::GetAspectRatio(),1.82f)/(4.0f/3.0f); +#if GTA_VERSION > GTA3_PS2_160 +#ifndef FIX_BUGS + // this seems problematic for very wide aspect ratios + // maybe just leaving it at 1.0 is the best thing to do + GenerationDistMultiplier = LODDistMultiplier; +#endif LODDistMultiplier *= CRenderer::ms_lodDistScale; - // +#endif // Keep track of speed if(m_bJustInitalised || m_bJust_Switched){ From b8bc54640d80db3d0c0a6392a0858d83a09e8304 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 17:24:56 +0100 Subject: [PATCH 05/11] fix cam-fix --- src/core/Camera.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index cd748f09..51876c93 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -717,12 +717,12 @@ CCamera::Process(void) LODDistMultiplier = 70.0f/CDraw::GetFOV() * CDraw::GetAspectRatio()/(4.0f/3.0f); else LODDistMultiplier = 1.0f; -#if GTA_VERSION > GTA3_PS2_160 -#ifndef FIX_BUGS - // this seems problematic for very wide aspect ratios - // maybe just leaving it at 1.0 is the best thing to do - GenerationDistMultiplier = LODDistMultiplier; +#ifdef FIX_BUGS + // from VC. to high values bug out spawns + LODDistMultiplier = Min(LODDistMultiplier, 2.2f); #endif +#if GTA_VERSION > GTA3_PS2_160 + GenerationDistMultiplier = LODDistMultiplier; LODDistMultiplier *= CRenderer::ms_lodDistScale; #endif From 83bbb631d1105502fb3c5b3af90578226ba35583 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 17:42:18 +0100 Subject: [PATCH 06/11] some more GTA_VERSIONs and CGame tidy-up (not much actual memory moving yet) --- src/animation/AnimBlendHierarchy.cpp | 11 ++ src/animation/AnimBlendHierarchy.h | 5 + src/animation/AnimBlendSequence.cpp | 21 ++++ src/animation/AnimBlendSequence.h | 5 + src/core/Game.cpp | 175 +++++++++++++++++++++++++-- src/core/main.cpp | 1 + src/rw/MemoryHeap.cpp | 2 +- src/rw/MemoryHeap.h | 1 + 8 files changed, 209 insertions(+), 12 deletions(-) diff --git a/src/animation/AnimBlendHierarchy.cpp b/src/animation/AnimBlendHierarchy.cpp index 67b19019..c7800de5 100644 --- a/src/animation/AnimBlendHierarchy.cpp +++ b/src/animation/AnimBlendHierarchy.cpp @@ -82,3 +82,14 @@ CAnimBlendHierarchy::RemoveUncompressedData(void) #endif compressed = 1; } + +#ifdef USE_CUSTOM_ALLOCATOR +void +CAnimBlendHierarchy::MoveMemory(bool onlyone) +{ + int i; + for(i = 0; i < numSequences; i++) + if(sequences[i].MoveMemory() && onlyone) + return; +} +#endif diff --git a/src/animation/AnimBlendHierarchy.h b/src/animation/AnimBlendHierarchy.h index 0144108d..e35b4925 100644 --- a/src/animation/AnimBlendHierarchy.h +++ b/src/animation/AnimBlendHierarchy.h @@ -2,6 +2,10 @@ #include "templates.h" +#ifdef MoveMemory +#undef MoveMemory // windows shit +#endif + class CAnimBlendSequence; // A collection of sequences @@ -23,6 +27,7 @@ public: void RemoveAnimSequences(void); void Uncompress(void); void RemoveUncompressedData(void); + void MoveMemory(bool onlyone = false); }; VALIDATE_SIZE(CAnimBlendHierarchy, 0x28); \ No newline at end of file diff --git a/src/animation/AnimBlendSequence.cpp b/src/animation/AnimBlendSequence.cpp index 5a2fa605..c958b71a 100644 --- a/src/animation/AnimBlendSequence.cpp +++ b/src/animation/AnimBlendSequence.cpp @@ -176,3 +176,24 @@ CAnimBlendSequence::RemoveUncompressedData(void) keyFrames = nil; } +#ifdef USE_CUSTOM_ALLOCATOR +bool +CAnimBlendSequence::MoveMemory(void) +{ + if(keyFrames){ + void *newaddr = gMainHeap.MoveMemory(keyFrames); + if(newaddr != keyFrames){ + keyFrames = newaddr; + return true; + } + }else if(keyFramesCompressed){ + void *newaddr = gMainHeap.MoveMemory(keyFramesCompressed); + if(newaddr != keyFramesCompressed){ + keyFramesCompressed = newaddr; + return true; + } + } + return false; +} +#endif + diff --git a/src/animation/AnimBlendSequence.h b/src/animation/AnimBlendSequence.h index e51e5aaa..c6e70f22 100644 --- a/src/animation/AnimBlendSequence.h +++ b/src/animation/AnimBlendSequence.h @@ -2,6 +2,10 @@ #include "Quaternion.h" +#ifdef MoveMemory +#undef MoveMemory // windows shit +#endif + // TODO: put them somewhere else? struct KeyFrame { CQuaternion rotation; @@ -53,6 +57,7 @@ public: void Uncompress(void); void CompressKeyframes(void); void RemoveUncompressedData(void); + bool MoveMemory(void); #ifdef PED_SKIN void SetBoneTag(int tag) { boneTag = tag; } diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 7043a5b2..262aa54a 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -167,6 +167,7 @@ void ReplaceAtomicPipeCallback(); #endif // PS2_ALPHA_TEST #endif // !LIBRW +// missing altogether on PS2, mostly done in GameInit there it seems bool CGame::InitialiseRenderWare(void) { @@ -233,6 +234,7 @@ CGame::InitialiseRenderWare(void) return (true); } +// missing altogether on PS2 void CGame::ShutdownRenderWare(void) { CMBlur::MotionBlurClose(); @@ -321,6 +323,7 @@ bool CGame::InitialiseOnceAfterRW(void) return true; } +// missing altogether on PS2 void CGame::FinalShutdown(void) { @@ -657,13 +660,11 @@ void CGame::ReInitGameObjectVariables(void) CGameLogic::InitAtStartOfGame(); #ifdef PS2_MENU if ( !TheMemoryCard.m_bWantToLoad ) +#endif { -#endif - TheCamera.Init(); - TheCamera.SetRwCamera(Scene.camera); -#ifdef PS2_MENU + TheCamera.Init(); + TheCamera.SetRwCamera(Scene.camera); } -#endif CDebug::DebugInitTextBuffer(); CWeather::Init(); CUserDisplay::Init(); @@ -769,8 +770,10 @@ void CGame::ReloadIPLs(void) void CGame::ShutDownForRestart(void) { +#ifndef GTA_PS2 // TODO: right define CReplay::FinishPlayback(); CReplay::EmptyReplayBuffer(); +#endif DMAudio.DestroyAllGameCreatedEntities(); for (int i = 0; i < NUMPLAYERS; i++) @@ -788,7 +791,7 @@ void CGame::ShutDownForRestart(void) CRadar::RemoveRadarSections(); FrontEndMenuManager.UnloadTextures(); CParticleObject::RemoveAllParticleObjects(); -#ifndef PS2 +#if GTA_VERSION >= GTA3_PS2_160 CPedType::Shutdown(); CSpecialFX::Shutdown(); #endif @@ -974,7 +977,9 @@ void CGame::Process(void) CSkidmarks::Update(); CAntennas::Update(); CGlass::Update(); +#ifndef GTA_PS2 // TODO: define CSceneEdit::Update(); +#endif CEventList::Update(); CParticle::Update(); gFireManager.Update(); @@ -988,7 +993,9 @@ void CGame::Process(void) CMovingThings::Update(); CWaterCannons::Update(); CUserDisplay::Process(); +#ifndef GTA_PS2 // TODO: define CReplay::Update(); +#endif PUSH_MEMID(MEMID_WORLD); CWorld::Process(); @@ -1001,10 +1008,14 @@ void CGame::Process(void) CRubbish::Update(); CSpecialFX::Update(); CTimeCycle::Update(); +#ifndef GTA_PS2 // TODO: define if (CReplay::ShouldStandardCameraBeProcessed()) +#endif TheCamera.Process(); CCullZones::Update(); +#ifndef GTA_PS2 // TODO: define if (!CReplay::IsPlayingBack()) +#endif CGameLogic::Update(); CBridge::Update(); CCoronas::DoSunAndMoon(); @@ -1012,7 +1023,9 @@ void CGame::Process(void) CShadows::UpdateStaticShadows(); CShadows::UpdatePermanentShadows(); gPhoneInfo.Update(); +#ifndef GTA_PS2 // TODO: define if (!CReplay::IsPlayingBack()) +#endif { PUSH_MEMID(MEMID_CARS); CCarCtrl::GenerateRandomCars(); @@ -1026,23 +1039,163 @@ void CGame::Process(void) #endif } -void CGame::DrasticTidyUpMemory(bool) +int32 gNumMemMoved; + +RwTexture * +MoveTextureMemoryCB(RwTexture *texture, void *pData) +{ + // TODO + return texture; +} + +bool +TidyUpModelInfo(CBaseModelInfo *,bool) +{ + // TODO + return false; +} + +void CGame::DrasticTidyUpMemory(bool flushDraw) { #ifdef USE_CUSTOM_ALLOCATOR - // meow + bool removedCol = false; + + TidyUpMemory(true, flushDraw); + + if(gMainHeap.GetLargestFreeBlock() < 200000 && !playingIntro){ + CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); + TidyUpMemory(true, flushDraw); + } + + if(gMainHeap.GetLargestFreeBlock() < 200000 && !playingIntro){ + CModelInfo::RemoveColModelsFromOtherLevels(LEVEL_GENERIC); + TidyUpMemory(true, flushDraw); + removedCol = true; + } + + if(gMainHeap.GetLargestFreeBlock() < 200000 && !playingIntro){ + CStreaming::RemoveBigBuildings(LEVEL_INDUSTRIAL); + CStreaming::RemoveBigBuildings(LEVEL_COMMERCIAL); + CStreaming::RemoveBigBuildings(LEVEL_SUBURBAN); + TidyUpMemory(true, flushDraw); + } + + if(removedCol){ + // different on PS2 + CFileLoader::LoadCollisionFromDatFile(CCollision::ms_collisionInMemory); + } + + if(!playingIntro) + CStreaming::RequestBigBuildings(currLevel); + + CStreaming::LoadAllRequestedModels(true); #endif } -void CGame::TidyUpMemory(bool, bool) +void CGame::TidyUpMemory(bool moveTextures, bool flushDraw) { #ifdef USE_CUSTOM_ALLOCATOR - // meow + printf("Largest free block before tidy %d\n", gMainHeap.GetLargestFreeBlock()); + + if(moveTextures){ + if(flushDraw){ +#ifdef GTA_PS2 + for(int i = 0; i < sweMaxFlips+1; i++){ +#else + for(int i = 0; i < 5; i++){ // probably more than needed +#endif + RwCameraBeginUpdate(Scene.camera); + RwCameraEndUpdate(Scene.camera); + RwCameraShowRaster(Scene.camera, nil, 0); + } + } + int fontSlot = CTxdStore::FindTxdSlot("fonts"); + + for(int i = 0; i < TXDSTORESIZE; i++){ + if(i == fontSlot || + CTxdStore::GetSlot(i) == nil) + continue; + RwTexDictionary *txd = CTxdStore::GetSlot(i)->texDict; + if(txd) + RwTexDictionaryForAllTextures(txd, MoveTextureMemoryCB, nil); + } + } + + // animations + for(int i = 0; i < NUMANIMATIONS; i++){ + CAnimBlendHierarchy *anim = CAnimManager::GetAnimation(i); + if(anim == nil) + continue; // cannot happen + anim->MoveMemory(); + } + + // model info + for(int i = 0; i < MODELINFOSIZE; i++){ + CBaseModelInfo *mi = CModelInfo::GetModelInfo(i); + if(mi == nil) + continue; + TidyUpModelInfo(mi, false); + } + + printf("Largest free block after tidy %d\n", gMainHeap.GetLargestFreeBlock()); #endif } void CGame::ProcessTidyUpMemory(void) { #ifdef USE_CUSTOM_ALLOCATOR - // meow + static int32 modelIndex = 0; + static int32 animIndex = 0; + static int32 txdIndex = 0; + bool txdReturn = false; + RwTexDictionary *txd = nil; + gNumMemMoved = 0; + + // model infos + for(int numCleanedUp = 0; numCleanedUp < 10; numCleanedUp++){ + CBaseModelInfo *mi; + do{ + mi = CModelInfo::GetModelInfo(modelIndex); + modelIndex++; + if(modelIndex >= MODELINFOSIZE) + modelIndex = 0; + }while(mi == nil); + + if(TidyUpModelInfo(mi, true)) + return; + } + + // tex dicts + for(int numCleanedUp = 0; numCleanedUp < 3; numCleanedUp++){ + if(gNumMemMoved > 80) + break; + + do{ +#ifdef FIX_BUGS + txd = nil; +#endif + if(CTxdStore::GetSlot(txdIndex)) + txd = CTxdStore::GetSlot(txdIndex)->texDict; + txdIndex++; + if(txdIndex >= TXDSTORESIZE) + txdIndex = 0; + }while(txd == nil); + + RwTexDictionaryForAllTextures(txd, MoveTextureMemoryCB, &txdReturn); + if(txdReturn) + return; + } + + // animations + CAnimBlendHierarchy *anim; + do{ + anim = CAnimManager::GetAnimation(animIndex); + animIndex++; + if(animIndex >= NUMANIMATIONS) + animIndex = 0; + }while(anim == nil); // always != nil + anim->MoveMemory(true); #endif } diff --git a/src/core/main.cpp b/src/core/main.cpp index 102548b6..fa16b6c2 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -415,6 +415,7 @@ PluginAttach(void) return TRUE; } +// rather different on PS2 static RwBool Initialise3D(void *param) { diff --git a/src/rw/MemoryHeap.cpp b/src/rw/MemoryHeap.cpp index 0b333ce1..469262d3 100644 --- a/src/rw/MemoryHeap.cpp +++ b/src/rw/MemoryHeap.cpp @@ -187,7 +187,7 @@ CMemoryHeap::Malloc(uint32 size) void *mem = Malloc(size); if (removeCollision) { CTimer::Stop(); - // different on PS2 + // TODO: different on PS2 CFileLoader::LoadCollisionFromDatFile(CCollision::ms_collisionInMemory); removeCollision = false; CTimer::Update(); diff --git a/src/rw/MemoryHeap.h b/src/rw/MemoryHeap.h index 484cbfab..23163c1c 100644 --- a/src/rw/MemoryHeap.h +++ b/src/rw/MemoryHeap.h @@ -198,6 +198,7 @@ public: void TidyHeap(void); uint32 GetMemoryUsed(int32 id); uint32 GetBlocksUsed(int32 id); + int32 GetLargestFreeBlock(void) { return m_freeList.m_last.m_prev->m_size; } void ParseHeap(void); From e33ab44b7d179a59887200fe6d22c15fa557c5e2 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 1 Dec 2020 22:08:05 +0200 Subject: [PATCH 07/11] Add GTA_REPLAY --- src/control/Pickups.cpp | 4 ++-- src/control/Replay.cpp | 3 ++- src/control/Replay.h | 33 ++++++++++++++++++++++----------- src/core/config.h | 1 + 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp index 2503f5c8..1b1c8cbc 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -353,11 +353,11 @@ CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId) m_pObject->GetMatrix().UpdateRW(); m_pObject->UpdateRwFrame(); - if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0) && waterLevel >= m_pObject->GetPosition().z) + if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false) && waterLevel >= m_pObject->GetPosition().z) m_eType = PICKUP_FLOATINGPACKAGE_FLOATING; break; case PICKUP_FLOATINGPACKAGE_FLOATING: - if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0)) + if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false)) m_pObject->GetMatrix().GetPosition().z = waterLevel; m_pObject->GetMatrix().UpdateRW(); diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index f21703ac..757af0a9 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -1,5 +1,5 @@ #include "common.h" - +#ifdef GTA_REPLAY #include "AnimBlendAssociation.h" #include "Boat.h" #include "SpecialFX.h" @@ -1585,3 +1585,4 @@ void CReplay::Display() if (Mode == MODE_PLAYBACK) CFont::PrintString(SCREEN_SCALE_X(63.5f), SCREEN_SCALE_Y(30.0f), TheText.Get("REPLAY")); } +#endif diff --git a/src/control/Replay.h b/src/control/Replay.h index 66bee3bf..cb58a602 100644 --- a/src/control/Replay.h +++ b/src/control/Replay.h @@ -63,6 +63,12 @@ struct CStoredDetailedAnimationState void PlayReplayFromHD(void); +#ifdef GTA_REPLAY +#define REPLAY_STUB +#else +#define REPLAY_STUB {} +#endif + class CReplay { enum { @@ -273,20 +279,24 @@ private: #endif public: - static void Init(void); - static void DisableReplays(void); - static void EnableReplays(void); - static void Update(void); - static void FinishPlayback(void); - static void EmptyReplayBuffer(void); - static void Display(void); - static void TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene); - static void StreamAllNecessaryCarsAndPeds(void); - static bool ShouldStandardCameraBeProcessed(void); + static void Init(void) REPLAY_STUB; + static void DisableReplays(void) REPLAY_STUB; + static void EnableReplays(void) REPLAY_STUB; + static void Update(void) REPLAY_STUB; + static void FinishPlayback(void) REPLAY_STUB; + static void EmptyReplayBuffer(void) REPLAY_STUB; + static void Display(void) REPLAY_STUB; + static void TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene) REPLAY_STUB; + static void StreamAllNecessaryCarsAndPeds(void) REPLAY_STUB; +#ifndef GTA_REPLAY + static bool ShouldStandardCameraBeProcessed(void) { return true; } + static bool IsPlayingBack() { return false; } + static bool IsPlayingBackFromFile() { return false; } +#else + static bool ShouldStandardCameraBeProcessed(void); static bool IsPlayingBack() { return Mode == MODE_PLAYBACK; } static bool IsPlayingBackFromFile() { return bPlayingBackFromFile; } - private: static void RecordThisFrame(void); static void StorePedUpdate(CPed *ped, int id); @@ -314,4 +324,5 @@ private: /* Absolute nonsense, but how could this function end up being outside of class? */ friend void PlayReplayFromHD(void); +#endif }; diff --git a/src/core/config.h b/src/core/config.h index 5d528d50..07e91ee2 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -196,6 +196,7 @@ enum Config { # define RANDOMSPLASH // use random splash as on PS2 # define PS2_MATFX # endif +# define GTA_REPLAY #elif defined GTA_XBOX #endif From 4980386e9ab8020e3bde3447330f85d84adca3df Mon Sep 17 00:00:00 2001 From: IlDucci Date: Sun, 29 Nov 2020 11:54:35 +0100 Subject: [PATCH 08/11] Spanish translation: adding new re3 strings. --- gamefiles/TEXT/spanish.gxt | Bin 246088 -> 251590 bytes utils/gxt/spanish.txt | 372 ++++++++++++++++++++++++++++++++++++- 2 files changed, 371 insertions(+), 1 deletion(-) diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 0fdccce3bfe30dc99a4edc338caf0d27e57f44a2..06ad194a02f0603a501a4a55f0246e7ae17afbfa 100644 GIT binary patch delta 48641 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 delta 43782 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 Mzeih6(D#)8A0B8{^Z)<= diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt index c0da2239..e7dc1537 100644 --- a/utils/gxt/spanish.txt +++ b/utils/gxt/spanish.txt @@ -8021,11 +8021,381 @@ Error al cargar el juego. El juego se reiniciará. RESTAURADO AJUSTE ORIGINAL [FET_RSC] -HARDAWARE NO DISPONIBLE. RESTAURADO AJUSTE ORIGINAL HARDWARE NOT AVAILABLE - ORIGINAL SETTING RESTORED +HARDAWARE NO DISPONIBLE. RESTAURADO AJUSTE ORIGINAL [CRED270] MIKE HONG +{ ======================================================================= } +{ ================= NEW STRINGS FROM THE iOS CONVERSION ================= } +{ ======================================================================= } + +[FEC_OFI] +Puedes arrastrar los botones y elementos de la interfaz. Toca dos veces cualquier botón para cambiar su tamaño. Toca dos veces la pantalla para volver al menú. + +[FEL_JPN] +JAPONÉS + +[MM_MARK] +MARKETING + +[MM_INV] +INVENCIBILIDAD + +[MM_MODE] +MODO DE MARKETING + +[MM_SLV] +PERMITIR SALTO DE NIVEL + +[MM_TUTS] +DESACTIVAR TUTORIALES + +[FET_RMS] +REINTENTAR MISIÓN + +[FESZ_RM] +¿REINTENTAR? + +[FET_CT7] +INVERTIR VISTA + +[FEA_OFF] +RADIO APAGADA + +[FEM_SL0] +Autoguardado sin usar + +[RM_KEY] +Leyenda + +[RM_TONI] +Toni Cipriani + +[RM_SALV] +Salvatore Leone + +[RM_RAY] +Ray Machowski + +[RM_KEN] +Kenji Kasen + +[RM_JOEY] +Joey Leone + +[RM_DON] +Donald Love + +[RM_EIG] +8 Ball + +[RM_ASU] +Asuka Kasen + +[RM_LUIG] +Club de Luigi + +[RM_CATA] +Catalina + +[RM_BPHO] +Diablos + +[RM_GPHO] +Jamaicanos + +[RM_RPHO] +Hoods + +[RM_SPRY] +Taller de pintura + +[RM_AMMU] +Ammu-Nation + +[RM_SAFE] +Piso franco + +[RM_BOMB] +Bombas + +[RM_G1] +Cártel colombiano + +[RM_G2] +Familia Leone + +[RM_G3] +Diablos + +[RM_G4] +Tríadas + +[RM_G5] +Yakuza + +[RM_G6] +Yardies + +[RM_G7] +Hoods del sur + +[SPLASH] +Toca para continuar + +[FEM_SL9] +Autoguardado sin usar + +[NEW_H1] +Toca el radar para acceder al mapa de la ciudad. Podrás ver tu objetivo así como los lugares importantes. + +[TUT_RAD] +Para cambiar la emisora de radio, desliza sobre el nombre de la emisora hacia la izquiera o a la derecha. + +[NEW_H2] +Para mirar alrededor, pulsa en el centro y desliza el dedo por la pantalla. + +{ EXTRA CREDIT STRINGS } + +[CRED345] +War Drum Studios + +[CRED346] +Thomas Williamson + +[CRED347] +Michael Owen + +[CRED348] +Morgan Hughes + +[CRED349] +Abner Williamson + +[RM_YOU] +Tu posición + +[RM_TARG] +Objetivo + +[RM_GANG] +Mostrar bandas + +[CNT_FOT] +a pie + +[CNT_LFT] +Izquierda + +[CNT_RHT] +Derecha + +[CNT_JMP] +Saltar + +[CNT_RUN] +Correr + +[CNT_SCP] +Mira + +[CNT_SHT] +Disparar + +[CNT_PCH] +Golpear + +[CNT_THR] +Lanzar + +[CNT_ZIN] +Acercar vista + +[CNT_ZOT] +Alejar vista + +[CNT_CAR] +en vehículo + +[CNT_ACL] +Acelerar + +[CNT_BRK] +Frenar + +[CNT_EEX] +Entrar/salir vehíc. + +[CNT_STC] +Disparar + +[CNT_HBK] +Freno de mano + +[CNT_HRN] +Claxon + +[CNT_RTL] +Girar a la izq. + +[CNT_RTR] +Girar a la der. + +[CNT_ATM] +Activar misión + +[CNT_MNU] +Menú + +[CNT_CAM] +Cámara + +[FED_HAP] +Vibración + +[FEL_KOR] +Coreano + +[FEM_CL7] +El archivo 7 no está en la nube + +[FEM_CL8] +El archivo 8 no está en la nube + +[FEM_NC] +La nube no está disponible + +[FEM_CSE] +Espacio vacío en la nube + +[FEH_RTE] +Valora GTA III + +[T_RATE] +Si te gusta jugar a GTA III, puntúalo. ~N~¡Gracias por tu apoyo! + +{ re3 updates } +{ new languages } +[FEL_JAP] +JAPONÉS + +[FEL_POL] +POLACO + +[FEL_RUS] +RUSO + +{ new display menus } +[FET_GRA] +AJUSTES GRÁFICOS + +[FED_MIP] +MIPMAPPING + +[FED_AAS] +SUAVIZADO DE BORDES + +[FED_FIL] +FILTRO DE TEXTURAS + +[FED_BIL] +BILINEAL + +[FED_TRL] +TRILINEAL + +[FED_WND] +VENTANA + +[FED_FLS] +PANTALLA COMPLETA + +[FEM_CSB] +BORDES EN CINEMÁTICAS + +[FEM_SCF] +FORMATO DE IMAGEN + +[FEM_ISL] +USO DE MEMORIA + +[FEM_LOW] +BAJO + +[FEM_MED] +MEDIO + +[FEM_HIG] +ALTO + +[FEM_2PR] +ALPHA TEST TIPO PS2 + +[FEC_FRC] +CÁMARA LIBRE + +{ Linux joy detection } +[FEC_JOD] +DETECTAR JOYSTICK + +[FEC_JPR] +Pulsa cualquier botón del joystick que quieras usar con el juego para seleccionarlo. + +[FEC_JDE] +Joystick detectado + +{ mission restart } +[FET_RMS] +REPETIR MISIÓN + +[FESZ_RM] +¿REINTENTAR? + +[FED_VPL] +FLUJO DE VEHÍCULOS + +[FED_PRM] +LUCES EN PEATONES + +[FED_RGL] +BRILLO DE CARRETERAS + +[FED_CLF] +FILTRO DE COLOR + +[FED_WLM] +MAPAS DE LUZ DEL MUNDO + +[FED_MBL] +DESENFOQ. MOVIMIENTO + +[FEM_SIM] +SIMPLE + +[FEM_NRM] +NORMAL + +[FEM_MOB] +MÓVIL + +[FED_MFX] +MATFX + +[FED_NEO] +NEO + +[FEM_PS2] +PS2 + +[FEM_XBX] +XBOX + +[FEC_IVP] +INVERTIR VERTICALIDAD MANDO + +{ end of file } + [DUMMY] THIS LABEL NEEDS TO BE HERE !!! AS THE LAST LABEL DOES NOT GET COMPILED \ No newline at end of file From 1a30d94523230fed15679861520881f903364f44 Mon Sep 17 00:00:00 2001 From: IlDucci Date: Sun, 29 Nov 2020 16:00:41 +0100 Subject: [PATCH 09/11] Removing iOS strings as requested. --- gamefiles/TEXT/spanish.gxt | Bin 251590 -> 247600 bytes utils/gxt/spanish.txt | 249 ------------------------------------- 2 files changed, 249 deletions(-) diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 06ad194a02f0603a501a4a55f0246e7ae17afbfa..13aa6f29f45fdf82b650babb011b8e31621bd602 100644 GIT binary patch delta 582 zcmX@MmVZMZKU;{mYotZ}Mm9OV%@+J8csJX~ws0;!qsGi+;5zx7<}#)Y?vu;3l#C?Y zm>Jw$o#VY+Tp3pAK-sn7{7U08BXAUti z+%uSg3u<7vk1vCp%jPm;A;!s5OgyBDz=r$8dpQO$G(p(`{yq#7oG0^{iivZ8{qGxZ z6cEJFWyc8grf%Q?G!66K%Tqd70 z6=QngGWnTlpVTL)DqmL@hEwt&2l~eQ`Z6%oxlish6XPp$gb4ZhGcXjmPu^#y$28A< z@;fst@nukr!Om_BNnqdj#s_=)PWCoWoV>%lg=v}lW;=^AW~Lao&4;Y{m?qz`ZDE?_ zygA8^jgiUDZF8BulKSK;X$Lm1Nf+SW%u~X`v{|OCfqnCq+89=*7w*kM&FwfL6!z&3`-J`7dYu^10==ez1I5)N2hadGd$LKA)~V=cFiGj7nzKp~J4ikxN&U zJQMWN6H1;nT{^AgSu>#P3R~78y4fpz^Ik+BD7l^KrF)gH9Te%W%BIKl={FMBN=`na z$CQyHV%lCeb85=w8CN5r!|WhzHcq!C`)@4j_iPJ zXO(1qxKN}ar8w+G^|tgcKfUjdJx~T#uDzp^KDv!}(K==&mSAzJ7?LpgXN}Y$= z@TEHMg!FABkVDv}AHTP~`9VFD?{3DSXc6ZR(KnR8Tkz=-B`;bYy}MTv{=R9`(IC$3 zSf@W7#7B3GrvIrtqQIetg7~c+tJ7};GWbEqrThH4zH_D4aH+^LyA(uL+}K{|*)QCj zQjh7=wH)h!{UW_6h&rWSFCa(R_#RqS;h-<1!QIk6^i6u*kI%KQZhA$yxuvYrMIYYA zyW{V+uW!nUJU|y_XjIT(Y{kECU%&GgN@o|kX|+hFTe8E5o>B5b=+G@CcTlfue!QjQ zT+dIG+O=}@tF_F=Ex9g{Em8*TWoW)r$$g>@wQVs=G-FD6(IeU$#((eFrXLUE4V`=2 zCRNlho2RWRQdn^5ebH8KDRj2Sk9L+DCT$rZboRu5=sc@WhV`%Pnn|TE2)pobDR5~+ zP=9kzT5q@}WKk&_b;W<$cUB+r>ZALYY3XSt58ROM4(in}t=qWoP1M14ONC-T(M^e6 z6W76q3VS(=*1!)op#vLR;;1hQ<9O&s(p{=$6D53Px9@O*i(V*A?Cg{AY#R zfj^SC*4=@ZG#G+JcPH>?72XBBRpBn+7ctdrV-~w>}(W~e>Mv+DJcV-`6s$UDA%-5dE z*EB4BAzw>PXM24*Ny9XRHAM!Msfu42cv?KGkd4uV&<)}_ja5;$v(ODgJ51wP6`D@w z&TEYij4*_tN=Fgs6m5f91h*r2Gq8~iHUoOBT2kAVv3xXFnuG$^vJw z9IPBHbHc;J(*va(Y>Ycb@SzEyDR9(B01a$rB24sejzy?>8wWu-6kB8kjebFj)6*wB z0$8#)+Yq8zcrQZ36eBW|^FL4BUtGhpJREMc9A1akq8 z;mL&_!e6e3f%0b zHP;9^EQ@X#6XeTq$pMvVP<1TtC3|T^G+zZfPr=H@a{|X=9KnLO<96ld9LC>C5pNos z^CU2lar{ow{YX6TI0Em=Rw#VHDZCiybT+MEn+eD>_&W|7d}yY5A(=a_tp(#eMB{K` z#(XSJvYe;?Z)^IGFt9$(HFXO6RI;A~}NPmcL;VvcG}tp>8h$*$4`5Hg78o*j_h zok@Llt{278j1dd}Ybnaor5GE;sN<^4l~nl{OLZB<QsoCX5s&H_oRT4-#&r37AeoDUBUGE26pC*u>e`jlUV3^BFkv zC#fuSJg%d6&&5^q5L{cXH;s*1D8C1MvA&(^96mEqP}_47V$Gn}-$?k4o{r%(ox=3<``6 zqnE&AF*SU4?oq;R&f~)#T+i}l>EeEJIlaaCm(S5VtQ=-}_%F#unv|62e~ zKii6car^a+xUDQ~%G1oWnZ%61mldHq(ddT-|FE%Sbs5P(P0b=h->^_V2g@uKiso5p} E0;5GbMgRZ+ diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt index e7dc1537..22063c35 100644 --- a/utils/gxt/spanish.txt +++ b/utils/gxt/spanish.txt @@ -8026,255 +8026,6 @@ HARDAWARE NO DISPONIBLE. RESTAURADO AJUSTE ORIGINAL [CRED270] MIKE HONG -{ ======================================================================= } -{ ================= NEW STRINGS FROM THE iOS CONVERSION ================= } -{ ======================================================================= } - -[FEC_OFI] -Puedes arrastrar los botones y elementos de la interfaz. Toca dos veces cualquier botón para cambiar su tamaño. Toca dos veces la pantalla para volver al menú. - -[FEL_JPN] -JAPONÉS - -[MM_MARK] -MARKETING - -[MM_INV] -INVENCIBILIDAD - -[MM_MODE] -MODO DE MARKETING - -[MM_SLV] -PERMITIR SALTO DE NIVEL - -[MM_TUTS] -DESACTIVAR TUTORIALES - -[FET_RMS] -REINTENTAR MISIÓN - -[FESZ_RM] -¿REINTENTAR? - -[FET_CT7] -INVERTIR VISTA - -[FEA_OFF] -RADIO APAGADA - -[FEM_SL0] -Autoguardado sin usar - -[RM_KEY] -Leyenda - -[RM_TONI] -Toni Cipriani - -[RM_SALV] -Salvatore Leone - -[RM_RAY] -Ray Machowski - -[RM_KEN] -Kenji Kasen - -[RM_JOEY] -Joey Leone - -[RM_DON] -Donald Love - -[RM_EIG] -8 Ball - -[RM_ASU] -Asuka Kasen - -[RM_LUIG] -Club de Luigi - -[RM_CATA] -Catalina - -[RM_BPHO] -Diablos - -[RM_GPHO] -Jamaicanos - -[RM_RPHO] -Hoods - -[RM_SPRY] -Taller de pintura - -[RM_AMMU] -Ammu-Nation - -[RM_SAFE] -Piso franco - -[RM_BOMB] -Bombas - -[RM_G1] -Cártel colombiano - -[RM_G2] -Familia Leone - -[RM_G3] -Diablos - -[RM_G4] -Tríadas - -[RM_G5] -Yakuza - -[RM_G6] -Yardies - -[RM_G7] -Hoods del sur - -[SPLASH] -Toca para continuar - -[FEM_SL9] -Autoguardado sin usar - -[NEW_H1] -Toca el radar para acceder al mapa de la ciudad. Podrás ver tu objetivo así como los lugares importantes. - -[TUT_RAD] -Para cambiar la emisora de radio, desliza sobre el nombre de la emisora hacia la izquiera o a la derecha. - -[NEW_H2] -Para mirar alrededor, pulsa en el centro y desliza el dedo por la pantalla. - -{ EXTRA CREDIT STRINGS } - -[CRED345] -War Drum Studios - -[CRED346] -Thomas Williamson - -[CRED347] -Michael Owen - -[CRED348] -Morgan Hughes - -[CRED349] -Abner Williamson - -[RM_YOU] -Tu posición - -[RM_TARG] -Objetivo - -[RM_GANG] -Mostrar bandas - -[CNT_FOT] -a pie - -[CNT_LFT] -Izquierda - -[CNT_RHT] -Derecha - -[CNT_JMP] -Saltar - -[CNT_RUN] -Correr - -[CNT_SCP] -Mira - -[CNT_SHT] -Disparar - -[CNT_PCH] -Golpear - -[CNT_THR] -Lanzar - -[CNT_ZIN] -Acercar vista - -[CNT_ZOT] -Alejar vista - -[CNT_CAR] -en vehículo - -[CNT_ACL] -Acelerar - -[CNT_BRK] -Frenar - -[CNT_EEX] -Entrar/salir vehíc. - -[CNT_STC] -Disparar - -[CNT_HBK] -Freno de mano - -[CNT_HRN] -Claxon - -[CNT_RTL] -Girar a la izq. - -[CNT_RTR] -Girar a la der. - -[CNT_ATM] -Activar misión - -[CNT_MNU] -Menú - -[CNT_CAM] -Cámara - -[FED_HAP] -Vibración - -[FEL_KOR] -Coreano - -[FEM_CL7] -El archivo 7 no está en la nube - -[FEM_CL8] -El archivo 8 no está en la nube - -[FEM_NC] -La nube no está disponible - -[FEM_CSE] -Espacio vacío en la nube - -[FEH_RTE] -Valora GTA III - -[T_RATE] -Si te gusta jugar a GTA III, puntúalo. ~N~¡Gracias por tu apoyo! - { re3 updates } { new languages } [FEL_JAP] From 9461998304219f91b3b24484d0cee5b5c5d4523c Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 23 Nov 2020 22:46:07 +0200 Subject: [PATCH 10/11] TexturePools --- src/core/Game.cpp | 3 + src/rw/RwHelper.cpp | 5 - src/rw/RwHelper.h | 2 - src/rw/TexturePools.cpp | 221 ++++++++++++++++++++++++++++++++++++++++ src/rw/TexturePools.h | 42 ++++++++ 5 files changed, 266 insertions(+), 7 deletions(-) create mode 100644 src/rw/TexturePools.cpp create mode 100644 src/rw/TexturePools.h diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 262aa54a..9a604757 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -91,6 +91,9 @@ #include "screendroplets.h" #include "crossplatform.h" #include "MemoryHeap.h" +#ifdef USE_TEXTURE_POOL +#include "TexturePools.h" +#endif eLevelName CGame::currLevel; bool CGame::bDemoMode = true; diff --git a/src/rw/RwHelper.cpp b/src/rw/RwHelper.cpp index ee370c37..e0133985 100644 --- a/src/rw/RwHelper.cpp +++ b/src/rw/RwHelper.cpp @@ -605,11 +605,6 @@ CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer) return (nil); } -#ifdef USE_TEXTURE_POOL -WRAPPER void _TexturePoolsInitialise() { EAXJMP(0x598B10); } -WRAPPER void _TexturePoolsShutdown() { EAXJMP(0x598B30); } -#endif - #ifdef LIBRW #include #include "VehicleModelInfo.h" diff --git a/src/rw/RwHelper.h b/src/rw/RwHelper.h index ed9b03ab..1a5f64b1 100644 --- a/src/rw/RwHelper.h +++ b/src/rw/RwHelper.h @@ -50,8 +50,6 @@ RwCamera *CameraCreate(RwInt32 width, RwBool zBuffer); -void _TexturePoolsInitialise(); -void _TexturePoolsShutdown(); RpAtomic *ConvertPlatformAtomic(RpAtomic *atomic, void *data); diff --git a/src/rw/TexturePools.cpp b/src/rw/TexturePools.cpp new file mode 100644 index 00000000..c2ba6cf9 --- /dev/null +++ b/src/rw/TexturePools.cpp @@ -0,0 +1,221 @@ +#ifndef LIBRW + +#include +#define WITHD3D +#include "common.h" +#include "TexturePools.h" + +// TODO: this needs to be integrated into RW + +extern "C" LPDIRECT3DDEVICE8 _RwD3DDevice; + +CTexturePool aTexturePools[12]; +CPaletteList PaletteList; +int numTexturePools; +int MaxPaletteIndex; +bool bUsePaletteIndex = true; + + +void +CTexturePool::Create(D3DFORMAT _Format, int _size, uint32 mipmapLevels, int32 numTextures) +{ + Format = _Format; + size = _size; + levels = mipmapLevels; + pTextures = new IDirect3DTexture8 *[numTextures]; + texturesMax = numTextures; + texturesNum = 0; + texturesUsed = 0; +} + +void +CTexturePool::Release() +{ + int i = 0; + while (i < texturesNum) { + pTextures[i]->Release(); + i++; + } + + delete[] pTextures; + + pTextures = nil; + texturesNum = 0; + texturesUsed = 0; +} + +IDirect3DTexture8 * +CTexturePool::FindTexture() +{ + if (texturesNum == 0) + return nil; + texturesUsed--; + return pTextures[--texturesNum]; +} + +bool +CTexturePool::AddTexture(IDirect3DTexture8 *texture) +{ + ++texturesUsed; + if (texturesNum >= texturesMax) + return false; + pTextures[texturesNum] = texture; + ++texturesNum; + return true; +} + +void +CTexturePool::Resize(int numTextures) +{ + if (numTextures == texturesMax) + return; + + IDirect3DTexture8 **newTextures = new IDirect3DTexture8 *[numTextures]; + + for (int i = 0; i < texturesNum && i < numTextures; i++) + newTextures[i] = pTextures[i]; + + if (numTextures < texturesNum) { + for (int i = numTextures; i < texturesNum; i++) + pTextures[i]->Release(); + } + delete[] pTextures; + pTextures = newTextures; + texturesMax = numTextures; +} + +void +CPaletteList::Alloc(int max) +{ + Data = new int[max]; + Max = max; + Num = 0; +} + +void +CPaletteList::Free() +{ + delete[] Data; + Data = nil; + Num = 0; +} + +int +CPaletteList::Find() +{ + if (Num == 0) + return -1; + return Data[--Num]; +} + +void +CPaletteList::Add(int item) +{ + if (Num < Max) + Data[Num++] = item; + else { + Resize(2 * Max); + Add(item); + } +} + +void +CPaletteList::Resize(int max) +{ + if (max == Max) + return; + + int *newData = new int[4 * max]; + for (int i = 0; i < Num && i < max; i++) + newData[i] = Data[i]; + delete[] Data; + Data = newData; + Max = max; +} + +HRESULT +CreateTexture(int width, int height, int levels, D3DFORMAT Format, IDirect3DTexture8 **texture) +{ + if (width == height) { + for (int i = 0; i < numTexturePools; i++) { + if (width != aTexturePools[i].GetSize() && levels == aTexturePools[i].levels && Format == aTexturePools[i].Format) + *texture = aTexturePools[i].FindTexture(); + } + } + if (*texture) + return D3D_OK; + else + return _RwD3DDevice->CreateTexture(width, height, levels, 0, Format, D3DPOOL_MANAGED, texture); +} + +void +ReleaseTexture(IDirect3DTexture8 *texture) +{ + int levels = 1; + if (texture->GetLevelCount() > 1) + levels = 0; + + D3DSURFACE_DESC SURFACE_DESC; + + texture->GetLevelDesc(0, &SURFACE_DESC); + + if (SURFACE_DESC.Width == SURFACE_DESC.Height) { + for (int i = 0; i < numTexturePools; i++) { + if (SURFACE_DESC.Width == aTexturePools[i].GetSize() && SURFACE_DESC.Format == aTexturePools[i].Format && levels == aTexturePools[i].levels) { + if (!aTexturePools[i].AddTexture(texture)) { + if (aTexturePools[i].texturesUsed > 3 * aTexturePools[i].texturesMax / 2) { + aTexturePools[i].Resize(2 * aTexturePools[i].texturesMax); + aTexturePools[i].texturesUsed--; + aTexturePools[i].AddTexture(texture); + } else { + texture->Release(); + } + } + return; + } + } + } + if (numTexturePools < 12 && bUsePaletteIndex && levels != 0 && SURFACE_DESC.Width == SURFACE_DESC.Height && + (SURFACE_DESC.Width == 64 || SURFACE_DESC.Width == 128 || SURFACE_DESC.Width == 256)) { + aTexturePools[numTexturePools].Create(SURFACE_DESC.Format, SURFACE_DESC.Width, 1, 16); + aTexturePools[numTexturePools].AddTexture(texture); + numTexturePools++; + } else + texture->Release(); +} + +int +FindAvailablePaletteIndex() +{ + int index = PaletteList.Find(); + if (index == -1) + index = MaxPaletteIndex++; + return index; +} + +void +AddAvailablePaletteIndex(int index) +{ + if (bUsePaletteIndex) + PaletteList.Add(index); +} + +void +_TexturePoolsInitialise() +{ + PaletteList.Alloc(100); + MaxPaletteIndex = 0; +} + +void +_TexturePoolsShutdown() +{ + for (int i = 0; i < numTexturePools; i++) + aTexturePools[i].Release(); + + numTexturePools = 0; + bUsePaletteIndex = false; + PaletteList.Free(); +} + +#endif // !LIBRW \ No newline at end of file diff --git a/src/rw/TexturePools.h b/src/rw/TexturePools.h new file mode 100644 index 00000000..75187432 --- /dev/null +++ b/src/rw/TexturePools.h @@ -0,0 +1,42 @@ +#pragma once + +class CTexturePool +{ +public: + D3DFORMAT Format; + int size; + uint32 levels; + int32 texturesMax; + int32 texturesUsed; + int32 texturesNum; + IDirect3DTexture8 **pTextures; + +public: + CTexturePool() {} + void Create(D3DFORMAT _Format, int size, uint32 mipmapLevels, int32 numTextures); + void Release(); + IDirect3DTexture8 *FindTexture(); + bool AddTexture(IDirect3DTexture8 *texture); + void Resize(int numTextures); +#ifdef FIX_BUGS + int GetSize() { return size; } +#else + float GetSize() { return size; } +#endif +}; + +class CPaletteList +{ + int Max; + int Num; + int *Data; +public: + void Alloc(int max); + void Free(); + int Find(); + void Add(int item); + void Resize(int max); +}; + +void _TexturePoolsInitialise(); +void _TexturePoolsShutdown(); \ No newline at end of file From 0b20fd7e77dafc34cf9eebc3ffd25318a7d81476 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 1 Dec 2020 22:35:53 +0200 Subject: [PATCH 11/11] Remove ifndef GTA_PS2 around replays --- src/core/Game.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 9a604757..6b9fd11f 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -581,9 +581,7 @@ bool CGame::Initialise(const char* datFile) CPlane::InitPlanes(); CCredits::Init(); CRecordDataForChase::Init(); -#ifndef GTA_PS2 // TODO: define for that CReplay::Init(); -#endif #ifdef PS2_MENU if ( !TheMemoryCard.m_bWantToLoad ) @@ -773,10 +771,8 @@ void CGame::ReloadIPLs(void) void CGame::ShutDownForRestart(void) { -#ifndef GTA_PS2 // TODO: right define CReplay::FinishPlayback(); CReplay::EmptyReplayBuffer(); -#endif DMAudio.DestroyAllGameCreatedEntities(); for (int i = 0; i < NUMPLAYERS; i++) @@ -996,9 +992,7 @@ void CGame::Process(void) CMovingThings::Update(); CWaterCannons::Update(); CUserDisplay::Process(); -#ifndef GTA_PS2 // TODO: define CReplay::Update(); -#endif PUSH_MEMID(MEMID_WORLD); CWorld::Process(); @@ -1011,14 +1005,10 @@ void CGame::Process(void) CRubbish::Update(); CSpecialFX::Update(); CTimeCycle::Update(); -#ifndef GTA_PS2 // TODO: define if (CReplay::ShouldStandardCameraBeProcessed()) -#endif TheCamera.Process(); CCullZones::Update(); -#ifndef GTA_PS2 // TODO: define if (!CReplay::IsPlayingBack()) -#endif CGameLogic::Update(); CBridge::Update(); CCoronas::DoSunAndMoon(); @@ -1026,9 +1016,7 @@ void CGame::Process(void) CShadows::UpdateStaticShadows(); CShadows::UpdatePermanentShadows(); gPhoneInfo.Update(); -#ifndef GTA_PS2 // TODO: define if (!CReplay::IsPlayingBack()) -#endif { PUSH_MEMID(MEMID_CARS); CCarCtrl::GenerateRandomCars();