using UnityEngine; using UnityEngine.Assertions; using UnityEditor; using UnityEditorInternal; using System; using System.IO; using System.Linq; using System.Collections; using System.Collections.Generic; #if UNITY_2018_3_OR_NEWER using UnityEditor.Experimental.SceneManagement; #endif namespace VoxelImporter { public abstract class VoxelBaseEditor : EditorCommon { public VoxelBase baseTarget { get; protected set; } public VoxelBaseCore baseCore { get; protected set; } protected ReorderableList materialList; protected VoxelEditorCommon editorCommon; protected bool drawEditorMesh = true; protected DataTable3 editVoxelList = new DataTable3(); protected VoxelData voxleDataBefore = null; protected static Rect editorConfigureEditorWindowRect = new Rect(8, 17 + 8, 0, 0); #region GUIStyle protected GUIStyle guiStyleMagentaBold; protected GUIStyle guiStyleRedBold; protected GUIStyle guiStyleFoldoutBold; protected GUIStyle guiStyleBoldActiveButton; protected GUIStyle guiStyleDropDown; protected GUIStyle guiStyleLabelMiddleLeftItalic; protected GUIStyle guiStyleTextFieldMiddleLeft; protected GUIStyle guiStyleEditorWindow; #endregion #region strings public static readonly string[] Edit_ConfigureMaterialMainModeString = { VoxelBase.Edit_ConfigureMaterialMainMode.Add.ToString(), VoxelBase.Edit_ConfigureMaterialMainMode.Remove.ToString(), }; public static readonly string[] Edit_ConfigureMaterialSubModeString = { VoxelBase.Edit_ConfigureMaterialSubMode.Voxel.ToString(), VoxelBase.Edit_ConfigureMaterialSubMode.Fill.ToString(), VoxelBase.Edit_ConfigureMaterialSubMode.Rect.ToString(), }; public static readonly string[] Edit_ConfigureDisableMainModeString = { VoxelBase.Edit_ConfigureDisableMainMode.Add.ToString(), VoxelBase.Edit_ConfigureDisableMainMode.Remove.ToString(), }; public static readonly string[] Edit_ConfigureDisableSubModeString = { VoxelBase.Edit_ConfigureDisableSubMode.Face.ToString(), VoxelBase.Edit_ConfigureDisableSubMode.Fill.ToString(), VoxelBase.Edit_ConfigureDisableSubMode.Rect.ToString(), }; public static readonly string[] Edit_AdvancedModeStrings = { "Simple", "Advanced", }; #endregion #region Prefab #if UNITY_2018_3_OR_NEWER protected PrefabAssetType prefabType { get { return PrefabUtility.GetPrefabAssetType(baseTarget.gameObject); } } protected bool prefabEnable { get { return prefabType == PrefabAssetType.Regular || isPrefabEditMode; } } protected bool isPrefab { get { return false; } } protected bool isPrefabEditMode { get { return PrefabStageUtility.GetCurrentPrefabStage() != null && PrefabStageUtility.GetCurrentPrefabStage().prefabContentsRoot != null; } } #else protected PrefabType prefabType { get { return PrefabUtility.GetPrefabType(baseTarget.gameObject); } } protected bool prefabEnable { get { var type = prefabType; return type == PrefabType.Prefab || type == PrefabType.PrefabInstance || type == PrefabType.DisconnectedPrefabInstance; } } protected bool isPrefab { get { return prefabType == PrefabType.Prefab; } } #endif #endregion protected virtual void OnEnable() { baseTarget = target as VoxelBase; if (baseTarget == null) return; PrefabUtility.prefabInstanceUpdated -= EditorPrefabInstanceUpdated; PrefabUtility.prefabInstanceUpdated += EditorPrefabInstanceUpdated; Undo.undoRedoPerformed -= EditorUndoRedoPerformed; Undo.undoRedoPerformed += EditorUndoRedoPerformed; } protected virtual void OnDisable() { if (baseTarget == null) return; AfterRefresh(); EditEnableMeshDestroy(); baseCore.SetSelectedWireframeHidden(false); #if !UNITY_2018_3_OR_NEWER if (isPrefab) { baseTarget.voxelData = null; } #endif PrefabUtility.prefabInstanceUpdated -= EditorPrefabInstanceUpdated; Undo.undoRedoPerformed -= EditorUndoRedoPerformed; } protected virtual void OnDestroy() { OnDisable(); } protected virtual void OnEnableInitializeSet() { baseCore.Initialize(); editorCommon = new VoxelEditorCommon(baseTarget, baseCore); UpdateMaterialList(); UpdateConfigureEnableMesh(); } protected virtual void GUIStyleReady() { //Styles if (guiStyleMagentaBold == null) guiStyleMagentaBold = new GUIStyle(EditorStyles.boldLabel); guiStyleMagentaBold.normal.textColor = Color.magenta; if (guiStyleRedBold == null) guiStyleRedBold = new GUIStyle(EditorStyles.boldLabel); guiStyleRedBold.normal.textColor = Color.red; if (guiStyleFoldoutBold == null) guiStyleFoldoutBold = new GUIStyle(EditorStyles.foldout); guiStyleFoldoutBold.fontStyle = FontStyle.Bold; if (guiStyleBoldActiveButton == null) guiStyleBoldActiveButton = new GUIStyle(GUI.skin.button); guiStyleBoldActiveButton.normal = guiStyleBoldActiveButton.active; if (guiStyleDropDown == null) guiStyleDropDown = new GUIStyle("DropDown"); guiStyleDropDown.alignment = TextAnchor.MiddleCenter; if (guiStyleLabelMiddleLeftItalic == null) guiStyleLabelMiddleLeftItalic = new GUIStyle(EditorStyles.label); guiStyleLabelMiddleLeftItalic.alignment = TextAnchor.MiddleLeft; guiStyleLabelMiddleLeftItalic.fontStyle = FontStyle.Italic; if (guiStyleTextFieldMiddleLeft == null) guiStyleTextFieldMiddleLeft = new GUIStyle(EditorStyles.textField); guiStyleTextFieldMiddleLeft.alignment = TextAnchor.MiddleLeft; if (guiStyleEditorWindow == null) { guiStyleEditorWindow = new GUIStyle(EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).window); } } public override void OnInspectorGUI() { if (baseTarget == null || editorCommon == null) { DrawDefaultInspector(); return; } baseCore.AutoSetSelectedWireframeHidden(); serializedObject.Update(); InspectorGUI(); serializedObject.ApplyModifiedProperties(); } protected virtual void InspectorGUI() { #if UNITY_2018_3_OR_NEWER { if (prefabType == PrefabAssetType.Regular && !isPrefabEditMode) { EditorGUILayout.HelpBox("Prefab can only be edited in Prefab mode.", MessageType.Info); } } #endif GUIStyleReady(); editorCommon.GUIStyleReady(); if (baseTarget.voxelData != voxleDataBefore) { UpdateMaterialList(); voxleDataBefore = baseTarget.voxelData; } #region Simple { EditorGUI.BeginChangeCheck(); var mode = GUILayout.Toolbar(baseTarget.advancedMode ? 1 : 0, Edit_AdvancedModeStrings); if (EditorGUI.EndChangeCheck()) { baseTarget.advancedMode = mode != 0 ? true : false; } } #endregion } protected void InspectorGUI_Import() { Event e = Event.current; baseTarget.edit_importFoldout = EditorGUILayout.Foldout(baseTarget.edit_importFoldout, "Import", guiStyleFoldoutBold); if (baseTarget.edit_importFoldout) { EditorGUI.BeginDisabledGroup(isPrefab); EditorGUILayout.BeginHorizontal(GUI.skin.box); EditorGUILayout.BeginVertical(); #region Voxel File { bool fileExists = baseCore.IsVoxelFileExists(); { EditorGUILayout.BeginHorizontal(); if (string.IsNullOrEmpty(baseTarget.voxelFilePath)) EditorGUILayout.LabelField("Voxel File", guiStyleMagentaBold); else if (!fileExists) EditorGUILayout.LabelField("Voxel File", guiStyleRedBold); else EditorGUILayout.LabelField("Voxel File", EditorStyles.boldLabel); Action OpenFile = (path, obj) => { if (!baseCore.IsEnableFile(path)) return; if (obj == null && path.Contains(Application.dataPath)) { var assetPath = path.Replace(Application.dataPath, "Assets"); obj = UnityEditor.AssetDatabase.LoadAssetAtPath(assetPath); } UndoRecordObject("Open Voxel File", true); baseCore.Reset(path, obj); baseCore.Create(path, obj); UpdateMaterialList(); }; var rect = GUILayoutUtility.GetRect(new GUIContent("Open"), guiStyleDropDown, GUILayout.Width(64)); if (GUI.Button(rect, "Open", guiStyleDropDown)) { InspectorGUI_ImportOpenBefore(); GenericMenu menu = new GenericMenu(); #region vox menu.AddItem(new GUIContent("MagicaVoxel (*.vox)"), false, () => { var path = EditorUtility.OpenFilePanel("Open MagicaVoxel File", !string.IsNullOrEmpty(baseTarget.voxelFilePath) ? Path.GetDirectoryName(baseTarget.voxelFilePath) : "", "vox"); if (!string.IsNullOrEmpty(path)) { OpenFile(path, null); } }); #endregion #region qb menu.AddItem(new GUIContent("Qubicle Binary (*.qb)"), false, () => { var path = EditorUtility.OpenFilePanel("Open Qubicle Binary File", !string.IsNullOrEmpty(baseTarget.voxelFilePath) ? Path.GetDirectoryName(baseTarget.voxelFilePath) : "", "qb"); if (!string.IsNullOrEmpty(path)) { OpenFile(path, null); } }); #endregion #region png menu.AddItem(new GUIContent("Pixel Art (*.png)"), false, () => { var path = EditorUtility.OpenFilePanel("Open Pixel Art File", !string.IsNullOrEmpty(baseTarget.voxelFilePath) ? Path.GetDirectoryName(baseTarget.voxelFilePath) : "", "png"); if (!string.IsNullOrEmpty(path)) { OpenFile(path, null); } }); #endregion menu.ShowAsContext(); } #region Drag&Drop { switch (e.type) { case EventType.DragUpdated: case EventType.DragPerform: if (!rect.Contains(e.mousePosition)) break; if (DragAndDrop.paths.Length != 1) break; DragAndDrop.AcceptDrag(); DragAndDrop.visualMode = DragAndDropVisualMode.Generic; if (e.type == EventType.DragPerform) { string path = DragAndDrop.paths[0]; if (Path.GetPathRoot(path) == "") path = Application.dataPath + DragAndDrop.paths[0].Remove(0, "Assets".Length); OpenFile(path, DragAndDrop.objectReferences.Length > 0 ? DragAndDrop.objectReferences[0] : null); e.Use(); } break; } } #endregion EditorGUILayout.EndHorizontal(); } EditorGUI.indentLevel++; { EditorGUILayout.BeginHorizontal(); if (fileExists) { if (baseTarget.voxelFileObject == null) { EditorGUILayout.LabelField(Path.GetFileName(baseTarget.voxelFilePath)); } else { EditorGUI.BeginChangeCheck(); var obj = EditorGUILayout.ObjectField(baseTarget.voxelFileObject, typeof(UnityEngine.Object), false); if (EditorGUI.EndChangeCheck()) { var path = Application.dataPath + AssetDatabase.GetAssetPath(obj).Remove(0, "Assets".Length); if (baseCore.IsEnableFile(path)) { UndoRecordObject("Open Voxel File", true); baseCore.Reset(path, obj); baseCore.Create(path, obj); UpdateMaterialList(); } } } if (baseTarget.advancedMode) { EditorGUILayout.LabelField(baseTarget.voxelData != null ? "Loaded" : "Unloaded", GUILayout.Width(80)); if (baseTarget.voxelData == null) { if (GUILayout.Button("Load", GUILayout.Width(54), GUILayout.Height(16))) { baseCore.ReadyVoxelData(); } } else { if (GUILayout.Button("UnLoad", GUILayout.Width(54), GUILayout.Height(16))) { baseTarget.voxelData = null; } } } } else { EditorGUILayout.HelpBox("Voxel file not found. Please open file.", MessageType.Error); } EditorGUILayout.EndHorizontal(); } EditorGUI.indentLevel--; } #endregion #region Settings { EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel); EditorGUI.indentLevel++; { if (baseTarget.advancedMode) { #region LegacyVoxImport if (baseTarget.fileType == VoxelBase.FileType.vox) { EditorGUI.BeginChangeCheck(); var legacyVoxImport = EditorGUILayout.Toggle(new GUIContent("Legacy Vox Import", "Import with legacy behavior up to Version 1.1.2.\nMultiple objects do not correspond.\nIt is deprecated for future use.\nThis is left for compatibility."), baseTarget.legacyVoxImport); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector", true); baseTarget.legacyVoxImport = legacyVoxImport; baseCore.ReadyVoxelData(true); Refresh(); } } #endregion #region Import Mode { EditorGUI.BeginChangeCheck(); var importMode = (VoxelObject.ImportMode)EditorGUILayout.EnumPopup("Import Mode", baseTarget.importMode); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.importMode = importMode; Refresh(); } } #endregion #region Import Flag { EditorGUI.BeginChangeCheck(); #if UNITY_2017_3_OR_NEWER var importFlags = (VoxelObject.ImportFlag)EditorGUILayout.EnumFlagsField("Import Flag", baseTarget.importFlags); #else var importFlags = (VoxelObject.ImportFlag)EditorGUILayout.EnumMaskField("Import Flag", baseTarget.importFlags); #endif if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector", true); baseTarget.importFlags = importFlags; baseCore.ReadyVoxelData(true); Refresh(); } } #endregion } #region Import Scale { InspectorGUI_ImportSettingsImportScale(); } #endregion #region Import Offset { EditorGUILayout.BeginHorizontal(); { InspectorGUI_ImportSettingsImportOffset(); } { if (GUILayout.Button("Set", guiStyleDropDown, GUILayout.Width(40), GUILayout.Height(14))) { GenericMenu menu = new GenericMenu(); #region Reset menu.AddItem(new GUIContent("Reset"), false, () => { UndoRecordObject("Inspector", true); baseTarget.importOffset = Vector3.zero; Refresh(); }); #endregion #region Center menu.AddItem(new GUIContent("Center"), false, () => { UndoRecordObject("Inspector", true); baseTarget.importOffset = Vector3.zero; baseTarget.importOffset = -baseCore.GetVoxelsCenter(); Refresh(); }); #endregion InspectorGUI_ImportOffsetSetExtra(menu); menu.ShowAsContext(); } } EditorGUILayout.EndHorizontal(); } #endregion if (baseTarget.advancedMode) { InspectorGUI_ConfigureDisable(); } InspectorGUI_ImportSettingsExtra(); } EditorGUI.indentLevel--; } #endregion #region Optimize if (baseTarget.advancedMode) { EditorGUILayout.LabelField("Optimize", EditorStyles.boldLabel); EditorGUI.indentLevel++; { #region combineFaces { EditorGUI.BeginChangeCheck(); var combineFaces = EditorGUILayout.Toggle("Combine Voxel Faces", baseTarget.combineFaces); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.combineFaces = combineFaces; Refresh(); } } #endregion #region Ignore the cavity { EditorGUI.BeginChangeCheck(); var ignoreCavity = EditorGUILayout.Toggle("Ignore Cavity", baseTarget.ignoreCavity); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.ignoreCavity = ignoreCavity; Refresh(); } } #endregion } EditorGUI.indentLevel--; } #endregion #region Output if (baseTarget.advancedMode) { EditorGUILayout.LabelField("Output", EditorStyles.boldLabel); EditorGUI.indentLevel++; { EditorGUILayout.BeginHorizontal(); EditorGUI.BeginDisabledGroup(true); EditorGUILayout.ObjectField(new GUIContent("Voxel Structure", "Save the structure information."), baseTarget.voxelStructure, typeof(VoxelStructure), false); EditorGUI.EndDisabledGroup(); if (baseTarget.voxelStructure == null) { if (GUILayout.Button("Save", GUILayout.Width(48), GUILayout.Height(16))) { #region Save UndoRecordObject("Inspector"); string path = EditorUtility.SaveFilePanel("Save as", baseCore.GetDefaultPath(), string.Format("{0}.asset", Path.GetFileNameWithoutExtension(baseTarget.voxelFilePath)), "asset"); if (!string.IsNullOrEmpty(path)) { if (path.IndexOf(Application.dataPath) < 0) { SaveInsideAssetsFolderDisplayDialog(); } else { path = path.Replace(Application.dataPath, "Assets"); baseTarget.voxelStructure = ScriptableObject.CreateInstance(); baseTarget.voxelStructure.Set(baseCore.voxelData); AssetDatabase.CreateAsset(baseTarget.voxelStructure, path); } } #endregion } } else { if (GUILayout.Button("Reset", GUILayout.Width(48), GUILayout.Height(16))) { #region Reset UndoRecordObject("Inspector"); baseTarget.voxelStructure = null; #endregion } } EditorGUILayout.EndHorizontal(); } EditorGUI.indentLevel--; } #endregion EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); EditorGUI.EndDisabledGroup(); } } protected virtual void UndoRecordObject(string text, bool reset = false) { if (baseTarget != null) Undo.RecordObject(baseTarget, text); } protected virtual void InspectorGUI_ImportOpenBefore() { } protected void InspectorGUI_ImportSettingsImportScale() { EditorGUILayout.BeginHorizontal(); InspectorGUI_ImportSettingsImportScaleVector(); if (GUILayout.Button("Set", guiStyleDropDown, GUILayout.Width(40), GUILayout.Height(14))) { GenericMenu menu = new GenericMenu(); #region Division { int[] ScaleTemplate = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, }; foreach (var value in ScaleTemplate) { menu.AddItem(new GUIContent(string.Format("Division/{0}", value)), false, () => { var tmp = 1f / (float)value; InspectorGUI_ImportSettingsImportScale_Set(new Vector3(tmp, tmp, tmp)); }); } } #endregion #region Template { float[] ScaleTemplate = { 1f, 0.75f, 0.5f, 0.25f, 0.1f, 0.075f, 0.05f, 0.025f, 0.001f, 0.0075f, 0.005f, 0.0025f, 0.0001f, }; foreach (var value in ScaleTemplate) { menu.AddItem(new GUIContent(string.Format("Template/{0}", value)), false, () => { InspectorGUI_ImportSettingsImportScale_Set(new Vector3(value, value, value)); }); } } #endregion menu.AddSeparator(""); #region Default value { menu.AddItem(new GUIContent("Default value/Save to default value"), false, () => { EditorPrefs.SetFloat("VoxelImporter_DefaultScaleX", baseTarget.importScale.x); EditorPrefs.SetFloat("VoxelImporter_DefaultScaleY", baseTarget.importScale.y); EditorPrefs.SetFloat("VoxelImporter_DefaultScaleZ", baseTarget.importScale.z); }); menu.AddItem(new GUIContent("Default value/Load from default value"), false, () => { var x = EditorPrefs.GetFloat("VoxelImporter_DefaultScaleX", 1f); var y = EditorPrefs.GetFloat("VoxelImporter_DefaultScaleY", 1f); var z = EditorPrefs.GetFloat("VoxelImporter_DefaultScaleZ", 1f); InspectorGUI_ImportSettingsImportScale_Set(new Vector3(x, y, z)); }); } #endregion menu.ShowAsContext(); } EditorGUILayout.EndHorizontal(); } protected virtual void InspectorGUI_ImportSettingsImportScaleVector() { EditorGUI.BeginChangeCheck(); var importScale = EditorGUILayout.Vector3Field("Import Scale", baseTarget.importScale); if (EditorGUI.EndChangeCheck()) { InspectorGUI_ImportSettingsImportScale_Set(importScale); } } protected virtual void InspectorGUI_ImportSettingsImportScale_Set(Vector3 scale) { UndoRecordObject("Inspector", true); baseTarget.importScale = scale; Refresh(); } protected virtual void InspectorGUI_ImportSettingsImportOffset() { EditorGUI.BeginChangeCheck(); var importOffset = EditorGUILayout.Vector3Field("Import Offset", baseTarget.importOffset); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector", true); baseTarget.importOffset = importOffset; Refresh(); } } protected virtual void InspectorGUI_ImportSettingsExtra() { } protected virtual void InspectorGUI_ImportOffsetSetExtra(GenericMenu menu) { } protected virtual void InspectorGUI_Object_Mesh_Settings() { #region Generate Lightmap UVs { EditorGUI.BeginChangeCheck(); var generateLightmapUVs = EditorGUILayout.Toggle(new GUIContent("Generate Lightmap UVs", "Generate lightmap UVs into UV2."), baseTarget.generateLightmapUVs); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.generateLightmapUVs = generateLightmapUVs; Refresh(); } if (baseTarget.generateLightmapUVs) { EditorGUI.indentLevel++; baseTarget.edit_generateLightmapUVsAdvancedFoldout = EditorGUILayout.Foldout(baseTarget.edit_generateLightmapUVsAdvancedFoldout, new GUIContent("Advanced")); if (baseTarget.edit_generateLightmapUVsAdvancedFoldout) { { EditorGUI.BeginChangeCheck(); var hardAngle = EditorGUILayout.Slider(new GUIContent("Hard Angle", "Angle between neighbor triangles that will generate seam."), baseTarget.generateLightmapUVsHardAngle, 0f, 180f); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.generateLightmapUVsHardAngle = Mathf.Round(hardAngle); Refresh(); } } { EditorGUI.BeginChangeCheck(); var packMargin = EditorGUILayout.Slider(new GUIContent("Pack Margin", "Measured in pixels, assuming mesh will cover an entire 1024x1024 lightmap."), baseTarget.generateLightmapUVsPackMargin, 1f, 64f); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.generateLightmapUVsPackMargin = Mathf.Round(packMargin); Refresh(); } } { EditorGUI.BeginChangeCheck(); var angleError = EditorGUILayout.Slider(new GUIContent("Angle Error", "Measured in percents. Angle error measures deviation of UV angles from geometry angles. Area error measures deviation of UV triangles area from geometry triangles if they were uniformly scaled."), baseTarget.generateLightmapUVsAngleError, 1f, 75f); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.generateLightmapUVsAngleError = Mathf.Round(angleError); Refresh(); } } { EditorGUI.BeginChangeCheck(); var areaError = EditorGUILayout.Slider(new GUIContent("Area Error"), baseTarget.generateLightmapUVsAreaError, 1f, 75f); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.generateLightmapUVsAreaError = Mathf.Round(areaError); Refresh(); } } } EditorGUI.indentLevel--; } } #endregion #region Generate Tangents { EditorGUI.BeginChangeCheck(); var generateTangents = EditorGUILayout.Toggle(new GUIContent("Generate Tangents", "Generate Tangents."), baseTarget.generateTangents); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.generateTangents = generateTangents; Refresh(); } } #endregion #region meshFaceVertexOffset { EditorGUI.BeginChangeCheck(); var value = EditorGUILayout.Slider(new GUIContent("Vertex Offset", "Increase this value if flickering of polygon gaps occurs at low resolution."), baseTarget.meshFaceVertexOffset, 0f, 0.01f); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.meshFaceVertexOffset = value; Refresh(); } } #endregion } protected virtual void InspectorGUI_Refresh() { if (GUILayout.Button("Refresh")) { UndoRecordObject("Inspector"); Refresh(); } } protected void InspectorGUI_ConfigureDisable() { if (baseTarget.disableData != null) { EditorGUI.BeginDisabledGroup(isPrefab); EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); if (GUILayout.Button("Configure Disable Face", baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable ? guiStyleBoldActiveButton : GUI.skin.button)) { UndoRecordObject("Configure Disable Face"); if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable) { baseTarget.edit_configureMode = VoxelBase.Edit_ConfigureMode.None; AfterRefresh(); } else { baseTarget.edit_configureMode = VoxelBase.Edit_ConfigureMode.Disable; UpdateConfigureEnableMesh(); editorConfigureEditorWindowRect.width = editorConfigureEditorWindowRect.height = 0; } InternalEditorUtility.RepaintAllViews(); } EditorGUILayout.Space(); EditorGUILayout.EndHorizontal(); EditorGUI.EndDisabledGroup(); EditorGUILayout.Space(); } else if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable) { baseTarget.edit_configureMode = VoxelBase.Edit_ConfigureMode.None; AfterRefresh(); } } protected void InspectorGUI_ConfigureMaterial() { if (baseTarget.materialData != null && baseTarget.materialData.Count > 1 && !baseTarget.loadFromVoxelFile) { EditorGUI.BeginDisabledGroup(isPrefab); EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); if (GUILayout.Button("Configure Material", baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material ? guiStyleBoldActiveButton : GUI.skin.button)) { UndoRecordObject("Configure Material"); if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material) { baseTarget.edit_configureMode = VoxelBase.Edit_ConfigureMode.None; AfterRefresh(); } else { baseTarget.edit_configureMode = VoxelBase.Edit_ConfigureMode.Material; UpdateConfigureEnableMesh(); editorConfigureEditorWindowRect.width = editorConfigureEditorWindowRect.height = 0; } InternalEditorUtility.RepaintAllViews(); } EditorGUILayout.Space(); EditorGUILayout.EndHorizontal(); EditorGUI.EndDisabledGroup(); EditorGUILayout.Space(); } else if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material) { baseTarget.edit_configureMode = VoxelBase.Edit_ConfigureMode.None; AfterRefresh(); } } protected virtual void OnSceneGUI() { if (baseTarget == null || editorCommon == null) return; GUIStyleReady(); editorCommon.GUIStyleReady(); Event e = Event.current; bool repaint = false; #region Configure Material if (baseTarget.edit_configureMode != VoxelBase.Edit_ConfigureMode.None) { if (SceneView.currentDrawingSceneView == SceneView.lastActiveSceneView) { if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material) { #region Material Editor if (baseTarget.materialData != null && materialList != null && baseTarget.edit_configureMaterialIndex > 0 && baseTarget.edit_configureMaterialIndex < baseTarget.materialData.Count) { editorConfigureEditorWindowRect = GUILayout.Window(EditorGUIUtility.GetControlID(FocusType.Passive, editorConfigureEditorWindowRect), editorConfigureEditorWindowRect, (id) => { #region MainMode { EditorGUI.BeginChangeCheck(); var edit_configureMaterialMainMode = (VoxelBase.Edit_ConfigureMaterialMainMode)GUILayout.Toolbar((int)baseTarget.edit_configureMaterialMainMode, Edit_ConfigureMaterialMainModeString); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(baseTarget, "Main Mode"); baseTarget.edit_configureMaterialMainMode = edit_configureMaterialMainMode; ShowNotification(); } } #endregion #region SubMode { EditorGUI.BeginChangeCheck(); var edit_configureMaterialSubMode = (VoxelBase.Edit_ConfigureMaterialSubMode)GUILayout.Toolbar((int)baseTarget.edit_configureMaterialSubMode, Edit_ConfigureMaterialSubModeString); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(baseTarget, "Sub Mode"); baseTarget.edit_configureMaterialSubMode = edit_configureMaterialSubMode; ShowNotification(); } } #endregion #region Transparent { EditorGUI.BeginChangeCheck(); var transparent = EditorGUILayout.Toggle("Transparent", baseTarget.materialData[baseTarget.edit_configureMaterialIndex].transparent); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(baseTarget, "Transparent"); baseTarget.materialData[baseTarget.edit_configureMaterialIndex].transparent = transparent; baseTarget.edit_afterRefresh = true; } } #endregion #region Clear { if (GUILayout.Button("Clear")) { Undo.RecordObject(baseTarget, "Clear"); baseTarget.materialData[baseTarget.edit_configureMaterialIndex].ClearMaterial(); UpdateConfigureEnableMesh(); baseTarget.edit_afterRefresh = true; } } #endregion #region PreviewMode { EditorGUI.BeginChangeCheck(); var edit_ConfigurePreviewMode = (VoxelBase.Edit_ConfigurePreviewMode)EditorGUILayout.EnumPopup("Preview", baseTarget.edit_ConfigurePreviewMode); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(baseTarget, "Preview Mode"); baseTarget.edit_ConfigurePreviewMode = edit_ConfigurePreviewMode; } } #endregion #region Help if (!baseTarget.edit_helpEnable) { #region "?" { EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); if (GUILayout.Button("?", baseTarget.edit_helpEnable ? editorCommon.guiStyleActiveButton : GUI.skin.button, GUILayout.Width(16))) { Undo.RecordObject(baseTarget, "Help Enable"); baseTarget.edit_helpEnable = !baseTarget.edit_helpEnable; } EditorGUILayout.EndHorizontal(); } #endregion } else { EditorGUI.BeginChangeCheck(); baseTarget.edit_helpEnable = EditorGUILayout.Foldout(baseTarget.edit_helpEnable, "Help"); if (EditorGUI.EndChangeCheck()) { editorConfigureEditorWindowRect.width = editorConfigureEditorWindowRect.height = 0; } EditorGUILayout.BeginVertical(GUI.skin.box); EditorGUILayout.LabelField("F5 Key - Refresh"); EditorGUILayout.LabelField("Press Space Key - Hide Preview"); EditorGUILayout.EndVertical(); } #endregion GUI.DragWindow(); }, "Material Editor", guiStyleEditorWindow); editorConfigureEditorWindowRect = editorCommon.ResizeSceneViewRect(editorConfigureEditorWindowRect); } #endregion } else if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable) { #region Disable Editor if (baseTarget.disableData != null) { editorConfigureEditorWindowRect = GUILayout.Window(EditorGUIUtility.GetControlID(FocusType.Passive, editorConfigureEditorWindowRect), editorConfigureEditorWindowRect, (id) => { #region MainMode { EditorGUI.BeginChangeCheck(); var edit_configureDisableMainMode = (VoxelBase.Edit_ConfigureDisableMainMode)GUILayout.Toolbar((int)baseTarget.edit_configureDisableMainMode, Edit_ConfigureDisableMainModeString); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(baseTarget, "Main Mode"); baseTarget.edit_configureDisableMainMode = edit_configureDisableMainMode; ShowNotification(); } } #endregion #region SubMode { EditorGUI.BeginChangeCheck(); var edit_configureDisableSubMode = (VoxelBase.Edit_ConfigureDisableSubMode)GUILayout.Toolbar((int)baseTarget.edit_configureDisableSubMode, Edit_ConfigureDisableSubModeString); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(baseTarget, "Sub Mode"); baseTarget.edit_configureDisableSubMode = edit_configureDisableSubMode; ShowNotification(); } } #endregion #region Set EditorGUILayout.BeginVertical(GUI.skin.box); { #region All { EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel("All"); if (GUILayout.Button("Add")) { Undo.RecordObject(baseTarget, "Add"); foreach (var voxel in baseTarget.voxelData.voxels) { var visible = voxel.visible & VoxelBase.FaceAllFlags; if (visible == 0) continue; baseTarget.disableData.SetDisable(voxel.position, visible); } UpdateConfigureEnableMesh(); baseTarget.edit_afterRefresh = true; } if (GUILayout.Button("Remove")) { Undo.RecordObject(baseTarget, "Remove"); baseTarget.disableData.ClearDisable(); UpdateConfigureEnableMesh(); baseTarget.edit_afterRefresh = true; } EditorGUILayout.EndHorizontal(); } #endregion #region Faces Action FaceAction = (label, flag) => { EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(label); if (GUILayout.Button("Add")) { Undo.RecordObject(baseTarget, "Add"); foreach (var voxel in baseTarget.voxelData.voxels) { var visible = voxel.visible & flag; if (visible == 0) continue; var face = baseTarget.disableData.GetDisable(voxel.position); baseTarget.disableData.SetDisable(voxel.position, face | flag); } UpdateConfigureEnableMesh(); baseTarget.edit_afterRefresh = true; } if (GUILayout.Button("Remove")) { Undo.RecordObject(baseTarget, "Remove"); baseTarget.disableData.AllAction((pos, face) => { baseTarget.disableData.SetDisable(pos, face & ~flag); }); UpdateConfigureEnableMesh(); baseTarget.edit_afterRefresh = true; } EditorGUILayout.EndHorizontal(); }; FaceAction("Right", VoxelBase.Face.right); FaceAction("Left", VoxelBase.Face.left); FaceAction("Up", VoxelBase.Face.up); FaceAction("Down", VoxelBase.Face.down); FaceAction("Forward", VoxelBase.Face.forward); FaceAction("Back", VoxelBase.Face.back); #endregion } EditorGUILayout.EndVertical(); #endregion #region PreviewMode { EditorGUI.BeginChangeCheck(); var edit_ConfigurePreviewMode = (VoxelBase.Edit_ConfigurePreviewMode)EditorGUILayout.EnumPopup("Preview", baseTarget.edit_ConfigurePreviewMode); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(baseTarget, "Preview Mode"); baseTarget.edit_ConfigurePreviewMode = edit_ConfigurePreviewMode; } } #endregion #region Help if (!baseTarget.edit_helpEnable) { #region "?" { EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); if (GUILayout.Button("?", baseTarget.edit_helpEnable ? editorCommon.guiStyleActiveButton : GUI.skin.button, GUILayout.Width(16))) { Undo.RecordObject(baseTarget, "Help Enable"); baseTarget.edit_helpEnable = !baseTarget.edit_helpEnable; } EditorGUILayout.EndHorizontal(); } #endregion } else { EditorGUI.BeginChangeCheck(); baseTarget.edit_helpEnable = EditorGUILayout.Foldout(baseTarget.edit_helpEnable, "Help"); if (EditorGUI.EndChangeCheck()) { editorConfigureEditorWindowRect.width = editorConfigureEditorWindowRect.height = 0; } EditorGUILayout.BeginVertical(GUI.skin.box); EditorGUILayout.LabelField("F5 Key - Refresh"); EditorGUILayout.LabelField("Press Space Key - Hide Preview"); EditorGUILayout.EndVertical(); } #endregion GUI.DragWindow(); }, "Disable Face Editor", guiStyleEditorWindow); editorConfigureEditorWindowRect = editorCommon.ResizeSceneViewRect(editorConfigureEditorWindowRect); } #endregion } } #region Event { var controlID = GUIUtility.GetControlID(FocusType.Passive); Tools.current = Tool.None; switch (e.type) { case EventType.MouseMove: editVoxelList.Clear(); editorCommon.selectionRect.Reset(); editorCommon.ClearPreviewMesh(); UpdateCursorMesh(); break; case EventType.MouseDown: if (editorCommon.CheckMousePositionEditorRects()) { if (!e.alt && e.button == 0) { editorCommon.ClearCursorMesh(); EventMouseDrag(true); } else if (!e.alt && e.button == 1) { ClearMakeAddData(); } } break; case EventType.MouseDrag: { if (!e.alt && e.button == 0) { EventMouseDrag(false); } } break; case EventType.MouseUp: if (!e.alt && e.button == 0) { EventMouseApply(); } ClearMakeAddData(); UpdateCursorMesh(); repaint = true; break; case EventType.Layout: HandleUtility.AddDefaultControl(controlID); break; } switch (e.type) { case EventType.KeyDown: if (!e.alt) { if (e.keyCode == KeyCode.F5) { Refresh(); } else if (e.keyCode == KeyCode.Space) { drawEditorMesh = false; } } break; case EventType.KeyUp: { if (e.keyCode == KeyCode.Space) { drawEditorMesh = true; } } break; } } #endregion if (drawEditorMesh) { #region SilhouetteMesh if (editorCommon.silhouetteMesh != null) { for (int i = 0; i < editorCommon.silhouetteMesh.Length; i++) { if (editorCommon.silhouetteMesh[i] == null) continue; editorCommon.unlitColorMaterial.color = new Color(0, 0, 0, 1f); editorCommon.unlitColorMaterial.SetPass(0); Graphics.DrawMeshNow(editorCommon.silhouetteMesh[i], baseTarget.transform.localToWorldMatrix); } } #endregion #region EnableMesh if (baseTarget.edit_enableMesh != null) { for (int i = 0; i < baseTarget.edit_enableMesh.Length; i++) { if (baseTarget.edit_enableMesh[i] == null) continue; if (baseTarget.edit_ConfigurePreviewMode == VoxelBase.Edit_ConfigurePreviewMode.Transparent) { editorCommon.vertexColorTransparentMaterial.color = new Color(1, 0, 0, 0.75f); editorCommon.vertexColorTransparentMaterial.SetPass(0); } else { editorCommon.vertexColorMaterial.color = new Color(1, 0, 0, 1); editorCommon.vertexColorMaterial.SetPass(0); } Graphics.DrawMeshNow(baseTarget.edit_enableMesh[i], baseTarget.transform.localToWorldMatrix); } } #endregion } if (SceneView.currentDrawingSceneView == SceneView.lastActiveSceneView) { #region Preview Mesh if (editorCommon.previewMesh != null) { Color color = Color.white; if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material) { if (baseTarget.edit_configureMaterialMainMode == VoxelBase.Edit_ConfigureMaterialMainMode.Add) color = new Color(1, 0, 0, 1); else if (baseTarget.edit_configureMaterialMainMode == VoxelBase.Edit_ConfigureMaterialMainMode.Remove) color = new Color(0, 0, 1, 1); } else if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable) { if (baseTarget.edit_configureDisableMainMode == VoxelBase.Edit_ConfigureDisableMainMode.Add) color = new Color(1, 0, 0, 1); else if (baseTarget.edit_configureDisableMainMode == VoxelBase.Edit_ConfigureDisableMainMode.Remove) color = new Color(0, 0, 1, 1); } else { Assert.IsTrue(false); } color.a = 0.5f + 0.5f * (1f - editorCommon.AnimationPower); for (int i = 0; i < editorCommon.previewMesh.Length; i++) { if (editorCommon.previewMesh[i] == null) continue; editorCommon.vertexColorTransparentMaterial.color = color; editorCommon.vertexColorTransparentMaterial.SetPass(0); Graphics.DrawMeshNow(editorCommon.previewMesh[i], baseTarget.transform.localToWorldMatrix); } repaint = true; } #endregion #region CursorMesh { float color = 0.2f + 0.4f * (1f - editorCommon.AnimationPower); if (editorCommon.cursorMesh != null) { for (int i = 0; i < editorCommon.cursorMesh.Length; i++) { if (editorCommon.cursorMesh[i] == null) continue; editorCommon.vertexColorTransparentMaterial.color = new Color(1, 1, 1, color); editorCommon.vertexColorTransparentMaterial.SetPass(0); Graphics.DrawMeshNow(editorCommon.cursorMesh[i], baseTarget.transform.localToWorldMatrix); } } repaint = true; } #endregion #region Selection Rect if (editorCommon.selectionRect.Enable) { bool enable = false; if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material) { if (baseTarget.edit_configureMaterialSubMode == VoxelBase.Edit_ConfigureMaterialSubMode.Rect) enable = true; } else if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable) { if (baseTarget.edit_configureDisableSubMode == VoxelBase.Edit_ConfigureDisableSubMode.Rect) enable = true; } else { Assert.IsTrue(false); } if (enable) { Handles.BeginGUI(); GUI.Box(editorCommon.selectionRect.rect, "", "SelectionRect"); Handles.EndGUI(); repaint = true; } } #endregion } } #endregion if (repaint) { SceneView.currentDrawingSceneView.Repaint(); } } protected void UpdateSilhouetteMeshMesh() { editorCommon.ClearSilhouetteMeshMesh(); if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material || baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable) { List voxels = new List(baseCore.voxelData.voxels.Length); for (int i = 0; i < baseCore.voxelData.voxels.Length; i++) { var voxel = baseCore.voxelData.voxels[i]; voxel.palette = -1; voxels.Add(voxel); } if (voxels.Count > 0) { editorCommon.silhouetteMesh = baseCore.Edit_CreateMesh(voxels, null, true); } } } protected void UpdatePreviewMesh() { editorCommon.ClearPreviewMesh(); if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material) { if (baseTarget.edit_configureMaterialIndex > 0 && baseTarget.edit_configureMaterialIndex < baseTarget.materialData.Count) { List voxels = new List(); editVoxelList.AllAction((x, y, z, face) => { var index = baseCore.voxelData.VoxelTableContains(x, y, z); if (index < 0) return; var voxel = baseCore.voxelData.voxels[index]; voxel.palette = -1; voxels.Add(voxel); }); if (voxels.Count > 0) { editorCommon.previewMesh = baseCore.Edit_CreateMesh(voxels, null, false); } } } else if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable) { List voxels = new List(); editVoxelList.AllAction((x, y, z, face) => { var index = baseCore.voxelData.VoxelTableContains(x, y, z); if (index < 0) return; var voxel = baseCore.voxelData.voxels[index]; voxel.palette = -1; voxel.visible = face; voxels.Add(voxel); }); if (voxels.Count > 0) { editorCommon.previewMesh = baseCore.Edit_CreateMesh(voxels, null, false); } } } protected void UpdateCursorMesh() { editorCommon.ClearCursorMesh(); if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material) { if (baseTarget.edit_configureMaterialIndex > 0 && baseTarget.edit_configureMaterialIndex < baseTarget.materialData.Count) { switch (baseTarget.edit_configureMaterialSubMode) { case VoxelBase.Edit_ConfigureMaterialSubMode.Voxel: { var result = editorCommon.GetMousePositionVoxel(); if (result.HasValue) { editorCommon.cursorMesh = baseCore.Edit_CreateMesh(new List() { new VoxelData.Voxel(result.Value.x, result.Value.y, result.Value.z, -1) }); } } break; case VoxelBase.Edit_ConfigureMaterialSubMode.Fill: { var pos = editorCommon.GetMousePositionVoxel(); if (pos.HasValue) { var faceAreaTable = editorCommon.GetFillVoxelFaceAreaTable(pos.Value); if (faceAreaTable != null) editorCommon.cursorMesh = new Mesh[1] { baseCore.Edit_CreateMeshOnly_Mesh(faceAreaTable, null, null) }; } } break; } } } else if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable) { switch (baseTarget.edit_configureDisableSubMode) { case VoxelBase.Edit_ConfigureDisableSubMode.Face: { IntVector3 pos; VoxelBase.Face face; if (editorCommon.GetMousePositionVoxelFace(out pos, out face)) { editorCommon.cursorMesh = baseCore.Edit_CreateMesh(new List() { new VoxelData.Voxel(pos.x, pos.y, pos.z, -1, face) }); } } break; case VoxelBase.Edit_ConfigureDisableSubMode.Fill: { IntVector3 pos; VoxelBase.Face face; if (editorCommon.GetMousePositionVoxelFace(out pos, out face)) { var faceAreaTable = editorCommon.GetFillVoxelFaceFaceAreaTable(pos, face); if (faceAreaTable != null) editorCommon.cursorMesh = new Mesh[1] { baseCore.Edit_CreateMeshOnly_Mesh(faceAreaTable, null, null) }; } } break; } } } protected void ClearMakeAddData() { editVoxelList.Clear(); editorCommon.selectionRect.Reset(); editorCommon.ClearPreviewMesh(); editorCommon.ClearCursorMesh(); } private void EventMouseDrag(bool first) { if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material) { UpdateCursorMesh(); switch (baseTarget.edit_configureMaterialSubMode) { case VoxelBase.Edit_ConfigureMaterialSubMode.Voxel: { var result = editorCommon.GetMousePositionVoxel(); if (result.HasValue) { editVoxelList.Set(result.Value, VoxelBase.FaceAllFlags); UpdatePreviewMesh(); } } break; case VoxelBase.Edit_ConfigureMaterialSubMode.Fill: { var pos = editorCommon.GetMousePositionVoxel(); if (pos.HasValue) { var result = editorCommon.GetFillVoxel(pos.Value); if (result != null) { for (int i = 0; i < result.Count; i++) editVoxelList.Set(result[i], VoxelBase.FaceAllFlags); UpdatePreviewMesh(); } } } break; case VoxelBase.Edit_ConfigureMaterialSubMode.Rect: { var pos = new IntVector2((int)Event.current.mousePosition.x, (int)Event.current.mousePosition.y); if (first) { editorCommon.selectionRect.Reset(); editorCommon.selectionRect.SetStart(pos); } else editorCommon.selectionRect.SetEnd(pos); // editVoxelList.Clear(); { var list = editorCommon.GetSelectionRectVoxel(); for (int i = 0; i < list.Count; i++) editVoxelList.Set(list[i], VoxelBase.FaceAllFlags); } UpdatePreviewMesh(); } break; } } else if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable) { UpdateCursorMesh(); switch (baseTarget.edit_configureDisableSubMode) { case VoxelBase.Edit_ConfigureDisableSubMode.Face: { IntVector3 pos; VoxelBase.Face face; if (editorCommon.GetMousePositionVoxelFace(out pos, out face)) { var combineFace = editVoxelList.Get(pos); combineFace |= face; editVoxelList.Set(pos, combineFace); UpdatePreviewMesh(); } } break; case VoxelBase.Edit_ConfigureDisableSubMode.Fill: { IntVector3 pos; VoxelBase.Face face; if (editorCommon.GetMousePositionVoxelFace(out pos, out face)) { var result = editorCommon.GetFillVoxelFace(pos, face); if (result != null) { for (int i = 0; i < result.Count; i++) { var combineFace = editVoxelList.Get(result[i]); combineFace |= face; editVoxelList.Set(result[i], combineFace); } UpdatePreviewMesh(); } } } break; case VoxelBase.Edit_ConfigureDisableSubMode.Rect: { var pos = new IntVector2((int)Event.current.mousePosition.x, (int)Event.current.mousePosition.y); if (first) { editorCommon.selectionRect.Reset(); editorCommon.selectionRect.SetStart(pos); } else editorCommon.selectionRect.SetEnd(pos); // editVoxelList.Clear(); { var list = editorCommon.GetSelectionRectVoxelFace(); foreach (var pair in list) { var combineFace = editVoxelList.Get(pair.Key); combineFace |= pair.Value; editVoxelList.Set(pair.Key, combineFace); } } UpdatePreviewMesh(); } break; } } } private void EventMouseApply() { if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material) { Undo.RecordObject(baseTarget, "Material"); bool update = false; if (baseTarget.edit_configureMaterialMainMode == VoxelBase.Edit_ConfigureMaterialMainMode.Add) { editVoxelList.AllAction((x, y, z, face) => { if (!update) DisconnectPrefabInstance(); for (int i = 0; i < baseTarget.materialData.Count; i++) { if (i == baseTarget.edit_configureMaterialIndex) continue; if (baseTarget.materialData[i].GetMaterial(new IntVector3(x, y, z))) { baseTarget.materialData[i].RemoveMaterial(new IntVector3(x, y, z)); } } baseTarget.materialData[baseTarget.edit_configureMaterialIndex].SetMaterial(new IntVector3(x, y, z)); update = true; }); } else if (baseTarget.edit_configureMaterialMainMode == VoxelBase.Edit_ConfigureMaterialMainMode.Remove) { editVoxelList.AllAction((x, y, z, face) => { if (baseTarget.materialData[baseTarget.edit_configureMaterialIndex].GetMaterial(new IntVector3(x, y, z))) { if (!update) DisconnectPrefabInstance(); baseTarget.materialData[baseTarget.edit_configureMaterialIndex].RemoveMaterial(new IntVector3(x, y, z)); update = true; } }); } else { Assert.IsTrue(false); } if (update) { UpdateConfigureEnableMesh(); baseTarget.edit_afterRefresh = true; } editVoxelList.Clear(); } else if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable) { Undo.RecordObject(baseTarget, "Disable Face"); if (baseTarget.edit_configureDisableMainMode == VoxelBase.Edit_ConfigureDisableMainMode.Add) { bool update = false; editVoxelList.AllAction((x, y, z, face) => { if (!update) DisconnectPrefabInstance(); var pos = new IntVector3(x, y, z); var combineFace = baseTarget.disableData.GetDisable(pos); combineFace |= face; if ((combineFace & VoxelBase.FaceAllFlags) != 0) baseTarget.disableData.SetDisable(pos, combineFace); else baseTarget.disableData.RemoveDisable(pos); update = true; }); if (update) { UpdateConfigureEnableMesh(); baseTarget.edit_afterRefresh = true; } } else if (baseTarget.edit_configureDisableMainMode == VoxelBase.Edit_ConfigureDisableMainMode.Remove) { bool update = false; editVoxelList.AllAction((x, y, z, face) => { if (!update) DisconnectPrefabInstance(); var pos = new IntVector3(x, y, z); var combineFace = baseTarget.disableData.GetDisable(pos); combineFace &= ~face; if ((combineFace & VoxelBase.FaceAllFlags) != 0) baseTarget.disableData.SetDisable(pos, combineFace); else baseTarget.disableData.RemoveDisable(pos); update = true; }); if (update) { UpdateConfigureEnableMesh(); baseTarget.edit_afterRefresh = true; } } else { Assert.IsTrue(false); } editVoxelList.Clear(); } } private void ShowNotification() { SceneView.currentDrawingSceneView.ShowNotification(new GUIContent(string.Format("{0} - {1}", baseTarget.edit_configureMaterialMainMode, baseTarget.edit_configureMaterialSubMode))); } protected abstract List GetMaterialListMaterials(); protected virtual void AddMaterialData(string name) { baseTarget.materialData.Add(new MaterialData() { name = name }); } protected virtual void RemoveMaterialData(int index) { baseTarget.materialData.RemoveAt(index); } protected void UpdateMaterialList() { materialList = null; if (baseTarget.materialData == null) return; materialList = new ReorderableList( serializedObject, serializedObject.FindProperty("materialData"), false, true, !baseTarget.loadFromVoxelFile, !baseTarget.loadFromVoxelFile ); materialList.elementHeight = 20; materialList.drawHeaderCallback = (rect) => { Rect r = rect; EditorGUI.LabelField(r, "Name", EditorStyles.boldLabel); r.x = 182; var materials = GetMaterialListMaterials(); if (materials != null) EditorGUI.LabelField(r, "Material", EditorStyles.boldLabel); #region LoadFormVoxelFile r.x = r.width - 128; { EditorGUI.BeginDisabledGroup(baseTarget.voxelData != null && baseTarget.voxelData.materials == null); EditorGUI.BeginChangeCheck(); string tooltip = null; if (baseTarget.voxelData == null) tooltip = "Voxel data is not loaded."; else if (baseTarget.voxelData.materials == null) tooltip = "Material is not included in the voxel data."; var loadFromVoxelFile = EditorGUI.ToggleLeft(r, new GUIContent("Load From Voxel File", tooltip), baseTarget.loadFromVoxelFile); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.loadFromVoxelFile = loadFromVoxelFile; EditorApplication.delayCall += () => { if (baseTarget.loadFromVoxelFile) { baseTarget.voxelData = null; baseTarget.voxelDataCreatedVoxelFileTimeTicks = 0; Refresh(); } else { UpdateMaterialList(); } }; } EditorGUI.EndDisabledGroup(); } #endregion }; materialList.drawElementCallback = (rect, index, isActive, isFocused) => { rect.yMin += 2; rect.yMax -= 2; if (index < baseTarget.materialData.Count) { #region Name { Rect r = rect; r.width = 144; if (index == 0) { EditorGUI.LabelField(r, "default", guiStyleLabelMiddleLeftItalic); } else if (!baseTarget.loadFromVoxelFile) { EditorGUI.BeginChangeCheck(); string name = EditorGUI.TextField(r, baseTarget.materialData[index].name, guiStyleTextFieldMiddleLeft); if (EditorGUI.EndChangeCheck()) { UndoRecordObject("Inspector"); baseTarget.materialData[index].name = name; } } else { EditorGUI.LabelField(r, baseTarget.materialData[index].name, guiStyleLabelMiddleLeftItalic); } } #endregion #region Material var materials = GetMaterialListMaterials(); if (materials != null && index < materials.Count) { { Rect r = rect; r.xMin = 182; r.width = rect.width - r.xMin; if (baseTarget.advancedMode) r.width -= 64; if (baseTarget.advancedMode && materials[index] != null && !IsMainAsset(materials[index])) r.width -= 48; EditorGUI.BeginDisabledGroup(true); EditorGUI.ObjectField(r, materials[index], typeof(Material), false); EditorGUI.EndDisabledGroup(); } if (baseTarget.advancedMode && materials[index] != null) { Rect r = rect; r.xMin += rect.width - 46; r.width = 48; { if (GUI.Button(r, "Reset")) { #region Reset Material EditorApplication.delayCall += () => { UndoRecordObject("Reset Material"); if (!IsMainAsset(materials[index])) materials[index] = null; else materials[index] = Instantiate(materials[index]); Refresh(); }; #endregion } } if (!IsMainAsset(materials[index])) { r.xMin -= 52; r.width = 48; if (GUI.Button(r, "Save")) { #region Create Material string path = EditorUtility.SaveFilePanel("Save material", baseCore.GetDefaultPath(), string.Format("{0}_mat{1}.mat", baseTarget.gameObject.name, index), "mat"); if (!string.IsNullOrEmpty(path)) { if (path.IndexOf(Application.dataPath) < 0) { SaveInsideAssetsFolderDisplayDialog(); } else { EditorApplication.delayCall += () => { UndoRecordObject("Save Material"); path = path.Replace(Application.dataPath, "Assets"); AssetDatabase.CreateAsset(Material.Instantiate(materials[index]), path); materials[index] = AssetDatabase.LoadAssetAtPath(path); Refresh(); }; } } #endregion } } } } #endregion } }; materialList.onSelectCallback = (list) => { UndoRecordObject("Inspector"); baseTarget.edit_configureMaterialIndex = list.index; UpdateConfigureEnableMesh(); InternalEditorUtility.RepaintAllViews(); }; materialList.onAddCallback = (list) => { var index = list.index; EditorApplication.delayCall += () => { UndoRecordObject("Inspector"); AddMaterialData(baseTarget.materialData.Count.ToString()); var materials = GetMaterialListMaterials(); if (materials != null) materials.Add(null); baseTarget.edit_configureMaterialIndex = index; list.index = baseTarget.edit_configureMaterialIndex; Refresh(); InternalEditorUtility.RepaintAllViews(); }; }; materialList.onRemoveCallback = (list) => { if (list.index > 0 && list.index < baseTarget.materialData.Count) { var index = list.index; EditorApplication.delayCall += () => { UndoRecordObject("Inspector"); RemoveMaterialData(index); var materials = GetMaterialListMaterials(); if (materials != null) materials.RemoveAt(index); baseTarget.edit_configureMaterialIndex = -1; Refresh(); InternalEditorUtility.RepaintAllViews(); }; } }; if (baseTarget.edit_configureMaterialIndex >= 0 && baseTarget.materialData != null && baseTarget.edit_configureMaterialIndex < baseTarget.materialData.Count) materialList.index = baseTarget.edit_configureMaterialIndex; else baseTarget.edit_configureMaterialIndex = 0; } protected virtual void UpdateConfigureEnableMesh() { UpdateSilhouetteMeshMesh(); if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Material) UpdateMaterialEnableMesh(); else if (baseTarget.edit_configureMode == VoxelBase.Edit_ConfigureMode.Disable) UpdateDisableEnableMesh(); } protected void UpdateMaterialEnableMesh() { if (baseTarget.materialData == null || baseCore.voxelData == null) { EditEnableMeshDestroy(); return; } List voxels = new List(baseCore.voxelData.voxels.Length); if (baseTarget.edit_configureMaterialIndex == 0) { for (int i = 0; i < baseCore.voxelData.voxels.Length; i++) { { bool enable = true; for (int j = 0; j < baseTarget.materialData.Count; j++) { if (baseTarget.materialData[j].GetMaterial(baseCore.voxelData.voxels[i].position)) { enable = false; break; } } if (!enable) continue; } var voxel = baseCore.voxelData.voxels[i]; voxel.palette = -1; voxels.Add(voxel); } } else if (baseTarget.edit_configureMaterialIndex >= 0 && baseTarget.edit_configureMaterialIndex < baseTarget.materialData.Count) { baseTarget.materialData[baseTarget.edit_configureMaterialIndex].AllAction((pos) => { var index = baseCore.voxelData.VoxelTableContains(pos); if (index < 0) return; var voxel = baseCore.voxelData.voxels[index]; voxel.palette = -1; voxels.Add(voxel); }); } baseTarget.edit_enableMesh = baseCore.Edit_CreateMesh(voxels); } protected void UpdateDisableEnableMesh() { if (baseTarget.disableData == null || baseCore.voxelData == null) { EditEnableMeshDestroy(); return; } List voxels = new List(baseCore.voxelData.voxels.Length); { baseTarget.disableData.AllAction((pos, face) => { var index = baseCore.voxelData.VoxelTableContains(pos); if (index < 0) return; var voxel = baseCore.voxelData.voxels[index]; voxel.palette = -1; voxel.visible = face; voxels.Add(voxel); }); } baseTarget.edit_enableMesh = baseCore.Edit_CreateMesh(voxels); } public void EditEnableMeshDestroy() { if (baseTarget.edit_enableMesh != null) { for (int i = 0; i < baseTarget.edit_enableMesh.Length; i++) { MonoBehaviour.DestroyImmediate(baseTarget.edit_enableMesh[i]); } baseTarget.edit_enableMesh = null; } } protected void AfterRefresh() { if (AnimationMode.InAnimationMode()) { return; } if (baseTarget.edit_afterRefresh) Refresh(); } protected virtual void Refresh() { baseCore.ReCreate(); UpdateMaterialList(); UpdateConfigureEnableMesh(); } protected void DisconnectPrefabInstance() { #if !UNITY_2018_3_OR_NEWER if (PrefabUtility.GetPrefabType(baseTarget) == PrefabType.PrefabInstance) { PrefabUtility.DisconnectPrefabInstance(baseTarget); } #endif } protected class PrefabCreateMonitoringAssetModificationProcessor : UnityEditor.AssetModificationProcessor { public static bool IsContains(string path) { return paths.Contains(path); } public static void Remove(string path) { paths.Remove(path); } private static List paths = new List(); private static bool delayCheck = false; private static void OnWillCreateAsset(string path) { if (Path.GetExtension(path) == ".prefab") { paths.Add(path); if (!delayCheck) { EditorApplication.delayCall += () => { CheckVoxelObject(); delayCheck = false; }; delayCheck = true; } } } private static void CheckVoxelObject() { List removeList = new List(); foreach (var path in paths) { var prefab = AssetDatabase.LoadAssetAtPath(path); if (prefab == null) { removeList.Add(path); continue; } var voxelBase = prefab.GetComponent(); if (voxelBase == null) { removeList.Add(path); continue; } } foreach (var path in removeList) { paths.Remove(path); } } } protected void EditorPrefabInstanceUpdated(GameObject go) { #if UNITY_2018_3_OR_NEWER var prefabType = PrefabUtility.GetPrefabAssetType(go); if (prefabType != PrefabAssetType.Regular) return; var prefab = PrefabUtility.GetCorrespondingObjectFromSource(go); #else var prefabType = PrefabUtility.GetPrefabType(go); if (prefabType != PrefabType.PrefabInstance) return; #if UNITY_2018_2_OR_NEWER var prefab = PrefabUtility.GetCorrespondingObjectFromSource(go); #else var prefab = PrefabUtility.GetPrefabParent(go); #endif #endif var path = AssetDatabase.GetAssetPath(prefab); if (!PrefabCreateMonitoringAssetModificationProcessor.IsContains(path)) return; PrefabCreateMonitoringAssetModificationProcessor.Remove(path); { #region Children { var childrenVoxelBases = go.GetComponentsInChildren(true); foreach (var vb in childrenVoxelBases) { VoxelBaseCore.StaticForceReCreate(vb); } } #endregion #region Extra { var childrenVoxelBaseExplosions = go.GetComponentsInChildren(true); foreach (var vb in childrenVoxelBaseExplosions) { VoxelBaseExplosionCore.StaticForceGenerate(vb); } } #endregion EditorApplication.delayCall += () => { #if UNITY_2018_3_OR_NEWER PrefabUtility.ApplyPrefabInstance(go, InteractionMode.AutomatedAction); #else PrefabUtility.ReplacePrefab(go, prefab, ReplacePrefabOptions.ConnectToPrefab); #endif }; } } protected virtual void EditorUndoRedoPerformed() { if (AnimationMode.InAnimationMode()) { baseTarget.edit_afterRefresh = true; return; } if (baseTarget != null && baseCore != null) { if (baseCore.RefreshCheckerCheck()) { if (baseTarget.importFlags != baseTarget.refreshChecker.importFlags) baseCore.ReadyVoxelData(true); Refresh(); } else { UpdateConfigureEnableMesh(); } } Repaint(); } } }