Skip to content
Permalink
Browse files

Reduce allocations for TXD loading

  • Loading branch information...
botder committed Sep 29, 2019
1 parent 830f01b commit d4475098e70f20abbee36a5e8fbac5ac041aeeb3
@@ -85,15 +85,15 @@ CModelTexturesInfo* CRenderWareSA::GetModelTexturesInfo(ushort usModelId)
// Load textures from a TXD file
//
////////////////////////////////////////////////////////////////
bool CRenderWareSA::ModelInfoTXDLoadTextures(SReplacementTextures* pReplacementTextures, const SString& strFilename, const CBuffer& fileData,
bool CRenderWareSA::ModelInfoTXDLoadTextures(SReplacementTextures* pReplacementTextures, const SString& strFilename, const SString& buffer,
bool bFilteringEnabled)
{
// Are we already loaded?
if (!pReplacementTextures->textures.empty())
return false;

// Try to load it
RwTexDictionary* pTxd = ReadTXD(strFilename, fileData);
RwTexDictionary* pTxd = ReadTXD(strFilename, buffer);
if (pTxd)
{
// Get the list of textures into our own list
@@ -199,16 +199,16 @@ CRenderWareSA::~CRenderWareSA()
}

// Reads and parses a TXD file specified by a path (szTXD)
RwTexDictionary* CRenderWareSA::ReadTXD(const SString& strFilename, const CBuffer& fileData)
RwTexDictionary* CRenderWareSA::ReadTXD(const SString& strFilename, const SString& buffer)
{
// open the stream
RwStream* streamTexture;
RwBuffer buffer;
if (!fileData.IsEmpty())
RwBuffer streamBuffer;
if (!buffer.empty())
{
buffer.ptr = (void*)fileData.GetData();
buffer.size = fileData.GetSize();
streamTexture = RwStreamOpen(STREAM_TYPE_BUFFER, STREAM_MODE_READ, &buffer);
streamBuffer.ptr = (void*)buffer.data();
streamBuffer.size = buffer.size();
streamTexture = RwStreamOpen(STREAM_TYPE_BUFFER, STREAM_MODE_READ, &streamBuffer);
}
else
streamTexture = RwStreamOpen(STREAM_TYPE_FILENAME, STREAM_MODE_READ, *strFilename);
@@ -31,15 +31,15 @@ class CRenderWareSA : public CRenderWare
CRenderWareSA(enum eGameVersion version);
~CRenderWareSA();
void Initialize();
bool ModelInfoTXDLoadTextures(SReplacementTextures* pReplacementTextures, const SString& strFilename, const CBuffer& fileData, bool bFilteringEnabled);
bool ModelInfoTXDLoadTextures(SReplacementTextures* pReplacementTextures, const SString& strFilename, const SString& buffer, bool bFilteringEnabled);
bool ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTextures, ushort usModelId);
void ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacementTextures);
void ClothesAddReplacementTxd(char* pFileData, ushort usFileId);
void ClothesRemoveReplacementTxd(char* pFileData);
bool HasClothesReplacementChanged();

// Reads and parses a TXD file specified by a path (szTXD)
RwTexDictionary* ReadTXD(const SString& strFilename, const CBuffer& fileData);
RwTexDictionary* ReadTXD(const SString& strFilename, const SString& buffer);

// Reads and parses a DFF file specified by a path (szDFF) into a CModelInfo identified by the object id (usModelID)
RpClump* ReadDFF(const SString& strFilename, const SString& buffer, unsigned short usModelID, bool bLoadEmbeddedCollisions);
@@ -29,38 +29,32 @@ CClientTXD::~CClientTXD()
}

// Remove us from all the clothes replacement doo dah
g_pGame->GetRenderWare()->ClothesRemoveReplacementTxd(m_FileData.GetData());
g_pGame->GetRenderWare()->ClothesRemoveReplacementTxd(m_FileData.data());
}

bool CClientTXD::LoadTXD(const SString& strFile, bool bFilteringEnabled, bool bIsRawData)
bool CClientTXD::Load(bool isRaw, SString input, bool enableFiltering)
{
// Do load here to check for errors.
m_bFilteringEnabled = bFilteringEnabled;
m_bIsRawData = bIsRawData;
if (input.empty())
return false;

m_bIsRawData = isRaw;
m_bFilteringEnabled = enableFiltering;

if (!m_bIsRawData)
if (isRaw)
{
m_strFilename = strFile;
SString strUseFilename;
if (!GetFilenameToUse(strUseFilename))
return false;
return g_pGame->GetRenderWare()->ModelInfoTXDLoadTextures(&m_ReplacementTextures, strUseFilename, CBuffer(), m_bFilteringEnabled);
return LoadFromBuffer(std::move(input));
}
else
{
m_FileData = CBuffer(strFile, strFile.length());
if (!g_pCore->GetNetwork()->CheckFile("txd", "", m_FileData.GetData(), m_FileData.GetSize()))
return false;

return g_pGame->GetRenderWare()->ModelInfoTXDLoadTextures(&m_ReplacementTextures, NULL, m_FileData, m_bFilteringEnabled);
return LoadFromFile(std::move(input));
}
}

