Files
Zombie/Assets/MantisLODEditor/Editor/MantisLODEditorBatch.cs

337 lines
12 KiB
C#

/*--------------------------------------------------------
MantisLODEditorBatch.cs
Created by MINGFEN WANG on 15-12-26.
Copyright (c) 2013 MINGFEN WANG. All rights reserved.
http://www.mesh-online.net/
--------------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using UnityEditor;
using UnityEngine;
namespace MantisLODEditor
{
public class MantisLODEditorBatch: EditorWindow {
// run when focused
[DllImport("MantisLOD")]
private static extern int create_progressive_mesh(Vector3[] vertex_array, int vertex_count, int[] triangle_array, int triangle_count, Vector3[] normal_array, int normal_count, Color[] color_array, int color_count, Vector2[] uv_array, int uv_count, int protect_boundary, int protect_detail, int protect_symmetry, int protect_normal, int protect_shape);
[DllImport("MantisLOD")]
private static extern int get_triangle_list(int index, float goal, int[] triangles, ref int triangle_count);
[DllImport("MantisLOD")]
private static extern int delete_progressive_mesh(int index);
private Mantis_Mesh[] Mantis_Meshes = null;
// define how to optimize the meshes
private int max_lod_count = 8;
private bool protect_boundary = true;
private bool protect_detail = false;
private bool protect_symmetry = false;
private bool protect_normal = false;
private bool protect_shape = true;
private int state = 0;
private float start_time = 0.0f;
private List<string> file_name_list = null;
private int file_name_index = 0;
private string file_name_hint = null;
private string message_hint = null;
[MenuItem("Window/Mantis LOD Editor/Assets/Create/Mantis LOD Editor Batch")]
static void Init () {
// Get existing open window or if none, make a new one:
MantisLODEditorBatch window = (MantisLODEditorBatch)EditorWindow.GetWindow (typeof (MantisLODEditorBatch));
window.Show();
}
void OnGUI () {
GUIStyle helpStyle = new GUIStyle(GUI.skin.box);
// display the title
GUI.enabled = true;
GUILayout.Label(
"Mantis LOD Editor Batch Edition V6.3"
, helpStyle
, GUILayout.ExpandWidth(true));
// display controls
GUI.enabled = (state == 0);
max_lod_count = EditorGUILayout.IntField("Max LOD Count", max_lod_count);
protect_boundary = EditorGUILayout.Toggle ("Protect Boundary", protect_boundary);
protect_detail = EditorGUILayout.Toggle ("More Details", protect_detail);
protect_symmetry = EditorGUILayout.Toggle ("Protect Symmetry", protect_symmetry);
protect_normal = EditorGUILayout.Toggle ("Protect Hard Edge", protect_normal);
protect_shape = EditorGUILayout.Toggle ("Beautiful Triangles", protect_shape);
// generate progressive meshes
if(GUILayout.Button("Batch Generate", GUILayout.ExpandWidth(true), GUILayout.ExpandWidth(true))) {
if (GetFileList()) {
message_hint = null;
// start the batch
start_update(1);
}
}
// we are still alive
if(state != 0) {
EditorGUILayout.LabelField(file_name_hint);
EditorGUILayout.LabelField("Time Elapse", (Time.realtimeSinceStartup - start_time).ToString("#0.0"));
}
// display something
if (message_hint != null) {
EditorUtility.DisplayDialog("Message", message_hint, "OK");
message_hint = null;
/* GUILayout.Label(
message_hint
, helpStyle
, GUILayout.ExpandWidth(true));*/
}
}
private void start_update(int one_state) {
state = one_state;
start_time = Time.realtimeSinceStartup;
EditorApplication.update += Update;
}
private void end_update() {
state = 0;
start_time = 0.0f;
EditorApplication.update -= Update;
}
void Update() {
// we cannot use nice yield method in Editor class, I have to write ugly code:(
switch(state) {
case 1: ShowModelName(); break;
case 2: GenerateProgressiveMesh(); break;
case 3: ShowResult(); break;
}
// show time elapse label in main thread
Repaint();
}
private void ShowModelName() {
file_name_hint = file_name_list[file_name_index];
state = 2;
}
private void ShowResult() {
message_hint = "All Done. Totally " + file_name_index.ToString() + " progressive meshes generated into 'Assets/Resources'.";
end_update();
}
private void GenerateProgressiveMesh() {
try {
CreateAsset(Path.GetFileNameWithoutExtension(file_name_list[file_name_index]));
} finally {
}
// forward to the next
file_name_index++;
// all done
if (file_name_index == file_name_list.Count) {
state = 3;
} else {
state = 1;
}
}
private bool GetFileList() {
if (!Directory.Exists("Assets/Resources")) {
message_hint = "Please create 'Assets/Resources' directory, then put all your 3d models into the directory and try again.";
return false;
}
// Reset file name list and its index
file_name_list = new List<string>();
file_name_index = 0;
// Get file name list of supported 3d models
List<string> temp_file_name_list = new List<string>(Directory.GetFiles("Assets/Resources"));
foreach (string filename in temp_file_name_list) {
string extensionname = Path.GetExtension(filename).ToLower();
// You may add extensions here
if (string.Compare(extensionname, ".fbx") == 0 ||
string.Compare(extensionname, ".dae") == 0 ||
string.Compare(extensionname, ".3ds") == 0 ||
string.Compare(extensionname, ".dxf") == 0 ||
string.Compare(extensionname, ".obj") == 0 ||
string.Compare(extensionname, ".mb") == 0 ||
string.Compare(extensionname, ".ma") == 0 ||
string.Compare(extensionname, ".c4d") == 0 ||
string.Compare(extensionname, ".max") == 0 ||
string.Compare(extensionname, ".jas") == 0 ||
string.Compare(extensionname, ".lxo") == 0 ||
string.Compare(extensionname, ".lws") == 0 ||
string.Compare(extensionname, ".blend") == 0) {
// Add to the list
file_name_list.Add(filename);
}
}
// No 3d model in the directory
if (file_name_list.Count == 0) {
message_hint = "Please put all your 3d models into 'Assets/Resources' and try again.\n\nSupported file extensions:\n.fbx\n.dae\n.3ds\n.dxf\n.obj\n.mb\n.ma\n.c4d\n.max\n.jas\n.lxo\n.lws\n.blend\n\nYou may modify the script(MantisLODEditorPro/Editor/ProgressiveMeshBatch.cs) to support future extensions.";
return false;
}
return true;
}
public void CreateAsset(string filename) {
ProgressiveMesh pm = (ProgressiveMesh)ScriptableObject.CreateInstance(typeof(ProgressiveMesh));
init_all(filename);
optimize();
fill_progressive_mesh(pm);
clean_all();
string filePath = "Assets/Resources/" + filename + "_Progressive_Mesh.asset";
AssetDatabase.CreateAsset(pm, filePath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
private void fill_progressive_mesh(ProgressiveMesh pm) {
int triangle_count = 0;
int[][][][] temp_triangles;
temp_triangles = new int[max_lod_count][][][];
// max lod count
triangle_count++;
for (int lod=0; lod<temp_triangles.Length; lod++) {
float quality = 100.0f * (temp_triangles.Length - lod) / temp_triangles.Length;
temp_triangles[lod] = new int[Mantis_Meshes.Length][][];
// mesh count
triangle_count++;
int mesh_count = 0;
pm.uuids = new string[Mantis_Meshes.Length];
foreach (Mantis_Mesh child in Mantis_Meshes) {
// get triangle list by quality value
if(child.index != -1 && get_triangle_list(child.index, quality, child.out_triangles, ref child.out_count) == 1) {
if(child.out_count > 0) {
int counter = 0;
int mat = 0;
temp_triangles[lod][mesh_count] = new int[child.mesh.subMeshCount][];
// sub mesh count
triangle_count++;
while(counter < child.out_count) {
int len = child.out_triangles[counter];
// triangle count
triangle_count++;
// triangle list count
triangle_count += len;
counter++;
int[] new_triangles = new int[len];
Array.Copy(child.out_triangles, counter, new_triangles, 0, len);
temp_triangles[lod][mesh_count][mat] = new_triangles;
counter += len;
mat++;
}
} else {
temp_triangles[lod][mesh_count] = new int[child.mesh.subMeshCount][];
// sub mesh count
triangle_count++;
for (int mat=0; mat<temp_triangles[lod][mesh_count].Length; mat++) {
temp_triangles[lod][mesh_count][mat] = new int[0];
// triangle count
triangle_count++;
}
}
}
pm.uuids[mesh_count] = child.uuid;
mesh_count++;
}
}
// create fix size array
pm.triangles = new int[triangle_count];
// reset the counter
triangle_count = 0;
// max lod count
pm.triangles[triangle_count] = temp_triangles.Length;
triangle_count++;
for (int lod=0; lod<temp_triangles.Length; lod++) {
// mesh count
pm.triangles[triangle_count] = temp_triangles[lod].Length;
triangle_count++;
for (int mesh_count=0; mesh_count<temp_triangles[lod].Length; mesh_count++) {
// sub mesh count
pm.triangles[triangle_count] = temp_triangles[lod][mesh_count].Length;
triangle_count++;
for (int mat=0; mat<temp_triangles[lod][mesh_count].Length; mat++) {
// triangle count
pm.triangles[triangle_count] = temp_triangles[lod][mesh_count][mat].Length;
triangle_count++;
Array.Copy(temp_triangles[lod][mesh_count][mat], 0, pm.triangles, triangle_count, temp_triangles[lod][mesh_count][mat].Length);
// triangle list count
triangle_count += temp_triangles[lod][mesh_count][mat].Length;
}
}
}
}
private void optimize() {
if (Mantis_Meshes != null) {
foreach (Mantis_Mesh child in Mantis_Meshes) {
int triangle_number = child.mesh.triangles.Length;
Vector3[] vertices = child.mesh.vertices;
// in data is large than origin data
int[] triangles = new int[triangle_number+child.mesh.subMeshCount];
// we need normal data to protect normal boundary
Vector3[] normals = child.mesh.normals;
// we need color data to protect color boundary
Color[] colors = child.mesh.colors;
// we need uv data to protect uv boundary
Vector2[] uvs = child.mesh.uv;
int counter = 0;
for(int i=0; i<child.mesh.subMeshCount; i++) {
int[] sub_triangles = child.mesh.GetTriangles(i);
triangles[counter] = sub_triangles.Length;
counter++;
Array.Copy(sub_triangles, 0, triangles, counter, sub_triangles.Length);
counter += sub_triangles.Length;
}
// create progressive mesh
child.index = create_progressive_mesh(vertices, vertices.Length, triangles, counter, normals, normals.Length, colors, colors.Length, uvs, uvs.Length, protect_boundary?1:0, protect_detail?1:0, protect_symmetry?1:0, protect_normal?1:0, protect_shape?1:0);
}
}
}
private void init_all(string filename) {
get_all_meshes(filename);
if (Mantis_Meshes != null) {
foreach (Mantis_Mesh child in Mantis_Meshes) {
int triangle_number = child.mesh.triangles.Length;
// out data is large than origin data
child.out_triangles = new int[triangle_number+child.mesh.subMeshCount];
child.index = -1;
}
}
}
private string get_uuid_from_mesh(Mesh mesh) {
string uuid = mesh.name + "_" + mesh.vertexCount.ToString() + "_" + mesh.subMeshCount.ToString();
for (int i=0; i<mesh.subMeshCount; ++i) {
uuid += "_" + mesh.GetIndexCount(i).ToString();
}
return uuid;
}
private void get_all_meshes(string filename) {
Mesh[] meshes = Resources.LoadAll<Mesh>(filename);
int mesh_count = meshes.Length;
if (mesh_count > 0) {
Mantis_Meshes = new Mantis_Mesh[mesh_count];
int counter = 0;
foreach (Mesh mesh in meshes) {
Mantis_Meshes[counter] = new Mantis_Mesh();
Mantis_Meshes[counter].mesh = mesh;
Mantis_Meshes[counter].uuid = get_uuid_from_mesh(mesh);
counter++;
}
}
}
private void clean_all() {
if (Mantis_Meshes != null) {
foreach (Mantis_Mesh child in Mantis_Meshes) {
if(child.index != -1) {
Resources.UnloadAsset(child.mesh);
// do not need it
delete_progressive_mesh (child.index);
child.index = -1;
}
}
Mantis_Meshes = null;
}
}
}
}