2019-05-15 14:52:37 +00:00
# include "common.h"
2020-04-17 13:31:11 +00:00
2019-10-29 23:12:58 +00:00
# include "General.h"
2019-06-26 19:33:58 +00:00
# include "Pad.h"
# include "Hud.h"
# include "Text.h"
2019-06-26 22:12:58 +00:00
# include "Clock.h"
# include "Renderer.h"
2019-06-20 12:49:16 +00:00
# include "ModelInfo.h"
# include "TxdStore.h"
2019-06-21 15:28:55 +00:00
# include "ModelIndices.h"
2019-06-20 12:49:16 +00:00
# include "Pools.h"
2020-03-28 14:47:52 +00:00
# include "Wanted.h"
2019-06-20 12:49:16 +00:00
# include "Directory.h"
# include "RwHelper.h"
2019-06-21 15:28:55 +00:00
# include "World.h"
2019-06-20 12:49:16 +00:00
# include "Entity.h"
# include "FileMgr.h"
2019-06-21 15:28:55 +00:00
# include "FileLoader.h"
2019-06-27 12:17:42 +00:00
# include "Zones.h"
2019-07-07 11:09:11 +00:00
# include "ZoneCull.h"
2019-06-27 12:17:42 +00:00
# include "Radar.h"
# include "Camera.h"
2019-06-28 10:34:02 +00:00
# include "Record.h"
# include "CarCtrl.h"
# include "Population.h"
# include "Gangs.h"
# include "CutsceneMgr.h"
2019-06-20 12:49:16 +00:00
# include "CdStream.h"
2019-05-15 14:52:37 +00:00
# include "Streaming.h"
2020-04-18 20:50:37 +00:00
# ifdef FIX_BUGS
# include "Replay.h"
# endif
2019-08-15 14:51:39 +00:00
# include "main.h"
2020-08-16 14:26:44 +00:00
# include "Frontend.h"
2020-11-26 16:11:55 +00:00
# include "Font.h"
2020-11-28 15:16:15 +00:00
# include "MemoryMgr.h"
2020-11-26 15:47:19 +00:00
# include "MemoryHeap.h"
2019-05-15 14:52:37 +00:00
2020-04-17 05:54:14 +00:00
bool CStreaming : : ms_disableStreaming ;
bool CStreaming : : ms_bLoadingBigModel ;
int32 CStreaming : : ms_numModelsRequested ;
CStreamingInfo CStreaming : : ms_aInfoForModel [ NUMSTREAMINFO ] ;
CStreamingInfo CStreaming : : ms_startLoadedList ;
CStreamingInfo CStreaming : : ms_endLoadedList ;
CStreamingInfo CStreaming : : ms_startRequestedList ;
CStreamingInfo CStreaming : : ms_endRequestedList ;
int32 CStreaming : : ms_oldSectorX ;
int32 CStreaming : : ms_oldSectorY ;
int32 CStreaming : : ms_streamingBufferSize ;
2020-10-04 19:39:54 +00:00
# ifndef ONE_THREAD_PER_CHANNEL
2020-04-17 05:54:14 +00:00
int8 * CStreaming : : ms_pStreamingBuffer [ 2 ] ;
2020-10-04 19:39:54 +00:00
# else
int8 * CStreaming : : ms_pStreamingBuffer [ 4 ] ;
# endif
2020-07-22 11:56:28 +00:00
size_t CStreaming : : ms_memoryUsed ;
2020-04-17 05:54:14 +00:00
CStreamingChannel CStreaming : : ms_channel [ 2 ] ;
int32 CStreaming : : ms_channelError ;
int32 CStreaming : : ms_numVehiclesLoaded ;
int32 CStreaming : : ms_vehiclesLoaded [ MAXVEHICLESLOADED ] ;
int32 CStreaming : : ms_lastVehicleDeleted ;
CDirectory * CStreaming : : ms_pExtraObjectsDir ;
int32 CStreaming : : ms_numPriorityRequests ;
bool CStreaming : : ms_hasLoadedLODs ;
int32 CStreaming : : ms_currentPedGrp ;
2019-06-20 12:49:16 +00:00
int32 CStreaming : : ms_currentPedLoading ;
int32 CStreaming : : ms_lastCullZone ;
2020-04-17 05:54:14 +00:00
uint16 CStreaming : : ms_loadedGangs ;
uint16 CStreaming : : ms_loadedGangCars ;
int32 CStreaming : : ms_imageOffsets [ NUMCDIMAGES ] ;
int32 CStreaming : : ms_lastImageRead ;
int32 CStreaming : : ms_imageSize ;
2020-07-22 11:56:28 +00:00
size_t CStreaming : : ms_memoryAvailable ;
2020-04-17 05:54:14 +00:00
int32 desiredNumVehiclesLoaded = 12 ;
CEntity * pIslandLODindustEntity ;
CEntity * pIslandLODcomIndEntity ;
CEntity * pIslandLODcomSubEntity ;
CEntity * pIslandLODsubIndEntity ;
CEntity * pIslandLODsubComEntity ;
int32 islandLODindust ;
int32 islandLODcomInd ;
int32 islandLODcomSub ;
int32 islandLODsubInd ;
int32 islandLODsubCom ;
2019-06-20 12:49:16 +00:00
2019-06-26 22:12:58 +00:00
bool
CStreamingInfo : : GetCdPosnAndSize ( uint32 & posn , uint32 & size )
{
if ( m_size = = 0 )
return false ;
posn = m_position ;
size = m_size ;
return true ;
}
void
CStreamingInfo : : SetCdPosnAndSize ( uint32 posn , uint32 size )
{
m_position = posn ;
m_size = size ;
}
void
CStreamingInfo : : AddToList ( CStreamingInfo * link )
{
// Insert this after link
m_next = link - > m_next ;
m_prev = link ;
link - > m_next = this ;
m_next - > m_prev = this ;
}
void
CStreamingInfo : : RemoveFromList ( void )
{
m_next - > m_prev = m_prev ;
m_prev - > m_next = m_next ;
m_next = nil ;
m_prev = nil ;
}
2019-06-12 18:07:37 +00:00
2019-06-20 12:49:16 +00:00
void
2020-05-05 11:02:42 +00:00
CStreaming : : Init2 ( void )
2019-06-20 12:49:16 +00:00
{
int i ;
for ( i = 0 ; i < NUMSTREAMINFO ; i + + ) {
ms_aInfoForModel [ i ] . m_loadState = STREAMSTATE_NOTLOADED ;
ms_aInfoForModel [ i ] . m_next = nil ;
ms_aInfoForModel [ i ] . m_prev = nil ;
ms_aInfoForModel [ i ] . m_nextID = - 1 ;
ms_aInfoForModel [ i ] . m_size = 0 ;
ms_aInfoForModel [ i ] . m_position = 0 ;
}
2019-06-26 19:33:58 +00:00
ms_channelError = - 1 ;
2019-06-20 12:49:16 +00:00
// init lists
ms_startLoadedList . m_next = & ms_endLoadedList ;
ms_startLoadedList . m_prev = nil ;
ms_endLoadedList . m_prev = & ms_startLoadedList ;
ms_endLoadedList . m_next = nil ;
ms_startRequestedList . m_next = & ms_endRequestedList ;
ms_startRequestedList . m_prev = nil ;
ms_endRequestedList . m_prev = & ms_startRequestedList ;
ms_endRequestedList . m_next = nil ;
// init misc
ms_oldSectorX = 0 ;
ms_oldSectorY = 0 ;
ms_streamingBufferSize = 0 ;
ms_disableStreaming = false ;
ms_memoryUsed = 0 ;
ms_bLoadingBigModel = false ;
// init channels
2019-06-24 16:44:23 +00:00
ms_channel [ 0 ] . state = CHANNELSTATE_IDLE ;
ms_channel [ 1 ] . state = CHANNELSTATE_IDLE ;
2019-06-20 12:49:16 +00:00
for ( i = 0 ; i < 4 ; i + + ) {
2019-06-24 16:44:23 +00:00
ms_channel [ 0 ] . streamIds [ i ] = - 1 ;
2019-06-20 12:49:16 +00:00
ms_channel [ 0 ] . offsets [ i ] = - 1 ;
2019-06-24 16:44:23 +00:00
ms_channel [ 1 ] . streamIds [ i ] = - 1 ;
2019-06-20 12:49:16 +00:00
ms_channel [ 1 ] . offsets [ i ] = - 1 ;
}
// init stream info, mark things that are already loaded
for ( i = 0 ; i < MODELINFOSIZE ; i + + ) {
CBaseModelInfo * mi = CModelInfo : : GetModelInfo ( i ) ;
if ( mi & & mi - > GetRwObject ( ) ) {
2019-06-24 16:44:23 +00:00
ms_aInfoForModel [ i ] . m_loadState = STREAMSTATE_LOADED ;
ms_aInfoForModel [ i ] . m_flags = STREAMFLAGS_DONT_REMOVE ;
2019-06-20 12:49:16 +00:00
if ( mi - > IsSimple ( ) )
( ( CSimpleModelInfo * ) mi ) - > m_alpha = 255 ;
}
}
for ( i = 0 ; i < TXDSTORESIZE ; i + + )
if ( CTxdStore : : GetSlot ( i ) & & CTxdStore : : GetSlot ( i ) - > texDict )
ms_aInfoForModel [ i + STREAM_OFFSET_TXD ] . m_loadState = STREAMSTATE_LOADED ;
for ( i = 0 ; i < MAXVEHICLESLOADED ; i + + )
ms_vehiclesLoaded [ i ] = - 1 ;
ms_numVehiclesLoaded = 0 ;
ms_pExtraObjectsDir = new CDirectory ( EXTRADIRSIZE ) ;
ms_numPriorityRequests = 0 ;
ms_hasLoadedLODs = true ;
ms_currentPedGrp = - 1 ;
ms_lastCullZone = - 1 ; // unused because RemoveModelsNotVisibleFromCullzone is gone
ms_loadedGangs = 0 ;
ms_currentPedLoading = 8 ; // unused, whatever it is
LoadCdDirectory ( ) ;
// allocate streaming buffers
if ( ms_streamingBufferSize & 1 ) ms_streamingBufferSize + + ;
2021-01-27 15:26:08 +00:00
# ifndef ONE_THREAD_PER_CHANNEL
2019-06-24 16:44:23 +00:00
ms_pStreamingBuffer [ 0 ] = ( int8 * ) RwMallocAlign ( ms_streamingBufferSize * CDSTREAM_SECTOR_SIZE , CDSTREAM_SECTOR_SIZE ) ;
2019-06-20 12:49:16 +00:00
ms_streamingBufferSize / = 2 ;
ms_pStreamingBuffer [ 1 ] = ms_pStreamingBuffer [ 0 ] + ms_streamingBufferSize * CDSTREAM_SECTOR_SIZE ;
2021-01-27 15:26:08 +00:00
# else
ms_pStreamingBuffer [ 0 ] = ( int8 * ) RwMallocAlign ( ms_streamingBufferSize * 2 * CDSTREAM_SECTOR_SIZE , CDSTREAM_SECTOR_SIZE ) ;
ms_streamingBufferSize / = 2 ;
ms_pStreamingBuffer [ 1 ] = ms_pStreamingBuffer [ 0 ] + ms_streamingBufferSize * CDSTREAM_SECTOR_SIZE ;
ms_pStreamingBuffer [ 2 ] = ms_pStreamingBuffer [ 1 ] + ms_streamingBufferSize * CDSTREAM_SECTOR_SIZE ;
2020-10-04 19:39:54 +00:00
ms_pStreamingBuffer [ 3 ] = ms_pStreamingBuffer [ 2 ] + ms_streamingBufferSize * CDSTREAM_SECTOR_SIZE ;
# endif
2019-06-20 12:49:16 +00:00
debug ( " Streaming buffer size is %d sectors " , ms_streamingBufferSize ) ;
// PC only, figure out how much memory we got
2019-06-27 08:58:51 +00:00
# ifdef GTA_PC
2019-06-20 12:49:16 +00:00
# define MB (1024*1024)
2020-07-22 11:56:28 +00:00
extern size_t _dwMemAvailPhys ;
2019-06-20 12:49:16 +00:00
ms_memoryAvailable = ( _dwMemAvailPhys - 10 * MB ) / 2 ;
if ( ms_memoryAvailable < 50 * MB )
ms_memoryAvailable = 50 * MB ;
2020-07-22 11:56:28 +00:00
desiredNumVehiclesLoaded = ( int32 ) ( ( ms_memoryAvailable / MB - 50 ) / 3 + 12 ) ;
2019-06-20 12:49:16 +00:00
if ( desiredNumVehiclesLoaded > MAXVEHICLESLOADED )
desiredNumVehiclesLoaded = MAXVEHICLESLOADED ;
2020-07-24 17:43:51 +00:00
debug ( " Memory allocated to Streaming is %zuMB " , ms_memoryAvailable / MB ) ; // original modifier was %d
2019-06-20 12:49:16 +00:00
# undef MB
2019-06-27 08:58:51 +00:00
# endif
2019-06-20 12:49:16 +00:00
// find island LODs
pIslandLODindustEntity = nil ;
pIslandLODcomIndEntity = nil ;
pIslandLODcomSubEntity = nil ;
pIslandLODsubIndEntity = nil ;
pIslandLODsubComEntity = nil ;
islandLODindust = - 1 ;
islandLODcomInd = - 1 ;
islandLODcomSub = - 1 ;
islandLODsubInd = - 1 ;
islandLODsubCom = - 1 ;
CModelInfo : : GetModelInfo ( " IslandLODInd " , & islandLODindust ) ;
CModelInfo : : GetModelInfo ( " IslandLODcomIND " , & islandLODcomInd ) ;
CModelInfo : : GetModelInfo ( " IslandLODcomSUB " , & islandLODcomSub ) ;
CModelInfo : : GetModelInfo ( " IslandLODsubIND " , & islandLODsubInd ) ;
CModelInfo : : GetModelInfo ( " IslandLODsubCOM " , & islandLODsubCom ) ;
2019-10-16 21:53:25 +00:00
for ( i = CPools : : GetBuildingPool ( ) - > GetSize ( ) - 1 ; i > = 0 ; i - - ) {
2019-06-20 12:49:16 +00:00
CBuilding * building = CPools : : GetBuildingPool ( ) - > GetSlot ( i ) ;
if ( building = = nil )
continue ;
if ( building - > GetModelIndex ( ) = = islandLODindust ) pIslandLODindustEntity = building ;
if ( building - > GetModelIndex ( ) = = islandLODcomInd ) pIslandLODcomIndEntity = building ;
if ( building - > GetModelIndex ( ) = = islandLODcomSub ) pIslandLODcomSubEntity = building ;
if ( building - > GetModelIndex ( ) = = islandLODsubInd ) pIslandLODsubIndEntity = building ;
if ( building - > GetModelIndex ( ) = = islandLODsubCom ) pIslandLODsubComEntity = building ;
}
2020-05-05 11:02:42 +00:00
}
void
CStreaming : : Init ( void )
{
# ifdef USE_TXD_CDIMAGE
int txdHandle = CFileMgr : : OpenFile ( " MODELS \\ TXD.IMG " , " r " ) ;
if ( txdHandle )
CFileMgr : : CloseFile ( txdHandle ) ;
if ( ! CheckVideoCardCaps ( ) & & txdHandle ) {
CdStreamAddImage ( " MODELS \\ TXD.IMG " ) ;
CStreaming : : Init2 ( ) ;
} else {
CStreaming : : Init2 ( ) ;
if ( CreateTxdImageForVideoCard ( ) ) {
CStreaming : : Shutdown ( ) ;
CdStreamAddImage ( " MODELS \\ TXD.IMG " ) ;
CStreaming : : Init2 ( ) ;
}
}
# else
2020-05-11 15:04:08 +00:00
CStreaming : : Init2 ( ) ;
2020-05-05 11:02:42 +00:00
# endif
2019-06-20 12:49:16 +00:00
}
void
CStreaming : : Shutdown ( void )
{
RwFreeAlign ( ms_pStreamingBuffer [ 0 ] ) ;
ms_streamingBufferSize = 0 ;
2020-08-20 21:45:05 +00:00
if ( ms_pExtraObjectsDir ) {
2019-06-20 12:49:16 +00:00
delete ms_pExtraObjectsDir ;
2020-08-20 21:45:05 +00:00
# ifdef FIX_BUGS
ms_pExtraObjectsDir = nil ;
# endif
}
2019-06-20 12:49:16 +00:00
}
2020-11-26 16:11:55 +00:00
# ifndef MASTER
uint64 timeProcessingTXD ;
uint64 timeProcessingDFF ;
# endif
2019-06-28 10:34:02 +00:00
void
CStreaming : : Update ( void )
{
CEntity * train ;
CStreamingInfo * si , * prev ;
bool requestedSubway = false ;
2020-11-26 16:11:55 +00:00
# ifndef MASTER
timeProcessingTXD = 0 ;
timeProcessingDFF = 0 ;
# endif
2019-06-28 10:34:02 +00:00
UpdateMemoryUsed ( ) ;
if ( ms_channelError ! = - 1 ) {
RetryLoadFile ( ms_channelError ) ;
return ;
}
if ( CTimer : : GetIsPaused ( ) )
return ;
train = FindPlayerTrain ( ) ;
if ( train & & train - > GetPosition ( ) . z < 0.0f ) {
RequestSubway ( ) ;
requestedSubway = true ;
} else if ( ! ms_disableStreaming )
AddModelsToRequestList ( TheCamera . GetPosition ( ) ) ;
DeleteFarAwayRwObjects ( TheCamera . GetPosition ( ) ) ;
if ( ! ms_disableStreaming & &
! CCutsceneMgr : : IsRunning ( ) & &
! requestedSubway & &
! CGame : : playingIntro & &
ms_numModelsRequested < 5 & &
2020-04-18 20:50:37 +00:00
! CRenderer : : m_loadingPriority
# ifdef FIX_BUGS
& & ! CReplay : : IsPlayingBack ( )
# endif
) {
2019-06-28 10:34:02 +00:00
StreamVehiclesAndPeds ( ) ;
2019-06-29 09:09:33 +00:00
StreamZoneModels ( FindPlayerCoors ( ) ) ;
2019-06-28 10:34:02 +00:00
}
LoadRequestedModels ( ) ;
2020-11-26 16:11:55 +00:00
# ifndef MASTER
if ( CPad : : GetPad ( 1 ) - > GetLeftShoulder1JustDown ( ) & & CPad : : GetPad ( 1 ) - > GetRightShoulder1 ( ) & & CPad : : GetPad ( 1 ) - > GetRightShoulder2 ( ) )
PrintStreamingBufferState ( ) ;
// TODO: PrintRequestList
//if (CPad::GetPad(1)->GetLeftShoulder2JustDown() && CPad::GetPad(1)->GetRightShoulder1() && CPad::GetPad(1)->GetRightShoulder2())
// PrintRequestList();
# endif
2020-05-05 11:02:42 +00:00
2019-06-28 10:34:02 +00:00
for ( si = ms_endRequestedList . m_prev ; si ! = & ms_startRequestedList ; si = prev ) {
prev = si - > m_prev ;
if ( ( si - > m_flags & ( STREAMFLAGS_KEEP_IN_MEMORY | STREAMFLAGS_PRIORITY ) ) = = 0 )
RemoveModel ( si - ms_aInfoForModel ) ;
}
}
2019-06-20 12:49:16 +00:00
void
CStreaming : : LoadCdDirectory ( void )
{
char dirname [ 132 ] ;
int i ;
2019-06-27 08:58:51 +00:00
# ifdef GTA_PC
2019-06-20 12:49:16 +00:00
ms_imageOffsets [ 0 ] = 0 ;
2019-06-27 08:58:51 +00:00
ms_imageOffsets [ 1 ] = - 1 ;
ms_imageOffsets [ 2 ] = - 1 ;
ms_imageOffsets [ 3 ] = - 1 ;
ms_imageOffsets [ 4 ] = - 1 ;
ms_imageOffsets [ 5 ] = - 1 ;
ms_imageOffsets [ 6 ] = - 1 ;
ms_imageOffsets [ 7 ] = - 1 ;
ms_imageOffsets [ 8 ] = - 1 ;
ms_imageOffsets [ 9 ] = - 1 ;
ms_imageOffsets [ 10 ] = - 1 ;
ms_imageOffsets [ 11 ] = - 1 ;
2019-06-20 12:49:16 +00:00
ms_imageSize = GetGTA3ImgSize ( ) ;
2019-06-24 16:44:23 +00:00
// PS2 uses CFileMgr::GetCdFile on all IMG files to fill the array
2019-06-27 08:58:51 +00:00
# endif
2019-06-24 16:44:23 +00:00
2019-06-20 12:49:16 +00:00
i = CdStreamGetNumImages ( ) ;
while ( i - - > = 1 ) {
strcpy ( dirname , CdStreamGetImageName ( i ) ) ;
strncpy ( strrchr ( dirname , ' . ' ) + 1 , " DIR " , 3 ) ;
LoadCdDirectory ( dirname , i ) ;
}
ms_lastImageRead = 0 ;
ms_imageSize / = CDSTREAM_SECTOR_SIZE ;
}
void
CStreaming : : LoadCdDirectory ( const char * dirname , int n )
{
int fd , lastID , imgSelector ;
int modelId , txdId ;
uint32 posn , size ;
CDirectory : : DirectoryInfo direntry ;
char * dot ;
lastID = - 1 ;
fd = CFileMgr : : OpenFile ( dirname , " rb " ) ;
assert ( fd > 0 ) ;
imgSelector = n < < 24 ;
assert ( sizeof ( direntry ) = = 32 ) ;
while ( CFileMgr : : Read ( fd , ( char * ) & direntry , sizeof ( direntry ) ) ) {
dot = strchr ( direntry . name , ' . ' ) ;
2020-11-11 08:42:30 +00:00
assert ( dot ) ;
2019-06-20 12:49:16 +00:00
if ( dot ) * dot = ' \0 ' ;
2019-06-26 14:49:32 +00:00
if ( direntry . size > ( uint32 ) ms_streamingBufferSize )
2019-06-20 12:49:16 +00:00
ms_streamingBufferSize = direntry . size ;
2019-10-29 23:12:58 +00:00
if ( ! CGeneral : : faststrcmp ( dot + 1 , " DFF " ) | | ! CGeneral : : faststrcmp ( dot + 1 , " dff " ) ) {
2019-06-20 12:49:16 +00:00
if ( CModelInfo : : GetModelInfo ( direntry . name , & modelId ) ) {
2019-06-24 16:44:23 +00:00
if ( ms_aInfoForModel [ modelId ] . GetCdPosnAndSize ( posn , size ) ) {
2019-06-20 12:49:16 +00:00
debug ( " %s appears more than once in %s \n " , direntry . name , dirname ) ;
lastID = - 1 ;
} else {
direntry . offset | = imgSelector ;
2019-06-24 16:44:23 +00:00
ms_aInfoForModel [ modelId ] . SetCdPosnAndSize ( direntry . offset , direntry . size ) ;
2019-06-20 12:49:16 +00:00
if ( lastID ! = - 1 )
2019-06-24 16:44:23 +00:00
ms_aInfoForModel [ lastID ] . m_nextID = modelId ;
lastID = modelId ;
2019-06-20 12:49:16 +00:00
}
} else {
2020-04-21 11:56:33 +00:00
# ifdef FIX_BUGS
// remember which cdimage this came from
ms_pExtraObjectsDir - > AddItem ( direntry , n ) ;
# else
2019-06-20 12:49:16 +00:00
ms_pExtraObjectsDir - > AddItem ( direntry ) ;
2020-04-21 11:56:33 +00:00
# endif
2019-06-20 12:49:16 +00:00
lastID = - 1 ;
}
2019-10-29 23:12:58 +00:00
} else if ( ! CGeneral : : faststrcmp ( dot + 1 , " TXD " ) | | ! CGeneral : : faststrcmp ( dot + 1 , " txd " ) ) {
2019-06-20 12:49:16 +00:00
txdId = CTxdStore : : FindTxdSlot ( direntry . name ) ;
if ( txdId = = - 1 )
txdId = CTxdStore : : AddTxdSlot ( direntry . name ) ;
2019-10-29 23:12:58 +00:00
if ( ms_aInfoForModel [ txdId + STREAM_OFFSET_TXD ] . GetCdPosnAndSize ( posn , size ) ) {
debug ( " %s appears more than once in %s \n " , direntry . name , dirname ) ;
lastID = - 1 ;
} else {
direntry . offset | = imgSelector ;
ms_aInfoForModel [ txdId + STREAM_OFFSET_TXD ] . SetCdPosnAndSize ( direntry . offset , direntry . size ) ;
if ( lastID ! = - 1 )
ms_aInfoForModel [ lastID ] . m_nextID = txdId + STREAM_OFFSET_TXD ;
lastID = txdId + STREAM_OFFSET_TXD ;
}
2019-06-20 12:49:16 +00:00
} else
lastID = - 1 ;
}
CFileMgr : : CloseFile ( fd ) ;
}
2020-11-30 22:44:58 +00:00
# ifdef USE_CUSTOM_ALLOCATOR
RpAtomic *
RegisterAtomicMemPtrsCB ( RpAtomic * atomic , void * data )
{
# if THIS_IS_COMPATIBLE_WITH_GTA3_RW31
// not quite sure what's going on here:
// gta3's RW 3.1 allocates separate memory for geometry data of RpGeometry.
// Is that a R* change? rpDefaultGeometryInstance also depends on it
RpGeometry * geo = RpAtomicGetGeometry ( atomic ) ;
if ( geo - > triangles )
REGISTER_MEMPTR ( & geo - > triangles ) ;
if ( geo - > matList . materials )
REGISTER_MEMPTR ( & geo - > matList . materials ) ;
if ( geo - > preLitLum )
REGISTER_MEMPTR ( & geo - > preLitLum ) ;
if ( geo - > texCoords [ 0 ] )
REGISTER_MEMPTR ( & geo - > texCoords [ 0 ] ) ;
if ( geo - > texCoords [ 1 ] )
REGISTER_MEMPTR ( & geo - > texCoords [ 1 ] ) ;
# else
// normally RpGeometry is allocated in one block (excluding morph targets)
// so we don't really have allocated pointers in the struct.
// NB: in librw we actually do it in two allocations (geometry itself and data)
// so we could conceivably come up with something here
# endif
return atomic ;
}
# endif
2019-06-21 15:28:55 +00:00
bool
CStreaming : : ConvertBufferToObject ( int8 * buf , int32 streamId )
{
RwMemory mem ;
RwStream * stream ;
int cdsize ;
uint32 startTime , endTime , timeDiff ;
CBaseModelInfo * mi ;
bool success ;
startTime = CTimer : : GetCurrentTimeInCycles ( ) / CTimer : : GetCyclesPerMillisecond ( ) ;
cdsize = ms_aInfoForModel [ streamId ] . GetCdSize ( ) ;
mem . start = ( uint8 * ) buf ;
mem . length = cdsize * CDSTREAM_SECTOR_SIZE ;
stream = RwStreamOpen ( rwSTREAMMEMORY , rwSTREAMREAD , & mem ) ;
if ( streamId < STREAM_OFFSET_TXD ) {
// Model
2019-06-24 16:44:23 +00:00
mi = CModelInfo : : GetModelInfo ( streamId ) ;
2019-06-21 15:28:55 +00:00
// Txd has to be loaded
2021-01-08 12:51:50 +00:00
# ifdef FIX_BUGS
if ( ! HasTxdLoaded ( mi - > GetTxdSlot ( ) ) ) {
# else
// texDict will exist even if only first part has loaded
2019-06-21 15:28:55 +00:00
if ( CTxdStore : : GetSlot ( mi - > GetTxdSlot ( ) ) - > texDict = = nil ) {
2021-01-08 12:51:50 +00:00
# endif
2021-01-08 19:50:59 +00:00
debug ( " failed to load %s because TXD %s is not in memory \n " , mi - > GetModelName ( ) , CTxdStore : : GetTxdName ( mi - > GetTxdSlot ( ) ) ) ;
2019-06-21 15:28:55 +00:00
RemoveModel ( streamId ) ;
2021-01-08 12:51:50 +00:00
# ifndef FIX_BUGS
// if we're just waiting for it to load, don't remove this
2019-06-24 16:44:23 +00:00
RemoveTxd ( mi - > GetTxdSlot ( ) ) ;
2021-01-08 12:51:50 +00:00
# endif
2019-06-24 16:44:23 +00:00
ReRequestModel ( streamId ) ;
2019-06-21 15:28:55 +00:00
RwStreamClose ( stream , & mem ) ;
return false ;
}
// Set Txd to use
CTxdStore : : AddRef ( mi - > GetTxdSlot ( ) ) ;
2020-11-26 15:47:19 +00:00
PUSH_MEMID ( MEMID_STREAM_MODELS ) ;
CTxdStore : : SetCurrentTxd ( mi - > GetTxdSlot ( ) ) ;
2019-06-21 15:28:55 +00:00
if ( mi - > IsSimple ( ) ) {
2019-06-24 16:44:23 +00:00
success = CFileLoader : : LoadAtomicFile ( stream , streamId ) ;
2020-11-30 22:44:58 +00:00
# ifdef USE_CUSTOM_ALLOCATOR
RegisterAtomicMemPtrsCB ( ( ( CSimpleModelInfo * ) mi ) - > m_atomics [ 0 ] , nil ) ;
# endif
2020-05-05 12:06:55 +00:00
} else if ( mi - > GetModelType ( ) = = MITYPE_VEHICLE ) {
2019-06-21 15:28:55 +00:00
// load vehicles in two parts
2019-06-24 16:44:23 +00:00
CModelInfo : : GetModelInfo ( streamId ) - > AddRef ( ) ;
success = CFileLoader : : StartLoadClumpFile ( stream , streamId ) ;
2019-06-21 15:28:55 +00:00
if ( success )
ms_aInfoForModel [ streamId ] . m_loadState = STREAMSTATE_STARTED ;
} else {
2019-06-24 16:44:23 +00:00
success = CFileLoader : : LoadClumpFile ( stream , streamId ) ;
2020-11-30 22:44:58 +00:00
# ifdef USE_CUSTOM_ALLOCATOR
if ( success )
RpClumpForAllAtomics ( ( RpClump * ) mi - > GetRwObject ( ) , RegisterAtomicMemPtrsCB , nil ) ;
# endif
2019-06-21 15:28:55 +00:00
}
2020-11-26 15:47:19 +00:00
POP_MEMID ( ) ;
2019-06-21 15:28:55 +00:00
UpdateMemoryUsed ( ) ;
// Txd no longer needed unless we only read part of the file
if ( ms_aInfoForModel [ streamId ] . m_loadState ! = STREAMSTATE_STARTED )
CTxdStore : : RemoveRefWithoutDelete ( mi - > GetTxdSlot ( ) ) ;
if ( ! success ) {
2021-01-08 19:50:59 +00:00
debug ( " Failed to load %s \n " , CModelInfo : : GetModelInfo ( streamId ) - > GetModelName ( ) ) ;
2019-06-21 15:28:55 +00:00
RemoveModel ( streamId ) ;
2019-06-24 16:44:23 +00:00
ReRequestModel ( streamId ) ;
2019-06-21 15:28:55 +00:00
RwStreamClose ( stream , & mem ) ;
return false ;
}
} else {
// Txd
assert ( streamId < NUMSTREAMINFO ) ;
if ( ( ms_aInfoForModel [ streamId ] . m_flags & STREAMFLAGS_KEEP_IN_MEMORY ) = = 0 & &
! IsTxdUsedByRequestedModels ( streamId - STREAM_OFFSET_TXD ) ) {
RemoveModel ( streamId ) ;
RwStreamClose ( stream , & mem ) ;
return false ;
}
2020-11-26 15:47:19 +00:00
PUSH_MEMID ( MEMID_STREAM_TEXUTRES ) ;
2019-06-21 15:28:55 +00:00
if ( ms_bLoadingBigModel | | cdsize > 200 ) {
success = CTxdStore : : StartLoadTxd ( streamId - STREAM_OFFSET_TXD , stream ) ;
if ( success )
ms_aInfoForModel [ streamId ] . m_loadState = STREAMSTATE_STARTED ;
} else
success = CTxdStore : : LoadTxd ( streamId - STREAM_OFFSET_TXD , stream ) ;
2020-11-26 15:47:19 +00:00
POP_MEMID ( ) ;
2019-06-21 15:28:55 +00:00
UpdateMemoryUsed ( ) ;
if ( ! success ) {
debug ( " Failed to load %s.txd \n " , CTxdStore : : GetTxdName ( streamId - STREAM_OFFSET_TXD ) ) ;
RemoveModel ( streamId ) ;
2019-06-24 16:44:23 +00:00
ReRequestModel ( streamId ) ;
2019-06-21 15:28:55 +00:00
RwStreamClose ( stream , & mem ) ;
return false ;
}
}
RwStreamClose ( stream , & mem ) ;
// We shouldn't even end up here unless load was successful
if ( ! success ) {
2019-06-24 16:44:23 +00:00
ReRequestModel ( streamId ) ;
2019-06-21 15:28:55 +00:00
if ( streamId < STREAM_OFFSET_TXD )
2021-01-08 19:50:59 +00:00
debug ( " Failed to load %s.dff \n " , mi - > GetModelName ( ) ) ;
2019-06-21 15:28:55 +00:00
else
debug ( " Failed to load %s.txd \n " , CTxdStore : : GetTxdName ( streamId - STREAM_OFFSET_TXD ) ) ;
return false ;
}
if ( streamId < STREAM_OFFSET_TXD ) {
// Model
// Vehicles and Peds not in loaded list
2020-05-05 12:06:55 +00:00
if ( mi - > GetModelType ( ) ! = MITYPE_VEHICLE & & mi - > GetModelType ( ) ! = MITYPE_PED ) {
2019-06-21 15:28:55 +00:00
CSimpleModelInfo * smi = ( CSimpleModelInfo * ) mi ;
// Set fading for some objects
if ( mi - > IsSimple ( ) & & ! smi - > m_isBigBuilding ) {
if ( ms_aInfoForModel [ streamId ] . m_flags & STREAMFLAGS_NOFADE )
smi - > m_alpha = 255 ;
else
smi - > m_alpha = 0 ;
}
2020-05-05 11:02:42 +00:00
if ( ( ms_aInfoForModel [ streamId ] . m_flags & STREAMFLAGS_CANT_REMOVE ) = = 0 )
2019-06-21 15:28:55 +00:00
ms_aInfoForModel [ streamId ] . AddToList ( & ms_startLoadedList ) ;
}
} else {
// Txd
2020-05-05 11:02:42 +00:00
if ( ( ms_aInfoForModel [ streamId ] . m_flags & STREAMFLAGS_CANT_REMOVE ) = = 0 )
2019-06-21 15:28:55 +00:00
ms_aInfoForModel [ streamId ] . AddToList ( & ms_startLoadedList ) ;
}
// Mark objects as loaded
if ( ms_aInfoForModel [ streamId ] . m_loadState ! = STREAMSTATE_STARTED ) {
ms_aInfoForModel [ streamId ] . m_loadState = STREAMSTATE_LOADED ;
2020-11-26 15:47:19 +00:00
# ifndef USE_CUSTOM_ALLOCATOR
2019-06-21 15:28:55 +00:00
ms_memoryUsed + = ms_aInfoForModel [ streamId ] . GetCdSize ( ) * CDSTREAM_SECTOR_SIZE ;
2020-11-26 15:47:19 +00:00
# endif
2019-06-21 15:28:55 +00:00
}
endTime = CTimer : : GetCurrentTimeInCycles ( ) / CTimer : : GetCyclesPerMillisecond ( ) ;
timeDiff = endTime - startTime ;
if ( timeDiff > 5 ) {
if ( streamId < STREAM_OFFSET_TXD )
2021-01-08 19:50:59 +00:00
debug ( " model %s took %d ms \n " , CModelInfo : : GetModelInfo ( streamId ) - > GetModelName ( ) , timeDiff ) ;
2019-06-21 15:28:55 +00:00
else
debug ( " txd %s took %d ms \n " , CTxdStore : : GetTxdName ( streamId - STREAM_OFFSET_TXD ) , timeDiff ) ;
}
return true ;
}
bool
CStreaming : : FinishLoadingLargeFile ( int8 * buf , int32 streamId )
{
RwMemory mem ;
RwStream * stream ;
uint32 startTime , endTime , timeDiff ;
CBaseModelInfo * mi ;
bool success ;
startTime = CTimer : : GetCurrentTimeInCycles ( ) / CTimer : : GetCyclesPerMillisecond ( ) ;
if ( ms_aInfoForModel [ streamId ] . m_loadState ! = STREAMSTATE_STARTED ) {
if ( streamId < STREAM_OFFSET_TXD )
2019-06-24 16:44:23 +00:00
CModelInfo : : GetModelInfo ( streamId ) - > RemoveRef ( ) ;
2019-06-21 15:28:55 +00:00
return false ;
}
mem . start = ( uint8 * ) buf ;
mem . length = ms_aInfoForModel [ streamId ] . GetCdSize ( ) * CDSTREAM_SECTOR_SIZE ;
stream = RwStreamOpen ( rwSTREAMMEMORY , rwSTREAMREAD , & mem ) ;
if ( streamId < STREAM_OFFSET_TXD ) {
// Model
2019-06-24 16:44:23 +00:00
mi = CModelInfo : : GetModelInfo ( streamId ) ;
2020-11-26 15:47:19 +00:00
PUSH_MEMID ( MEMID_STREAM_MODELS ) ;
2019-06-21 15:28:55 +00:00
CTxdStore : : SetCurrentTxd ( mi - > GetTxdSlot ( ) ) ;
success = CFileLoader : : FinishLoadClumpFile ( stream , streamId ) ;
2020-11-30 22:44:58 +00:00
if ( success ) {
# ifdef USE_CUSTOM_ALLOCATOR
RpClumpForAllAtomics ( ( RpClump * ) mi - > GetRwObject ( ) , RegisterAtomicMemPtrsCB , nil ) ;
# endif
2019-06-21 15:28:55 +00:00
success = AddToLoadedVehiclesList ( streamId ) ;
2020-11-30 22:44:58 +00:00
}
2020-11-26 15:47:19 +00:00
POP_MEMID ( ) ;
2019-06-21 15:28:55 +00:00
mi - > RemoveRef ( ) ;
CTxdStore : : RemoveRefWithoutDelete ( mi - > GetTxdSlot ( ) ) ;
} else {
// Txd
CTxdStore : : AddRef ( streamId - STREAM_OFFSET_TXD ) ;
2020-11-26 15:47:19 +00:00
PUSH_MEMID ( MEMID_STREAM_TEXUTRES ) ;
2019-06-21 15:28:55 +00:00
success = CTxdStore : : FinishLoadTxd ( streamId - STREAM_OFFSET_TXD , stream ) ;
2020-11-26 15:47:19 +00:00
POP_MEMID ( ) ;
2019-06-21 15:28:55 +00:00
CTxdStore : : RemoveRefWithoutDelete ( streamId - STREAM_OFFSET_TXD ) ;
}
RwStreamClose ( stream , & mem ) ;
2020-11-26 15:47:19 +00:00
ms_aInfoForModel [ streamId ] . m_loadState = STREAMSTATE_LOADED ; // only done if success on PS2
# ifndef USE_CUSTOM_ALLOCATOR
2019-06-21 15:28:55 +00:00
ms_memoryUsed + = ms_aInfoForModel [ streamId ] . GetCdSize ( ) * CDSTREAM_SECTOR_SIZE ;
2020-11-26 15:47:19 +00:00
# endif
2019-06-21 15:28:55 +00:00
if ( ! success ) {
RemoveModel ( streamId ) ;
2019-06-24 16:44:23 +00:00
ReRequestModel ( streamId ) ;
2020-11-26 15:47:19 +00:00
UpdateMemoryUsed ( ) ; // directly after pop on PS2
2019-06-21 15:28:55 +00:00
return false ;
}
2020-11-26 15:47:19 +00:00
UpdateMemoryUsed ( ) ; // directly after pop on PS2
2019-06-21 15:28:55 +00:00
endTime = CTimer : : GetCurrentTimeInCycles ( ) / CTimer : : GetCyclesPerMillisecond ( ) ;
timeDiff = endTime - startTime ;
if ( timeDiff > 5 ) {
if ( streamId < STREAM_OFFSET_TXD )
2021-01-08 19:50:59 +00:00
debug ( " finish model %s took %d ms \n " , CModelInfo : : GetModelInfo ( streamId ) - > GetModelName ( ) , timeDiff ) ;
2019-06-21 15:28:55 +00:00
else
debug ( " finish txd %s took %d ms \n " , CTxdStore : : GetTxdName ( streamId - STREAM_OFFSET_TXD ) , timeDiff ) ;
}
return true ;
}
void
CStreaming : : RequestModel ( int32 id , int32 flags )
{
CSimpleModelInfo * mi ;
if ( ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_INQUEUE ) {
// updgrade to priority
2019-06-26 14:49:32 +00:00
if ( flags & STREAMFLAGS_PRIORITY & & ! ms_aInfoForModel [ id ] . IsPriority ( ) ) {
2019-06-21 15:28:55 +00:00
ms_numPriorityRequests + + ;
ms_aInfoForModel [ id ] . m_flags | = STREAMFLAGS_PRIORITY ;
}
} else if ( ms_aInfoForModel [ id ] . m_loadState ! = STREAMSTATE_NOTLOADED ) {
flags & = ~ STREAMFLAGS_PRIORITY ;
}
ms_aInfoForModel [ id ] . m_flags | = flags ;
if ( ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_LOADED ) {
// Already loaded, only check changed flags
if ( ms_aInfoForModel [ id ] . m_flags & STREAMFLAGS_NOFADE & & id < STREAM_OFFSET_TXD ) {
2019-06-24 16:44:23 +00:00
mi = ( CSimpleModelInfo * ) CModelInfo : : GetModelInfo ( id ) ;
2019-06-21 15:28:55 +00:00
if ( mi - > IsSimple ( ) )
mi - > m_alpha = 255 ;
}
// reinsert into list
if ( ms_aInfoForModel [ id ] . m_next ) {
ms_aInfoForModel [ id ] . RemoveFromList ( ) ;
2020-05-05 11:02:42 +00:00
if ( ( ms_aInfoForModel [ id ] . m_flags & STREAMFLAGS_CANT_REMOVE ) = = 0 )
2019-06-21 15:28:55 +00:00
ms_aInfoForModel [ id ] . AddToList ( & ms_startLoadedList ) ;
}
} else if ( ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_NOTLOADED | |
ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_LOADED ) { // how can this be true again?
if ( ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_NOTLOADED ) {
if ( id < STREAM_OFFSET_TXD )
2019-06-24 16:44:23 +00:00
RequestTxd ( CModelInfo : : GetModelInfo ( id ) - > GetTxdSlot ( ) , flags ) ;
2019-06-21 15:28:55 +00:00
ms_aInfoForModel [ id ] . AddToList ( & ms_startRequestedList ) ;
ms_numModelsRequested + + ;
if ( flags & STREAMFLAGS_PRIORITY )
ms_numPriorityRequests + + ;
}
ms_aInfoForModel [ id ] . m_loadState = STREAMSTATE_INQUEUE ;
ms_aInfoForModel [ id ] . m_flags = flags ;
}
}
void
CStreaming : : RequestSubway ( void )
{
RequestModel ( MI_SUBWAY1 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY2 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY3 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY4 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY5 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY6 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY7 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY8 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY9 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY10 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY11 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY12 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY13 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY14 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY15 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY16 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY17 , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBWAY18 , STREAMFLAGS_NOFADE ) ;
switch ( CGame : : currLevel ) {
case LEVEL_INDUSTRIAL :
RequestModel ( MI_SUBPLATFORM_IND , STREAMFLAGS_NOFADE ) ;
break ;
case LEVEL_COMMERCIAL :
if ( FindPlayerTrain ( ) - > GetPosition ( ) . y < - 700.0f ) {
RequestModel ( MI_SUBPLATFORM_COMS , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBPLATFORM_COMS2 , STREAMFLAGS_NOFADE ) ;
} else {
RequestModel ( MI_SUBPLATFORM_COMN , STREAMFLAGS_NOFADE ) ;
}
break ;
case LEVEL_SUBURBAN :
RequestModel ( MI_SUBPLATFORM_SUB , STREAMFLAGS_NOFADE ) ;
RequestModel ( MI_SUBPLATFORM_SUB2 , STREAMFLAGS_NOFADE ) ;
break ;
2020-05-11 23:24:57 +00:00
default : break ;
2019-06-21 15:28:55 +00:00
}
}
2020-05-05 11:02:42 +00:00
# define BIGBUILDINGFLAGS STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY
2019-06-21 15:28:55 +00:00
void
CStreaming : : RequestBigBuildings ( eLevelName level )
{
int i , n ;
CBuilding * b ;
2019-10-16 21:53:25 +00:00
n = CPools : : GetBuildingPool ( ) - > GetSize ( ) - 1 ;
for ( i = n ; i > = 0 ; i - - ) {
2019-06-21 15:28:55 +00:00
b = CPools : : GetBuildingPool ( ) - > GetSlot ( i ) ;
2020-07-09 16:18:42 +00:00
if ( b & & b - > bIsBIGBuilding
2020-08-16 14:26:44 +00:00
# ifdef NO_ISLAND_LOADING
2020-11-13 16:28:15 +00:00
& & ( ( ( CMenuManager : : m_PrefsIslandLoading ! = CMenuManager : : ISLAND_LOADING_LOW ) & & ( b ! = pIslandLODindustEntity ) & & ( b ! = pIslandLODcomIndEntity ) & &
( b ! = pIslandLODcomSubEntity ) & & ( b ! = pIslandLODsubIndEntity ) & & ( b ! = pIslandLODsubComEntity )
) | | ( b - > m_level = = level ) )
2020-08-16 14:26:44 +00:00
# else
2020-07-09 16:18:42 +00:00
& & b - > m_level = = level
# endif
)
2020-05-05 11:02:42 +00:00
RequestModel ( b - > GetModelIndex ( ) , BIGBUILDINGFLAGS ) ;
2019-06-21 15:28:55 +00:00
}
RequestIslands ( level ) ;
ms_hasLoadedLODs = false ;
}
void
CStreaming : : RequestIslands ( eLevelName level )
{
2020-08-19 00:31:42 +00:00
ISLAND_LOADING_ISNT ( HIGH )
2019-06-21 15:28:55 +00:00
switch ( level ) {
case LEVEL_INDUSTRIAL :
2020-05-05 11:02:42 +00:00
RequestModel ( islandLODcomInd , BIGBUILDINGFLAGS ) ;
RequestModel ( islandLODsubInd , BIGBUILDINGFLAGS ) ;
2019-06-21 15:28:55 +00:00
break ;
case LEVEL_COMMERCIAL :
2020-05-05 11:02:42 +00:00
RequestModel ( islandLODindust , BIGBUILDINGFLAGS ) ;
RequestModel ( islandLODsubCom , BIGBUILDINGFLAGS ) ;
2019-06-21 15:28:55 +00:00
break ;
case LEVEL_SUBURBAN :
2020-05-05 11:02:42 +00:00
RequestModel ( islandLODindust , BIGBUILDINGFLAGS ) ;
RequestModel ( islandLODcomSub , BIGBUILDINGFLAGS ) ;
2019-06-21 15:28:55 +00:00
break ;
2020-05-11 23:24:57 +00:00
default : break ;
2019-06-21 15:28:55 +00:00
}
}
void
CStreaming : : RequestSpecialModel ( int32 modelId , const char * modelName , int32 flags )
{
CBaseModelInfo * mi ;
int txdId ;
char oldName [ 48 ] ;
uint32 pos , size ;
mi = CModelInfo : : GetModelInfo ( modelId ) ;
2021-01-08 19:50:59 +00:00
if ( ! CGeneral : : faststrcmp ( mi - > GetModelName ( ) , modelName ) ) {
2019-06-21 15:28:55 +00:00
// Already have the correct name, just request it
RequestModel ( modelId , flags ) ;
return ;
}
2021-01-08 19:50:59 +00:00
strcpy ( oldName , mi - > GetModelName ( ) ) ;
mi - > SetModelName ( modelName ) ;
2019-06-21 15:28:55 +00:00
// What exactly is going on here?
if ( CModelInfo : : GetModelInfo ( oldName , nil ) ) {
txdId = CTxdStore : : FindTxdSlot ( oldName ) ;
if ( txdId ! = - 1 & & CTxdStore : : GetSlot ( txdId ) - > texDict ) {
CTxdStore : : AddRef ( txdId ) ;
RemoveModel ( modelId ) ;
CTxdStore : : RemoveRefWithoutDelete ( txdId ) ;
} else
RemoveModel ( modelId ) ;
} else
RemoveModel ( modelId ) ;
2020-04-24 22:40:14 +00:00
bool found = ms_pExtraObjectsDir - > FindItem ( modelName , pos , size ) ;
assert ( found ) ;
2019-06-21 15:28:55 +00:00
mi - > ClearTexDictionary ( ) ;
if ( CTxdStore : : FindTxdSlot ( modelName ) = = - 1 )
mi - > SetTexDictionary ( " generic " ) ;
else
mi - > SetTexDictionary ( modelName ) ;
ms_aInfoForModel [ modelId ] . SetCdPosnAndSize ( pos , size ) ;
RequestModel ( modelId , flags ) ;
}
void
CStreaming : : RequestSpecialChar ( int32 charId , const char * modelName , int32 flags )
{
RequestSpecialModel ( charId + MI_SPECIAL01 , modelName , flags ) ;
}
2019-06-28 10:34:02 +00:00
bool
CStreaming : : HasSpecialCharLoaded ( int32 id )
{
return HasModelLoaded ( id + MI_SPECIAL01 ) ;
}
void
CStreaming : : SetMissionDoesntRequireSpecialChar ( int32 id )
{
return SetMissionDoesntRequireModel ( id + MI_SPECIAL01 ) ;
}
2019-06-26 14:49:32 +00:00
void
CStreaming : : DecrementRef ( int32 id )
{
ms_numModelsRequested - - ;
if ( ms_aInfoForModel [ id ] . IsPriority ( ) ) {
ms_aInfoForModel [ id ] . m_flags & = ~ STREAMFLAGS_PRIORITY ;
ms_numPriorityRequests - - ;
}
}
2019-06-21 15:28:55 +00:00
void
CStreaming : : RemoveModel ( int32 id )
{
int i ;
if ( ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_NOTLOADED )
return ;
if ( ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_LOADED ) {
if ( id < STREAM_OFFSET_TXD )
2019-06-24 16:44:23 +00:00
CModelInfo : : GetModelInfo ( id ) - > DeleteRwObject ( ) ;
2019-06-21 15:28:55 +00:00
else
CTxdStore : : RemoveTxd ( id - STREAM_OFFSET_TXD ) ;
2020-11-26 15:47:19 +00:00
# ifdef USE_CUSTOM_ALLOCATOR
UpdateMemoryUsed ( ) ;
# else
2019-06-21 15:28:55 +00:00
ms_memoryUsed - = ms_aInfoForModel [ id ] . GetCdSize ( ) * CDSTREAM_SECTOR_SIZE ;
2020-11-26 15:47:19 +00:00
# endif
2019-06-21 15:28:55 +00:00
}
if ( ms_aInfoForModel [ id ] . m_next ) {
// Remove from list, model is neither loaded nor requested
2019-06-26 14:49:32 +00:00
if ( ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_INQUEUE )
DecrementRef ( id ) ;
2019-06-21 15:28:55 +00:00
ms_aInfoForModel [ id ] . RemoveFromList ( ) ;
} else if ( ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_READING ) {
for ( i = 0 ; i < 4 ; i + + ) {
2019-06-24 16:44:23 +00:00
if ( ms_channel [ 0 ] . streamIds [ i ] = = id )
ms_channel [ 0 ] . streamIds [ i ] = - 1 ;
if ( ms_channel [ 1 ] . streamIds [ i ] = = id )
ms_channel [ 1 ] . streamIds [ i ] = - 1 ;
2019-06-21 15:28:55 +00:00
}
}
if ( ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_STARTED ) {
if ( id < STREAM_OFFSET_TXD )
RpClumpGtaCancelStream ( ) ;
else
CTxdStore : : RemoveTxd ( id - STREAM_OFFSET_TXD ) ;
2020-11-26 15:47:19 +00:00
# ifdef USE_CUSTOM_ALLOCATOR
UpdateMemoryUsed ( ) ;
# endif
2019-06-21 15:28:55 +00:00
}
ms_aInfoForModel [ id ] . m_loadState = STREAMSTATE_NOTLOADED ;
}
2019-06-24 16:44:23 +00:00
void
CStreaming : : RemoveUnusedBuildings ( eLevelName level )
{
if ( level ! = LEVEL_INDUSTRIAL )
RemoveBuildings ( LEVEL_INDUSTRIAL ) ;
if ( level ! = LEVEL_COMMERCIAL )
RemoveBuildings ( LEVEL_COMMERCIAL ) ;
if ( level ! = LEVEL_SUBURBAN )
RemoveBuildings ( LEVEL_SUBURBAN ) ;
}
void
CStreaming : : RemoveBuildings ( eLevelName level )
{
int i , n ;
CEntity * e ;
CBaseModelInfo * mi ;
2019-10-16 21:53:25 +00:00
n = CPools : : GetBuildingPool ( ) - > GetSize ( ) - 1 ;
for ( i = n ; i > = 0 ; i - - ) {
2019-06-24 16:44:23 +00:00
e = CPools : : GetBuildingPool ( ) - > GetSlot ( i ) ;
if ( e & & e - > m_level = = level ) {
mi = CModelInfo : : GetModelInfo ( e - > GetModelIndex ( ) ) ;
if ( ! e - > bImBeingRendered ) {
e - > DeleteRwObject ( ) ;
2020-05-05 12:06:55 +00:00
if ( mi - > GetNumRefs ( ) = = 0 )
2019-06-24 16:44:23 +00:00
RemoveModel ( e - > GetModelIndex ( ) ) ;
}
}
}
2019-10-16 21:53:25 +00:00
n = CPools : : GetTreadablePool ( ) - > GetSize ( ) - 1 ;
for ( i = n ; i > = 0 ; i - - ) {
2019-06-24 16:44:23 +00:00
e = CPools : : GetTreadablePool ( ) - > GetSlot ( i ) ;
if ( e & & e - > m_level = = level ) {
mi = CModelInfo : : GetModelInfo ( e - > GetModelIndex ( ) ) ;
if ( ! e - > bImBeingRendered ) {
e - > DeleteRwObject ( ) ;
2020-05-05 12:06:55 +00:00
if ( mi - > GetNumRefs ( ) = = 0 )
2019-06-24 16:44:23 +00:00
RemoveModel ( e - > GetModelIndex ( ) ) ;
}
}
}
2019-10-16 21:53:25 +00:00
n = CPools : : GetObjectPool ( ) - > GetSize ( ) - 1 ;
for ( i = n ; i > = 0 ; i - - ) {
2019-06-24 16:44:23 +00:00
e = CPools : : GetObjectPool ( ) - > GetSlot ( i ) ;
if ( e & & e - > m_level = = level ) {
mi = CModelInfo : : GetModelInfo ( e - > GetModelIndex ( ) ) ;
if ( ! e - > bImBeingRendered & & ( ( CObject * ) e ) - > ObjectCreatedBy = = GAME_OBJECT ) {
e - > DeleteRwObject ( ) ;
2020-05-05 12:06:55 +00:00
if ( mi - > GetNumRefs ( ) = = 0 )
2019-06-24 16:44:23 +00:00
RemoveModel ( e - > GetModelIndex ( ) ) ;
}
}
}
2019-10-16 21:53:25 +00:00
n = CPools : : GetDummyPool ( ) - > GetSize ( ) - 1 ;
for ( i = n ; i > = 0 ; i - - ) {
2019-06-24 16:44:23 +00:00
e = CPools : : GetDummyPool ( ) - > GetSlot ( i ) ;
if ( e & & e - > m_level = = level ) {
mi = CModelInfo : : GetModelInfo ( e - > GetModelIndex ( ) ) ;
if ( ! e - > bImBeingRendered ) {
e - > DeleteRwObject ( ) ;
2020-05-05 12:06:55 +00:00
if ( mi - > GetNumRefs ( ) = = 0 )
2019-06-24 16:44:23 +00:00
RemoveModel ( e - > GetModelIndex ( ) ) ;
}
}
}
}
void
CStreaming : : RemoveUnusedBigBuildings ( eLevelName level )
{
2020-08-19 00:31:42 +00:00
ISLAND_LOADING_IS ( LOW )
2020-08-16 14:26:44 +00:00
{
if ( level ! = LEVEL_INDUSTRIAL )
RemoveBigBuildings ( LEVEL_INDUSTRIAL ) ;
if ( level ! = LEVEL_COMMERCIAL )
RemoveBigBuildings ( LEVEL_COMMERCIAL ) ;
if ( level ! = LEVEL_SUBURBAN )
RemoveBigBuildings ( LEVEL_SUBURBAN ) ;
}
2019-06-24 16:44:23 +00:00
RemoveIslandsNotUsed ( level ) ;
}
void
DeleteIsland ( CEntity * island )
{
if ( island = = nil )
return ;
if ( island - > bImBeingRendered )
debug ( " Didn't delete island because it was being rendered \n " ) ;
else {
island - > DeleteRwObject ( ) ;
CStreaming : : RemoveModel ( island - > GetModelIndex ( ) ) ;
}
}
void
CStreaming : : RemoveIslandsNotUsed ( eLevelName level )
{
2020-08-16 14:26:44 +00:00
# ifdef NO_ISLAND_LOADING
if ( CMenuManager : : m_PrefsIslandLoading = = CMenuManager : : ISLAND_LOADING_HIGH ) {
DeleteIsland ( pIslandLODindustEntity ) ;
DeleteIsland ( pIslandLODcomIndEntity ) ;
DeleteIsland ( pIslandLODcomSubEntity ) ;
DeleteIsland ( pIslandLODsubIndEntity ) ;
DeleteIsland ( pIslandLODsubComEntity ) ;
} else
# endif
2019-06-24 16:44:23 +00:00
switch ( level ) {
case LEVEL_INDUSTRIAL :
DeleteIsland ( pIslandLODindustEntity ) ;
DeleteIsland ( pIslandLODcomSubEntity ) ;
DeleteIsland ( pIslandLODsubComEntity ) ;
break ;
case LEVEL_COMMERCIAL :
DeleteIsland ( pIslandLODcomIndEntity ) ;
DeleteIsland ( pIslandLODcomSubEntity ) ;
DeleteIsland ( pIslandLODsubIndEntity ) ;
break ;
case LEVEL_SUBURBAN :
DeleteIsland ( pIslandLODsubIndEntity ) ;
DeleteIsland ( pIslandLODsubComEntity ) ;
DeleteIsland ( pIslandLODcomIndEntity ) ;
break ;
default :
DeleteIsland ( pIslandLODindustEntity ) ;
DeleteIsland ( pIslandLODcomIndEntity ) ;
DeleteIsland ( pIslandLODcomSubEntity ) ;
DeleteIsland ( pIslandLODsubIndEntity ) ;
DeleteIsland ( pIslandLODsubComEntity ) ;
break ;
}
}
void
CStreaming : : RemoveBigBuildings ( eLevelName level )
{
int i , n ;
CEntity * e ;
CBaseModelInfo * mi ;
2019-10-16 21:53:25 +00:00
n = CPools : : GetBuildingPool ( ) - > GetSize ( ) - 1 ;
for ( i = n ; i > = 0 ; i - - ) {
2019-06-24 16:44:23 +00:00
e = CPools : : GetBuildingPool ( ) - > GetSlot ( i ) ;
if ( e & & e - > bIsBIGBuilding & & e - > m_level = = level ) {
mi = CModelInfo : : GetModelInfo ( e - > GetModelIndex ( ) ) ;
if ( ! e - > bImBeingRendered ) {
e - > DeleteRwObject ( ) ;
2020-05-05 12:06:55 +00:00
if ( mi - > GetNumRefs ( ) = = 0 )
2019-06-24 16:44:23 +00:00
RemoveModel ( e - > GetModelIndex ( ) ) ;
}
}
}
}
bool
CStreaming : : RemoveLoadedVehicle ( void )
{
int i , id ;
for ( i = 0 ; i < MAXVEHICLESLOADED ; i + + ) {
ms_lastVehicleDeleted + + ;
if ( ms_lastVehicleDeleted = = MAXVEHICLESLOADED )
ms_lastVehicleDeleted = 0 ;
id = ms_vehiclesLoaded [ ms_lastVehicleDeleted ] ;
if ( id ! = - 1 & &
2020-05-05 12:21:13 +00:00
( ms_aInfoForModel [ id ] . m_flags & STREAMFLAGS_CANT_REMOVE ) = = 0 & & CModelInfo : : GetModelInfo ( id ) - > GetNumRefs ( ) = = 0 & &
2019-06-24 16:44:23 +00:00
ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_LOADED )
goto found ;
}
return false ;
found :
RemoveModel ( ms_vehiclesLoaded [ ms_lastVehicleDeleted ] ) ;
ms_numVehiclesLoaded - - ;
ms_vehiclesLoaded [ ms_lastVehicleDeleted ] = - 1 ;
return true ;
}
bool
CStreaming : : RemoveLeastUsedModel ( void )
{
CStreamingInfo * si ;
int streamId ;
for ( si = ms_endLoadedList . m_prev ; si ! = & ms_startLoadedList ; si = si - > m_prev ) {
streamId = si - ms_aInfoForModel ;
if ( streamId < STREAM_OFFSET_TXD ) {
2020-05-05 12:06:55 +00:00
if ( CModelInfo : : GetModelInfo ( streamId ) - > GetNumRefs ( ) = = 0 ) {
2019-06-24 16:44:23 +00:00
RemoveModel ( streamId ) ;
return true ;
}
} else {
2019-06-26 19:33:58 +00:00
if ( CTxdStore : : GetNumRefs ( streamId - STREAM_OFFSET_TXD ) = = 0 & &
! IsTxdUsedByRequestedModels ( streamId - STREAM_OFFSET_TXD ) ) {
2019-06-24 16:44:23 +00:00
RemoveModel ( streamId ) ;
return true ;
}
}
}
return ms_numVehiclesLoaded > 7 & & RemoveLoadedVehicle ( ) ;
}
void
CStreaming : : RemoveAllUnusedModels ( void )
{
int i ;
for ( i = 0 ; i < MAXVEHICLESLOADED ; i + + )
RemoveLoadedVehicle ( ) ;
2019-10-06 21:39:25 +00:00
for ( i = NUM_DEFAULT_MODELS ; i < MODELINFOSIZE ; i + + ) {
2019-06-24 16:44:23 +00:00
if ( ms_aInfoForModel [ i ] . m_loadState = = STREAMSTATE_LOADED & &
ms_aInfoForModel [ i ] . m_flags & STREAMFLAGS_DONT_REMOVE & &
2020-05-05 12:06:55 +00:00
CModelInfo : : GetModelInfo ( i ) - > GetNumRefs ( ) = = 0 ) {
2019-06-24 16:44:23 +00:00
RemoveModel ( i ) ;
ms_aInfoForModel [ i ] . m_loadState = STREAMSTATE_NOTLOADED ;
}
}
}
bool
2020-07-22 11:56:28 +00:00
CStreaming : : RemoveReferencedTxds ( size_t mem )
2019-06-24 16:44:23 +00:00
{
CStreamingInfo * si ;
int streamId ;
for ( si = ms_endLoadedList . m_prev ; si ! = & ms_startLoadedList ; si = si - > m_prev ) {
streamId = si - ms_aInfoForModel ;
if ( streamId > = STREAM_OFFSET_TXD & &
CTxdStore : : GetNumRefs ( streamId - STREAM_OFFSET_TXD ) = = 0 ) {
RemoveModel ( streamId ) ;
if ( ms_memoryUsed < mem )
return true ;
}
}
return false ;
}
void
CStreaming : : RemoveUnusedModelsInLoadedList ( void )
{
// empty
}
bool
CStreaming : : IsTxdUsedByRequestedModels ( int32 txdId )
{
CStreamingInfo * si ;
int streamId ;
int i ;
2019-06-26 19:46:55 +00:00
for ( si = ms_startRequestedList . m_next ; si ! = & ms_endRequestedList ; si = si - > m_next ) {
2019-06-24 16:44:23 +00:00
streamId = si - ms_aInfoForModel ;
if ( streamId < STREAM_OFFSET_TXD & &
CModelInfo : : GetModelInfo ( streamId ) - > GetTxdSlot ( ) = = txdId )
return true ;
}
for ( i = 0 ; i < 4 ; i + + ) {
streamId = ms_channel [ 0 ] . streamIds [ i ] ;
if ( streamId ! = - 1 & & streamId < STREAM_OFFSET_TXD & &
CModelInfo : : GetModelInfo ( streamId ) - > GetTxdSlot ( ) = = txdId )
return true ;
streamId = ms_channel [ 1 ] . streamIds [ i ] ;
if ( streamId ! = - 1 & & streamId < STREAM_OFFSET_TXD & &
CModelInfo : : GetModelInfo ( streamId ) - > GetTxdSlot ( ) = = txdId )
return true ;
}
return false ;
}
int32
CStreaming : : GetAvailableVehicleSlot ( void )
{
int i ;
for ( i = 0 ; i < MAXVEHICLESLOADED ; i + + )
if ( ms_vehiclesLoaded [ i ] = = - 1 )
return i ;
return - 1 ;
}
bool
CStreaming : : AddToLoadedVehiclesList ( int32 modelId )
{
int i ;
int id ;
if ( ms_numVehiclesLoaded < desiredNumVehiclesLoaded ) {
// still room for vehicles
for ( i = 0 ; i < MAXVEHICLESLOADED ; i + + ) {
if ( ms_vehiclesLoaded [ ms_lastVehicleDeleted ] = = - 1 )
break ;
ms_lastVehicleDeleted + + ;
if ( ms_lastVehicleDeleted = = MAXVEHICLESLOADED )
ms_lastVehicleDeleted = 0 ;
}
assert ( ms_vehiclesLoaded [ ms_lastVehicleDeleted ] = = - 1 ) ;
ms_numVehiclesLoaded + + ;
} else {
// find vehicle we can remove
for ( i = 0 ; i < MAXVEHICLESLOADED ; i + + ) {
id = ms_vehiclesLoaded [ ms_lastVehicleDeleted ] ;
if ( id ! = - 1 & &
2020-05-05 12:21:13 +00:00
( ms_aInfoForModel [ id ] . m_flags & STREAMFLAGS_CANT_REMOVE ) = = 0 & & CModelInfo : : GetModelInfo ( id ) - > GetNumRefs ( ) = = 0 )
2019-06-24 16:44:23 +00:00
goto found ;
ms_lastVehicleDeleted + + ;
if ( ms_lastVehicleDeleted = = MAXVEHICLESLOADED )
ms_lastVehicleDeleted = 0 ;
}
id = - 1 ;
found :
if ( id = = - 1 ) {
// didn't find anything, try a free slot
id = GetAvailableVehicleSlot ( ) ;
if ( id = = - 1 )
return false ; // still no luck
ms_lastVehicleDeleted = id ;
2020-08-20 21:45:05 +00:00
// this is more than we wanted actually
2019-06-24 16:44:23 +00:00
ms_numVehiclesLoaded + + ;
} else
RemoveModel ( id ) ;
}
ms_vehiclesLoaded [ ms_lastVehicleDeleted + + ] = modelId ;
if ( ms_lastVehicleDeleted = = MAXVEHICLESLOADED )
ms_lastVehicleDeleted = 0 ;
return true ;
}
bool
CStreaming : : IsObjectInCdImage ( int32 id )
{
uint32 posn , size ;
return ms_aInfoForModel [ id ] . GetCdPosnAndSize ( posn , size ) ;
}
void
CStreaming : : HaveAllBigBuildingsLoaded ( eLevelName level )
{
int i , n ;
CEntity * e ;
if ( ms_hasLoadedLODs )
return ;
if ( level = = LEVEL_INDUSTRIAL ) {
if ( ms_aInfoForModel [ islandLODcomInd ] . m_loadState ! = STREAMSTATE_LOADED | |
ms_aInfoForModel [ islandLODsubInd ] . m_loadState ! = STREAMSTATE_LOADED )
return ;
} else if ( level = = LEVEL_COMMERCIAL ) {
if ( ms_aInfoForModel [ islandLODindust ] . m_loadState ! = STREAMSTATE_LOADED | |
ms_aInfoForModel [ islandLODsubCom ] . m_loadState ! = STREAMSTATE_LOADED )
return ;
} else if ( level = = LEVEL_SUBURBAN ) {
if ( ms_aInfoForModel [ islandLODindust ] . m_loadState ! = STREAMSTATE_LOADED | |
ms_aInfoForModel [ islandLODcomSub ] . m_loadState ! = STREAMSTATE_LOADED )
return ;
}
2019-10-16 21:53:25 +00:00
n = CPools : : GetBuildingPool ( ) - > GetSize ( ) - 1 ;
for ( i = n ; i > = 0 ; i - - ) {
2019-06-24 16:44:23 +00:00
e = CPools : : GetBuildingPool ( ) - > GetSlot ( i ) ;
if ( e & & e - > bIsBIGBuilding & & e - > m_level = = level & &
ms_aInfoForModel [ e - > GetModelIndex ( ) ] . m_loadState ! = STREAMSTATE_LOADED )
return ;
}
RemoveUnusedBigBuildings ( level ) ;
ms_hasLoadedLODs = true ;
}
void
CStreaming : : SetModelIsDeletable ( int32 id )
{
ms_aInfoForModel [ id ] . m_flags & = ~ STREAMFLAGS_DONT_REMOVE ;
2020-05-05 12:06:55 +00:00
if ( ( id > = STREAM_OFFSET_TXD | | CModelInfo : : GetModelInfo ( id ) - > GetModelType ( ) ! = MITYPE_VEHICLE ) & &
2019-06-26 19:33:58 +00:00
( ms_aInfoForModel [ id ] . m_flags & STREAMFLAGS_SCRIPTOWNED ) = = 0 ) {
2019-06-24 16:44:23 +00:00
if ( ms_aInfoForModel [ id ] . m_loadState ! = STREAMSTATE_LOADED )
RemoveModel ( id ) ;
else if ( ms_aInfoForModel [ id ] . m_next = = nil )
ms_aInfoForModel [ id ] . AddToList ( & ms_startLoadedList ) ;
}
}
void
CStreaming : : SetModelTxdIsDeletable ( int32 id )
{
SetModelIsDeletable ( CModelInfo : : GetModelInfo ( id ) - > GetTxdSlot ( ) + STREAM_OFFSET_TXD ) ;
}
void
CStreaming : : SetMissionDoesntRequireModel ( int32 id )
{
ms_aInfoForModel [ id ] . m_flags & = ~ STREAMFLAGS_SCRIPTOWNED ;
2020-05-05 12:06:55 +00:00
if ( ( id > = STREAM_OFFSET_TXD | | CModelInfo : : GetModelInfo ( id ) - > GetModelType ( ) ! = MITYPE_VEHICLE ) & &
2019-06-26 19:33:58 +00:00
( ms_aInfoForModel [ id ] . m_flags & STREAMFLAGS_DONT_REMOVE ) = = 0 ) {
2019-06-24 16:44:23 +00:00
if ( ms_aInfoForModel [ id ] . m_loadState ! = STREAMSTATE_LOADED )
RemoveModel ( id ) ;
else if ( ms_aInfoForModel [ id ] . m_next = = nil )
ms_aInfoForModel [ id ] . AddToList ( & ms_startLoadedList ) ;
}
}
void
CStreaming : : LoadInitialPeds ( void )
{
RequestModel ( MI_COP , STREAMFLAGS_DONT_REMOVE ) ;
RequestModel ( MI_MALE01 , STREAMFLAGS_DONT_REMOVE ) ;
RequestModel ( MI_TAXI_D , STREAMFLAGS_DONT_REMOVE ) ;
}
void
CStreaming : : LoadInitialVehicles ( void )
{
int id ;
ms_numVehiclesLoaded = 0 ;
ms_lastVehicleDeleted = 0 ;
if ( CModelInfo : : GetModelInfo ( " taxi " , & id ) )
RequestModel ( id , STREAMFLAGS_DONT_REMOVE ) ;
if ( CModelInfo : : GetModelInfo ( " police " , & id ) )
RequestModel ( id , STREAMFLAGS_DONT_REMOVE ) ;
}
2019-06-28 10:34:02 +00:00
void
CStreaming : : StreamVehiclesAndPeds ( void )
{
int i , model ;
static int timeBeforeNextLoad = 0 ;
static int modelQualityClass = 0 ;
2020-04-10 08:03:38 +00:00
if ( CRecordDataForGame : : IsRecording ( ) | |
2020-04-18 20:50:37 +00:00
CRecordDataForGame : : IsPlayingBack ( )
# ifdef FIX_BUGS
| | CReplay : : IsPlayingBack ( )
# endif
)
2019-06-28 10:34:02 +00:00
return ;
if ( FindPlayerPed ( ) - > m_pWanted - > AreSwatRequired ( ) ) {
RequestModel ( MI_ENFORCER , STREAMFLAGS_DONT_REMOVE ) ;
RequestModel ( MI_SWAT , STREAMFLAGS_DONT_REMOVE ) ;
} else {
SetModelIsDeletable ( MI_ENFORCER ) ;
if ( ! HasModelLoaded ( MI_ENFORCER ) )
SetModelIsDeletable ( MI_SWAT ) ;
}
if ( FindPlayerPed ( ) - > m_pWanted - > AreFbiRequired ( ) ) {
RequestModel ( MI_FBICAR , STREAMFLAGS_DONT_REMOVE ) ;
RequestModel ( MI_FBI , STREAMFLAGS_DONT_REMOVE ) ;
} else {
SetModelIsDeletable ( MI_FBICAR ) ;
if ( ! HasModelLoaded ( MI_FBICAR ) )
SetModelIsDeletable ( MI_FBI ) ;
}
if ( FindPlayerPed ( ) - > m_pWanted - > AreArmyRequired ( ) ) {
RequestModel ( MI_RHINO , STREAMFLAGS_DONT_REMOVE ) ;
RequestModel ( MI_BARRACKS , STREAMFLAGS_DONT_REMOVE ) ;
RequestModel ( MI_ARMY , STREAMFLAGS_DONT_REMOVE ) ;
} else {
SetModelIsDeletable ( MI_RHINO ) ;
SetModelIsDeletable ( MI_BARRACKS ) ;
if ( ! HasModelLoaded ( MI_RHINO ) & & ! HasModelLoaded ( MI_BARRACKS ) )
SetModelIsDeletable ( MI_ARMY ) ;
}
if ( FindPlayerPed ( ) - > m_pWanted - > NumOfHelisRequired ( ) > 0 )
RequestModel ( MI_CHOPPER , STREAMFLAGS_DONT_REMOVE ) ;
else
SetModelIsDeletable ( MI_CHOPPER ) ;
if ( timeBeforeNextLoad > = 0 )
timeBeforeNextLoad - - ;
else if ( ms_numVehiclesLoaded < = desiredNumVehiclesLoaded ) {
2020-03-07 19:22:43 +00:00
for ( i = 1 ; i < = 10 ; i + + ) {
2019-06-28 10:34:02 +00:00
model = CCarCtrl : : ChooseCarModel ( modelQualityClass ) ;
modelQualityClass + + ;
2020-05-07 10:48:57 +00:00
if ( modelQualityClass > = CCarCtrl : : TOTAL_CUSTOM_CLASSES )
2019-06-28 10:34:02 +00:00
modelQualityClass = 0 ;
// check if we want to load this model
if ( ms_aInfoForModel [ model ] . m_loadState = = STREAMSTATE_NOTLOADED & &
( ( CVehicleModelInfo * ) CModelInfo : : GetModelInfo ( model ) ) - > m_level & ( 1 < < ( CGame : : currLevel - 1 ) ) )
break ;
}
if ( i < = 10 ) {
RequestModel ( model , STREAMFLAGS_DEPENDENCY ) ;
timeBeforeNextLoad = 500 ;
}
}
}
void
CStreaming : : StreamZoneModels ( const CVector & pos )
{
int i ;
uint16 gangsToLoad , gangCarsToLoad , bit ;
CZoneInfo info ;
CTheZones : : GetZoneInfoForTimeOfDay ( & pos , & info ) ;
if ( info . pedGroup ! = ms_currentPedGrp ) {
// unload pevious group
if ( ms_currentPedGrp ! = - 1 )
2020-05-07 19:56:09 +00:00
for ( i = 0 ; i < NUMMODELSPERPEDGROUP ; i + + ) {
2020-08-20 21:45:05 +00:00
if ( CPopulation : : ms_pPedGroups [ ms_currentPedGrp ] . models [ i ] ! = - 1 ) {
SetModelIsDeletable ( CPopulation : : ms_pPedGroups [ ms_currentPedGrp ] . models [ i ] ) ;
SetModelTxdIsDeletable ( CPopulation : : ms_pPedGroups [ ms_currentPedGrp ] . models [ i ] ) ;
}
2019-06-28 10:34:02 +00:00
}
ms_currentPedGrp = info . pedGroup ;
2020-05-07 19:56:09 +00:00
for ( i = 0 ; i < NUMMODELSPERPEDGROUP ; i + + ) {
2020-08-20 21:45:05 +00:00
if ( CPopulation : : ms_pPedGroups [ ms_currentPedGrp ] . models [ i ] ! = - 1 )
RequestModel ( CPopulation : : ms_pPedGroups [ ms_currentPedGrp ] . models [ i ] , STREAMFLAGS_DONT_REMOVE ) ;
2019-06-28 10:34:02 +00:00
}
}
RequestModel ( MI_MALE01 , STREAMFLAGS_DONT_REMOVE ) ;
gangsToLoad = 0 ;
gangCarsToLoad = 0 ;
if ( info . gangDensity [ 0 ] ! = 0 ) gangsToLoad | = 1 < < 0 ;
if ( info . gangDensity [ 1 ] ! = 0 ) gangsToLoad | = 1 < < 1 ;
if ( info . gangDensity [ 2 ] ! = 0 ) gangsToLoad | = 1 < < 2 ;
if ( info . gangDensity [ 3 ] ! = 0 ) gangsToLoad | = 1 < < 3 ;
if ( info . gangDensity [ 4 ] ! = 0 ) gangsToLoad | = 1 < < 4 ;
if ( info . gangDensity [ 5 ] ! = 0 ) gangsToLoad | = 1 < < 5 ;
if ( info . gangDensity [ 6 ] ! = 0 ) gangsToLoad | = 1 < < 6 ;
if ( info . gangDensity [ 7 ] ! = 0 ) gangsToLoad | = 1 < < 7 ;
if ( info . gangDensity [ 8 ] ! = 0 ) gangsToLoad | = 1 < < 8 ;
if ( info . gangThreshold [ 0 ] ! = info . copDensity ) gangCarsToLoad | = 1 < < 0 ;
if ( info . gangThreshold [ 1 ] ! = info . gangThreshold [ 0 ] ) gangCarsToLoad | = 1 < < 1 ;
if ( info . gangThreshold [ 2 ] ! = info . gangThreshold [ 1 ] ) gangCarsToLoad | = 1 < < 2 ;
if ( info . gangThreshold [ 3 ] ! = info . gangThreshold [ 2 ] ) gangCarsToLoad | = 1 < < 3 ;
if ( info . gangThreshold [ 4 ] ! = info . gangThreshold [ 3 ] ) gangCarsToLoad | = 1 < < 4 ;
if ( info . gangThreshold [ 5 ] ! = info . gangThreshold [ 4 ] ) gangCarsToLoad | = 1 < < 5 ;
if ( info . gangThreshold [ 6 ] ! = info . gangThreshold [ 5 ] ) gangCarsToLoad | = 1 < < 6 ;
if ( info . gangThreshold [ 7 ] ! = info . gangThreshold [ 6 ] ) gangCarsToLoad | = 1 < < 7 ;
if ( info . gangThreshold [ 8 ] ! = info . gangThreshold [ 7 ] ) gangCarsToLoad | = 1 < < 8 ;
if ( gangsToLoad = = ms_loadedGangs & & gangCarsToLoad = = ms_loadedGangCars )
return ;
// This makes things simpler than the game does it
gangsToLoad | = gangCarsToLoad ;
for ( i = 0 ; i < NUM_GANGS ; i + + ) {
bit = 1 < < i ;
if ( gangsToLoad & bit & & ( ms_loadedGangs & bit ) = = 0 ) {
RequestModel ( MI_GANG01 + i * 2 , STREAMFLAGS_DONT_REMOVE ) ;
RequestModel ( MI_GANG01 + i * 2 + 1 , STREAMFLAGS_DONT_REMOVE ) ;
ms_loadedGangs | = bit ;
} else if ( ( gangsToLoad & bit ) = = 0 & & ms_loadedGangs & bit ) {
SetModelIsDeletable ( MI_GANG01 + i * 2 ) ;
SetModelIsDeletable ( MI_GANG01 + i * 2 + 1 ) ;
SetModelTxdIsDeletable ( MI_GANG01 + i * 2 ) ;
SetModelTxdIsDeletable ( MI_GANG01 + i * 2 + 1 ) ;
ms_loadedGangs & = ~ bit ;
}
if ( gangCarsToLoad & bit & & ( ms_loadedGangCars & bit ) = = 0 ) {
RequestModel ( CGangs : : GetGangInfo ( i ) - > m_nVehicleMI , STREAMFLAGS_DONT_REMOVE ) ;
} else if ( ( gangCarsToLoad & bit ) = = 0 & & ms_loadedGangCars & bit ) {
SetModelIsDeletable ( CGangs : : GetGangInfo ( i ) - > m_nVehicleMI ) ;
SetModelTxdIsDeletable ( CGangs : : GetGangInfo ( i ) - > m_nVehicleMI ) ;
}
}
ms_loadedGangCars = gangCarsToLoad ;
}
void
CStreaming : : RemoveCurrentZonesModels ( void )
{
int i ;
if ( ms_currentPedGrp ! = - 1 )
for ( i = 0 ; i < 8 ; i + + ) {
if ( CPopulation : : ms_pPedGroups [ ms_currentPedGrp ] . models [ i ] = = - 1 )
break ;
if ( CPopulation : : ms_pPedGroups [ ms_currentPedGrp ] . models [ i ] ! = MI_MALE01 )
SetModelIsDeletable ( CPopulation : : ms_pPedGroups [ ms_currentPedGrp ] . models [ i ] ) ;
}
for ( i = 0 ; i < NUM_GANGS ; i + + ) {
SetModelIsDeletable ( MI_GANG01 + i * 2 ) ;
SetModelIsDeletable ( MI_GANG01 + i * 2 + 1 ) ;
if ( CGangs : : GetGangInfo ( i ) - > m_nVehicleMI ! = - 1 )
SetModelIsDeletable ( CGangs : : GetGangInfo ( i ) - > m_nVehicleMI ) ;
}
ms_currentPedGrp = - 1 ;
ms_loadedGangs = 0 ;
ms_loadedGangCars = 0 ;
}
2019-06-24 16:44:23 +00:00
2019-06-26 14:49:32 +00:00
// Find starting offset of the cdimage we next want to read
// Not useful at all on PC...
int32
CStreaming : : GetCdImageOffset ( int32 lastPosn )
{
int offset , off ;
int i , img ;
int dist , mindist ;
img = - 1 ;
2020-05-11 02:55:57 +00:00
mindist = INT32_MAX ;
2019-06-26 14:49:32 +00:00
offset = ms_imageOffsets [ ms_lastImageRead ] ;
if ( lastPosn < = offset | | lastPosn > offset + ms_imageSize ) {
// last read position is not in last image
for ( i = 0 ; i < NUMCDIMAGES ; i + + ) {
off = ms_imageOffsets [ i ] ;
if ( off = = - 1 ) continue ;
if ( ( uint32 ) lastPosn > ( uint32 ) off )
// after start of image, get distance from end
// negative if before end!
dist = lastPosn - ( off + ms_imageSize ) ;
else
// before image, get offset to start
// this will never be negative
dist = off - lastPosn ;
if ( dist < mindist ) {
img = i ;
mindist = dist ;
}
}
assert ( img > = 0 ) ;
offset = ms_imageOffsets [ img ] ;
ms_lastImageRead = img ;
}
return offset ;
}
inline bool
2020-05-08 18:58:40 +00:00
ModelNotLoaded ( int32 modelId )
2019-06-26 14:49:32 +00:00
{
2020-05-08 18:58:40 +00:00
CStreamingInfo * si = & CStreaming : : ms_aInfoForModel [ modelId ] ;
return si - > m_loadState ! = STREAMSTATE_LOADED & & si - > m_loadState ! = STREAMSTATE_READING ;
2019-06-26 14:49:32 +00:00
}
2020-05-08 18:58:40 +00:00
inline bool TxdNotLoaded ( int32 txdId ) { return ModelNotLoaded ( txdId + STREAM_OFFSET_TXD ) ; }
2019-06-26 14:49:32 +00:00
// Find stream id of next requested file in cdimage
int32
CStreaming : : GetNextFileOnCd ( int32 lastPosn , bool priority )
{
CStreamingInfo * si , * next ;
int streamId ;
uint32 posn , size ;
int streamIdFirst , streamIdNext ;
uint32 posnFirst , posnNext ;
streamIdFirst = - 1 ;
streamIdNext = - 1 ;
2020-05-11 02:55:57 +00:00
posnFirst = UINT32_MAX ;
posnNext = UINT32_MAX ;
2019-06-26 14:49:32 +00:00
for ( si = ms_startRequestedList . m_next ; si ! = & ms_endRequestedList ; si = next ) {
next = si - > m_next ;
streamId = si - ms_aInfoForModel ;
// only priority requests if there are any
if ( priority & & ms_numPriorityRequests ! = 0 & & ! si - > IsPriority ( ) )
continue ;
// request Txd if necessary
2020-05-08 18:58:40 +00:00
if ( streamId < STREAM_OFFSET_TXD ) {
int txdId = CModelInfo : : GetModelInfo ( streamId ) - > GetTxdSlot ( ) ;
if ( TxdNotLoaded ( txdId ) ) {
ReRequestTxd ( txdId ) ;
continue ;
}
}
if ( ms_aInfoForModel [ streamId ] . GetCdPosnAndSize ( posn , size ) ) {
2019-06-26 14:49:32 +00:00
if ( posn < posnFirst ) {
// find first requested file in image
streamIdFirst = streamId ;
posnFirst = posn ;
}
if ( posn < posnNext & & posn > = ( uint32 ) lastPosn ) {
// find first requested file after last read position
streamIdNext = streamId ;
posnNext = posn ;
}
} else {
// empty file
DecrementRef ( streamId ) ;
si - > RemoveFromList ( ) ;
si - > m_loadState = STREAMSTATE_LOADED ;
}
}
// wrap around
if ( streamIdNext = = - 1 )
streamIdNext = streamIdFirst ;
if ( streamIdNext = = - 1 & & ms_numPriorityRequests ! = 0 ) {
// try non-priority files
ms_numPriorityRequests = 0 ;
streamIdNext = GetNextFileOnCd ( lastPosn , false ) ;
}
return streamIdNext ;
}
/*
* Streaming buffer size is half of the largest file .
* Files larger than the buffer size can only be loaded by channel 0 ,
* which then uses both buffers , while channel 1 is idle .
* ms_bLoadingBigModel is set to true to indicate this state .
*/
// Make channel read from disc
void
CStreaming : : RequestModelStream ( int32 ch )
{
int lastPosn , imgOffset , streamId ;
int totalSize ;
uint32 posn , size , unused ;
int i ;
int haveBigFile , havePed ;
lastPosn = CdStreamGetLastPosn ( ) ;
imgOffset = GetCdImageOffset ( lastPosn ) ;
streamId = GetNextFileOnCd ( lastPosn - imgOffset , true ) ;
if ( streamId = = - 1 )
return ;
// remove Txds that aren't requested anymore
while ( streamId > = STREAM_OFFSET_TXD ) {
if ( ms_aInfoForModel [ streamId ] . m_flags & STREAMFLAGS_KEEP_IN_MEMORY | |
IsTxdUsedByRequestedModels ( streamId - STREAM_OFFSET_TXD ) )
break ;
RemoveModel ( streamId ) ;
// so try next file
ms_aInfoForModel [ streamId ] . GetCdPosnAndSize ( posn , size ) ;
streamId = GetNextFileOnCd ( posn + size , true ) ;
}
if ( streamId = = - 1 )
return ;
ms_aInfoForModel [ streamId ] . GetCdPosnAndSize ( posn , size ) ;
if ( size > ( uint32 ) ms_streamingBufferSize ) {
// Can only load big models on channel 0, and 1 has to be idle
if ( ch = = 1 | | ms_channel [ 1 ] . state ! = CHANNELSTATE_IDLE )
return ;
ms_bLoadingBigModel = true ;
}
// Load up to 4 adjacent files
haveBigFile = 0 ;
havePed = 0 ;
totalSize = 0 ;
for ( i = 0 ; i < 4 ; i + + ) {
// no more files we can read
if ( streamId = = - 1 | | ms_aInfoForModel [ streamId ] . m_loadState ! = STREAMSTATE_INQUEUE )
break ;
// also stop at non-priority files
ms_aInfoForModel [ streamId ] . GetCdPosnAndSize ( unused , size ) ;
if ( ms_numPriorityRequests ! = 0 & & ! ms_aInfoForModel [ streamId ] . IsPriority ( ) )
break ;
// Can't load certain combinations of files together
if ( streamId < STREAM_OFFSET_TXD ) {
2020-05-05 12:06:55 +00:00
if ( havePed & & CModelInfo : : GetModelInfo ( streamId ) - > GetModelType ( ) = = MITYPE_PED | |
haveBigFile & & CModelInfo : : GetModelInfo ( streamId ) - > GetModelType ( ) = = MITYPE_VEHICLE | |
2020-05-08 18:58:40 +00:00
TxdNotLoaded ( CModelInfo : : GetModelInfo ( streamId ) - > GetTxdSlot ( ) ) )
2019-06-26 14:49:32 +00:00
break ;
} else {
if ( haveBigFile & & size > 200 )
break ;
}
// Now add the file
ms_channel [ ch ] . streamIds [ i ] = streamId ;
ms_channel [ ch ] . offsets [ i ] = totalSize ;
totalSize + = size ;
// To big for buffer, remove again
if ( totalSize > ms_streamingBufferSize & & i > 0 ) {
totalSize - = size ;
break ;
}
if ( streamId < STREAM_OFFSET_TXD ) {
2020-05-05 12:06:55 +00:00
if ( CModelInfo : : GetModelInfo ( streamId ) - > GetModelType ( ) = = MITYPE_PED )
2019-06-26 14:49:32 +00:00
havePed = 1 ;
2020-05-05 12:06:55 +00:00
if ( CModelInfo : : GetModelInfo ( streamId ) - > GetModelType ( ) = = MITYPE_VEHICLE )
2019-06-26 14:49:32 +00:00
haveBigFile = 1 ;
} else {
if ( size > 200 )
haveBigFile = 1 ;
}
ms_aInfoForModel [ streamId ] . m_loadState = STREAMSTATE_READING ;
ms_aInfoForModel [ streamId ] . RemoveFromList ( ) ;
DecrementRef ( streamId ) ;
streamId = ms_aInfoForModel [ streamId ] . m_nextID ;
}
// clear remaining slots
for ( ; i < 4 ; i + + )
ms_channel [ ch ] . streamIds [ i ] = - 1 ;
// Now read the data
assert ( ! ( ms_bLoadingBigModel & & ch = = 1 ) ) ; // this would clobber the buffer
if ( CdStreamRead ( ch , ms_pStreamingBuffer [ ch ] , imgOffset + posn , totalSize ) = = STREAM_NONE )
debug ( " FUCKFUCKFUCK \n " ) ;
ms_channel [ ch ] . state = CHANNELSTATE_READING ;
ms_channel [ ch ] . field24 = 0 ;
ms_channel [ ch ] . size = totalSize ;
ms_channel [ ch ] . position = imgOffset + posn ;
ms_channel [ ch ] . numTries = 0 ;
}
2019-06-24 16:44:23 +00:00
2019-06-26 14:49:32 +00:00
// Load data previously read from disc
2019-06-24 16:44:23 +00:00
bool
CStreaming : : ProcessLoadingChannel ( int32 ch )
{
int status ;
int i , id , cdsize ;
status = CdStreamGetStatus ( ch ) ;
if ( status ! = STREAM_NONE ) {
// busy
if ( status ! = STREAM_READING & & status ! = STREAM_WAITING ) {
ms_channelError = ch ;
ms_channel [ ch ] . state = CHANNELSTATE_ERROR ;
ms_channel [ ch ] . status = status ;
}
return false ;
}
if ( ms_channel [ ch ] . state = = CHANNELSTATE_STARTED ) {
ms_channel [ ch ] . state = CHANNELSTATE_IDLE ;
FinishLoadingLargeFile ( & ms_pStreamingBuffer [ ch ] [ ms_channel [ ch ] . offsets [ 0 ] * CDSTREAM_SECTOR_SIZE ] ,
ms_channel [ ch ] . streamIds [ 0 ] ) ;
ms_channel [ ch ] . streamIds [ 0 ] = - 1 ;
} else {
ms_channel [ ch ] . state = CHANNELSTATE_IDLE ;
for ( i = 0 ; i < 4 ; i + + ) {
id = ms_channel [ ch ] . streamIds [ i ] ;
if ( id = = - 1 )
continue ;
cdsize = ms_aInfoForModel [ id ] . GetCdSize ( ) ;
2020-05-05 12:06:55 +00:00
if ( id < STREAM_OFFSET_TXD & & CModelInfo : : GetModelInfo ( id ) - > GetModelType ( ) = = MITYPE_VEHICLE & &
2019-06-24 16:44:23 +00:00
ms_numVehiclesLoaded > = desiredNumVehiclesLoaded & &
2019-06-26 19:33:58 +00:00
! RemoveLoadedVehicle ( ) & &
2020-05-05 11:02:42 +00:00
( ( ms_aInfoForModel [ id ] . m_flags & STREAMFLAGS_CANT_REMOVE ) = = 0 | | GetAvailableVehicleSlot ( ) = = - 1 ) ) {
2019-06-24 16:44:23 +00:00
// can't load vehicle
RemoveModel ( id ) ;
2020-05-05 11:02:42 +00:00
if ( ms_aInfoForModel [ id ] . m_flags & STREAMFLAGS_CANT_REMOVE )
2019-06-24 16:44:23 +00:00
ReRequestModel ( id ) ;
else if ( CTxdStore : : GetNumRefs ( CModelInfo : : GetModelInfo ( id ) - > GetTxdSlot ( ) ) = = 0 )
RemoveTxd ( CModelInfo : : GetModelInfo ( id ) - > GetTxdSlot ( ) ) ;
} else {
MakeSpaceFor ( cdsize * CDSTREAM_SECTOR_SIZE ) ;
ConvertBufferToObject ( & ms_pStreamingBuffer [ ch ] [ ms_channel [ ch ] . offsets [ i ] * CDSTREAM_SECTOR_SIZE ] ,
id ) ;
if ( ms_aInfoForModel [ id ] . m_loadState = = STREAMSTATE_STARTED ) {
// queue for second part
ms_channel [ ch ] . state = CHANNELSTATE_STARTED ;
ms_channel [ ch ] . offsets [ 0 ] = ms_channel [ ch ] . offsets [ i ] ;
ms_channel [ ch ] . streamIds [ 0 ] = id ;
if ( i ! = 0 )
ms_channel [ ch ] . streamIds [ i ] = - 1 ;
} else
ms_channel [ ch ] . streamIds [ i ] = - 1 ;
}
}
}
if ( ms_bLoadingBigModel & & ms_channel [ ch ] . state ! = CHANNELSTATE_STARTED ) {
ms_bLoadingBigModel = false ;
// reset channel 1 after loading a big model
2019-06-26 19:33:58 +00:00
for ( i = 0 ; i < 4 ; i + + )
2019-06-24 16:44:23 +00:00
ms_channel [ 1 ] . streamIds [ i ] = - 1 ;
ms_channel [ 1 ] . state = CHANNELSTATE_IDLE ;
}
return true ;
}
2019-06-26 19:33:58 +00:00
void
CStreaming : : RetryLoadFile ( int32 ch )
{
2020-05-11 23:24:57 +00:00
Const char * key ;
2019-06-26 19:33:58 +00:00
CPad : : StopPadsShaking ( ) ;
if ( ms_channel [ ch ] . numTries > = 3 ) {
switch ( ms_channel [ ch ] . status ) {
case STREAM_ERROR_NOCD : key = " NOCD " ; break ;
case STREAM_ERROR_OPENCD : key = " OPENCD " ; break ;
case STREAM_ERROR_WRONGCD : key = " WRONGCD " ; break ;
default : key = " CDERROR " ; break ;
}
CHud : : SetMessage ( TheText . Get ( key ) ) ;
CTimer : : SetCodePause ( true ) ;
}
switch ( ms_channel [ ch ] . state ) {
2019-10-05 23:41:35 +00:00
case CHANNELSTATE_ERROR :
ms_channel [ ch ] . numTries + + ;
if ( CdStreamGetStatus ( ch ) = = STREAM_READING | | CdStreamGetStatus ( ch ) = = STREAM_WAITING ) break ;
2019-06-26 19:33:58 +00:00
case CHANNELSTATE_IDLE :
CdStreamRead ( ch , ms_pStreamingBuffer [ ch ] , ms_channel [ ch ] . position , ms_channel [ ch ] . size ) ;
ms_channel [ ch ] . state = CHANNELSTATE_READING ;
ms_channel [ ch ] . field24 = - 600 ;
break ;
case CHANNELSTATE_READING :
if ( ProcessLoadingChannel ( ch ) ) {
ms_channelError = - 1 ;
CTimer : : SetCodePause ( false ) ;
}
break ;
}
}
2019-06-26 14:49:32 +00:00
void
CStreaming : : LoadRequestedModels ( void )
2019-06-24 16:44:23 +00:00
{
2019-06-26 14:49:32 +00:00
static int currentChannel = 0 ;
// We can't read with channel 1 while channel 0 is using its buffer
if ( ms_bLoadingBigModel )
currentChannel = 0 ;
// We have data, load
if ( ms_channel [ currentChannel ] . state = = CHANNELSTATE_READING | |
ms_channel [ currentChannel ] . state = = CHANNELSTATE_STARTED )
ProcessLoadingChannel ( currentChannel ) ;
if ( ms_channelError = = - 1 ) {
// Channel is idle, read more data
if ( ms_channel [ currentChannel ] . state = = CHANNELSTATE_IDLE )
RequestModelStream ( currentChannel ) ;
// Switch channel
if ( ms_channel [ currentChannel ] . state ! = CHANNELSTATE_STARTED )
currentChannel = 1 - currentChannel ;
}
2019-06-24 16:44:23 +00:00
}
2020-10-04 19:39:54 +00:00
2021-01-27 15:26:08 +00:00
// Let's load models in 4 threads; when one of them becomes idle, process the file, and fill thread with another file. Unfortunately processing models are still single-threaded.
2020-10-04 19:39:54 +00:00
// Currently only supported on POSIX streamer.
2021-01-27 15:26:08 +00:00
// WIP - some files are loaded swapped (CdStreamPosix problem?)
#if 0 //def ONE_THREAD_PER_CHANNEL
2020-10-04 19:39:54 +00:00
void
CStreaming : : LoadAllRequestedModels ( bool priority )
{
static bool bInsideLoadAll = false ;
int imgOffset , streamId , status ;
int i ;
uint32 posn , size ;
if ( bInsideLoadAll )
return ;
FlushChannels ( ) ;
imgOffset = GetCdImageOffset ( CdStreamGetLastPosn ( ) ) ;
int streamIds [ ARRAY_SIZE ( ms_pStreamingBuffer ) ] ;
int streamSizes [ ARRAY_SIZE ( ms_pStreamingBuffer ) ] ;
int streamPoses [ ARRAY_SIZE ( ms_pStreamingBuffer ) ] ;
2021-01-27 15:26:08 +00:00
int readOrder [ 4 ] = { - 1 } ; // Channel IDs ordered by read time
int readI = 0 ;
2020-10-04 19:39:54 +00:00
int processI = 0 ;
2021-01-27 15:26:08 +00:00
bool first = true ;
// All those "first" checks are because of variables aren't initialized in first pass.
2020-10-04 19:39:54 +00:00
while ( true ) {
for ( int i = 0 ; i < ARRAY_SIZE ( ms_pStreamingBuffer ) ; i + + ) {
2021-01-27 15:26:08 +00:00
// Channel has file to load
2020-10-04 19:39:54 +00:00
if ( ! first & & streamIds [ i ] ! = - 1 ) {
continue ;
}
if ( ms_endRequestedList . m_prev ! = & ms_startRequestedList ) {
streamId = GetNextFileOnCd ( 0 , priority ) ;
if ( streamId = = - 1 ) {
streamIds [ i ] = - 1 ;
break ;
}
if ( ms_aInfoForModel [ streamId ] . GetCdPosnAndSize ( posn , size ) ) {
streamIds [ i ] = - 1 ;
2021-01-27 15:26:08 +00:00
// Big file, needs 2 buffer
2020-10-04 19:39:54 +00:00
if ( size > ( uint32 ) ms_streamingBufferSize ) {
if ( i + 1 = = ARRAY_SIZE ( ms_pStreamingBuffer ) )
2021-01-27 15:26:08 +00:00
break ;
2020-10-04 19:39:54 +00:00
else if ( ! first & & streamIds [ i + 1 ] ! = - 1 )
continue ;
2021-01-27 15:26:08 +00:00
2020-10-04 19:39:54 +00:00
} else {
2021-01-27 15:26:08 +00:00
// Buffer of current channel is part of a "big file", pass
2020-10-04 19:39:54 +00:00
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 ;
2021-01-27 15:26:08 +00:00
if ( ! first )
assert ( readOrder [ readI ] = = - 1 ) ;
//printf("read: order %d, ch %d, id %d, size %d\n", readI, i, streamId, size);
2020-10-04 19:39:54 +00:00
CdStreamRead ( i , ms_pStreamingBuffer [ i ] , imgOffset + posn , size ) ;
2021-01-27 15:26:08 +00:00
readOrder [ readI ] = i ;
if ( first & & readI + 1 ! = ARRAY_SIZE ( readOrder ) )
readOrder [ readI + 1 ] = - 1 ;
readI = ( readI + 1 ) % ARRAY_SIZE ( readOrder ) ;
2020-10-04 19:39:54 +00:00
} else {
ms_aInfoForModel [ streamId ] . RemoveFromList ( ) ;
DecrementRef ( streamId ) ;
ms_aInfoForModel [ streamId ] . m_loadState = STREAMSTATE_LOADED ;
streamIds [ i ] = - 1 ;
}
2021-01-27 15:26:08 +00:00
} else {
2020-10-04 19:39:54 +00:00
streamIds [ i ] = - 1 ;
2021-01-27 15:26:08 +00:00
break ;
}
2020-10-04 19:39:54 +00:00
}
first = false ;
2021-01-27 15:26:08 +00:00
int nextChannel = readOrder [ processI ] ;
2020-10-04 19:39:54 +00:00
2021-01-27 15:26:08 +00:00
// Now start processing
if ( nextChannel = = - 1 | | streamIds [ nextChannel ] = = - 1 )
2020-10-04 19:39:54 +00:00
break ;
2021-01-27 15:26:08 +00:00
//printf("process: order %d, ch %d, id %d\n", processI, nextChannel, streamIds[nextChannel]);
2020-10-04 19:39:54 +00:00
// Try again on error
2021-01-27 15:26:08 +00:00
while ( CdStreamSync ( nextChannel ) ! = STREAM_NONE ) {
CdStreamRead ( nextChannel , ms_pStreamingBuffer [ nextChannel ] , imgOffset + streamPoses [ nextChannel ] , streamSizes [ nextChannel ] ) ;
}
ms_aInfoForModel [ streamIds [ nextChannel ] ] . m_loadState = STREAMSTATE_READING ;
MakeSpaceFor ( streamSizes [ nextChannel ] * CDSTREAM_SECTOR_SIZE ) ;
ConvertBufferToObject ( ms_pStreamingBuffer [ nextChannel ] , streamIds [ nextChannel ] ) ;
if ( ms_aInfoForModel [ streamIds [ nextChannel ] ] . m_loadState = = STREAMSTATE_STARTED )
FinishLoadingLargeFile ( ms_pStreamingBuffer [ nextChannel ] , streamIds [ nextChannel ] ) ;
if ( streamIds [ nextChannel ] < STREAM_OFFSET_TXD ) {
CSimpleModelInfo * mi = ( CSimpleModelInfo * ) CModelInfo : : GetModelInfo ( streamIds [ nextChannel ] ) ;
2020-10-04 19:39:54 +00:00
if ( mi - > IsSimple ( ) )
mi - > m_alpha = 255 ;
}
2021-01-27 15:26:08 +00:00
streamIds [ nextChannel ] = - 1 ;
readOrder [ processI ] = - 1 ;
processI = ( processI + 1 ) % ARRAY_SIZE ( readOrder ) ;
2020-10-04 19:39:54 +00:00
}
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
2019-06-26 14:49:32 +00:00
void
CStreaming : : LoadAllRequestedModels ( bool priority )
2019-06-24 16:44:23 +00:00
{
2019-06-26 14:49:32 +00:00
static bool bInsideLoadAll = false ;
int imgOffset , streamId , status ;
int i ;
2019-06-24 16:44:23 +00:00
uint32 posn , size ;
2019-06-26 14:49:32 +00:00
if ( bInsideLoadAll )
return ;
2019-06-24 16:44:23 +00:00
2019-06-26 14:49:32 +00:00
FlushChannels ( ) ;
imgOffset = GetCdImageOffset ( CdStreamGetLastPosn ( ) ) ;
while ( ms_endRequestedList . m_prev ! = & ms_startRequestedList ) {
streamId = GetNextFileOnCd ( 0 , priority ) ;
if ( streamId = = - 1 )
break ;
ms_aInfoForModel [ streamId ] . RemoveFromList ( ) ;
DecrementRef ( streamId ) ;
if ( ms_aInfoForModel [ streamId ] . GetCdPosnAndSize ( posn , size ) ) {
do
status = CdStreamRead ( 0 , ms_pStreamingBuffer [ 0 ] , imgOffset + posn , size ) ;
while ( CdStreamSync ( 0 ) | | status = = STREAM_NONE ) ;
ms_aInfoForModel [ streamId ] . m_loadState = STREAMSTATE_READING ;
2021-01-27 15:26:08 +00:00
2019-06-26 14:49:32 +00:00
MakeSpaceFor ( size * CDSTREAM_SECTOR_SIZE ) ;
ConvertBufferToObject ( ms_pStreamingBuffer [ 0 ] , streamId ) ;
if ( ms_aInfoForModel [ streamId ] . m_loadState = = STREAMSTATE_STARTED )
FinishLoadingLargeFile ( ms_pStreamingBuffer [ 0 ] , streamId ) ;
if ( streamId < STREAM_OFFSET_TXD ) {
CSimpleModelInfo * mi = ( CSimpleModelInfo * ) CModelInfo : : GetModelInfo ( streamId ) ;
if ( mi - > IsSimple ( ) )
mi - > m_alpha = 255 ;
2019-06-24 16:44:23 +00:00
}
} else {
2019-06-26 14:49:32 +00:00
// empty
ms_aInfoForModel [ streamId ] . m_loadState = STREAMSTATE_LOADED ;
2019-06-24 16:44:23 +00:00
}
}
2019-06-26 14:49:32 +00:00
ms_bLoadingBigModel = false ;
for ( i = 0 ; i < 4 ; i + + ) {
ms_channel [ 1 ] . streamIds [ i ] = - 1 ;
ms_channel [ 1 ] . offsets [ i ] = - 1 ;
2019-06-24 16:44:23 +00:00
}
2019-06-26 14:49:32 +00:00
ms_channel [ 1 ] . state = CHANNELSTATE_IDLE ;
bInsideLoadAll = false ;
2019-06-24 16:44:23 +00:00
}
2020-10-04 19:39:54 +00:00
# endif
2019-06-24 16:44:23 +00:00
void
CStreaming : : FlushChannels ( void )
{
if ( ms_channel [ 1 ] . state = = CHANNELSTATE_STARTED )
ProcessLoadingChannel ( 1 ) ;
2019-06-26 14:49:32 +00:00
if ( ms_channel [ 0 ] . state = = CHANNELSTATE_READING ) {
2019-06-24 16:44:23 +00:00
CdStreamSync ( 0 ) ;
ProcessLoadingChannel ( 0 ) ;
}
if ( ms_channel [ 0 ] . state = = CHANNELSTATE_STARTED )
ProcessLoadingChannel ( 0 ) ;
2019-06-26 14:49:32 +00:00
if ( ms_channel [ 1 ] . state = = CHANNELSTATE_READING ) {
2019-06-24 16:44:23 +00:00
CdStreamSync ( 1 ) ;
ProcessLoadingChannel ( 1 ) ;
}
if ( ms_channel [ 1 ] . state = = CHANNELSTATE_STARTED )
ProcessLoadingChannel ( 1 ) ;
}
void
CStreaming : : FlushRequestList ( void )
{
CStreamingInfo * si , * next ;
for ( si = ms_startRequestedList . m_next ; si ! = & ms_endRequestedList ; si = next ) {
next = si - > m_next ;
RemoveModel ( si - ms_aInfoForModel ) ;
}
2021-01-27 15:26:08 +00:00
# ifdef FLUSHABLE_STREAMING
2020-10-04 19:39:54 +00:00
if ( ms_channel [ 0 ] . state = = CHANNELSTATE_READING ) {
flushStream [ 0 ] = 1 ;
}
if ( ms_channel [ 1 ] . state = = CHANNELSTATE_READING ) {
flushStream [ 1 ] = 1 ;
}
# endif
2019-06-24 16:44:23 +00:00
FlushChannels ( ) ;
}
2019-06-21 15:28:55 +00:00
2019-06-12 18:07:37 +00:00
void
CStreaming : : ImGonnaUseStreamingMemory ( void )
{
2020-11-26 15:47:19 +00:00
PUSH_MEMID ( MEMID_STREAM ) ;
2019-06-12 18:07:37 +00:00
}
void
CStreaming : : IHaveUsedStreamingMemory ( void )
{
2020-11-26 15:47:19 +00:00
POP_MEMID ( ) ;
2019-06-12 18:07:37 +00:00
UpdateMemoryUsed ( ) ;
}
void
CStreaming : : UpdateMemoryUsed ( void )
{
2020-11-26 15:47:19 +00:00
# ifdef USE_CUSTOM_ALLOCATOR
ms_memoryUsed =
gMainHeap . GetMemoryUsed ( MEMID_STREAM ) +
gMainHeap . GetMemoryUsed ( MEMID_STREAM_MODELS ) +
gMainHeap . GetMemoryUsed ( MEMID_STREAM_TEXUTRES ) ;
# endif
2019-06-12 18:07:37 +00:00
}
2019-06-20 12:49:16 +00:00
2020-08-20 21:45:05 +00:00
# define STREAM_DIST 80.0f
2019-06-20 12:49:16 +00:00
2019-06-26 22:12:58 +00:00
void
CStreaming : : AddModelsToRequestList ( const CVector & pos )
2019-06-20 12:49:16 +00:00
{
2019-06-26 22:12:58 +00:00
float xmin , xmax , ymin , ymax ;
int ixmin , ixmax , iymin , iymax ;
int ix , iy ;
int dx , dy , d ;
CSector * sect ;
xmin = pos . x - STREAM_DIST ;
ymin = pos . y - STREAM_DIST ;
xmax = pos . x + STREAM_DIST ;
ymax = pos . y + STREAM_DIST ;
ixmin = CWorld : : GetSectorIndexX ( xmin ) ;
if ( ixmin < 0 ) ixmin = 0 ;
ixmax = CWorld : : GetSectorIndexX ( xmax ) ;
if ( ixmax > = NUMSECTORS_X ) ixmax = NUMSECTORS_X - 1 ;
iymin = CWorld : : GetSectorIndexY ( ymin ) ;
if ( iymin < 0 ) iymin = 0 ;
iymax = CWorld : : GetSectorIndexY ( ymax ) ;
if ( iymax > = NUMSECTORS_Y ) iymax = NUMSECTORS_Y - 1 ;
CWorld : : AdvanceCurrentScanCode ( ) ;
2020-03-07 19:22:43 +00:00
for ( iy = iymin ; iy < = iymax ; iy + + ) {
2019-06-26 22:12:58 +00:00
dy = iy - CWorld : : GetSectorIndexY ( pos . y ) ;
2020-03-07 19:22:43 +00:00
for ( ix = ixmin ; ix < = ixmax ; ix + + ) {
2019-06-26 22:12:58 +00:00
if ( CRenderer : : m_loadingPriority & & ms_numModelsRequested > 5 )
return ;
dx = ix - CWorld : : GetSectorIndexX ( pos . x ) ;
d = dx * dx + dy * dy ;
sect = CWorld : : GetSector ( ix , iy ) ;
if ( d < = 1 ) {
ProcessEntitiesInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] ) ;
ProcessEntitiesInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS_OVERLAP ] ) ;
ProcessEntitiesInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] ) ;
ProcessEntitiesInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] ) ;
} else if ( d < = 4 * 4 ) {
ProcessEntitiesInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] , pos . x , pos . y , xmin , ymin , xmax , ymax ) ;
ProcessEntitiesInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS_OVERLAP ] , pos . x , pos . y , xmin , ymin , xmax , ymax ) ;
ProcessEntitiesInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] , pos . x , pos . y , xmin , ymin , xmax , ymax ) ;
ProcessEntitiesInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] , pos . x , pos . y , xmin , ymin , xmax , ymax ) ;
}
}
}
2019-06-20 12:49:16 +00:00
}
void
2019-06-26 22:12:58 +00:00
CStreaming : : ProcessEntitiesInSectorList ( CPtrList & list , float x , float y , float xmin , float ymin , float xmax , float ymax )
2019-06-20 12:49:16 +00:00
{
2019-06-26 22:12:58 +00:00
CPtrNode * node ;
CEntity * e ;
float lodDistSq ;
CVector2D pos ;
for ( node = list . first ; node ; node = node - > next ) {
e = ( CEntity * ) node - > item ;
if ( e - > m_scanCode = = CWorld : : GetCurrentScanCode ( ) )
continue ;
e - > m_scanCode = CWorld : : GetCurrentScanCode ( ) ;
2019-06-27 12:17:42 +00:00
if ( ! e - > bStreamingDontDelete & & ! e - > bIsSubway & &
2019-06-26 22:12:58 +00:00
( ! e - > IsObject ( ) | | ( ( CObject * ) e ) - > ObjectCreatedBy ! = TEMP_OBJECT ) ) {
CTimeModelInfo * mi = ( CTimeModelInfo * ) CModelInfo : : GetModelInfo ( e - > GetModelIndex ( ) ) ;
2020-05-05 12:06:55 +00:00
if ( mi - > GetModelType ( ) ! = MITYPE_TIME | | CClock : : GetIsTimeInRange ( mi - > GetTimeOn ( ) , mi - > GetTimeOff ( ) ) ) {
2019-06-26 22:12:58 +00:00
lodDistSq = sq ( mi - > GetLargestLodDistance ( ) ) ;
2020-04-19 16:34:08 +00:00
lodDistSq = Min ( lodDistSq , sq ( STREAM_DIST ) ) ;
2019-06-26 22:12:58 +00:00
pos = CVector2D ( e - > GetPosition ( ) ) ;
if ( xmin < pos . x & & pos . x < xmax & &
ymin < pos . y & & pos . y < ymax & &
( CVector2D ( x , y ) - pos ) . MagnitudeSqr ( ) < lodDistSq )
if ( CRenderer : : IsEntityCullZoneVisible ( e ) )
RequestModel ( e - > GetModelIndex ( ) , 0 ) ;
}
}
}
2019-06-20 12:49:16 +00:00
}
void
2019-06-26 22:12:58 +00:00
CStreaming : : ProcessEntitiesInSectorList ( CPtrList & list )
2019-06-20 12:49:16 +00:00
{
2019-06-26 22:12:58 +00:00
CPtrNode * node ;
CEntity * e ;
for ( node = list . first ; node ; node = node - > next ) {
e = ( CEntity * ) node - > item ;
if ( e - > m_scanCode = = CWorld : : GetCurrentScanCode ( ) )
continue ;
e - > m_scanCode = CWorld : : GetCurrentScanCode ( ) ;
2019-06-27 12:17:42 +00:00
if ( ! e - > bStreamingDontDelete & & ! e - > bIsSubway & &
2019-06-26 22:12:58 +00:00
( ! e - > IsObject ( ) | | ( ( CObject * ) e ) - > ObjectCreatedBy ! = TEMP_OBJECT ) ) {
CTimeModelInfo * mi = ( CTimeModelInfo * ) CModelInfo : : GetModelInfo ( e - > GetModelIndex ( ) ) ;
2020-05-05 12:06:55 +00:00
if ( mi - > GetModelType ( ) ! = MITYPE_TIME | | CClock : : GetIsTimeInRange ( mi - > GetTimeOn ( ) , mi - > GetTimeOff ( ) ) )
2019-06-26 22:12:58 +00:00
if ( CRenderer : : IsEntityCullZoneVisible ( e ) )
RequestModel ( e - > GetModelIndex ( ) , 0 ) ;
}
}
2019-06-20 12:49:16 +00:00
}
void
2019-06-26 22:12:58 +00:00
CStreaming : : DeleteFarAwayRwObjects ( const CVector & pos )
2019-06-20 12:49:16 +00:00
{
2019-06-27 12:17:42 +00:00
int posx , posy ;
int x , y ;
int r , i ;
CSector * sect ;
posx = CWorld : : GetSectorIndexX ( pos . x ) ;
posy = CWorld : : GetSectorIndexY ( pos . y ) ;
// Move oldSectorX/Y to new sector and delete RW objects in its "wake" for every step:
// O is the old sector, <- is the direction in which we move it,
// X are the sectors we delete RW objects from (except we go up to 10)
// X
// X X
// X X X
// X X X
// <- O X X X
// X X X
// X X X
// X X
// X
while ( posx ! = ms_oldSectorX ) {
if ( posx < ms_oldSectorX ) {
for ( r = 2 ; r < = 10 ; r + + ) {
x = ms_oldSectorX + r ;
if ( x < 0 )
continue ;
if ( x > = NUMSECTORS_X )
break ;
for ( i = - r ; i < = r ; i + + ) {
y = ms_oldSectorY + i ;
if ( y < 0 )
continue ;
if ( y > = NUMSECTORS_Y )
break ;
sect = CWorld : : GetSector ( x , y ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] ) ;
DeleteRwObjectsInOverlapSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS_OVERLAP ] , ms_oldSectorX , ms_oldSectorY ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] ) ;
}
}
ms_oldSectorX - - ;
} else {
for ( r = 2 ; r < = 10 ; r + + ) {
x = ms_oldSectorX - r ;
if ( x < 0 )
break ;
if ( x > = NUMSECTORS_X )
continue ;
for ( i = - r ; i < = r ; i + + ) {
y = ms_oldSectorY + i ;
if ( y < 0 )
continue ;
if ( y > = NUMSECTORS_Y )
break ;
sect = CWorld : : GetSector ( x , y ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] ) ;
DeleteRwObjectsInOverlapSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS_OVERLAP ] , ms_oldSectorX , ms_oldSectorY ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] ) ;
}
}
ms_oldSectorX + + ;
}
}
while ( posy ! = ms_oldSectorY ) {
if ( posy < ms_oldSectorY ) {
for ( r = 2 ; r < = 10 ; r + + ) {
y = ms_oldSectorY + r ;
if ( y < 0 )
continue ;
if ( y > = NUMSECTORS_Y )
break ;
for ( i = - r ; i < = r ; i + + ) {
x = ms_oldSectorX + i ;
if ( x < 0 )
continue ;
if ( x > = NUMSECTORS_X )
break ;
sect = CWorld : : GetSector ( x , y ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] ) ;
DeleteRwObjectsInOverlapSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS_OVERLAP ] , ms_oldSectorX , ms_oldSectorY ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] ) ;
}
}
ms_oldSectorY - - ;
} else {
for ( r = 2 ; r < = 10 ; r + + ) {
y = ms_oldSectorY - r ;
if ( y < 0 )
break ;
if ( y > = NUMSECTORS_Y )
continue ;
for ( i = - r ; i < = r ; i + + ) {
x = ms_oldSectorX + i ;
if ( x < 0 )
continue ;
if ( x > = NUMSECTORS_X )
break ;
sect = CWorld : : GetSector ( x , y ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] ) ;
DeleteRwObjectsInOverlapSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS_OVERLAP ] , ms_oldSectorX , ms_oldSectorY ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] ) ;
}
}
ms_oldSectorY + + ;
}
}
2019-06-26 22:12:58 +00:00
}
void
CStreaming : : DeleteAllRwObjects ( void )
{
int x , y ;
CSector * sect ;
for ( x = 0 ; x < NUMSECTORS_X ; x + + )
for ( y = 0 ; y < NUMSECTORS_Y ; y + + ) {
sect = CWorld : : GetSector ( x , y ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS_OVERLAP ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS_OVERLAP ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES_OVERLAP ] ) ;
}
}
void
CStreaming : : DeleteRwObjectsAfterDeath ( const CVector & pos )
{
int ix , iy ;
int x , y ;
CSector * sect ;
ix = CWorld : : GetSectorIndexX ( pos . x ) ;
2020-03-07 19:22:43 +00:00
iy = CWorld : : GetSectorIndexY ( pos . y ) ;
2019-06-26 22:12:58 +00:00
for ( x = 0 ; x < NUMSECTORS_X ; x + + )
for ( y = 0 ; y < NUMSECTORS_Y ; y + + )
2019-07-10 15:18:26 +00:00
if ( Abs ( ix - x ) > 3.0f & &
Abs ( iy - y ) > 3.0f ) {
2019-06-26 22:12:58 +00:00
sect = CWorld : : GetSector ( x , y ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS_OVERLAP ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS_OVERLAP ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] ) ;
DeleteRwObjectsInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES_OVERLAP ] ) ;
}
}
2019-06-27 12:17:42 +00:00
void
2020-07-22 11:56:28 +00:00
CStreaming : : DeleteRwObjectsBehindCamera ( size_t mem )
2019-06-27 12:17:42 +00:00
{
int ix , iy ;
int x , y ;
int xmin , xmax , ymin , ymax ;
int inc ;
CSector * sect ;
if ( ms_memoryUsed < mem )
return ;
ix = CWorld : : GetSectorIndexX ( TheCamera . GetPosition ( ) . x ) ;
2020-03-07 19:22:43 +00:00
iy = CWorld : : GetSectorIndexY ( TheCamera . GetPosition ( ) . y ) ;
2019-06-27 12:17:42 +00:00
2019-07-10 15:18:26 +00:00
if ( Abs ( TheCamera . GetForward ( ) . x ) > Abs ( TheCamera . GetForward ( ) . y ) ) {
2019-06-27 12:17:42 +00:00
// looking west/east
2020-04-19 16:34:08 +00:00
ymin = Max ( iy - 10 , 0 ) ;
ymax = Min ( iy + 10 , NUMSECTORS_Y - 1 ) ;
2019-06-27 12:17:42 +00:00
assert ( ymin < = ymax ) ;
// Delete a block of sectors that we know is behind the camera
2020-08-20 21:45:05 +00:00
if ( TheCamera . GetForward ( ) . x > 0.0f ) {
2019-06-27 12:17:42 +00:00
// looking east
2020-04-19 16:34:08 +00:00
xmax = Max ( ix - 2 , 0 ) ;
xmin = Max ( ix - 10 , 0 ) ;
2019-06-27 12:17:42 +00:00
inc = 1 ;
} else {
// looking west
2020-04-19 16:34:08 +00:00
xmax = Min ( ix + 2 , NUMSECTORS_X - 1 ) ;
xmin = Min ( ix + 10 , NUMSECTORS_X - 1 ) ;
2019-06-27 12:17:42 +00:00
inc = - 1 ;
}
for ( y = ymin ; y < = ymax ; y + + ) {
for ( x = xmin ; x ! = xmax ; x + = inc ) {
sect = CWorld : : GetSector ( x , y ) ;
if ( DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] , mem ) | |
DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] , mem ) | |
DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] , mem ) )
return ;
}
}
// Now a block that intersects with the camera's frustum
2020-08-20 21:45:05 +00:00
if ( TheCamera . GetForward ( ) . x > 0.0f ) {
2019-06-27 12:17:42 +00:00
// looking east
2020-04-19 16:34:08 +00:00
xmax = Max ( ix + 10 , 0 ) ;
xmin = Max ( ix - 2 , 0 ) ;
2019-06-27 12:17:42 +00:00
inc = 1 ;
} else {
// looking west
2020-04-19 16:34:08 +00:00
xmax = Min ( ix - 10 , NUMSECTORS_X - 1 ) ;
xmin = Min ( ix + 2 , NUMSECTORS_X - 1 ) ;
2019-06-27 12:17:42 +00:00
inc = - 1 ;
}
for ( y = ymin ; y < = ymax ; y + + ) {
for ( x = xmin ; x ! = xmax ; x + = inc ) {
sect = CWorld : : GetSector ( x , y ) ;
if ( DeleteRwObjectsNotInFrustumInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] , mem ) | |
DeleteRwObjectsNotInFrustumInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] , mem ) | |
DeleteRwObjectsNotInFrustumInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] , mem ) )
return ;
}
}
if ( RemoveReferencedTxds ( mem ) )
return ;
// As last resort, delete objects from the last step more aggressively
for ( y = ymin ; y < = ymax ; y + + ) {
for ( x = xmax ; x ! = xmin ; x - = inc ) {
sect = CWorld : : GetSector ( x , y ) ;
if ( DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] , mem ) | |
DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] , mem ) | |
DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] , mem ) )
return ;
}
}
} else {
// looking north/south
2020-04-19 16:34:08 +00:00
xmin = Max ( ix - 10 , 0 ) ;
xmax = Min ( ix + 10 , NUMSECTORS_X - 1 ) ;
2019-06-27 12:17:42 +00:00
assert ( xmin < = xmax ) ;
// Delete a block of sectors that we know is behind the camera
2020-08-20 21:45:05 +00:00
if ( TheCamera . GetForward ( ) . y > 0.0f ) {
2019-06-27 12:17:42 +00:00
// looking north
2020-04-19 16:34:08 +00:00
ymax = Max ( iy - 2 , 0 ) ;
ymin = Max ( iy - 10 , 0 ) ;
2019-06-27 12:17:42 +00:00
inc = 1 ;
} else {
// looking south
2020-04-19 16:34:08 +00:00
ymax = Min ( iy + 2 , NUMSECTORS_Y - 1 ) ;
ymin = Min ( iy + 10 , NUMSECTORS_Y - 1 ) ;
2019-06-27 12:17:42 +00:00
inc = - 1 ;
}
for ( x = xmin ; x < = xmax ; x + + ) {
for ( y = ymin ; y ! = ymax ; y + = inc ) {
sect = CWorld : : GetSector ( x , y ) ;
if ( DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] , mem ) | |
DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] , mem ) | |
DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] , mem ) )
return ;
}
}
// Now a block that intersects with the camera's frustum
2020-08-20 21:45:05 +00:00
if ( TheCamera . GetForward ( ) . y > 0.0f ) {
2019-06-27 12:17:42 +00:00
// looking north
2020-04-19 16:34:08 +00:00
ymax = Max ( iy + 10 , 0 ) ;
ymin = Max ( iy - 2 , 0 ) ;
2019-06-27 12:17:42 +00:00
inc = 1 ;
} else {
// looking south
2020-04-19 16:34:08 +00:00
ymax = Min ( iy - 10 , NUMSECTORS_Y - 1 ) ;
ymin = Min ( iy + 2 , NUMSECTORS_Y - 1 ) ;
2019-06-27 12:17:42 +00:00
inc = - 1 ;
}
for ( x = xmin ; x < = xmax ; x + + ) {
for ( y = ymin ; y ! = ymax ; y + = inc ) {
sect = CWorld : : GetSector ( x , y ) ;
if ( DeleteRwObjectsNotInFrustumInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] , mem ) | |
DeleteRwObjectsNotInFrustumInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] , mem ) | |
DeleteRwObjectsNotInFrustumInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] , mem ) )
return ;
}
}
if ( RemoveReferencedTxds ( mem ) )
return ;
// As last resort, delete objects from the last step more aggressively
for ( x = xmin ; x < = xmax ; x + + ) {
for ( y = ymax ; y ! = ymin ; y - = inc ) {
sect = CWorld : : GetSector ( x , y ) ;
if ( DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_BUILDINGS ] , mem ) | |
DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_DUMMIES ] , mem ) | |
DeleteRwObjectsBehindCameraInSectorList ( sect - > m_lists [ ENTITYLIST_OBJECTS ] , mem ) )
return ;
}
}
}
}
2019-06-26 22:12:58 +00:00
void
CStreaming : : DeleteRwObjectsInSectorList ( CPtrList & list )
{
CPtrNode * node ;
CEntity * e ;
for ( node = list . first ; node ; node = node - > next ) {
e = ( CEntity * ) node - > item ;
2019-06-27 12:17:42 +00:00
if ( ! e - > bStreamingDontDelete & & ! e - > bImBeingRendered )
2019-06-26 22:12:58 +00:00
e - > DeleteRwObject ( ) ;
}
}
void
CStreaming : : DeleteRwObjectsInOverlapSectorList ( CPtrList & list , int32 x , int32 y )
{
CPtrNode * node ;
CEntity * e ;
for ( node = list . first ; node ; node = node - > next ) {
e = ( CEntity * ) node - > item ;
2019-06-27 12:17:42 +00:00
if ( e - > m_rwObject & & ! e - > bStreamingDontDelete & & ! e - > bImBeingRendered ) {
2019-06-26 22:12:58 +00:00
// Now this is pretty weird...
2019-07-10 15:18:26 +00:00
if ( Abs ( CWorld : : GetSectorIndexX ( e - > GetPosition ( ) . x ) - x ) > = 2.0f )
2019-06-26 22:12:58 +00:00
// {
e - > DeleteRwObject ( ) ;
// return; // BUG?
// }
else // FIX?
2019-07-10 15:18:26 +00:00
if ( Abs ( CWorld : : GetSectorIndexY ( e - > GetPosition ( ) . y ) - y ) > = 2.0f )
2019-06-26 22:12:58 +00:00
e - > DeleteRwObject ( ) ;
}
}
2019-06-20 12:49:16 +00:00
}
2019-06-27 12:17:42 +00:00
bool
2020-07-22 11:56:28 +00:00
CStreaming : : DeleteRwObjectsBehindCameraInSectorList ( CPtrList & list , size_t mem )
2019-06-27 12:17:42 +00:00
{
CPtrNode * node ;
CEntity * e ;
for ( node = list . first ; node ; node = node - > next ) {
e = ( CEntity * ) node - > item ;
if ( ! e - > bStreamingDontDelete & & ! e - > bImBeingRendered & &
e - > m_rwObject & & ms_aInfoForModel [ e - > GetModelIndex ( ) ] . m_next ) {
e - > DeleteRwObject ( ) ;
2020-05-05 12:06:55 +00:00
if ( CModelInfo : : GetModelInfo ( e - > GetModelIndex ( ) ) - > GetNumRefs ( ) = = 0 ) {
2019-06-27 12:17:42 +00:00
RemoveModel ( e - > GetModelIndex ( ) ) ;
if ( ms_memoryUsed < mem )
return true ;
}
}
}
return false ;
}
bool
2020-07-22 11:56:28 +00:00
CStreaming : : DeleteRwObjectsNotInFrustumInSectorList ( CPtrList & list , size_t mem )
2019-06-27 12:17:42 +00:00
{
CPtrNode * node ;
CEntity * e ;
for ( node = list . first ; node ; node = node - > next ) {
e = ( CEntity * ) node - > item ;
if ( ! e - > bStreamingDontDelete & & ! e - > bImBeingRendered & &
e - > m_rwObject & & ! e - > IsVisible ( ) & & ms_aInfoForModel [ e - > GetModelIndex ( ) ] . m_next ) {
e - > DeleteRwObject ( ) ;
2020-05-05 12:06:55 +00:00
if ( CModelInfo : : GetModelInfo ( e - > GetModelIndex ( ) ) - > GetNumRefs ( ) = = 0 ) {
2019-06-27 12:17:42 +00:00
RemoveModel ( e - > GetModelIndex ( ) ) ;
if ( ms_memoryUsed < mem )
return true ;
}
}
}
return false ;
}
void
CStreaming : : MakeSpaceFor ( int32 size )
{
2020-10-03 14:17:24 +00:00
# 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
2020-07-22 11:56:28 +00:00
while ( ms_memoryUsed > = ms_memoryAvailable - size )
2020-10-03 14:17:24 +00:00
if ( ! RemoveLeastUsedModel ( ) ) {
2019-06-27 12:17:42 +00:00
DeleteRwObjectsBehindCamera ( ms_memoryAvailable - size ) ;
return ;
}
}
void
CStreaming : : LoadScene ( const CVector & pos )
{
CStreamingInfo * si , * prev ;
eLevelName level ;
2020-05-06 10:23:26 +00:00
level = CTheZones : : GetLevelFromPosition ( & pos ) ;
2019-06-27 12:17:42 +00:00
debug ( " Start load scene \n " ) ;
for ( si = ms_endRequestedList . m_prev ; si ! = & ms_startRequestedList ; si = prev ) {
prev = si - > m_prev ;
if ( ( si - > m_flags & ( STREAMFLAGS_KEEP_IN_MEMORY | STREAMFLAGS_PRIORITY ) ) = = 0 )
RemoveModel ( si - ms_aInfoForModel ) ;
}
CRenderer : : m_loadingPriority = false ;
CCullZones : : ForceCullZoneCoors ( pos ) ;
DeleteAllRwObjects ( ) ;
AddModelsToRequestList ( pos ) ;
CRadar : : StreamRadarSections ( pos ) ;
RemoveUnusedBigBuildings ( level ) ;
RequestBigBuildings ( level ) ;
LoadAllRequestedModels ( false ) ;
debug ( " End load scene \n " ) ;
}
2019-06-28 10:34:02 +00:00
void
2019-10-08 20:07:11 +00:00
CStreaming : : MemoryCardSave ( uint8 * buf , uint32 * size )
2019-06-28 10:34:02 +00:00
{
int i ;
2019-10-08 20:07:11 +00:00
* size = NUM_DEFAULT_MODELS ;
2019-10-06 21:39:25 +00:00
for ( i = 0 ; i < NUM_DEFAULT_MODELS ; i + + )
2019-06-28 10:34:02 +00:00
if ( ms_aInfoForModel [ i ] . m_loadState = = STREAMSTATE_LOADED )
2019-10-08 20:07:11 +00:00
buf [ i ] = ms_aInfoForModel [ i ] . m_flags ;
2019-06-28 10:34:02 +00:00
else
2019-10-08 20:07:11 +00:00
buf [ i ] = 0xFF ;
2019-06-28 10:34:02 +00:00
}
void
2019-10-08 20:07:11 +00:00
CStreaming : : MemoryCardLoad ( uint8 * buf , uint32 size )
2019-06-28 10:34:02 +00:00
{
uint32 i ;
2019-10-08 20:07:11 +00:00
assert ( size = = NUM_DEFAULT_MODELS ) ;
for ( i = 0 ; i < size ; i + + )
2019-06-28 10:34:02 +00:00
if ( ms_aInfoForModel [ i ] . m_loadState = = STREAMSTATE_LOADED )
2019-10-08 20:07:11 +00:00
if ( buf [ i ] ! = 0xFF )
ms_aInfoForModel [ i ] . m_flags = buf [ i ] ;
2019-06-28 10:34:02 +00:00
}
2019-08-15 14:51:39 +00:00
void
CStreaming : : UpdateForAnimViewer ( void )
{
if ( CStreaming : : ms_channelError = = - 1 ) {
CStreaming : : AddModelsToRequestList ( CVector ( 0.0f , 0.0f , 0.0f ) ) ;
CStreaming : : LoadRequestedModels ( ) ;
2020-07-24 17:43:51 +00:00
sprintf ( gString , " Requested %d, memory size %zuK \n " , CStreaming : : ms_numModelsRequested , 2 * CStreaming : : ms_memoryUsed ) ; // original modifier was %d
2019-08-15 14:51:39 +00:00
}
else {
CStreaming : : RetryLoadFile ( CStreaming : : ms_channelError ) ;
}
}
2020-11-26 16:11:55 +00:00
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
2021-01-08 19:50:59 +00:00
sprintf ( str , " model %d,%s, refs%d, size%dK, flags%x " , modelIndex , modelInfo - > GetModelName ( ) , modelInfo - > GetNumRefs ( ) , 2 * size ,
2020-11-26 16:11:55 +00:00
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 ( ) ;
2021-01-27 15:26:08 +00:00
}