501 lines
17 KiB
C#
501 lines
17 KiB
C#
|
//////////////////////////////////////////////////////
|
|||
|
// Copyright (c) BrainFailProductions
|
|||
|
//////////////////////////////////////////////////////
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEditor;
|
|||
|
using UnityEngine;
|
|||
|
using static BrainFailProductions.PolyFew.CombiningInformation;
|
|||
|
|
|||
|
namespace BrainFailProductions.PolyFew
|
|||
|
{
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class DataContainer
|
|||
|
{
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class TempGameObjectWrapper
|
|||
|
{
|
|||
|
[HideInInspector]
|
|||
|
[SerializeField]
|
|||
|
private GameObject gameObject;
|
|||
|
|
|||
|
// This is the unique Id for the current GameObject and it's children hierarchy
|
|||
|
[HideInInspector]
|
|||
|
[SerializeField]
|
|||
|
private int uniqueId;
|
|||
|
|
|||
|
private TempGameObjectWrapper(GameObject gameObject)
|
|||
|
{
|
|||
|
this.gameObject = gameObject ?? throw new ArgumentNullException(nameof(gameObject));
|
|||
|
uniqueId = gameObject.GetInstanceID();
|
|||
|
}
|
|||
|
|
|||
|
public static implicit operator GameObject(TempGameObjectWrapper gameObjectWrapper) => gameObjectWrapper.gameObject;
|
|||
|
|
|||
|
public static explicit operator TempGameObjectWrapper(GameObject gameObject) => new TempGameObjectWrapper(gameObject);
|
|||
|
|
|||
|
public override int GetHashCode()
|
|||
|
{
|
|||
|
return uniqueId;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public override bool Equals(object obj)
|
|||
|
{
|
|||
|
if ((obj == null) || !GetType().Equals(obj.GetType()))
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return (GetHashCode() == obj.GetHashCode());
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class ObjectMeshPair : SerializableDictionary<GameObject, MeshRendererPair> { }
|
|||
|
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class MeshRendererPair
|
|||
|
{
|
|||
|
public bool attachedToMeshFilter;
|
|||
|
public Mesh mesh;
|
|||
|
|
|||
|
public MeshRendererPair(bool attachedToMeshFilter, Mesh mesh)
|
|||
|
{
|
|||
|
this.attachedToMeshFilter = attachedToMeshFilter;
|
|||
|
this.mesh = mesh;
|
|||
|
}
|
|||
|
|
|||
|
public void Destruct()
|
|||
|
{
|
|||
|
if(mesh != null)
|
|||
|
{
|
|||
|
UnityEngine.Object.DestroyImmediate(mesh);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class CustomMeshActionStructure
|
|||
|
{
|
|||
|
public MeshRendererPair meshRendererPair;
|
|||
|
public GameObject gameObject;
|
|||
|
public Action action;
|
|||
|
|
|||
|
public CustomMeshActionStructure(MeshRendererPair meshRendererPair, GameObject gameObject, Action action)
|
|||
|
{
|
|||
|
this.meshRendererPair = meshRendererPair;
|
|||
|
this.gameObject = gameObject;
|
|||
|
this.action = action;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class ObjectHistory
|
|||
|
{
|
|||
|
public bool isReduceDeep;
|
|||
|
public ObjectMeshPair objectMeshPairs;
|
|||
|
|
|||
|
public ObjectHistory(bool isReduceDeep, ObjectMeshPair objectMeshPairs)
|
|||
|
{
|
|||
|
this.isReduceDeep = isReduceDeep;
|
|||
|
this.objectMeshPairs = objectMeshPairs;
|
|||
|
}
|
|||
|
|
|||
|
public void Destruct()
|
|||
|
{
|
|||
|
|
|||
|
if (objectMeshPairs == null || objectMeshPairs.Count == 0)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
foreach (var item in objectMeshPairs)
|
|||
|
{
|
|||
|
item.Value.Destruct();
|
|||
|
}
|
|||
|
|
|||
|
objectMeshPairs = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class UndoRedoOps
|
|||
|
{
|
|||
|
private const int OBJECT_HISTORY_LIMIT = 5;
|
|||
|
public GameObject gameObject;
|
|||
|
public List<ObjectHistory> undoOperations;
|
|||
|
public List<ObjectHistory> redoOperations;
|
|||
|
|
|||
|
public UndoRedoOps(GameObject gameObject, List<ObjectHistory> undoOperations, List<ObjectHistory> redoOperations)
|
|||
|
{
|
|||
|
this.gameObject = gameObject;
|
|||
|
this.undoOperations = undoOperations;
|
|||
|
this.redoOperations = redoOperations;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public void SaveRecord(bool isReduceDeep, bool isUndo, ObjectMeshPair originalMeshesClones)
|
|||
|
{
|
|||
|
|
|||
|
if (undoOperations == null)
|
|||
|
{
|
|||
|
undoOperations = new List<ObjectHistory>();
|
|||
|
}
|
|||
|
|
|||
|
if (redoOperations == null)
|
|||
|
{
|
|||
|
redoOperations = new List<ObjectHistory>();
|
|||
|
}
|
|||
|
|
|||
|
if (isUndo)
|
|||
|
{
|
|||
|
if (undoOperations.Count == OBJECT_HISTORY_LIMIT)
|
|||
|
{
|
|||
|
undoOperations[0].Destruct();
|
|||
|
undoOperations[0] = null;
|
|||
|
undoOperations.RemoveAt(0);
|
|||
|
}
|
|||
|
|
|||
|
ObjectHistory undoOperation = new ObjectHistory(isReduceDeep, originalMeshesClones);
|
|||
|
|
|||
|
undoOperations.Add(undoOperation);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
else
|
|||
|
{
|
|||
|
if (redoOperations.Count == OBJECT_HISTORY_LIMIT)
|
|||
|
{
|
|||
|
redoOperations[0].Destruct();
|
|||
|
redoOperations[0] = null;
|
|||
|
redoOperations.RemoveAt(0);
|
|||
|
}
|
|||
|
|
|||
|
ObjectHistory redoOperation = new ObjectHistory(isReduceDeep, originalMeshesClones);
|
|||
|
|
|||
|
redoOperations.Add(redoOperation);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public void ApplyUndoRedoOperation(bool isUndo)
|
|||
|
{
|
|||
|
|
|||
|
if (isUndo)
|
|||
|
{
|
|||
|
if (undoOperations == null || undoOperations.Count == 0)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
else
|
|||
|
{
|
|||
|
if (redoOperations == null || redoOperations.Count == 0)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
List<ObjectHistory> operations = isUndo ? undoOperations : redoOperations;
|
|||
|
ObjectHistory lastOp = operations[operations.Count - 1];
|
|||
|
|
|||
|
|
|||
|
if (lastOp.isReduceDeep)
|
|||
|
{
|
|||
|
if (isUndo)
|
|||
|
{
|
|||
|
//Debug.Log("Last undo operation was reduce deep ObjectMeshPair count " + lastOp.objectMeshPairs.Count);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//Debug.Log("Last redo operation was reduce deep ObjectMeshPair count " + lastOp.objectMeshPairs.Count);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
else
|
|||
|
{
|
|||
|
if (isUndo)
|
|||
|
{
|
|||
|
//Debug.Log("Last undo operation was NOT reduce deep ObjectMeshPair count " + lastOp.objectMeshPairs.Count);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//Debug.Log("Last redo operation was NOT reduce deep ObjectMeshPair count " + lastOp.objectMeshPairs.Count);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
ObjectMeshPair originalMeshesClones = new ObjectMeshPair();
|
|||
|
int totalOverwrites = lastOp.objectMeshPairs.Count;
|
|||
|
int done = 0;
|
|||
|
|
|||
|
foreach (var kvp in lastOp.objectMeshPairs)
|
|||
|
{
|
|||
|
|
|||
|
EditorUtility.DisplayProgressBar("Performing Undo/Redo", $"Reverting mesh changes to existing files {++done}/{totalOverwrites}", ((float)done / totalOverwrites));
|
|||
|
|
|||
|
MeshRendererPair meshRendererPair = kvp.Value;
|
|||
|
GameObject gameObject = kvp.Key;
|
|||
|
|
|||
|
if (gameObject == null) { continue; }
|
|||
|
if (meshRendererPair == null) { continue; }
|
|||
|
if (meshRendererPair.mesh == null) { continue; }
|
|||
|
|
|||
|
|
|||
|
if (meshRendererPair.attachedToMeshFilter)
|
|||
|
{
|
|||
|
MeshFilter filter = gameObject.GetComponent<MeshFilter>();
|
|||
|
|
|||
|
if (filter != null)
|
|||
|
{
|
|||
|
Mesh origMesh = UnityEngine.Object.Instantiate(filter.sharedMesh);
|
|||
|
MeshRendererPair originalPair = new MeshRendererPair(true, origMesh);
|
|||
|
originalMeshesClones.Add(gameObject, originalPair);
|
|||
|
|
|||
|
// Overwrites the mesh assets and keeps references intact
|
|||
|
if (UtilityServices.OverwriteAssetWith(filter.sharedMesh, meshRendererPair.mesh, true)) { }
|
|||
|
else
|
|||
|
{
|
|||
|
filter.sharedMesh.Clear();
|
|||
|
EditorUtility.CopySerialized(meshRendererPair.mesh, filter.sharedMesh);
|
|||
|
filter.sharedMesh.vertices = meshRendererPair.mesh.vertices;
|
|||
|
}
|
|||
|
|
|||
|
//meshRendererPair.Destruct();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
else
|
|||
|
{
|
|||
|
SkinnedMeshRenderer sRenderer = gameObject.GetComponent<SkinnedMeshRenderer>();
|
|||
|
|
|||
|
if (sRenderer != null)
|
|||
|
{
|
|||
|
Mesh origMesh = UnityEngine.Object.Instantiate(sRenderer.sharedMesh);
|
|||
|
MeshRendererPair originalPair = new MeshRendererPair(false, origMesh);
|
|||
|
originalMeshesClones.Add(gameObject, originalPair);
|
|||
|
|
|||
|
//sRenderer.sharedMesh.MakeSimilarToOtherMesh(meshRendererPair.mesh);
|
|||
|
|
|||
|
//sRenderer.sharedMesh.Clear();
|
|||
|
//EditorUtility.CopySerialized(meshRendererPair.mesh, sRenderer.sharedMesh);
|
|||
|
|
|||
|
//Overwrites the mesh assets and keeps references intact
|
|||
|
if (UtilityServices.OverwriteAssetWith(sRenderer.sharedMesh, meshRendererPair.mesh, true)) { }
|
|||
|
else
|
|||
|
{
|
|||
|
sRenderer.sharedMesh.Clear();
|
|||
|
EditorUtility.CopySerialized(meshRendererPair.mesh, sRenderer.sharedMesh);
|
|||
|
sRenderer.sharedMesh.vertices = meshRendererPair.mesh.vertices;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//meshRendererPair.Destruct();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SaveRecord(lastOp.isReduceDeep, !isUndo, originalMeshesClones);
|
|||
|
|
|||
|
lastOp.objectMeshPairs = null;
|
|||
|
lastOp = null;
|
|||
|
operations.RemoveAt(operations.Count - 1);
|
|||
|
|
|||
|
EditorUtility.ClearProgressBar();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public void Destruct()
|
|||
|
{
|
|||
|
if (undoOperations != null && undoOperations.Count > 0)
|
|||
|
{
|
|||
|
foreach (var operation in undoOperations)
|
|||
|
{
|
|||
|
operation.Destruct();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (redoOperations != null && redoOperations.Count > 0)
|
|||
|
{
|
|||
|
foreach (var operation in redoOperations)
|
|||
|
{
|
|||
|
operation.Destruct();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class LODLevelSettings
|
|||
|
{
|
|||
|
|
|||
|
public float reductionStrength;
|
|||
|
public float transitionHeight;
|
|||
|
public bool preserveUVFoldover;
|
|||
|
public bool preserveUVSeams;
|
|||
|
public bool preserveBorders;
|
|||
|
public bool useEdgeSort;
|
|||
|
public bool recalculateNormals;
|
|||
|
public float aggressiveness;
|
|||
|
public int maxIterations;
|
|||
|
public bool regardCurvature;
|
|||
|
public bool regardTolerance;
|
|||
|
public bool combineMeshes;
|
|||
|
public bool simplificationOptionsFoldout;
|
|||
|
public bool intensityFoldout;
|
|||
|
public List<float> sphereIntensities;
|
|||
|
|
|||
|
|
|||
|
public LODLevelSettings(float reductionStrength, float transitionHeight, bool preserveUVFoldover, bool preserveUVSeams, bool preserveBorders, bool smartLinking, bool recalculateNormals, float aggressiveness, int maxIterations, bool regardTolerance, bool regardCurvature, bool combineMeshes, List<float> preservationStrengths)
|
|||
|
{
|
|||
|
this.reductionStrength = reductionStrength;
|
|||
|
this.transitionHeight = transitionHeight;
|
|||
|
this.preserveUVFoldover = preserveUVFoldover;
|
|||
|
this.preserveUVSeams = preserveUVSeams;
|
|||
|
this.preserveBorders = preserveBorders;
|
|||
|
this.useEdgeSort = smartLinking;
|
|||
|
this.recalculateNormals = recalculateNormals;
|
|||
|
this.aggressiveness = aggressiveness;
|
|||
|
this.maxIterations = maxIterations;
|
|||
|
this.regardTolerance = regardTolerance;
|
|||
|
this.regardCurvature = regardCurvature;
|
|||
|
this.combineMeshes = combineMeshes;
|
|||
|
this.sphereIntensities = preservationStrengths;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class LODBackup
|
|||
|
{
|
|||
|
[SerializeField]
|
|||
|
private Renderer[] originalRenderers = null;
|
|||
|
[SerializeField]
|
|||
|
public GameObject lodParentObject;
|
|||
|
|
|||
|
|
|||
|
public Renderer[] OriginalRenderers
|
|||
|
{
|
|||
|
get { return originalRenderers; }
|
|||
|
set { originalRenderers = value; }
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public UndoRedoOps objectsHistory;
|
|||
|
|
|||
|
public ObjectMeshPair objectMeshPairs;
|
|||
|
|
|||
|
public List<LODLevelSettings> currentLodLevelSettings;
|
|||
|
|
|||
|
public List<ToleranceSphere> toleranceSpheres;
|
|||
|
|
|||
|
public LODBackup lodBackup;
|
|||
|
|
|||
|
|
|||
|
#region BATCH FEW DATA
|
|||
|
|
|||
|
public TextureArrayGroup textureArraysSettings;
|
|||
|
public List<MaterialProperties> materialsToRestore;
|
|||
|
public ObjectMaterialLinks lastObjMaterialLinks; // BeforeSerialization
|
|||
|
public bool relocateMaterialLinks;
|
|||
|
public bool reInitializeTempMatProps;
|
|||
|
|
|||
|
public int choiceTextureMap = 0;
|
|||
|
public int choiceDiffuseColorSpace = 0;
|
|||
|
|
|||
|
|
|||
|
public readonly string[] textureMapsChoices = new[] { "Albedo", "Metallic", "Specular", "Normal", "Height", "Occlusion", "Emission", "Detail Mask", "Detail Albedo", "Detail Normal" };
|
|||
|
//public readonly string[] compressionTypesChoices = new[] { "Uncompressed", "DXT1", "ETC2_RGB", "PVRTC_RGB4", "ASTC_RGB", "DXT1_CRUNCHED" };
|
|||
|
public readonly string[] compressionTypesChoices = new[] { "Uncompressed", "DXT1", "ETC2_RGB", "PVRTC_RGB4", "ASTC_RGB"};
|
|||
|
public readonly string[] resolutionsChoices = new[] { "32", "64", "128", "256", "512", "1024", "2048", "4096" };
|
|||
|
public readonly string[] filteringModesChoices = new[] { "Point (no filter)", "Bilinear", "Trilinear" };
|
|||
|
public readonly string[] compressionQualitiesChoices = new[] { "Low", "Medium", "High" };
|
|||
|
public readonly string[] colorSpaceChoices = new[] { "Non_Linear", "Linear" };
|
|||
|
public string batchFewSavePath = "";
|
|||
|
|
|||
|
#endregion BATCH FEW DATA
|
|||
|
|
|||
|
|
|||
|
#region ALTER TEXTURE ARRAYS
|
|||
|
|
|||
|
public List<Texture2DArray> existingTextureArrays = new List<Texture2DArray>();
|
|||
|
public bool existingTextureArraysFoldout;
|
|||
|
public int existingTextureArraysSize;
|
|||
|
public bool textureArraysPropsFoldout;
|
|||
|
public TextureArrayUserSettings existingArraysProps;
|
|||
|
public int choiceColorSpace = 0; //non linear
|
|||
|
|
|||
|
#endregion ALTER TEXTURE ARRAYS
|
|||
|
|
|||
|
|
|||
|
#region INSPECTOR DRAWER VARS
|
|||
|
|
|||
|
public bool preserveBorders;
|
|||
|
public bool preserveUVSeams;
|
|||
|
public bool preserveUVFoldover;
|
|||
|
public bool useEdgeSort = false;
|
|||
|
public bool recalculateNormals;
|
|||
|
public int maxIterations = 100;
|
|||
|
public float aggressiveness = 7;
|
|||
|
public bool regardCurvature = false;
|
|||
|
public bool considerChildren;
|
|||
|
public bool isPreservationActive;
|
|||
|
public float sphereDiameter = 0.5f;
|
|||
|
public Vector3 oldSphereScale;
|
|||
|
public float reductionStrength;
|
|||
|
public bool reductionPending;
|
|||
|
public GameObject prevFeasibleTarget;
|
|||
|
public bool runOnThreads;
|
|||
|
public int triangleCount;
|
|||
|
[SerializeField]
|
|||
|
public UnityEngine.Object lastDrawer;
|
|||
|
public bool foldoutAutoLOD;
|
|||
|
public bool foldoutBatchFew;
|
|||
|
public bool foldoutAutoLODMultiple;
|
|||
|
public Vector3 objPositionPrevFrame;
|
|||
|
public Vector3 objScalePrevFrame;
|
|||
|
public bool considerChildrenBatchFew = true;
|
|||
|
public string autoLODSavePath = "";
|
|||
|
|
|||
|
public bool foldoutAdditionalOpts;
|
|||
|
public bool generateUV2LODs;
|
|||
|
public bool copyParentStaticFlags;
|
|||
|
public bool copyParentTag;
|
|||
|
public bool copyParentLayer;
|
|||
|
public bool createAsChildren;
|
|||
|
public bool removeLODBackupComponent;
|
|||
|
public bool generateUV2batchfew;
|
|||
|
public bool removeMaterialLinksComponent;
|
|||
|
public bool clearBlendshapesComplete;
|
|||
|
public bool clearBlendshapesNormals;
|
|||
|
public bool clearBlendshapesTangents;
|
|||
|
|
|||
|
public bool isPlainSkin = false;
|
|||
|
|
|||
|
#endregion INSPECTOR DRAWER VARS
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endif
|