bool CClientTXD::Import(unsigned short usModelID)
{
if (usModelID >= CLOTHES_TEX_ID_FIRST && usModelID <= CLOTHES_TEX_ID_LAST)
{
if (m_FileData.IsEmpty() && m_bIsRawData)
if (m_FileData.empty() && m_bIsRawData)
return false; // Raw data has been freed already because texture was first used as non-clothes

// If using for clothes only, unload 'replacing model textures' stuff to save memory
@@ -70,17 +64,19 @@ bool CClientTXD::Import(unsigned short usModelID)
m_ReplacementTextures = SReplacementTextures();
}
// Load txd file data if not already done
if (m_FileData.IsEmpty())
if (m_FileData.empty())
{
SString strUseFilename;

if (!GetFilenameToUse(strUseFilename))
return false;
if (!m_FileData.LoadFromFile(strUseFilename))

if (!FileLoad(std::nothrow, strUseFilename, m_FileData))
return false;
}
m_bUsingFileDataForClothes = true;
// Note: ClothesAddReplacementTxd uses the pointer from m_FileData, so don't touch m_FileData until matching ClothesRemove call
g_pGame->GetRenderWare()->ClothesAddReplacementTxd(m_FileData.GetData(), usModelID - CLOTHES_MODEL_ID_FIRST);
g_pGame->GetRenderWare()->ClothesAddReplacementTxd(m_FileData.data(), usModelID - CLOTHES_MODEL_ID_FIRST);
return true;
}
else
@@ -93,7 +89,7 @@ bool CClientTXD::Import(unsigned short usModelID)
SString strUseFilename;
if (!GetFilenameToUse(strUseFilename))
return false;
g_pGame->GetRenderWare()->ModelInfoTXDLoadTextures(&m_ReplacementTextures, strUseFilename, CBuffer(), m_bFilteringEnabled);
g_pGame->GetRenderWare()->ModelInfoTXDLoadTextures(&m_ReplacementTextures, strUseFilename, SString(), m_bFilteringEnabled);
if (m_ReplacementTextures.textures.empty())
return false;
}
@@ -109,7 +105,7 @@ bool CClientTXD::Import(unsigned short usModelID)
if (m_bIsRawData && !m_bUsingFileDataForClothes)
{
// This means the texture can't be used for clothes now
m_FileData = CBuffer();
SString().swap(m_FileData);
}

// Have we got textures and haven't already imported into this model?
@@ -130,6 +126,28 @@ bool CClientTXD::IsImportableModel(unsigned short usModelID)
(usModelID >= CLOTHES_TEX_ID_FIRST && usModelID <= CLOTHES_TEX_ID_LAST);
}

bool CClientTXD::LoadFromFile(SString filePath)
{
m_strFilename = std::move(filePath);

SString strUseFilename;

if (!GetFilenameToUse(strUseFilename))
return false;

return g_pGame->GetRenderWare()->ModelInfoTXDLoadTextures(&m_ReplacementTextures, strUseFilename, SString(), m_bFilteringEnabled);
}

bool CClientTXD::LoadFromBuffer(SString buffer)
{
if (!g_pCore->GetNetwork()->CheckFile("txd", "", buffer.data(), buffer.size()))
return false;

m_FileData = std::move(buffer);

return g_pGame->GetRenderWare()->ModelInfoTXDLoadTextures(&m_ReplacementTextures, NULL, m_FileData, m_bFilteringEnabled);
}

void CClientTXD::Restream(unsigned short usModelID)
{
if (CClientVehicleManager::IsValidModel(usModelID))
@@ -25,19 +25,22 @@ class CClientTXD : public CClientEntity
void SetPosition(const CVector& vecPosition){};

eClientEntityType GetType() const { return CCLIENTTXD; }
bool LoadTXD(const SString& strFile, bool bFilteringEnabled, bool bIsRawData);
bool Load(bool isRaw, SString input, bool enableFiltering);
bool Import(unsigned short usModelID);
static bool IsImportableModel(unsigned short usModelID);
static bool IsTXDData(const SString& strData);

protected:
private:
bool LoadFromFile(SString filePath);
bool LoadFromBuffer(SString buffer);

void Restream(unsigned short usModel);
bool GetFilenameToUse(SString& strOutFilename);

SString m_strFilename;
bool m_bFilteringEnabled;
bool m_bIsRawData;
bool m_bUsingFileDataForClothes;
CBuffer m_FileData;
SString m_FileData;
SReplacementTextures m_ReplacementTextures;
};
@@ -257,11 +257,10 @@ int CLuaEngineDefs::EngineLoadDFF(lua_State* luaVM)

