summaryrefslogtreecommitdiff
path: root/VRCSDK3Worlds/Assets/MeshBaker/Editor/MB3_BatchPrefabBakerEditor.cs
blob: b2625b792f3e5e1e387f7034d57e0878a05726e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
using UnityEngine;
using UnityEditor;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using DigitalOpus.MB.Core;
using System.Text.RegularExpressions;

namespace DigitalOpus.MB.MBEditor
{
    [CustomEditor(typeof(MB3_BatchPrefabBaker))]
    public class MB3_BatchPrefabBakerEditor : Editor
    {
        SerializedObject prefabBaker = null;

        GUIContent GUIContentLogLevelContent = new GUIContent("Log Level");
        GUIContent GUIContentBatchBakePrefabReplacePrefab = new GUIContent("Batch Bake Prefabs (Replace Prefab)",
            "This will clone the source prefab, replace the meshes in the clone with baked versions and replace the target prefab with the clone.\n\n" +
            "IF ANY CHANGES HAD BEEN MADE TO THE TARGET PREFAB, THOSE WILL BE LOST.");
        GUIContent GUIContentBatchBakePrefabOnlyMeshesAndMats = new GUIContent("Batch Bake Prefabs (Only Replace Meshes & Materials)",
            "This will attempt to match the meshes used by the target prefab to those used by the source prefab. For this to work" +
            " well, the source and target prefabs should have the same hierarchy. The meshes and materials in the target prefab will be updated to baked versions. " +
            " Modifications to the target prefab other than the meshes and materials will be preserved.\n\n" +
            "Check the console for errors after baking the prefabs.");

        SerializedProperty prefabRows, outputFolder, logLevel;

        Color buttonColor = new Color(.8f, .8f, 1f, 1f);

        [MenuItem("GameObject/Create Other/Mesh Baker/Batch Prefab Baker", false, 1000)]
        public static void CreateNewBatchPrefabBaker()
        {
            //if (MB3_MeshCombiner.EVAL_VERSION)
            //{
            //    Debug.LogError("The prefab baker is only available in the full version of MeshBaker.");
            //    return;
            //}

            MB3_TextureBaker[] mbs = (MB3_TextureBaker[])Editor.FindObjectsOfType(typeof(MB3_TextureBaker));
            // Generate unique name
            int largest = 0;
            {
                Regex regex = new Regex(@"\((\d+)\)$", RegexOptions.Compiled | RegexOptions.CultureInvariant);
                try
                {
                    for (int i = 0; i < mbs.Length; i++)
                    {
                        Match match = regex.Match(mbs[i].name);
                        if (match.Success)
                        {
                            int val = Convert.ToInt32(match.Groups[1].Value);
                            if (val >= largest)
                                largest = val + 1;
                        }
                    }
                }
                catch (Exception e)
                {
                    if (e == null) e = null; //Do nothing supress compiler warning
                }
            }

            GameObject nmb = new GameObject("BatchPrefabBaker (" + largest + ")");
            nmb.transform.position = Vector3.zero;

            MB3_BatchPrefabBaker bpb = nmb.AddComponent<MB3_BatchPrefabBaker>();
            nmb.AddComponent<MB3_TextureBaker>();
            nmb.AddComponent<MB3_MeshBaker>();
            bpb.prefabRows = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow[0];
            bpb.outputPrefabFolder = "";
        }

        void OnEnable()
        {
            prefabBaker = new SerializedObject(target);
            prefabRows = prefabBaker.FindProperty("prefabRows");
            outputFolder = prefabBaker.FindProperty("outputPrefabFolder");
            logLevel = prefabBaker.FindProperty("LOG_LEVEL");
        }

        void OnDisable()
        {
            prefabBaker = null;
        }

