using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using UnityEngine.ProBuilder;
namespace UnityEditor.ProBuilder
{
///
///
/// Custom editor for ProBuilderMesh type.
///
[CustomEditor(typeof(ProBuilderMesh))]
[CanEditMultipleObjects]
sealed class ProBuilderMeshEditor : Editor
{
static class Styles
{
static bool s_Initialized;
public static GUIStyle miniButton;
public static readonly GUIContent lightmapStatic = new GUIContent("Lightmap Static", "Controls whether the geometry will be marked as Static for lightmapping purposes. When enabled, this mesh will be present in lightmap calculations.");
public static readonly GUIContent lightmapUVs = new GUIContent("Generate Lightmap UVs");
public static void Init()
{
if (s_Initialized)
return;
s_Initialized = true;
miniButton = new GUIStyle(GUI.skin.button);
miniButton.stretchHeight = false;
miniButton.stretchWidth = false;
miniButton.padding = new RectOffset(6, 6, 3, 3);
}
}
internal static event System.Action onGetFrameBoundsEvent;
ProBuilderMesh m_Mesh;
SerializedObject m_GameObjectsSerializedObject;
SerializedProperty m_UnwrapParameters;
SerializedProperty m_StaticEditorFlags;
bool m_AnyMissingLightmapUVs;
bool m_ModifyingMesh;
ProBuilderEditor editor
{
get { return ProBuilderEditor.instance; }
}
Renderer m_MeshRenderer = null;
void OnEnable()
{
if (EditorApplication.isPlayingOrWillChangePlaymode)
return;
m_Mesh = (ProBuilderMesh)target;
if (!m_Mesh)
return;
m_GameObjectsSerializedObject = new SerializedObject(serializedObject.targetObjects.Select(t => ((Component)t).gameObject).ToArray());
m_UnwrapParameters = serializedObject.FindProperty("m_UnwrapParameters");
m_StaticEditorFlags = m_GameObjectsSerializedObject.FindProperty("m_StaticEditorFlags");
m_MeshRenderer = m_Mesh.gameObject.GetComponent();
VertexManipulationTool.beforeMeshModification += OnBeginMeshModification;
VertexManipulationTool.afterMeshModification += OnFinishMeshModification;
}
void OnDisable()
{
VertexManipulationTool.beforeMeshModification -= OnBeginMeshModification;
VertexManipulationTool.afterMeshModification -= OnFinishMeshModification;
}
void OnBeginMeshModification(IEnumerable selection)
{
m_ModifyingMesh = true;
}
void OnFinishMeshModification(IEnumerable selection)
{
m_ModifyingMesh = false;
}
public override void OnInspectorGUI()
{
if (m_UnwrapParameters == null || m_StaticEditorFlags == null)
return;
Styles.Init();
if (GUILayout.Button("Open ProBuilder"))
ProBuilderEditor.MenuOpenWindow();
Vector3 bounds = m_MeshRenderer != null ? m_MeshRenderer.bounds.size : Vector3.zero;
EditorGUILayout.Vector3Field("Object Size (read only)", bounds);
#if PB_DEBUG
GUILayout.TextField(string.IsNullOrEmpty(pb.asset_guid) ? "null" : pb.asset_guid);
#endif
serializedObject.Update();
LightmapStaticSettings();
serializedObject.ApplyModifiedProperties();
#if DEVELOPER_MODE
GUILayout.Label("Compiled Mesh Information", EditorStyles.boldLabel);
if (m_Mesh != null && m_Mesh.mesh != null)
{
GUILayout.Label("Vertex Count: " + m_Mesh.mesh.vertexCount);
GUILayout.Label("Submesh Count: " + m_Mesh.mesh.subMeshCount);
}
#endif
}
void LightmapStaticSettings()
{
m_GameObjectsSerializedObject.Update();
#if UNITY_2019_2_OR_NEWER
bool lightmapStatic = (m_StaticEditorFlags.intValue & (int)StaticEditorFlags.ContributeGI) != 0;
#else
bool lightmapStatic = (m_StaticEditorFlags.intValue & (int)StaticEditorFlags.LightmapStatic) != 0;
#endif
EditorGUI.BeginChangeCheck();
lightmapStatic = EditorGUILayout.Toggle(Styles.lightmapStatic, lightmapStatic);
if (EditorGUI.EndChangeCheck())
{
#if UNITY_2019_2_OR_NEWER
SceneModeUtility.SetStaticFlags(m_GameObjectsSerializedObject.targetObjects, (int)StaticEditorFlags.ContributeGI, lightmapStatic);
#else
SceneModeUtility.SetStaticFlags(m_GameObjectsSerializedObject.targetObjects, (int)StaticEditorFlags.LightmapStatic, lightmapStatic);
#endif
}
if (lightmapStatic)
{
EditorGUILayout.PropertyField(m_UnwrapParameters, true);
if (m_UnwrapParameters.isExpanded)
{
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Reset", Styles.miniButton))
ResetUnwrapParams(m_UnwrapParameters);
if (GUILayout.Button("Apply", Styles.miniButton))
RebuildLightmapUVs();
GUILayout.EndHorizontal();
GUILayout.Space(4);
}
if (!m_ModifyingMesh)
{
m_AnyMissingLightmapUVs = targets.Any(x =>
{
if (x is ProBuilderMesh)
return !((ProBuilderMesh)x).HasArrays(MeshArrays.Texture1);
return false;
});
}
if (m_AnyMissingLightmapUVs)
{
EditorGUILayout.HelpBox("Lightmap UVs are missing, please generate Lightmap UVs.", MessageType.Warning);
if (GUILayout.Button("Generate Lightmap UVs"))
RebuildLightmapUVs();
}
}
else
{
EditorGUILayout.HelpBox("To enable generation of lightmap UVs for this Mesh, please enable the 'Lightmap Static' property.", MessageType.Info);
}
}
void RebuildLightmapUVs(bool forceRebuildAll = true)
{
foreach (var obj in targets)
{
if (obj is ProBuilderMesh)
{
var mesh = (ProBuilderMesh)obj;
#if UNITY_2019_2_OR_NEWER
if (!mesh.gameObject.HasStaticFlag(StaticEditorFlags.ContributeGI))
continue;
#else
if (!mesh.gameObject.HasStaticFlag(StaticEditorFlags.LightmapStatic))
continue;
#endif
if (forceRebuildAll || !mesh.HasArrays(MeshArrays.Texture1))
mesh.Optimize(true);
}
}
}
void ResetUnwrapParams(SerializedProperty prop)
{
var hardAngle = prop.FindPropertyRelative("m_HardAngle");
var packMargin = prop.FindPropertyRelative("m_PackMargin");
var angleError = prop.FindPropertyRelative("m_AngleError");
var areaError = prop.FindPropertyRelative("m_AreaError");
hardAngle.floatValue = UnwrapParameters.k_HardAngle;
packMargin.floatValue = UnwrapParameters.k_PackMargin;
angleError.floatValue = UnwrapParameters.k_AngleError;
areaError.floatValue = UnwrapParameters.k_AreaError;
RebuildLightmapUVs();
}
bool HasFrameBounds()
{
if (m_Mesh == null)
m_Mesh = (ProBuilderMesh)target;
return ProBuilderEditor.instance != null &&
InternalUtility.GetComponents(Selection.transforms).Sum(x => x.selectedIndexesInternal.Length) > 0;
}
Bounds OnGetFrameBounds()
{
if (!ProBuilderEditor.selectMode.IsMeshElementMode())
return m_MeshRenderer != null ? m_MeshRenderer.bounds : default(Bounds);
if (onGetFrameBoundsEvent != null)
onGetFrameBoundsEvent();
Vector3 min = Vector3.zero, max = Vector3.zero;
bool init = false;
foreach (ProBuilderMesh mesh in InternalUtility.GetComponents(Selection.transforms))
{
int[] tris = mesh.selectedIndexesInternal;
if (tris == null || tris.Length < 1)
continue;
Vector3[] verts = mesh.positionsInternal;
var trs = mesh.transform;
if (!init)
{
init = true;
min = trs.TransformPoint(verts[tris[0]]);
max = trs.TransformPoint(verts[tris[0]]);
}
for (int i = 0, c = tris.Length; i < c; i++)
{
Vector3 p = trs.TransformPoint(verts[tris[i]]);
min.x = Mathf.Min(p.x, min.x);
max.x = Mathf.Max(p.x, max.x);
min.y = Mathf.Min(p.y, min.y);
max.y = Mathf.Max(p.y, max.y);
min.z = Mathf.Min(p.z, min.z);
max.z = Mathf.Max(p.z, max.z);
}
}
return new Bounds((min + max) / 2f, max != min ? max - min : Vector3.one * .1f);
}
[MenuItem("CONTEXT/ProBuilderMesh/Open ProBuilder")]
static void OpenProBuilder()
{
ProBuilderEditor.MenuOpenWindow();
}
}
}