//////////////////////////////////////////////////////////////// // // CRenderWareSA::ModelInfoTXDRemoveTextures // // Remove the textures from the txds that are using them. // //////////////////////////////////////////////////////////////// void CRenderWareSA::ModelInfoTXDRemoveTextures ( SReplacementTextures* pReplacementTextures ) { // For each using txd for ( uint i = 0 ; i < pReplacementTextures->perTxdList.size () ; i++ ) { SReplacementTextures::SPerTxd& perTxdInfo = pReplacementTextures->perTxdList[i]; // Get textures info ushort usTxdId = perTxdInfo.usTxdId; CModelTexturesInfo* pInfo = MapFind ( ms_ModelTexturesInfoMap, usTxdId ); // Validate dassert ( MapFind ( ms_ModelTexturesInfoMap, usTxdId ) ); dassert ( ListContains ( pInfo->usedByReplacements, pReplacementTextures ) ); // Remove replacement textures for ( uint i = 0 ; i < perTxdInfo.usingTextures.size () ; i++ ) { RwTexture* pOldTexture = perTxdInfo.usingTextures[i]; RwTexDictionaryRemoveTexture ( pInfo->pTxd, pOldTexture ); dassert ( !RwTexDictionaryContainsTexture ( pInfo->pTxd, pOldTexture ) ); if ( perTxdInfo.bTexturesAreCopies ) { // Destroy the copy (but not the raster as that was not copied) pOldTexture->raster = NULL; RwTextureDestroy ( pOldTexture ); } } // Ensure there are original named textures in the txd for ( uint i = 0 ; i < pInfo->originalTextures.size () ; i++ ) { RwTexture* pOriginalTexture = pInfo->originalTextures[i]; if ( !RwTexDictionaryFindNamedTexture ( pInfo->pTxd, pOriginalTexture->name ) ) RwTexDictionaryAddTexture ( pInfo->pTxd, pOriginalTexture ); } // Remove refs ListRemove ( pInfo->usedByReplacements, pReplacementTextures ); // If no refs left, check original state and then remove info if ( pInfo->usedByReplacements.empty () ) { // txd should now contain the same textures as 'originalTextures' #ifdef MTA_DEBUG std::vector < RwTexture* > currentTextures; GetTxdTextures ( currentTextures, pInfo->pTxd ); assert ( currentTextures.size () == pInfo->originalTextures.size () ); for ( uint i = 0 ; i < pInfo->originalTextures.size () ; i++ ) { RwTexture* pOriginalTexture = pInfo->originalTextures[i]; assert ( ListContains ( currentTextures, pOriginalTexture ) ); ListRemove ( currentTextures, pOriginalTexture ); } assert ( currentTextures.empty () ); #endif // Remove info CTxdStore_RemoveRef ( pInfo->usTxdId ); MapRemove ( ms_ModelTexturesInfoMap, usTxdId ); } } // Destroy replacement textures for ( uint i = 0 ; i < pReplacementTextures->textures.size () ; i++ ) { RwTexture* pOldTexture = pReplacementTextures->textures[i]; DestroyTexture ( pOldTexture ); } pReplacementTextures->textures.clear (); }
///////////////////////////////////////////////////////////////////////////// // // CRenderWareSA::RightSizeTxd // // Check textures in a txd and shrink if required. // Returns true if shrunk file was written // ///////////////////////////////////////////////////////////////////////////// bool CRenderWareSA::RightSizeTxd( const SString& strInTxdFilename, const SString& strOutTxdFilename, uint uiSizeLimit ) { // // Read txd from memory // RwStream* pStream = RwStreamOpen( STREAM_TYPE_FILENAME, STREAM_MODE_READ, *strInTxdFilename ); if ( pStream == NULL ) return false; // Find our txd chunk if ( RwStreamFindChunk( pStream, 0x16, NULL, NULL ) == false ) { RwStreamClose( pStream, NULL ); return false; } // read the txd RwTexDictionary* pTxd = RwTexDictionaryGtaStreamRead( pStream ); RwStreamClose( pStream, NULL ); if ( !pTxd ) return false; // // Process each texture in the txd // std::vector < RwTexture* > textureList; pGame->GetRenderWareSA()->GetTxdTextures( textureList, pTxd ); bool bChanged = false; for ( std::vector < RwTexture* > ::iterator iter = textureList.begin() ; iter != textureList.end() ; iter++ ) { RwTexture* pTexture = *iter; RwTexture* pNewRwTexture = RightSizeTexture( pTexture, uiSizeLimit ); if ( pNewRwTexture && pNewRwTexture != pTexture ) { // Replace texture in txd if changed RwTextureDestroy( pTexture ); RwTexDictionaryAddTexture( pTxd, pNewRwTexture ); bChanged = true; } else { // Keep texture (Reinsert to preserve order for easier debugging) RwTexDictionaryRemoveTexture( pTxd, pTexture ); RwTexDictionaryAddTexture( pTxd, pTexture ); } } // // Save shrunked txd if changed // if ( bChanged ) { pStream = RwStreamOpen( STREAM_TYPE_FILENAME, STREAM_MODE_WRITE, *strOutTxdFilename ); if ( pStream ) { RwTexDictionaryStreamWrite( pTxd, pStream ); RwStreamClose( pStream, NULL ); RwTexDictionaryDestroy( pTxd ); return true; } } RwTexDictionaryDestroy( pTxd ); return false; }
//////////////////////////////////////////////////////////////// // // CRenderWareSA::ModelInfoTXDAddTextures // // Adds texture into the TXD of a model. // Returns true if model was affected. // //////////////////////////////////////////////////////////////// bool CRenderWareSA::ModelInfoTXDAddTextures ( SReplacementTextures* pReplacementTextures, ushort usModelId ) { // Already done for this modelid? if ( ListContains ( pReplacementTextures->usedInModelIds, usModelId ) ) return false; // Get valid textures info for this model CModelTexturesInfo* pInfo = GetModelTexturesInfo ( usModelId ); if ( !pInfo ) return false; // Remember which models this set has been applied to pReplacementTextures->usedInModelIds.push_back ( usModelId ); // Already done for this txd? if ( ListContains ( pReplacementTextures->usedInTxdIds, pInfo->usTxdId ) ) return true; // Return true as model may need restreaming // // Add section for this txd // pReplacementTextures->perTxdList.push_back ( SReplacementTextures::SPerTxd () ); SReplacementTextures::SPerTxd& perTxdInfo = pReplacementTextures->perTxdList.back (); perTxdInfo.usTxdId = pInfo->usTxdId; perTxdInfo.bTexturesAreCopies = ( pReplacementTextures->usedInTxdIds.size () > 0 ); // Copy / clone textures for ( std::vector < RwTexture* >::iterator iter = pReplacementTextures->textures.begin () ; iter != pReplacementTextures->textures.end () ; iter++ ) { RwTexture* pNewTexture = *iter; // Use a copy if not first txd if ( perTxdInfo.bTexturesAreCopies ) { // Reuse the given texture's raster RwTexture* pCopyTex = RwTextureCreate ( pNewTexture->raster ); // Copy over additional properties MemCpyFast ( &pCopyTex->name, &pNewTexture->name, RW_TEXTURE_NAME_LENGTH ); MemCpyFast ( &pCopyTex->mask, &pNewTexture->mask, RW_TEXTURE_NAME_LENGTH ); pCopyTex->flags = pNewTexture->flags; pNewTexture = pCopyTex; } perTxdInfo.usingTextures.push_back ( pNewTexture ); } // // Add each texture to the target txd // for ( std::vector < RwTexture* >::iterator iter = perTxdInfo.usingTextures.begin () ; iter != perTxdInfo.usingTextures.end () ; iter++ ) { RwTexture* pNewTexture = *iter; // If there is a name clash with an existing texture, replace it RwTexture* pExistingTexture = RwTexDictionaryFindNamedTexture ( pInfo->pTxd, pNewTexture->name ); if ( pExistingTexture ) { RwTexDictionaryRemoveTexture ( pInfo->pTxd, pExistingTexture ); } // Add the texture dassert ( !RwTexDictionaryContainsTexture ( pInfo->pTxd, pNewTexture ) ); RwTexDictionaryAddTexture ( pInfo->pTxd, pNewTexture ); } // Remember which txds this set has been applied to pReplacementTextures->usedInTxdIds.push_back ( pInfo->usTxdId ); dassert ( !ListContains ( pInfo->usedByReplacements, pReplacementTextures ) ); pInfo->usedByReplacements.push_back ( pReplacementTextures ); return true; }