        public override void OnInspectorGUI()
        {
            prefabBaker.Update();

            EditorGUILayout.HelpBox(
                                    "This tool speeds up the process of preparing prefabs " +
                                    " for static and dynamic batching. It creates duplicate prefab assets and meshes " +
                                    "that share a combined material. Source assets are not touched.\n\n" +
                                    "1) Create instances of source prefabs to this scene.\n" +
                                    "2) Add these instances to the TextureBaker on this GameObject and bake the textures used by the prefabs.\n" +
                                    "2) Using the BatchPrefabBaker component click 'Populate Prefab Rows From Texture Baker' or manually set up Prefab Rows by dragging to the Prefab Rows list.\n" +
                                    "4) Choose a folder where the result prefabs will be stored and click 'Create Empty Result Prefabs'\n" +
                                    "5) click 'Batch Bake Prefabs'\n" +
                                    "6) Check the console for messages and errors\n" +
                                    "7) (Optional) If you want to compare the source objects to the result objects use the BatchPrefabBaker '...' menu command 'Create Instances For Prefab Rows'. This will create aligned instances of the prefabs in the scene so that it is easy to see any differences.\n", MessageType.Info);
            EditorGUILayout.PropertyField(logLevel, GUIContentLogLevelContent);

            EditorGUILayout.PropertyField(prefabRows, true);

            EditorGUILayout.LabelField("Output Folder", EditorStyles.boldLabel);
            EditorGUILayout.LabelField(outputFolder.stringValue);

            if (GUILayout.Button("Browse For Output Folder"))
            {
                string path = EditorUtility.OpenFolderPanel("Browse For Output Folder", "", "");
                path = MB_BatchPrefabBakerEditorFunctions.ConvertFullPathToProjectRelativePath(path);
                outputFolder.stringValue = path;
            }

            if (GUILayout.Button("Create Empty Result Prefabs"))
            {
                 MB_BatchPrefabBakerEditorFunctions.CreateEmptyOutputPrefabs(outputFolder.stringValue, (MB3_BatchPrefabBaker) target);
            }

            Color oldColor = GUI.backgroundColor;
            GUI.backgroundColor = buttonColor;
            if (GUILayout.Button(GUIContentBatchBakePrefabReplacePrefab))
            {
                MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
                MB_BatchPrefabBakerEditorFunctions.BakePrefabs(pb, true);
            }
            if (GUILayout.Button(GUIContentBatchBakePrefabOnlyMeshesAndMats))
            {
                MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
                MB_BatchPrefabBakerEditorFunctions.BakePrefabs(pb, false);
            }
            GUI.backgroundColor = oldColor;

            if (GUILayout.Button("Poplate Prefab Rows From Texture Baker"))
            {
                PopulatePrefabRowsFromTextureBaker((MB3_BatchPrefabBaker)prefabBaker.targetObject);
            }

            if (GUILayout.Button("Open Replace Prefabs In Scene Window"))
            {
                MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
                MB_ReplacePrefabsInSceneEditorWindow.ShowWindow(pb.prefabRows);
            }


            prefabBaker.ApplyModifiedProperties();
            prefabBaker.SetIsDifferentCacheDirty();
        }

        public void PopulatePrefabRowsFromTextureBaker(MB3_BatchPrefabBaker prefabBaker)
        {
            MB3_TextureBaker texBaker = prefabBaker.GetComponent<MB3_TextureBaker>();
            List<GameObject> newPrefabs = new List<GameObject>();
            List<GameObject> gos = texBaker.GetObjectsToCombine();
            for (int i = 0; i < gos.Count; i++)
            {
                GameObject go = (GameObject)PrefabUtility.FindPrefabRoot(gos[i]);
                UnityEngine.Object obj = MBVersionEditor.PrefabUtility_GetCorrespondingObjectFromSource(go);

                if (obj != null && obj is GameObject)
                {
                    if (!newPrefabs.Contains((GameObject)obj)) newPrefabs.Add((GameObject)obj);
                }
                else
                {
                    Debug.LogWarning(String.Format("Object {0} did not have a prefab", gos[i]));
                }

            }

            // Remove prefabs that are already in the list of batch prefab baker's prefabs.
            {
                List<GameObject> tmpNewPrefabs = new List<GameObject>();
                for (int i = 0; i < newPrefabs.Count; i++)
                {
                    bool found = false;
                    for (int j = 0; j < prefabBaker.prefabRows.Length; j++)
                    {
                        if (prefabBaker.prefabRows[j].sourcePrefab == newPrefabs[i])
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        tmpNewPrefabs.Add(newPrefabs[i]);
                    }
                }

                newPrefabs = tmpNewPrefabs;
            }

            if (MB3_MeshCombiner.EVAL_VERSION)
            {
                int numPrefabsLimit = MB_BatchPrefabBakerEditorFunctions.EvalVersionPrefabLimit;
                int numNew = numPrefabsLimit - prefabBaker.prefabRows.Length;
                if (newPrefabs.Count + prefabBaker.prefabRows.Length > numPrefabsLimit)
                {
                    Debug.LogError("The free version of mesh baker is limited to batch baking " + numPrefabsLimit +
                        " prefabs. The full version has no limit on the number of prefabs that can be baked. " + (newPrefabs.Count - numNew) + " prefabs were not added.");

                }

                
                for (int i = newPrefabs.Count - 1; i >= numNew; i--)
                {
                    newPrefabs.RemoveAt(i);
                }
            }

            List<MB3_BatchPrefabBaker.MB3_PrefabBakerRow> newRows = new List<MB3_BatchPrefabBaker.MB3_PrefabBakerRow>();
            if (prefabBaker.prefabRows == null) prefabBaker.prefabRows = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow[0];
            newRows.AddRange(prefabBaker.prefabRows);
            for (int i = 0; i < newPrefabs.Count; i++)
            {
                MB3_BatchPrefabBaker.MB3_PrefabBakerRow row = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow();
                row.sourcePrefab = newPrefabs[i];
                newRows.Add(row);
            }


            Undo.RecordObject(prefabBaker, "Populate prefab rows");
            prefabBaker.prefabRows = newRows.ToArray();
        }
    }
}