private static void AddToDictionary(Mesh sourceMesh, ProcessedMeshInfo pmi, Dictionary <Mesh, List <ProcessedMeshInfo> > dict)
    {
        List <ProcessedMeshInfo> lpmi;

        if (!dict.ContainsKey(sourceMesh))
        {
            lpmi             = new List <ProcessedMeshInfo>();
            dict[sourceMesh] = lpmi;
        }
        else
        {
            lpmi = dict[sourceMesh];
        }
        lpmi.Add(pmi);
    }
    private static void ProcessPrefabRowReplaceTargetPrefab(MB3_BatchPrefabBaker pb, MB3_BatchPrefabBaker.MB3_PrefabBakerRow pr, MB2_TextureBakeResults tbr, List <UnityTransform> unityTransforms, MB3_MeshBaker mb)
    {
        if (pb.LOG_LEVEL >= MB2_LogLevel.info)
        {
            Debug.Log("==== Processing Source Prefab " + pr.sourcePrefab);
        }

        GameObject srcPrefab        = pr.sourcePrefab;
        GameObject targetPrefab     = pr.resultPrefab;
        string     targetPrefabName = AssetDatabase.GetAssetPath(targetPrefab);
        GameObject prefabInstance   = GameObject.Instantiate(srcPrefab);

        Renderer[] rs = prefabInstance.GetComponentsInChildren <Renderer>();
        if (rs.Length < 1)
        {
            Debug.LogWarning("Prefab " + pr.sourcePrefab + " does not have a renderer");
            DestroyImmediate(prefabInstance);
            return;
        }

        Renderer[] sourceRenderers = prefabInstance.GetComponentsInChildren <Renderer>();

        Dictionary <Mesh, List <ProcessedMeshInfo> > processedMeshesSrcToTargetMap = new Dictionary <Mesh, List <ProcessedMeshInfo> >();

        for (int i = 0; i < sourceRenderers.Length; i++)
        {
            if (!IsGoodToBake(sourceRenderers[i], tbr))
            {
                continue;
            }

            Mesh sourceMesh = MB_Utility.GetMesh(sourceRenderers[i].gameObject);

            if (pb.LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("== Visiting renderer: " + sourceRenderers[i]);
            }
            // Try to find an existing mesh in the target that we can re-use
            Mesh      targetMeshAsset = null;
            Transform tr = FindCorrespondingTransform(prefabInstance.transform, sourceRenderers[i].transform, targetPrefab.transform);
            if (tr != null)
            {
                Mesh targMesh = MB_Utility.GetMesh(tr.gameObject);

                // Only replace target meshes if they are part of the target prefab.
                if (AssetDatabase.GetAssetPath(targMesh) == AssetDatabase.GetAssetPath(targetPrefab))
                {
                    targetMeshAsset = MB_Utility.GetMesh(tr.gameObject);
                    if (pb.LOG_LEVEL >= MB2_LogLevel.trace)
                    {
                        Debug.Log("Found correspoinding transform in target prefab: " + tr + " mesh: " + targetMeshAsset);
                    }
                }
            }

            // Check that we haven't processed this mesh already.
            List <ProcessedMeshInfo> lpmi;
            if (processedMeshesSrcToTargetMap.TryGetValue(sourceMesh, out lpmi))
            {
                Material[] srcMats = MB_Utility.GetGOMaterials(sourceRenderers[i].gameObject);
                for (int j = 0; j < lpmi.Count; j++)
                {
                    if (ComapreMaterials(srcMats, lpmi[j].srcMaterials))
                    {
                        if (pb.LOG_LEVEL >= MB2_LogLevel.trace)
                        {
                            Debug.Log("Found already processed mesh that uses the same mats");
                        }
                        targetMeshAsset = lpmi[j].targetMesh;
                        break;
                    }
                }
            }

            Material[]          sourceMaterials     = MB_Utility.GetGOMaterials(sourceRenderers[i].gameObject);
            TargetMeshTreatment targetMeshTreatment = TargetMeshTreatment.createNewMesh;
            string newMeshName = sourceMesh.name;
            if (targetMeshAsset != null)
            {
                // check if this mesh has already been processed
                processedMeshesSrcToTargetMap.TryGetValue(sourceMesh, out lpmi);
                if (lpmi != null)
                {
                    // check if this mesh uses the same materials as one of the processed meshs
                    bool       foundMatch            = false;
                    bool       targetMeshHasBeenUsed = false;
                    Material[] foundMatchMaterials   = null;
                    for (int j = 0; j < lpmi.Count; j++)
                    {
                        if (lpmi[j].targetMesh == targetMeshAsset)
                        {
                            targetMeshHasBeenUsed = true;
                        }
                        if (ComapreMaterials(sourceMaterials, lpmi[j].srcMaterials))
                        {
                            foundMatchMaterials = lpmi[j].targMaterials;
                            foundMatch          = true;
                            break;
                        }
                    }

                    if (foundMatch)
                    {
                        // If materials match then we can re-use this processed mesh don't process.
                        if (pb.LOG_LEVEL >= MB2_LogLevel.trace)
                        {
                            Debug.Log(" we can re-use this processed mesh don't process. " + targetMeshAsset);
                        }
                        targetMeshTreatment = TargetMeshTreatment.reuseMesh;
                        MB_Utility.SetMesh(sourceRenderers[i].gameObject, targetMeshAsset);
                        SetMaterials(foundMatchMaterials, sourceRenderers[i]);
                        continue;
                    }
                    else
                    {
                        if (targetMeshHasBeenUsed)
                        {
                            // we need a new target mesh with a safe different name
                            if (pb.LOG_LEVEL >= MB2_LogLevel.trace)
                            {
                                Debug.Log(" we can't re-use this processed mesh create new with different name. " + targetMeshAsset);
                            }
                            newMeshName         = GetNameForNewMesh(AssetDatabase.GetAssetPath(targetPrefab), newMeshName);
                            targetMeshTreatment = TargetMeshTreatment.createNewMesh;
                            targetMeshAsset     = null;
                        }
                        else
                        {
                            // is it safe to reuse the target mesh
                            // we need a new target mesh with a safe different name
                            if (pb.LOG_LEVEL >= MB2_LogLevel.trace)
                            {
                                Debug.Log(" we can replace this processed mesh. " + targetMeshAsset);
                            }
                            targetMeshTreatment = TargetMeshTreatment.replaceMesh;
                        }
                    }
                }
                else
                {
                    // source mesh has not been processed can reuse the target mesh
                    targetMeshTreatment = TargetMeshTreatment.replaceMesh;
                }
            }

            if (targetMeshTreatment == TargetMeshTreatment.replaceMesh)
            {
                if (pb.LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("Replace mesh " + targetMeshAsset);
                }
                EditorUtility.CopySerialized(sourceMesh, targetMeshAsset);
                AssetDatabase.SaveAssets();
                AssetDatabase.ImportAsset(targetPrefabName);
            }
            else if (targetMeshTreatment == TargetMeshTreatment.createNewMesh)
            {
                if (pb.LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("Create new mesh " + newMeshName);
                }
                targetMeshAsset      = GameObject.Instantiate <Mesh>(sourceMesh);
                targetMeshAsset.name = newMeshName;
                AssetDatabase.AddObjectToAsset(targetMeshAsset, targetPrefab);
#if UNITY_2018_3_OR_NEWER
                PrefabUtility.SavePrefabAsset(targetPrefab);
#endif
                Debug.Assert(targetMeshAsset != null);
                // need a new mesh
            }

            if (targetMeshTreatment == TargetMeshTreatment.createNewMesh || targetMeshTreatment == TargetMeshTreatment.replaceMesh)
            {
                if (ProcessMesh(sourceRenderers[i], targetMeshAsset, unityTransforms, mb))
                {
                    if (pb.LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("Done processing mesh " + targetMeshAsset + " verts " + targetMeshAsset.vertexCount);
                    }
                    ProcessedMeshInfo pmi = new ProcessedMeshInfo();
                    pmi.targetMesh    = targetMeshAsset;
                    pmi.srcMaterials  = sourceMaterials;
                    pmi.targMaterials = sourceRenderers[i].sharedMaterials;
                    AddToDictionary(sourceMesh, pmi, processedMeshesSrcToTargetMap);
                }
                else
                {
                    Debug.LogError("Error processing mesh " + targetMeshAsset);
                }
            }

            MB_Utility.SetMesh(sourceRenderers[i].gameObject, targetMeshAsset);
        }

        // TODO replace this with MBVersionEditor.ReplacePrefab I tried to do this, but when I did,
        // ProcessedMeshInfo.targetMesh becomes null, not sure what is going on there.
        GameObject obj = (GameObject)AssetDatabase.LoadAssetAtPath(targetPrefabName, typeof(GameObject));
        PrefabUtility.ReplacePrefab(prefabInstance, obj, ReplacePrefabOptions.ReplaceNameBased);
        GameObject.DestroyImmediate(prefabInstance);

        // Destroy obsolete meshes
        UnityEngine.Object[] allAssets    = AssetDatabase.LoadAllAssetsAtPath(targetPrefabName);
        HashSet <Mesh>       usedByTarget = new HashSet <Mesh>();
        foreach (List <ProcessedMeshInfo> ll in processedMeshesSrcToTargetMap.Values)
        {
            for (int i = 0; i < ll.Count; i++)
            {
                usedByTarget.Add(ll[i].targetMesh);
            }
        }
        int numDestroyed = 0;
        for (int i = 0; i < allAssets.Length; i++)
        {
            if (allAssets[i] is Mesh)
            {
                if (!usedByTarget.Contains((Mesh)allAssets[i]) && AssetDatabase.GetAssetPath(allAssets[i]) == AssetDatabase.GetAssetPath(targetPrefab))
                {
                    numDestroyed++;
                    GameObject.DestroyImmediate(allAssets[i], true);
                }
            }
        }

        if (pb.LOG_LEVEL >= MB2_LogLevel.debug)
        {
            Debug.Log("Destroyed " + numDestroyed + " meshes");
        }
        AssetDatabase.SaveAssets();
        //--------------------------
    }