2
0
Fork 0
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1651 lines
58 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

namespace MagicaVoxelToolbox
{
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using MagicaVoxelToolbox;
using MagicaVoxelToolbox.Saving;
public class VoxelToUnityWindow : MoenenEditorWindow
{
#region --- SUB ---
public struct PathData
{
public string Path;
public string Extension;
public string Root;
}
public enum Task
{
Prefab = 0,
Lod = 1,
Material = 2,
Obj = 3,
ToJson = 4,
ToVox = 5,
ToQb = 6,
}
public enum ExportMod
{
Specified = 0,
OriginalPath = 1,
AskEverytime = 2,
}
public enum PivotMod
{
Specified = 0,
MagicaVoxelWorldMod = 1,
}
public enum _25DSpriteNum
{
_1 = 1,
_4 = 4,
_8 = 8,
_16 = 16,
}
public enum FacingOption
{
PositiveZInUnity = 0,
NegativeZInUnity = 1,
}
#endregion
#region --- VAR ---
// Global
private static Vector2[] SHADER_VALUE_REMAP_SOURCE = new Vector2[SHADER_PROPERTY_NUM] {
new Vector2(0, 100),
new Vector2(0, 100),
new Vector2(0, 100),
new Vector2(0, 100),
new Vector2(0, 100),
new Vector2(0, 100),
new Vector2(0, 100),
new Vector2(0, 100),
new Vector2(1, 2),
new Vector2(0, 100),
new Vector2(0, 100),
new Vector2(1, 5),
new Vector2(0, 100),
};
private const int SHADER_NUM = VoxelData.MaterialData.SHADER_NUM;
private const int SHADER_PROPERTY_NUM = VoxelData.MaterialData.SHADER_PROPERTY_NUM;
private static readonly string[] SHADER_NAMES = new string[SHADER_NUM] { "Diffuse", "Metal", "Plastic", "Glass", "Emiss", };
// Short
private static ExportMod TheExportMod
{
get
{
return (ExportMod)ExportModIndex.Value;
}
set
{
ExportModIndex.Value = (int)value;
}
}
private static Core_Voxel.LightMapSupportType LightMapSupportMode
{
get
{
return (Core_Voxel.LightMapSupportType)LightMapSupportTypeIndex.Value;
}
set
{
LightMapSupportTypeIndex.Value = (int)value;
}
}
private static Shader TheDiffuseShader
{
get
{
return Shader.Find(Shader_Paths[0]);
}
set
{
Shader_Paths[0].Value = value ? value.name : "Mobile/Diffuse";
}
}
private static Shader TheMetalShader
{
get
{
return Shader.Find(Shader_Paths[1]);
}
set
{
Shader_Paths[1].Value = value ? value.name : "Mobile/Diffuse";
}
}
private static Shader ThePlasticShader
{
get
{
return Shader.Find(Shader_Paths[2]);
}
set
{
Shader_Paths[2].Value = value ? value.name : "Mobile/Diffuse";
}
}
private static Shader TheGlassShader
{
get
{
return Shader.Find(Shader_Paths[3]);
}
set
{
Shader_Paths[3].Value = value ? value.name : "Mobile/Diffuse";
}
}
private static Shader TheEmissionShader
{
get
{
return Shader.Find(Shader_Paths[4]);
}
set
{
Shader_Paths[4].Value = value ? value.name : "Mobile/Diffuse";
}
}
private static Shader[] TheShaders
{
get
{
return new Shader[SHADER_NUM] {
Shader.Find(Shader_Paths[0]),
Shader.Find(Shader_Paths[1]),
Shader.Find(Shader_Paths[2]),
Shader.Find(Shader_Paths[3]),
Shader.Find(Shader_Paths[4]),
};
}
}
private static string[] ShaderKeywords
{
get
{
return new string[SHADER_PROPERTY_NUM] {
Shader_Keywords[0],
Shader_Keywords[1],
Shader_Keywords[2],
Shader_Keywords[3],
Shader_Keywords[4],
Shader_Keywords[5],
Shader_Keywords[6],
Shader_Keywords[7],
Shader_Keywords[8],
Shader_Keywords[9],
Shader_Keywords[10],
Shader_Keywords[11],
Shader_Keywords[12],
};
}
}
private static Vector2[] ShaderValueRemaps
{
get
{
return new Vector2[SHADER_PROPERTY_NUM] {
Shader_ValueRemaps[0],
Shader_ValueRemaps[1],
Shader_ValueRemaps[2],
Shader_ValueRemaps[3],
Shader_ValueRemaps[4],
Shader_ValueRemaps[5],
Shader_ValueRemaps[6],
Shader_ValueRemaps[7],
Shader_ValueRemaps[8],
Shader_ValueRemaps[9],
Shader_ValueRemaps[10],
Shader_ValueRemaps[11],
Shader_ValueRemaps[12],
};
}
}
// Data
private Vector2 MasterScrollPosition;
private static bool AboutFold_Contact = false;
private static bool AboutFold_Ad = false;
// Selection
private static Dictionary<Object, PathData> TaskMap = new Dictionary<Object, PathData>();
private static int VoxNum = 0;
private static int QbNum = 0;
private static int FolderNum = 0;
private static int ObjNum = 0;
private static int JsonNum = 0;
private static Texture2D VoxFileIcon = null;
private static Texture2D QbFileIcon = null;
private static Texture2D JsonFileIcon = null;
// Saving
private static EditorSavingBool ViewPanelOpen = new EditorSavingBool("V2U.ViewPanelOpen", true);
private static EditorSavingBool CreatePanelOpen = new EditorSavingBool("V2U.CreatePanelOpen", true);
private static EditorSavingBool SettingPanelOpen = new EditorSavingBool("V2U.SettingPanelOpen", false);
private static EditorSavingBool AboutPanelOpen = new EditorSavingBool("V2U.AboutPanelOpen", false);
private static EditorSavingBool ModelGenerationSettingPanelOpen = new EditorSavingBool("V2U.ModelGenerationSettingPanelOpen", false);
private static EditorSavingBool OptimizationSettingPanelOpen = new EditorSavingBool("V2U.OptimizationSettingPanelOpen", false);
private static EditorSavingBool ShaderSettingPanelOpen = new EditorSavingBool("V2U.ShaderSettingPanelOpen", false);
private static EditorSavingBool SpriteGenerationSettingPanelOpen = new EditorSavingBool("V2U.SpriteGenerationSettingPanelOpen", false);
private static EditorSavingBool SystemSettingPanelOpen = new EditorSavingBool("V2U.SystemSettingPanelOpen", false);
private static EditorSavingBool ToolPanelOpen = new EditorSavingBool("V2U.ToolPanelOpen", true);
private static EditorSavingBool ColorfulTitle = new EditorSavingBool("V2U.ColorfulTitle", true);
private static EditorSavingString ExportPath = new EditorSavingString("V2U.ExportPath", "Assets");
private static EditorSavingInt LightMapSupportTypeIndex = new EditorSavingInt("V2U.LightMapSupportTypeIndex", 0);
private static EditorSavingInt ExportModIndex = new EditorSavingInt("V2U.ExportModIndex", 2);
private static EditorSavingFloat ModelScale = new EditorSavingFloat("V2U.ModelScale", 0.1f);
private static EditorSavingInt LodNum = new EditorSavingInt("V2U.LodNum", 2);
private static EditorSavingBool LogMessage = new EditorSavingBool("V2U.LogMessage", true);
private static EditorSavingBool ShowDialog = new EditorSavingBool("V2U.ShowDialog", true);
private static EditorSavingBool EditorDockToScene = new EditorSavingBool("V2U.EditorDockToScene", true);
private static EditorSavingVector3 ModelPivot = new EditorSavingVector3("V2U.ModelPivot", Vector3.one * 0.5f);
private static EditorSavingBool OptimizeFront = new EditorSavingBool("V2U.OptimizeFront", true);
private static EditorSavingBool OptimizeBack = new EditorSavingBool("V2U.OptimizeBack", true);
private static EditorSavingBool OptimizeUp = new EditorSavingBool("V2U.OptimizeUp", true);
private static EditorSavingBool OptimizeDown = new EditorSavingBool("V2U.OptimizeDown", true);
private static EditorSavingBool OptimizeLeft = new EditorSavingBool("V2U.OptimizeLeft", true);
private static EditorSavingBool OptimizeRight = new EditorSavingBool("V2U.OptimizeRight", true);
private static EditorSavingBool FacingYPlusInMV = new EditorSavingBool("V2U.FacingYPlusInMV", true);
private static EditorSavingInt CurrentShowingShaderIndex = new EditorSavingInt("V2U.CurrentShowingShaderIndex", 0);
private static EditorSavingInt ReplacementModeIndex = new EditorSavingInt("V2U.ReplacementModeIndex", 0);
private static EditorSavingString ShaderMainTextureKeyword = new EditorSavingString("V2U.ShaderMainTextureKeyword", "_MainTex");// Keyword Using in VEditor
private static EditorSavingString[] Shader_Paths = new EditorSavingString[5] {
new EditorSavingString("V2U.ShaderPath_Diffuse", "Mobile/Diffuse"),
new EditorSavingString("V2U.ShaderPath_Matel", "Standard"),
new EditorSavingString("V2U.ShaderPath_Plastic", "Standard"),
new EditorSavingString("V2U.ShaderPath_Glass", "Sprites/Default"),
new EditorSavingString("V2U.ShaderPath_Emission", "Sprites/Default"),
};
private static EditorSavingString[] Shader_Keywords = new EditorSavingString[SHADER_PROPERTY_NUM] {
new EditorSavingString("V2U.ShaderKeyword_MetalWeight", "$c_Color"), // 0-100 0-1
new EditorSavingString("V2U.ShaderKeyword_MetalRough", "_Metallic"), // 0-100 0-1
new EditorSavingString("V2U.ShaderKeyword_MetalSpecular",""), // 0-100 0-1
new EditorSavingString("V2U.ShaderKeyword_PlasticWeight","$c_Color"), // 0-100 0-1
new EditorSavingString("V2U.ShaderKeyword_PlasticRough","_Metallic"), // 0-100 0-1
new EditorSavingString("V2U.ShaderKeyword_PlasticSpecular",""), // 0-100 0-1
new EditorSavingString("V2U.ShaderKeyword_GlassWeight","$a_Color"), // 0-100 0-1
new EditorSavingString("V2U.ShaderKeyword_GlassRough",""), // 0-100 0-1
new EditorSavingString("V2U.ShaderKeyword_GlassRefract",""), // 1-2 0-1
new EditorSavingString("V2U.ShaderKeyword_GlassAttenuate",""), // 0-100 0-1
new EditorSavingString("V2U.ShaderKeyword_EmitWeight","$c_Color"), // 0-100 0-1
new EditorSavingString("V2U.ShaderKeyword_EmitPower",""), // 1-5 0-4
new EditorSavingString("V2U.ShaderKeyword_EmitLdr",""), // 0-100 0-1
};
private static EditorSavingVector2[] Shader_ValueRemaps = new EditorSavingVector2[SHADER_PROPERTY_NUM] {
new EditorSavingVector2("V2U.ShaderValueRemap_MetalWeight", new Vector2(0.5f, 1f)),
new EditorSavingVector2("V2U.ShaderValueRemap_MetalRough", new Vector2(0f, 0.8f)),
new EditorSavingVector2("V2U.ShaderValueRemap_MetalSpecular", new Vector2(0f, 0.8f)),
new EditorSavingVector2("V2U.ShaderValueRemap_PlasticWeight", new Vector2(0.5f, 1f)),
new EditorSavingVector2("V2U.ShaderValueRemap_PlasticRough", new Vector2(0f, 0.2f)),
new EditorSavingVector2("V2U.ShaderValueRemap_PlasticSpecular", new Vector2(0f, 0.2f)),
new EditorSavingVector2("V2U.ShaderValueRemap_GlassWeight", new Vector2(0.8f, 0.3f)),
new EditorSavingVector2("V2U.ShaderValueRemap_GlassRough", new Vector2(0f, 1f)),
new EditorSavingVector2("V2U.ShaderValueRemap_GlassRefract", new Vector2(0f, 1f)),
new EditorSavingVector2("V2U.ShaderValueRemap_GlassAttenuate", new Vector2(0f, 1f)),
new EditorSavingVector2("V2U.ShaderValueRemap_EmitWeight", new Vector2(0.5f, 1f)),
new EditorSavingVector2("V2U.ShaderValueRemap_EmitPower", new Vector2(0f, 1f)),
new EditorSavingVector2("V2U.ShaderValueRemap_EmitLdr", new Vector2(0f, 1f)),
};
#endregion
#region --- MSG ---
[MenuItem("Tools/MagicaVoxel Toolbox/Toolbox")]
public static void OpenWindow()
{
var inspector = typeof(Editor).Assembly.GetType("UnityEditor.InspectorWindow");
VoxelToUnityWindow window = inspector != null ?
GetWindow<VoxelToUnityWindow>("Voxel To Unity", true, inspector) :
GetWindow<VoxelToUnityWindow>("Voxel To Unity", true);
window.minSize = new Vector2(275, 400);
window.maxSize = new Vector2(600, 1000);
}
private void OnEnable()
{
Window_Enable();
}
private void OnFocus()
{
RefreshSelection();
Repaint();
}
private void OnSelectionChange()
{
RefreshSelection();
Repaint();
}
private void OnGUI()
{
MasterScrollPosition = GUILayout.BeginScrollView(MasterScrollPosition, GUI.skin.scrollView);
TitleGUI();
Window_Main();
GUILayout.EndScrollView();
if (Event.current.type == EventType.MouseDown)
{
GUI.FocusControl(null);
Repaint();
}
}
private void TitleGUI()
{
const string MAIN_TITLE = "Voxel to Unity";
const string MAIN_TITLE_RICH = "<color=#ff3333>V</color><color=#ffcc00>o</color><color=#ffff33>x</color><color=#33ff33>e</color><color=#33ccff>l</color><color=#eeeeee> to Unity</color>";
Space(6);
LayoutV(() =>
{
GUIStyle style = new GUIStyle()
{
alignment = TextAnchor.LowerCenter,
fontSize = 12,
fontStyle = FontStyle.Bold
};
style.normal.textColor = Color.white;
style.richText = true;
Rect rect = GUIRect(0, 18);
GUIStyle shadowStyle = new GUIStyle(style)
{
richText = false
};
EditorGUI.DropShadowLabel(rect, MAIN_TITLE, shadowStyle);
GUI.Label(rect, ColorfulTitle ? MAIN_TITLE_RICH : MAIN_TITLE, style);
});
Space(6);
}
#endregion
#region --- API ---
public static void Window_Enable()
{
LoadSetting();
RefreshSelection();
RefreshMergeSetting();
}
public static void Window_Main()
{
ViewGUI();
CreateGUI();
// ToolGUI();
SettingGUI();
// AboutGUI();
if (GUI.changed)
{
SaveSetting();
}
}
#endregion
#region --- GUI ---
private static void ViewGUI()
{
LayoutF(() =>
{
bool addSpaceFlag = true;
Space(2);
int iconSize = 26;
LayoutH(() =>
{
// Init
GUIStyle labelStyle = new GUIStyle(GUI.skin.label)
{
alignment = TextAnchor.MiddleLeft,
fontSize = 10
};
// Icons
if (FolderNum > 0)
{
if (VoxNum + QbNum + JsonNum <= 0)
{
// None With Folder
EditorGUI.HelpBox(GUIRect(0, iconSize + 14), "There are NO .vox or .qb file in selecting folder.", MessageType.Warning);
addSpaceFlag = false;
}
}
else if (VoxNum + QbNum + JsonNum <= 0)
{
if (ObjNum > 0)
{
// Selecting Not Voxel File
EditorGUI.HelpBox(GUIRect(0, iconSize + 14), "The file selecting is NOT .vox or .qb file.", MessageType.Warning);
addSpaceFlag = false;
}
else
{
// None
EditorGUI.HelpBox(GUIRect(0, iconSize + 14), "Select *.vox, *.qb, *.json or folder in Project View.", MessageType.Info);
addSpaceFlag = false;
}
}
Space(4);
if (VoxNum > 0)
{
// Vox
LayoutH(() =>
{
if (VoxFileIcon)
{
GUI.DrawTexture(GUIRect(iconSize, iconSize), VoxFileIcon);
}
}, true);
GUI.Label(GUIRect(0, iconSize), ".vox\n× " + VoxNum.ToString(), labelStyle);
Space(4);
}
if (QbNum > 0)
{
// Qb
LayoutH(() =>
{
if (QbFileIcon)
{
GUI.DrawTexture(GUIRect(iconSize, iconSize), QbFileIcon);
}
}, true);
GUI.Label(GUIRect(0, iconSize), ".qb\n× " + QbNum.ToString(), labelStyle);
}
if (JsonNum > 0)
{
// Json
LayoutH(() =>
{
if (JsonFileIcon)
{
GUI.DrawTexture(GUIRect(iconSize, iconSize), JsonFileIcon);
}
}, true);
GUI.Label(GUIRect(0, iconSize), ".json\n× " + JsonNum.ToString(), labelStyle);
}
});
Space(addSpaceFlag ? 16 : 6);
// Scale Too Small Warning
if (ModelScale == 0)
{
EditorGUI.HelpBox(GUIRect(0, iconSize + 14), "Model scale has been set to 0. Your model will be invisible.", MessageType.Error);
Space(6);
}
else if (ModelScale <= 0.0001f)
{
EditorGUI.HelpBox(GUIRect(0, iconSize + 14), "Model scale is too small. Your may not able to see them.", MessageType.Warning);
Space(6);
}
// Combine Warning
if (!OptimizeFront || !OptimizeBack || !OptimizeLeft || !OptimizeRight || !OptimizeUp || !OptimizeDown)
{
EditorGUI.HelpBox(GUIRect(0, iconSize + 14), "Faces in some direction will NOT be combine.\nSee \"Setting\" > \"Optimization\".", MessageType.Info);
Space(6);
}
}, "Selecting Files", ViewPanelOpen, true);
}
private static void CreateGUI()
{
LayoutF(() =>
{
bool oldEnable = GUI.enabled;
GUI.enabled = VoxNum > 0 || QbNum > 0;
int buttonHeight = 34;
string s = VoxNum + QbNum > 1 ? "s" : "";
var dotStyle = new GUIStyle(GUI.skin.label)
{
richText = true,
alignment = TextAnchor.MiddleLeft,
};
Space(6);
Rect rect = new Rect();
if (GUI.Button(rect = GUIRect(0, buttonHeight), "Create Prefab" + s))
{
// Create Prefab
DoTask(Task.Prefab);
}
GUI.Label(rect, GUI.enabled ? " <color=#33ccff>●</color>" : "", dotStyle);
// Space(4);
// if (GUI.Button(rect = GUIRect(0, buttonHeight), "Create LOD Prefab" + s)) {
// // Create LOD Prefab
// DoTask(Task.Lod);
// }
// GUI.Label(rect, GUI.enabled ? " <color=#33ccff>●</color>" : "", dotStyle);
// Space(4);
// bool oldE = GUI.enabled;
// GUI.enabled = oldE && VoxNum > 0;
// if (GUI.Button(rect = GUIRect(0, buttonHeight), "Create Material Prefab" + s)) {
// // Create Material Prefab
// DoTask(Task.Material);
// }
// GUI.Label(rect, GUI.enabled ? " <color=#33ccff>●</color>" : "", dotStyle);
// GUI.enabled = oldE;
// Space(4);
// if (GUI.Button(rect = GUIRect(0, buttonHeight), "Create Obj File" + s)) {
// // Create Obj File
// DoTask(Task.Obj);
// }
// GUI.Label(rect, GUI.enabled ? " <color=#33ff66>●</color>" : "", dotStyle);
// Space(4);
// LayoutH(() => {
// GUI.enabled = VoxNum > 0 || QbNum > 0;
// if (GUI.Button(rect = GUIRect(0, buttonHeight), " To Json")) {
// // To Json
// DoTask(Task.ToJson);
// }
// GUI.Label(rect, GUI.enabled ? " <color=#cccccc>●</color>" : "", dotStyle);
// Space(2);
// GUI.enabled = JsonNum > 0 || QbNum > 0;
// if (GUI.Button(rect = GUIRect(0, buttonHeight), " To Vox")) {
// // To Vox
// DoTask(Task.ToVox);
// }
// GUI.Label(rect, GUI.enabled ? " <color=#cc66ff>●</color>" : "", dotStyle);
// Space(2);
// GUI.enabled = JsonNum > 0 || VoxNum > 0;
// if (GUI.Button(rect = GUIRect(0, buttonHeight), " To Qb")) {
// // To Qb
// DoTask(Task.ToQb);
// }
// GUI.Label(rect, GUI.enabled ? " <color=#cc66ff>●</color>" : "", dotStyle);
// });
// Space(6);
// // Export To
// LayoutV(() => {
// GUI.enabled = true;
// Space(4);
LayoutH(() =>
{
GUI.Label(GUIRect(0, 18), "Export To:");
TheExportMod = (ExportMod)EditorGUI.EnumPopup(GUIRect(110, 18), TheExportMod);
});
if (TheExportMod == ExportMod.Specified)
{
Space(4);
LayoutH(() =>
{
Space(6);
EditorGUI.SelectableLabel(GUIRect(0, 18), ExportPath, GUI.skin.textField);
if (GUI.Button(GUIRect(60, 18), "Browse", EditorStyles.miniButtonMid))
{
BrowseExportPath();
}
});
Space(2);
}
// Space(2);
// GUI.enabled = oldEnable;
// }, true);
// Space(4);
// GUI.enabled = oldEnable;
}, "Create", CreatePanelOpen, true);
}
private static void ToolGUI()
{
LayoutF(() =>
{
var dotStyle = new GUIStyle(GUI.skin.label)
{
fontSize = 9,
richText = true,
alignment = TextAnchor.MiddleLeft,
};
// Rigging Editor
LayoutH(() =>
{
GUIRect(16, 26);
Rect rect = new Rect();
if (GUI.Button(rect = GUIRect(0, 28), " Rigging Editor"))
{
VoxelEditorWindow.OpenWindow(VoxelEditorWindow.EditorMode.Rigging, EditorDockToScene);
}
GUI.Label(rect, " <color=#33ccff>●</color>", dotStyle);
GUIRect(16, 26);
});
Space(4);
// Skeletal Animation Editor
LayoutH(() =>
{
GUIRect(16, 26);
Rect rect = new Rect();
if (GUI.Button(rect = GUIRect(0, 28), " Skeletal Animation Editor"))
{
var window = VoxelEditorWindow.OpenWindow(VoxelEditorWindow.EditorMode.Skeletal, EditorDockToScene);
if (window)
{
window.OpenSkeletal();
}
}
GUI.Label(rect, " <color=#33cccc>●</color>", dotStyle);
GUIRect(16, 26);
});
Space(4);
// Sprite Editor
LayoutH(() =>
{
GUIRect(16, 26);
Rect rect = new Rect();
if (GUI.Button(rect = GUIRect(0, 28), " Sprite Editor"))
{
VoxelEditorWindow.OpenWindow(VoxelEditorWindow.EditorMode.Sprite, EditorDockToScene);
}
GUI.Label(rect, " <color=#ffcc00>●</color>", dotStyle);
GUIRect(16, 26);
});
Space(4);
// Map Generator
LayoutH(() =>
{
GUIRect(16, 26);
Rect rect = new Rect();
if (GUI.Button(rect = GUIRect(0, 28), " Map Generator"))
{
var window = VoxelEditorWindow.OpenWindow(VoxelEditorWindow.EditorMode.MapGenerator, EditorDockToScene);
if (window)
{
window.OpenGenerator();
}
}
GUI.Label(rect, " <color=#cc66ff>●</color>", dotStyle);
GUIRect(16, 26);
});
Space(4);
// Character Generator
LayoutH(() =>
{
GUIRect(16, 26);
Rect rect = new Rect();
if (GUI.Button(rect = GUIRect(0, 28), " Character Generator"))
{
var window = VoxelEditorWindow.OpenWindow(VoxelEditorWindow.EditorMode.CharacterGenerator, EditorDockToScene);
if (window)
{
window.OpenGenerator();
}
}
GUI.Label(rect, " <color=#cc66ff>●</color>", dotStyle);
GUIRect(16, 26);
});
Space(4);
// Prefab Combiner
LayoutH(() =>
{
GUIRect(16, 26);
Rect rect = new Rect();
if (GUI.Button(rect = GUIRect(0, 28), " Prefab Combiner"))
{
var window = VoxelEditorWindow.OpenWindow(VoxelEditorWindow.EditorMode.PrefabCombiner, EditorDockToScene);
if (window)
{
window.OpenCombiner();
}
}
GUI.Label(rect, " <color=#33ccff>●</color>", dotStyle);
GUIRect(16, 26);
});
Space(4);
Space(4);
}, "Tools", ToolPanelOpen, true);
}
private static void SettingGUI()
{
LayoutF(() =>
{
const int HEIGHT = 16;
// Model Generation
LayoutF(() =>
{
Space(2);
// Pivot
LayoutH(() =>
{
EditorGUI.LabelField(GUIRect(48, 18), "Pivot");
ModelPivot.Value = EditorGUI.Vector3Field(GUIRect(0, 18), "", ModelPivot);
});
Space(2);
// Scale
ModelScale.Value = Mathf.Max(EditorGUI.FloatField(GUIRect(0, HEIGHT), "Scale (unit/voxel)", ModelScale), 0f);
Space(4);
// LOD
LodNum.Value = Mathf.Clamp(EditorGUI.IntField(GUIRect(0, HEIGHT), "LOD Num", LodNum), 2, 4);
Space(4);
// Facing Y+
FacingYPlusInMV.Value = (FacingOption)EditorGUI.EnumPopup(GUIRect(0, HEIGHT), "Y+ in MagicaVoxel is", (FacingOption)(FacingYPlusInMV.Value ? 0 : 1)) == 0;
Space(4);
// LightMapSupportType
LightMapSupportMode = (Core_Voxel.LightMapSupportType)EditorGUI.EnumPopup(GUIRect(0, HEIGHT), "Lightmap", LightMapSupportMode);
Space(4);
// Replacement Mode
ReplacementModeIndex.Value = (int)(Core_File.ReplacementMode)EditorGUI.EnumPopup(GUIRect(0, HEIGHT), new GUIContent("Object Replacement", "Only for sub objects inside prefab"), (Core_File.ReplacementMode)ReplacementModeIndex.Value);
Space(4);
}, "Model Generation", ModelGenerationSettingPanelOpen, true);
// Optimization
LayoutF(() =>
{
LayoutH(() =>
{
OptimizeLeft.Value = EditorGUI.ToggleLeft(GUIRect(0, HEIGHT), "Combine X-", OptimizeLeft);
Space(2);
OptimizeRight.Value = EditorGUI.ToggleLeft(GUIRect(0, HEIGHT), "Combine X+", OptimizeRight);
});
Space(2);
LayoutH(() =>
{
OptimizeDown.Value = EditorGUI.ToggleLeft(GUIRect(0, HEIGHT), "Combine Y-", OptimizeDown);
Space(2);
OptimizeUp.Value = EditorGUI.ToggleLeft(GUIRect(0, HEIGHT), "Combine Y+", OptimizeUp);
});
Space(2);
LayoutH(() =>
{
OptimizeBack.Value = EditorGUI.ToggleLeft(GUIRect(0, HEIGHT), "Combine Z-", OptimizeBack);
Space(2);
OptimizeFront.Value = EditorGUI.ToggleLeft(GUIRect(0, HEIGHT), "Combine Z+", OptimizeFront);
});
Space(6);
EditorGUI.HelpBox(
GUIRect(0, 32),
"The check boxes above will make faces only combines on specified directions.",
MessageType.Info
);
Space(6);
}, "Optimization", OptimizationSettingPanelOpen, true);
// Shaders
LayoutF(() =>
{
// Bar
LayoutH(() =>
{
for (int i = 0; i < SHADER_NUM; i++)
{
var style = i == 0 ? EditorStyles.miniButtonLeft : i == SHADER_NUM - 1 ? EditorStyles.miniButtonRight : EditorStyles.miniButtonMid;
if (CurrentShowingShaderIndex == i)
{
style = new GUIStyle(style)
{
normal = style.active,
};
}
if (GUI.Button(GUIRect(0, 16), SHADER_NAMES[i], style))
{
CurrentShowingShaderIndex.Value = i;
GUI.FocusControl(null);
}
}
});
Space(4);
switch (CurrentShowingShaderIndex)
{
default:
case 0:
// Diffuse
LayoutV(() =>
{
Space(2);
TheDiffuseShader = (Shader)EditorGUI.ObjectField(GUIRect(0, 16), "Diffuse Shader", TheDiffuseShader, typeof(Shader), false);
Space(2);
ShaderMainTextureKeyword.Value = EditorGUI.TextField(GUIRect(0, 16), "MainText Keyword", ShaderMainTextureKeyword.Value);
Space(2);
}, true);
Space(2);
break;
case 1:
// Metal
LayoutV(() =>
{
Space(2);
TheMetalShader = (Shader)EditorGUI.ObjectField(GUIRect(0, 16), "Metal Shader", TheMetalShader, typeof(Shader), false);
// Prop
ShaderPropertyGUI(-1, "");
Space(2);
ShaderPropertyGUI(0, "Weight");
Space(6);
ShaderPropertyGUI(1, "Rough");
Space(6);
ShaderPropertyGUI(2, "Specular");
Space(6);
}, true);
Space(2);
break;
case 2:
// Plastic
LayoutV(() =>
{
Space(2);
ThePlasticShader = (Shader)EditorGUI.ObjectField(GUIRect(0, 16), "Plastic Shader", ThePlasticShader, typeof(Shader), false);
// Prop
ShaderPropertyGUI(-1, "");
Space(2);
ShaderPropertyGUI(3, "Weight");
Space(6);
ShaderPropertyGUI(4, "Rough");
Space(6);
ShaderPropertyGUI(5, "Specular");
Space(6);
}, true);
Space(2);
break;
case 3:
// Glass
LayoutV(() =>
{
Space(2);
TheGlassShader = (Shader)EditorGUI.ObjectField(GUIRect(0, 16), "Glass Shader", TheGlassShader, typeof(Shader), false);
// Prop
ShaderPropertyGUI(-1, "");
Space(2);
ShaderPropertyGUI(6, "Weight");
Space(6);
ShaderPropertyGUI(7, "Rough");
Space(6);
ShaderPropertyGUI(8, "Refract");
Space(6);
ShaderPropertyGUI(9, "Attenuate");
Space(6);
}, true);
Space(2);
break;
case 4:
// Emission
LayoutV(() =>
{
Space(2);
TheEmissionShader = (Shader)EditorGUI.ObjectField(GUIRect(0, 16), "Emission Shader", TheEmissionShader, typeof(Shader), false);
// Prop
ShaderPropertyGUI(-1, "");
Space(2);
ShaderPropertyGUI(10, "Weight");
Space(6);
ShaderPropertyGUI(11, "Power");
Space(6);
ShaderPropertyGUI(12, "LDR");
Space(6);
}, true);
Space(2);
break;
}
if (CurrentShowingShaderIndex != 0)
{
Space(2);
EditorGUI.HelpBox(
GUIRect(0, 72),
"Add tag for keyword will make it represent color. No tag means float.\n" +
"\"$a\" = alpha \"$r\" = r \"$g\" = g\n\"$b\" = b \"$c\" = rgb\n eg. \"$aTint\", \"$r_Color\", \"FloatValue\"",
MessageType.Info
);
Space(6);
}
}, "Shader", ShaderSettingPanelOpen, true);
// System
LayoutF(() =>
{
Space(2);
LayoutH(() =>
{
LogMessage.Value = EditorGUI.Toggle(GUIRect(HEIGHT, HEIGHT), LogMessage);
GUI.Label(GUIRect(0, 18), "Log To Console");
Space(2);
ShowDialog.Value = EditorGUI.Toggle(GUIRect(HEIGHT, HEIGHT), ShowDialog);
GUI.Label(GUIRect(0, 18), "Dialog Window");
});
Space(2);
LayoutH(() =>
{
ColorfulTitle.Value = EditorGUI.Toggle(GUIRect(HEIGHT, HEIGHT), ColorfulTitle);
GUI.Label(GUIRect(0, 18), "Colorful Title");
EditorDockToScene.Value = EditorGUI.Toggle(GUIRect(HEIGHT, HEIGHT), EditorDockToScene);
GUI.Label(GUIRect(0, 18), "Dock Editor To Scene");
});
Space(2);
}, "System", SystemSettingPanelOpen, true);
}, "Setting", SettingPanelOpen, true);
}
#endregion
#region --- TSK ---
public static void DoTask(Task task)
{
if (TaskMap.Count == 0) { return; }
if (TheExportMod == ExportMod.AskEverytime && !BrowseExportPath()) { return; }
RefreshMergeSetting();
string failMessage = "[Voxel] Failed to create model for {0} model{1}.";
int successedNum = 0;
int failedNum = 0;
int taskCount = TaskMap.Count;
bool useLOD = task == Task.Lod;
bool useMaterial = task == Task.Material;
var resultList = new List<Core_Voxel.Result>();
Util.ProgressBar("Creating", "Starting task...", 0f);
Util.StartWatch();
ForAllSelection((pathData) =>
{
try
{
string fileName = Util.GetNameWithoutExtension(pathData.Path);
Util.ProgressBar("Creating", string.Format("[{1}/{2}] Creating {0}", fileName, successedNum + failedNum + 1, taskCount), (float)(successedNum + failedNum + 1) / (taskCount + 1));
VoxelData voxelData = null;
switch (task)
{
case Task.Prefab:
// Model
if (pathData.Extension == ".vox" || pathData.Extension == ".qb")
{
voxelData = VoxelFile.GetVoxelData(
Util.FileToByte(pathData.Path),
pathData.Extension == ".vox"
);
// Rotate 180 in Y-Axis (No Rig Data)
if (!FacingYPlusInMV)
{
voxelData.Rotate180InY();
}
// Create Result
var result = Core_Voxel.CreateLodModel(
voxelData,
ModelScale,
useLOD ? LodNum : 1,
useMaterial,
LightMapSupportMode,
ModelPivot
);
if (TheExportMod == ExportMod.OriginalPath)
{
result.ExportRoot = Util.GetParentPath(pathData.Path);
result.ExportSubRoot = "";
}
else
{
result.ExportRoot = ExportPath;
result.ExportSubRoot = pathData.Root;
}
result.FileName = fileName;
result.Extension = task == Task.Obj ? ".obj" : ".prefab";
result.IsRigged = false;
result.WithAvatar = false;
resultList.Add(result);
}
break;
}
successedNum++;
}
catch (System.Exception ex)
{
failMessage += "\n[path] " + pathData.Path + "\n" + ex.Message;
failedNum++;
}
});
// File
try
{
Core_File.CreateFileForResult(
resultList,
useMaterial ? TheShaders : new Shader[1] { TheDiffuseShader },
ShaderKeywords,
ShaderValueRemaps,
ModelScale,
ModelPivot,
(Core_File.ReplacementMode)ReplacementModeIndex.Value,
ShaderMainTextureKeyword.Value
);
double taskTime = Util.StopWatchAndGetTime();
// Log Messages
if (successedNum > 0)
{
string msg = string.Format("[Voxel] {0} model{1} created in {2}sec.", successedNum, (successedNum > 1 ? "s" : ""), taskTime.ToString("0.00"));
if (LogMessage)
{
Debug.Log(msg);
}
if (ShowDialog)
{
Util.Dialog("Success", msg, "OK");
}
}
if (failedNum > 0)
{
string msg = string.Format(failMessage, failedNum.ToString(), (failedNum > 1 ? "s" : ""));
if (LogMessage)
{
Debug.LogWarning(msg);
}
if (ShowDialog)
{
Util.Dialog("Warning", msg, "OK");
}
}
}
catch (System.Exception ex)
{
Debug.LogError(ex.Message);
}
Util.ClearProgressBar();
}
#endregion
#region --- LGC ---
public static void LoadSetting()
{
ViewPanelOpen.Load();
CreatePanelOpen.Load();
SettingPanelOpen.Load();
AboutPanelOpen.Load();
ModelGenerationSettingPanelOpen.Load();
SpriteGenerationSettingPanelOpen.Load();
SystemSettingPanelOpen.Load();
ToolPanelOpen.Load();
ColorfulTitle.Load();
ExportPath.Load();
ExportModIndex.Load();
ModelScale.Load();
LodNum.Load();
LogMessage.Load();
ShowDialog.Load();
LightMapSupportTypeIndex.Load();
OptimizationSettingPanelOpen.Load();
ShaderSettingPanelOpen.Load();
OptimizeFront.Load();
OptimizeBack.Load();
OptimizeUp.Load();
OptimizeDown.Load();
OptimizeLeft.Load();
OptimizeRight.Load();
EditorDockToScene.Load();
ModelPivot.Load();
FacingYPlusInMV.Load();
CurrentShowingShaderIndex.Load();
ReplacementModeIndex.Load();
ShaderMainTextureKeyword.Load();
for (int i = 0; i < Shader_Paths.Length; i++)
{
Shader_Paths[i].Load();
}
for (int i = 0; i < Shader_Keywords.Length; i++)
{
Shader_Keywords[i].Load();
}
for (int i = 0; i < Shader_ValueRemaps.Length; i++)
{
Shader_ValueRemaps[i].Load();
}
}
private static void SaveSetting()
{
ViewPanelOpen.TrySave();
CreatePanelOpen.TrySave();
SettingPanelOpen.TrySave();
AboutPanelOpen.TrySave();
ModelGenerationSettingPanelOpen.TrySave();
SpriteGenerationSettingPanelOpen.TrySave();
SystemSettingPanelOpen.TrySave();
ToolPanelOpen.TrySave();
ColorfulTitle.TrySave();
ExportPath.TrySave();
ExportModIndex.TrySave();
ModelScale.TrySave();
LodNum.TrySave();
LogMessage.TrySave();
ShowDialog.TrySave();
LightMapSupportTypeIndex.TrySave();
OptimizationSettingPanelOpen.TrySave();
ShaderSettingPanelOpen.TrySave();
OptimizeFront.TrySave();
OptimizeBack.TrySave();
OptimizeUp.TrySave();
OptimizeDown.TrySave();
OptimizeLeft.TrySave();
OptimizeRight.TrySave();
EditorDockToScene.TrySave();
ModelPivot.TrySave();
FacingYPlusInMV.TrySave();
CurrentShowingShaderIndex.TrySave();
ReplacementModeIndex.TrySave();
ShaderMainTextureKeyword.TrySave();
for (int i = 0; i < Shader_Paths.Length; i++)
{
Shader_Paths[i].TrySave();
}
for (int i = 0; i < Shader_Keywords.Length; i++)
{
Shader_Keywords[i].TrySave();
}
for (int i = 0; i < Shader_ValueRemaps.Length; i++)
{
Shader_ValueRemaps[i].TrySave();
}
}
private static void RefreshSelection()
{
VoxNum = 0;
QbNum = 0;
FolderNum = 0;
JsonNum = 0;
// Fix Selection
var fixedSelection = new List<KeyValuePair<Object, string>>();
for (int i = 0; i < Selection.objects.Length; i++)
{
fixedSelection.Add(new KeyValuePair<Object, string>(
Selection.objects[i],
AssetDatabase.GetAssetPath(Selection.objects[i]))
);
}
for (int i = 0; i < fixedSelection.Count; i++)
{
if (!fixedSelection[i].Key) { continue; }
var pathI = fixedSelection[i].Value;
for (int j = 0; j < fixedSelection.Count; j++)
{
if (i == j || !fixedSelection[j].Key) { continue; }
var pathJ = fixedSelection[j].Value;
if (Util.IsChildPathCompair(pathJ, pathI))
{
fixedSelection[j] = new KeyValuePair<Object, string>(null, null);
}
}
}
UpdateTaskMap(fixedSelection);
}
public static void UpdateTaskMap(List<KeyValuePair<Object, string>> fixedSelection)
{
// Get Task Map
TaskMap.Clear();
for (int i = 0; i < fixedSelection.Count; i++)
{
if (ReferenceEquals(fixedSelection[i].Key, null)) { continue; }
var obj = fixedSelection[i].Key;
var path = fixedSelection[i].Value;
path = Util.FixPath(path);
var ex = Util.GetExtension(path);
if (AssetDatabase.IsValidFolder(path))
{
FolderNum++;
var files = Util.GetFilesIn(path, "*.vox", "*.qb", "*.json");
for (int j = 0; j < files.Length; j++)
{
var filePath = Util.FixedRelativePath(files[j].FullName);
var fileEx = Util.GetExtension(filePath);
if (fileEx == ".vox" || fileEx == ".qb" || fileEx == ".json")
{
var fileObj = AssetDatabase.LoadAssetAtPath<Object>(filePath);
if (fileObj && !TaskMap.ContainsKey(fileObj))
{
TaskMap.Add(fileObj, new PathData()
{
Path = filePath,
Extension = fileEx,
Root = Util.FixPath(filePath.Substring(
path.Length,
filePath.Length - path.Length - Util.GetNameWithExtension(filePath).Length
)),
});
if (fileEx == ".vox")
{
VoxNum++;
FixVoxIcon(fileObj);
}
else if (fileEx == ".qb")
{
QbNum++;
FixQbIcon(fileObj);
}
else if (fileEx == ".json")
{
JsonNum++;
FixJsonIcon(fileObj);
}
}
}
}
}
else if (ex == ".vox" || ex == ".qb" || ex == ".json")
{
if (!TaskMap.ContainsKey(obj))
{
TaskMap.Add(obj, new PathData()
{
Path = path,
Extension = ex,
Root = "",
});
if (ex == ".vox")
{
VoxNum++;
FixVoxIcon(obj);
}
else if (ex == ".qb")
{
QbNum++;
FixQbIcon(obj);
}
else if (ex == ".json")
{
JsonNum++;
FixJsonIcon(obj);
}
}
}
}
ObjNum = Selection.objects.Length;
}
private static void ForAllSelection(System.Action<PathData> action)
{
foreach (var key_Value in TaskMap)
{
action(key_Value.Value);
}
}
private static void FixVoxIcon(Object vox)
{
if (!VoxFileIcon)
{
VoxFileIcon = AssetPreview.GetMiniThumbnail(vox);
}
}
private static void FixQbIcon(Object qb)
{
if (!QbFileIcon)
{
QbFileIcon = AssetPreview.GetMiniThumbnail(qb);
}
}
private static void FixJsonIcon(Object json)
{
if (!JsonFileIcon)
{
JsonFileIcon = AssetPreview.GetMiniThumbnail(json);
}
}
private static bool BrowseExportPath()
{
string newPath = Util.FixPath(EditorUtility.OpenFolderPanel("Select Export Path", ExportPath, ""));
if (!string.IsNullOrEmpty(newPath))
{
newPath = Util.FixedRelativePath(newPath);
if (!string.IsNullOrEmpty(newPath))
{
ExportPath.Value = newPath;
return true;
}
else
{
Util.Dialog("Warning", "Export path must in Assets folder.", "OK");
}
}
return false;
}
#endregion
#region --- UTL ---
public static void RefreshMergeSetting()
{
Core_Voxel.SetMergeInDirection(OptimizeFront, OptimizeBack, OptimizeUp, OptimizeDown, OptimizeLeft, OptimizeRight);
}
private static void ShaderPropertyGUI(int index, string name)
{
const int GAP = 12;
if (index < 0)
{
// Title
LayoutH(() =>
{
EditorGUI.LabelField(GUIRect(0, 16), "");
EditorGUI.LabelField(GUIRect(0, 16), "Keyword", EditorStyles.centeredGreyMiniLabel);
Space(GAP);
EditorGUI.LabelField(GUIRect(18 * 4 + 30 + 2 + 2, 16), "Remap", EditorStyles.centeredGreyMiniLabel);
});
}
else
{
// Content
LayoutH(() =>
{
EditorGUI.LabelField(GUIRect(0, 16), name);
Shader_Keywords[index].Value = EditorGUI.TextField(GUIRect(0, 16), Shader_Keywords[index]);
Space(GAP);
bool oldE = GUI.enabled;
GUI.enabled = false;
EditorGUI.FloatField(GUIRect(18, 16), SHADER_VALUE_REMAP_SOURCE[index].x);
Space(2);
EditorGUI.FloatField(GUIRect(30, 16), SHADER_VALUE_REMAP_SOURCE[index].y);
GUI.enabled = oldE;
EditorGUI.LabelField(GUIRect(18, 16), "→", EditorStyles.centeredGreyMiniLabel);
Vector2 newRemap = Vector2.zero;
newRemap.x = EditorGUI.FloatField(GUIRect(18, 16), Shader_ValueRemaps[index].Value.x);
Space(2);
newRemap.y = EditorGUI.FloatField(GUIRect(18, 16), Shader_ValueRemaps[index].Value.y);
Shader_ValueRemaps[index].Value = newRemap;
});
}
}
#endregion
}
[CustomEditor(typeof(DefaultAsset)), CanEditMultipleObjects]
public class VoxelInspector : Editor
{
private void OnEnable()
{
if (HasVoxelTarget())
{
VoxelToUnityWindow.Window_Enable();
}
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
if (HasVoxelTarget())
{
bool oldE = GUI.enabled;
GUI.enabled = true;
VoxelToUnityWindow.Window_Main();
GUI.enabled = oldE;
}
}
private bool HasVoxelTarget()
{
for (int i = 0; i < targets.Length; i++)
{
string path = AssetDatabase.GetAssetPath(targets[i]);
string ex = Util.GetExtension(path);
if (ex == ".vox" || ex == ".qb" || Util.HasFileIn(path, "*.vox", "*.qb"))
{
return true;
}
}
return false;
}
}
}