@@ -496,49 +496,46 @@ bool CRenderWareSA::ReplaceObjectModel(RpClump* newClump, std::uint16_t modelID)
496496 if ((newClump == reinterpret_cast <RpClump*>(currentModelInterface->pRwObject ) || DoContainTheSameGeometry (newClump, nullptr , reinterpret_cast <RpAtomic*>(currentModelInterface->pRwObject ))) && pModelInfo->IsSameModelType ())
497497 return true ;
498498
499- // We create a copy of the current interface to later call DeleteRwObject on it,
500- // so we can remove the old RwObject after setting the new one
501- // Old RwObject must be deleted after setting the new one to avoid crashes during restream
502- CBaseModelInfoSAInterface* copyCurrentModelInterface = nullptr ;
503- switch (reinterpret_cast <std::uintptr_t >(currentModelInterface->VFTBL ))
499+ // We need to make a copy here because DeleteRwObject removes atomics from our new clump
500+ RpClump* clonedClump = RpClumpClone (newClump);
501+ if (!clonedClump)
502+ return false ;
503+
504+ // Add extra reference to prevent the TXD from being unloaded after calling DeleteRwObject
505+ bool extraRefAdded = false ;
506+ if (currentModelInterface->pRwObject )
504507 {
505- case VTBL_CAtomicModelInfo:
506- {
507- copyCurrentModelInterface = new CAtomicModelInfoSAInterface ();
508- MemCpyFast (copyCurrentModelInterface, currentModelInterface, sizeof (CAtomicModelInfoSAInterface));
508+ CTxdStore_AddRef (currentModelInterface->usTextureDictionary );
509+ extraRefAdded = true ;
510+ }
509511
510- break ;
511- }
512- case VTBL_CDamageAtomicModelInfo:
513- {
514- copyCurrentModelInterface = new CDamageableModelInfoSAInterface ();
515- MemCpyFast (copyCurrentModelInterface, currentModelInterface, sizeof (CDamageableModelInfoSAInterface));
512+ // Destroy RwObject from original interface after type conversion
513+ CBaseModelInfoSAInterface* originalInterface = pModelInfo->GetOriginalInterface ();
514+ if (originalInterface && originalInterface->pRwObject )
515+ {
516+ originalInterface->DeleteRwObject ();
516517
517- break ;
518- }
519- case VTBL_CClumpModelInfo:
520- {
521- copyCurrentModelInterface = new CClumpModelInfoSAInterface ();
522- MemCpyFast (copyCurrentModelInterface, currentModelInterface, sizeof (CClumpModelInfoSAInterface));
518+ // If the originalInterface has an existing RwObject, it points to the same one as copyCurrentModelInterface
519+ currentModelInterface->pRwObject = nullptr ;
520+ }
523521
524- break ;
525- }
526- case VTBL_CTimeModelInfo:
527- {
528- copyCurrentModelInterface = new CTimeModelInfoSAInterface ();
529- MemCpyFast (copyCurrentModelInterface, currentModelInterface, sizeof (CTimeModelInfoSAInterface));
522+ // The user can convert the same model multiple times, but its original model interface is saved only once,
523+ // so we remove the RwObject and the interface created during the last conversion
524+ CBaseModelInfoSAInterface* lastConversionInterface = pModelInfo->GetLastConversionInterface ();
525+ if (lastConversionInterface)
526+ {
527+ if (lastConversionInterface->pRwObject == currentModelInterface->pRwObject )
528+ currentModelInterface->pRwObject = nullptr ;
530529
531- break ;
532- }
533- }
530+ lastConversionInterface->DeleteRwObject ();
531+ delete lastConversionInterface;
534532
535- copyCurrentModelInterface-> usNumberOfRefs = 0 ;
536- currentModelInterface-> pRwObject = nullptr ;
533+ pModelInfo-> SetLastConversionInterface ( nullptr ) ;
534+ }
537535
538- // We need to make a copy here because DeleteRwObject removes atomics from our new clump
539- RpClump* clonedClump = RpClumpClone (newClump);
540- if (!clonedClump)
541- return false ;
536+ // Destroy current (old) RwObject
537+ if (currentModelInterface->pRwObject )
538+ currentModelInterface->DeleteRwObject ();
542539
543540 // Check model type
544541 switch (pModelInfo->GetModelType ())
@@ -549,6 +546,9 @@ bool CRenderWareSA::ReplaceObjectModel(RpClump* newClump, std::uint16_t modelID)
549546 if (!atomic)
550547 return false ;
551548
549+ // Create main root frame
550+ RpAtomicSetFrame (atomic, RwFrameCreate ());
551+
552552 // Is damageable object?
553553 if (currentModelInterface->IsDamageAtomicVTBL ())
554554 {
@@ -573,6 +573,8 @@ bool CRenderWareSA::ReplaceObjectModel(RpClump* newClump, std::uint16_t modelID)
573573 else
574574 static_cast <CAtomicModelInfoSAInterface*>(damagedInfo->baseInterface )->SetAtomic (atomic);
575575
576+ // Create main root frame
577+ RpAtomicSetFrame (atomic, RwFrameCreate ());
576578 pGame->GetVisibilityPlugins ()->SetAtomicId (atomic, damagedInfo->modelId );
577579
578580 // Remove our atomic from temp clump
@@ -599,6 +601,9 @@ bool CRenderWareSA::ReplaceObjectModel(RpClump* newClump, std::uint16_t modelID)
599601 if (!atomic)
600602 return false ;
601603
604+ // Create main root frame
605+ RpAtomicSetFrame (atomic, RwFrameCreate ());
606+
602607 static_cast <CTimeModelInfoSAInterface*>(currentModelInterface)->SetAtomic (atomic);
603608 pGame->GetVisibilityPlugins ()->SetAtomicId (atomic, modelID);
604609
@@ -618,52 +623,10 @@ bool CRenderWareSA::ReplaceObjectModel(RpClump* newClump, std::uint16_t modelID)
618623 }
619624 }
620625
621- // Destroy old RwObject
622- // RwObject from original interface after type conversion
623- CBaseModelInfoSAInterface* originalInterface = pModelInfo->GetOriginalInterface ();
624- if (originalInterface && originalInterface->pRwObject )
625- {
626- originalInterface->DeleteRwObject ();
627-
628- // If the originalInterface has an existing RwObject, it points to the same one as copyCurrentModelInterface
629- copyCurrentModelInterface->pRwObject = nullptr ;
630- }
631-
632- // The user can convert the same model multiple times, but its original model interface is saved only once,
633- // so we remove the RwObject and the interface created during the last conversion
634- CBaseModelInfoSAInterface* lastConversionInterface = pModelInfo->GetLastConversionInterface ();
635- if (lastConversionInterface)
636- {
637- if (lastConversionInterface->pRwObject == copyCurrentModelInterface->pRwObject )
638- copyCurrentModelInterface->pRwObject = nullptr ;
639-
640- lastConversionInterface->DeleteRwObject ();
641- delete lastConversionInterface;
642-
643- pModelInfo->SetLastConversionInterface (nullptr );
644- }
645-
646- // Delete old RwObject (after setting the new one)
647- if (copyCurrentModelInterface)
648- {
649- // Update 2dfx counter
650- RwObject* object = copyCurrentModelInterface->pRwObject ;
651- if (object)
652- {
653- if (object->type == RP_TYPE_ATOMIC)
654- currentModelInterface->ucNumOf2DEffects -= RpGeometryGet2dFxCount (reinterpret_cast <RpAtomic*>(object)->geometry );
655- else if (object->type == RP_TYPE_CLUMP)
656- {
657- RpAtomic* atomic = Get2DEffectAtomic (reinterpret_cast <RpClump*>(object));
658- if (atomic)
659- currentModelInterface->ucNumOf2DEffects -= RpGeometryGet2dFxCount (atomic->geometry );
660- }
661- }
662-
663- copyCurrentModelInterface->DeleteRwObject ();
664- delete copyCurrentModelInterface;
665- }
666-
626+ // Remove extra ref
627+ if (extraRefAdded)
628+ CTxdStore_RemoveRef (currentModelInterface->usTextureDictionary );
629+
667630 return true ;
668631}
669632
0 commit comments