int CLuaEngineDefs::EngineLoadTXD(lua_State* luaVM)
{
SString strFile = "";
SString input;
bool bFilteringEnabled = true;
CScriptArgReader argStream(luaVM);
// Grab the TXD filename or data
argStream.ReadString(strFile);
argStream.ReadString(input);
if (argStream.NextIsBool()) // Some scripts have a number here (in error)
argStream.ReadBool(bFilteringEnabled, true);

@@ -275,10 +274,20 @@ int CLuaEngineDefs::EngineLoadTXD(lua_State* luaVM)
CResource* pResource = pLuaMain->GetResource();
if (pResource)
{
bool bIsRawData = CClientTXD::IsTXDData(strFile);
SString strPath;
// Is this a legal filepath?
if (bIsRawData || CResourceManager::ParseResourcePathInput(strFile, pResource, &strPath))
bool bIsRawData = CClientTXD::IsTXDData(input);

// Do not proceed if the file path length appears too long to be real
if (!bIsRawData && input.size() > 32767)
{
argStream.SetCustomError("Corrupt TXD file data or file path too long", "Error loading TXD");
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
lua_pushboolean(luaVM, false);
return 1;
}

SString filePath;

if (bIsRawData || CResourceManager::ParseResourcePathInput(input, pResource, &filePath))
{
// Grab the resource root entity
CClientEntity* pRoot = pResource->GetResourceTXDRoot();
@@ -287,7 +296,7 @@ int CLuaEngineDefs::EngineLoadTXD(lua_State* luaVM)
CClientTXD* pTXD = new CClientTXD(m_pManager, INVALID_ELEMENT_ID);

// Try to load the TXD file
if (pTXD->LoadTXD(bIsRawData ? strFile : strPath, bFilteringEnabled, bIsRawData))
if (pTXD->Load(bIsRawData, bIsRawData ? std::move(input) : std::move(filePath), bFilteringEnabled))
{
// Success loading the file. Set parent to TXD root
pTXD->SetParent(pRoot);
@@ -300,18 +309,20 @@ int CLuaEngineDefs::EngineLoadTXD(lua_State* luaVM)
{
// Delete it again
delete pTXD;
argStream.SetCustomError(bIsRawData ? "raw data" : strFile, "Error loading TXD");
argStream.SetCustomError(bIsRawData ? "raw data" : input, "Error loading TXD");
}
}
else
argStream.SetCustomError(bIsRawData ? "raw data" : strFile, "Bad file path");
argStream.SetCustomError(bIsRawData ? "raw data" : input, "Bad file path");
}
}
}

if (argStream.HasErrors())
{
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
}

// We failed
lua_pushboolean(luaVM, false);
return 1;
}
@@ -62,14 +62,14 @@ typedef void (*PFN_WATCH_CALLBACK)(CSHADERDUMMY* pContext, CD3DDUMMY* pD3DDataNe
class CRenderWare
{
public:
virtual bool ModelInfoTXDLoadTextures(SReplacementTextures* pReplacementTextures, const SString& strFilename, const CBuffer& fileData,
virtual bool ModelInfoTXDLoadTextures(SReplacementTextures* pReplacementTextures, const SString& strFilename, const SString& buffer,
bool bFilteringEnabled) = 0;
virtual bool ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTextures, ushort usModelId) = 0;
virtual void ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacementTextures) = 0;
virtual void ClothesAddReplacementTxd(char* pFileData, ushort usFileId) = 0;
virtual void ClothesRemoveReplacementTxd(char* pFileData) = 0;
virtual bool HasClothesReplacementChanged() = 0;
virtual RwTexDictionary* ReadTXD(const SString& strFilename, const CBuffer& fileData) = 0;
virtual RwTexDictionary* ReadTXD(const SString& strFilename, const SString& buffer) = 0;
virtual RpClump* ReadDFF(const SString& strFilename, const SString& buffer, unsigned short usModelID, bool bLoadEmbeddedCollisions) = 0;
virtual CColModel* ReadCOL(const CBuffer& fileData) = 0;
virtual void DestroyDFF(RpClump* pClump) = 0;
@@ -22,6 +22,7 @@ namespace SharedUtil
//
bool FileLoad(const SString& strFilename, std::vector<char>& buffer, int iMaxSize = INT_MAX, int iOffset = 0);
bool FileLoad(const SString& strFilename, SString& strBuffer, int iMaxSize = INT_MAX, int iOffset = 0);
bool FileLoad(std::nothrow_t, const SString& filePath, SString& outBuffer, size_t maxSize = INT_MAX, size_t offset = 0) noexcept;

//
// Save to a file

0 comments on commit d447509

Please sign in to comment.
You can’t perform that action at this time.