|
|
|
|
|
namespace MagicaVoxelToolbox {
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
|
|
public struct Util {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region --- File ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string Read (string path) {
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
StreamReader sr = File.OpenText(path);
|
|
|
|
|
|
string data = sr.ReadToEnd();
|
|
|
|
|
|
sr.Close();
|
|
|
|
|
|
return data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void Write (string data, string path) {
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
FileStream fs = new FileStream(path, FileMode.Create);
|
|
|
|
|
|
StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
|
|
|
|
|
|
sw.Write(data);
|
|
|
|
|
|
sw.Close();
|
|
|
|
|
|
fs.Close();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void CreateFolder (string path) {
|
|
|
|
|
|
if (!string.IsNullOrEmpty(path) && !DirectoryExists(path)) {
|
|
|
|
|
|
string pPath = GetParentPath(path);
|
|
|
|
|
|
if (!DirectoryExists(pPath)) {
|
|
|
|
|
|
CreateFolder(pPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
Directory.CreateDirectory(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static byte[] FileToByte (string path) {
|
|
|
|
|
|
byte[] bytes = null;
|
|
|
|
|
|
if (FileExists(path)) {
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
bytes = File.ReadAllBytes(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
return bytes;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void ByteToFile (byte[] bytes, string path) {
|
|
|
|
|
|
string parentPath = GetParentPath(path);
|
|
|
|
|
|
CreateFolder(parentPath);
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write);
|
|
|
|
|
|
fs.Write(bytes, 0, bytes.Length);
|
|
|
|
|
|
fs.Close();
|
|
|
|
|
|
fs.Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static bool HasFileIn (string path, params string[] searchPattern) {
|
|
|
|
|
|
if (PathIsDirectory(path)) {
|
|
|
|
|
|
for (int i = 0; i < searchPattern.Length; i++) {
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
if (new DirectoryInfo(path).GetFiles(searchPattern[i], SearchOption.AllDirectories).Length > 0) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static FileInfo[] GetFilesIn (string path, params string[] searchPattern) {
|
|
|
|
|
|
List<FileInfo> allFiles = new List<FileInfo>();
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
if (PathIsDirectory(path)) {
|
|
|
|
|
|
if (searchPattern.Length > 0) {
|
|
|
|
|
|
allFiles.AddRange(new DirectoryInfo(path).GetFiles("*.*", SearchOption.AllDirectories));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
for (int i = 0; i < searchPattern.Length; i++) {
|
|
|
|
|
|
allFiles.AddRange(new DirectoryInfo(path).GetFiles(searchPattern[i], SearchOption.AllDirectories));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return allFiles.ToArray();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void DeleteFile (string path) {
|
|
|
|
|
|
if (FileExists(path)) {
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
File.Delete(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region --- Path ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private const string ROOT_NAME = "MagicaVoxel Toolbox";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string GetRootPath (ScriptableObject scriptObj) {
|
|
|
|
|
|
var rootPath = "";
|
|
|
|
|
|
var script = MonoScript.FromScriptableObject(scriptObj);
|
|
|
|
|
|
if (script) {
|
|
|
|
|
|
var path = AssetDatabase.GetAssetPath(script);
|
|
|
|
|
|
string rootName = ROOT_NAME;
|
|
|
|
|
|
if (!string.IsNullOrEmpty(path)) {
|
|
|
|
|
|
int index = path.LastIndexOf(rootName);
|
|
|
|
|
|
if (index >= 0) {
|
|
|
|
|
|
rootPath = path.Substring(0, index + rootName.Length);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return rootPath;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string FixPath (string path, bool forUnity = true) {
|
|
|
|
|
|
char dsChar = forUnity ? '/' : Path.DirectorySeparatorChar;
|
|
|
|
|
|
char adsChar = forUnity ? '\\' : Path.AltDirectorySeparatorChar;
|
|
|
|
|
|
path = path.Replace(adsChar, dsChar);
|
|
|
|
|
|
path = path.Replace(new string(dsChar, 2), dsChar.ToString());
|
|
|
|
|
|
while (path.Length > 0 && path[0] == dsChar) {
|
|
|
|
|
|
path = path.Remove(0, 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
while (path.Length > 0 && path[path.Length - 1] == dsChar) {
|
|
|
|
|
|
path = path.Remove(path.Length - 1, 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
return path;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string GetParentPath (string path) {
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
return FixedRelativePath(Directory.GetParent(path).FullName);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string FixedRelativePath (string path) {
|
|
|
|
|
|
path = FixPath(path);
|
|
|
|
|
|
if (path.StartsWith("Assets")) {
|
|
|
|
|
|
return path;
|
|
|
|
|
|
}
|
|
|
|
|
|
var fixedDataPath = FixPath(Application.dataPath);
|
|
|
|
|
|
if (path.StartsWith(fixedDataPath)) {
|
|
|
|
|
|
return "Assets" + path.Substring(fixedDataPath.Length);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string GetFullPath (string path) {
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
return new FileInfo(path).FullName;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string CombinePaths (params string[] paths) {
|
|
|
|
|
|
string path = "";
|
|
|
|
|
|
for (int i = 0; i < paths.Length; i++) {
|
|
|
|
|
|
path = Path.Combine(path, paths[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
return path;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string GetExtension (string path) {
|
|
|
|
|
|
return Path.GetExtension(path);//.txt
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string GetNameWithoutExtension (string path) {
|
|
|
|
|
|
return Path.GetFileNameWithoutExtension(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string GetNameWithExtension (string path) {
|
|
|
|
|
|
return Path.GetFileName(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string ChangeExtension (string path, string newEx) {
|
|
|
|
|
|
return Path.ChangeExtension(path, newEx);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static bool DirectoryExists (string path) {
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
return Directory.Exists(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static bool FileExists (string path) {
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
return File.Exists(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static bool PathIsDirectory (string path) {
|
|
|
|
|
|
if (!DirectoryExists(path)) { return false; }
|
|
|
|
|
|
path = FixPath(path, false);
|
|
|
|
|
|
FileAttributes attr = File.GetAttributes(path);
|
|
|
|
|
|
if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
|
|
|
|
|
|
return true;
|
|
|
|
|
|
else
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static bool IsChildPath (string pathA, string pathB) {
|
|
|
|
|
|
if (pathA.Length == pathB.Length) {
|
|
|
|
|
|
return pathA == pathB;
|
|
|
|
|
|
} else if (pathA.Length > pathB.Length) {
|
|
|
|
|
|
return IsChildPathCompair(pathA, pathB);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return IsChildPathCompair(pathB, pathA);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static bool IsChildPathCompair (string longPath, string path) {
|
|
|
|
|
|
if (longPath.Length <= path.Length || !PathIsDirectory(path) || !longPath.StartsWith(path)) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
char c = longPath[path.Length];
|
|
|
|
|
|
if (c != Path.DirectorySeparatorChar && c != Path.AltDirectorySeparatorChar) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region --- Message ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static bool Dialog (string title, string msg, string ok, string cancel = "") {
|
|
|
|
|
|
//EditorApplication.Beep();
|
|
|
|
|
|
PauseWatch();
|
|
|
|
|
|
if (string.IsNullOrEmpty(cancel)) {
|
|
|
|
|
|
bool sure = EditorUtility.DisplayDialog(title, msg, ok);
|
|
|
|
|
|
RestartWatch();
|
|
|
|
|
|
return sure;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
bool sure = EditorUtility.DisplayDialog(title, msg, ok, cancel);
|
|
|
|
|
|
RestartWatch();
|
|
|
|
|
|
return sure;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static int DialogComplex (string title, string msg, string ok, string cancel, string alt) {
|
|
|
|
|
|
//EditorApplication.Beep();
|
|
|
|
|
|
PauseWatch();
|
|
|
|
|
|
int index = EditorUtility.DisplayDialogComplex(title, msg, ok, cancel, alt);
|
|
|
|
|
|
RestartWatch();
|
|
|
|
|
|
return index;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void ProgressBar (string title, string msg, float value) {
|
|
|
|
|
|
value = Mathf.Clamp01(value);
|
|
|
|
|
|
EditorUtility.DisplayProgressBar(title, msg, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void ClearProgressBar () {
|
|
|
|
|
|
EditorUtility.ClearProgressBar();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region --- Watch ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static System.Diagnostics.Stopwatch TheWatch;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void StartWatch () {
|
|
|
|
|
|
TheWatch = new System.Diagnostics.Stopwatch();
|
|
|
|
|
|
TheWatch.Start();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void PauseWatch () {
|
|
|
|
|
|
if (TheWatch != null) {
|
|
|
|
|
|
TheWatch.Stop();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void RestartWatch () {
|
|
|
|
|
|
if (TheWatch != null) {
|
|
|
|
|
|
TheWatch.Start();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static double StopWatchAndGetTime () {
|
|
|
|
|
|
if (TheWatch != null) {
|
|
|
|
|
|
TheWatch.Stop();
|
|
|
|
|
|
return TheWatch.Elapsed.TotalSeconds;
|
|
|
|
|
|
}
|
|
|
|
|
|
return 0f;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region --- Misc ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static bool IsTypingInGUI () {
|
|
|
|
|
|
return GUIUtility.keyboardControl != 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static bool NoFuncKeyPressing () {
|
|
|
|
|
|
return !Event.current.alt && !Event.current.control && !Event.current.shift;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Mesh CreateConeMesh (float radius, float height, int subdivisions = 12) {
|
|
|
|
|
|
Mesh mesh = new Mesh();
|
|
|
|
|
|
|
|
|
|
|
|
Vector3[] vertices = new Vector3[subdivisions + 2];
|
|
|
|
|
|
Vector2[] uv = new Vector2[vertices.Length];
|
|
|
|
|
|
int[] triangles = new int[(subdivisions * 2) * 3];
|
|
|
|
|
|
|
|
|
|
|
|
vertices[0] = Vector3.zero;
|
|
|
|
|
|
uv[0] = new Vector2(0.5f, 0f);
|
|
|
|
|
|
for (int i = 0, n = subdivisions - 1; i < subdivisions; i++) {
|
|
|
|
|
|
float ratio = (float)i / n;
|
|
|
|
|
|
float r = ratio * (Mathf.PI * 2f);
|
|
|
|
|
|
float x = Mathf.Cos(r) * radius;
|
|
|
|
|
|
float z = Mathf.Sin(r) * radius;
|
|
|
|
|
|
vertices[i + 1] = new Vector3(x, 0f, z);
|
|
|
|
|
|
uv[i + 1] = new Vector2(ratio, 0f);
|
|
|
|
|
|
}
|
|
|
|
|
|
vertices[subdivisions + 1] = new Vector3(0f, height, 0f);
|
|
|
|
|
|
uv[subdivisions + 1] = new Vector2(0.5f, 1f);
|
|
|
|
|
|
|
|
|
|
|
|
// construct bottom
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0, n = subdivisions - 1; i < n; i++) {
|
|
|
|
|
|
int offset = i * 3;
|
|
|
|
|
|
triangles[offset] = 0;
|
|
|
|
|
|
triangles[offset + 1] = i + 1;
|
|
|
|
|
|
triangles[offset + 2] = i + 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// construct sides
|
|
|
|
|
|
|
|
|
|
|
|
int bottomOffset = subdivisions * 3;
|
|
|
|
|
|
for (int i = 0, n = subdivisions - 1; i < n; i++) {
|
|
|
|
|
|
int offset = i * 3 + bottomOffset;
|
|
|
|
|
|
triangles[offset] = i + 1;
|
|
|
|
|
|
triangles[offset + 1] = subdivisions + 1;
|
|
|
|
|
|
triangles[offset + 2] = i + 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mesh.vertices = vertices;
|
|
|
|
|
|
mesh.uv = uv;
|
|
|
|
|
|
mesh.triangles = triangles;
|
|
|
|
|
|
mesh.RecalculateBounds();
|
|
|
|
|
|
mesh.RecalculateNormals();
|
|
|
|
|
|
|
|
|
|
|
|
return mesh;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Mesh CreateSectorMesh (float radiusA, float radiusB, float height, float angle, int subDivisions = 12) {
|
|
|
|
|
|
|
|
|
|
|
|
subDivisions = Mathf.Clamp(subDivisions, 2, 128);
|
|
|
|
|
|
angle = Mathf.Repeat(angle, 360f);
|
|
|
|
|
|
|
|
|
|
|
|
Mesh mesh = new Mesh();
|
|
|
|
|
|
|
|
|
|
|
|
int triLen = (8 * (subDivisions - 1) + 4) * 3;
|
|
|
|
|
|
int vLen = subDivisions * 4;
|
|
|
|
|
|
var vs = new Vector3[vLen];
|
|
|
|
|
|
var uv = new Vector2[vLen];
|
|
|
|
|
|
var tris = new int[triLen];
|
|
|
|
|
|
|
|
|
|
|
|
float currentAngle = -angle / 2f;
|
|
|
|
|
|
for (int i = 0; i < subDivisions; i++, currentAngle += angle / (subDivisions - 1)) {
|
|
|
|
|
|
|
|
|
|
|
|
float rAngle = currentAngle * Mathf.Deg2Rad;
|
|
|
|
|
|
|
|
|
|
|
|
vs[i * 4 + 0] = new Vector3(Mathf.Sin(rAngle) * radiusA, -height * 0.5f, Mathf.Cos(rAngle) * radiusA);
|
|
|
|
|
|
vs[i * 4 + 1] = new Vector3(Mathf.Sin(rAngle) * radiusB, -height * 0.5f, Mathf.Cos(rAngle) * radiusB);
|
|
|
|
|
|
vs[i * 4 + 2] = new Vector3(Mathf.Sin(rAngle) * radiusA, height * 0.5f, Mathf.Cos(rAngle) * radiusA);
|
|
|
|
|
|
vs[i * 4 + 3] = new Vector3(Mathf.Sin(rAngle) * radiusB, height * 0.5f, Mathf.Cos(rAngle) * radiusB);
|
|
|
|
|
|
|
|
|
|
|
|
uv[i * 4 + 0] = new Vector2(0, 0);
|
|
|
|
|
|
uv[i * 4 + 1] = new Vector2(0, 1);
|
|
|
|
|
|
uv[i * 4 + 2] = new Vector2(1, 0);
|
|
|
|
|
|
uv[i * 4 + 3] = new Vector2(1, 1);
|
|
|
|
|
|
|
|
|
|
|
|
if (i < subDivisions - 1) {
|
|
|
|
|
|
|
|
|
|
|
|
tris[i * 24 + 0] = i * 4 + 2;
|
|
|
|
|
|
tris[i * 24 + 1] = i * 4 + 3;
|
|
|
|
|
|
tris[i * 24 + 2] = i * 4 + 7;
|
|
|
|
|
|
|
|
|
|
|
|
tris[i * 24 + 3] = i * 4 + 2;
|
|
|
|
|
|
tris[i * 24 + 4] = i * 4 + 7;
|
|
|
|
|
|
tris[i * 24 + 5] = i * 4 + 6;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tris[i * 24 + 6] = i * 4 + 0;
|
|
|
|
|
|
tris[i * 24 + 7] = i * 4 + 2;
|
|
|
|
|
|
tris[i * 24 + 8] = i * 4 + 6;
|
|
|
|
|
|
|
|
|
|
|
|
tris[i * 24 + 9] = i * 4 + 0;
|
|
|
|
|
|
tris[i * 24 + 10] = i * 4 + 6;
|
|
|
|
|
|
tris[i * 24 + 11] = i * 4 + 4;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tris[i * 24 + 12] = i * 4 + 0;
|
|
|
|
|
|
tris[i * 24 + 13] = i * 4 + 5;
|
|
|
|
|
|
tris[i * 24 + 14] = i * 4 + 1;
|
|
|
|
|
|
|
|
|
|
|
|
tris[i * 24 + 15] = i * 4 + 0;
|
|
|
|
|
|
tris[i * 24 + 16] = i * 4 + 4;
|
|
|
|
|
|
tris[i * 24 + 17] = i * 4 + 5;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tris[i * 24 + 18] = i * 4 + 1;
|
|
|
|
|
|
tris[i * 24 + 19] = i * 4 + 7;
|
|
|
|
|
|
tris[i * 24 + 20] = i * 4 + 3;
|
|
|
|
|
|
|
|
|
|
|
|
tris[i * 24 + 21] = i * 4 + 1;
|
|
|
|
|
|
tris[i * 24 + 22] = i * 4 + 5;
|
|
|
|
|
|
tris[i * 24 + 23] = i * 4 + 7;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tris[triLen - 12] = 0;
|
|
|
|
|
|
tris[triLen - 11] = 1;
|
|
|
|
|
|
tris[triLen - 10] = 3;
|
|
|
|
|
|
|
|
|
|
|
|
tris[triLen - 9] = 0;
|
|
|
|
|
|
tris[triLen - 8] = 3;
|
|
|
|
|
|
tris[triLen - 7] = 2;
|
|
|
|
|
|
|
|
|
|
|
|
tris[triLen - 6] = vLen - 4;
|
|
|
|
|
|
tris[triLen - 5] = vLen - 2;
|
|
|
|
|
|
tris[triLen - 4] = vLen - 1;
|
|
|
|
|
|
|
|
|
|
|
|
tris[triLen - 3] = vLen - 4;
|
|
|
|
|
|
tris[triLen - 2] = vLen - 1;
|
|
|
|
|
|
tris[triLen - 1] = vLen - 3;
|
|
|
|
|
|
|
|
|
|
|
|
mesh.vertices = vs;
|
|
|
|
|
|
mesh.triangles = tris;
|
|
|
|
|
|
mesh.RecalculateBounds();
|
|
|
|
|
|
mesh.RecalculateNormals();
|
|
|
|
|
|
|
|
|
|
|
|
return mesh;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static bool InRange (int x, int y, int z, int sizeX, int sizeY, int sizeZ) {
|
|
|
|
|
|
return x >= 0 && x < sizeX && y >= 0 && y < sizeY && z >= 0 && z < sizeZ;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Vector2 VectorAbs (Vector2 v) {
|
|
|
|
|
|
v.x = Mathf.Abs(v.x);
|
|
|
|
|
|
v.y = Mathf.Abs(v.y);
|
|
|
|
|
|
return v;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Vector3 VectorAbs (Vector3 v) {
|
|
|
|
|
|
v.x = Mathf.Abs(v.x);
|
|
|
|
|
|
v.y = Mathf.Abs(v.y);
|
|
|
|
|
|
v.z = Mathf.Abs(v.z);
|
|
|
|
|
|
return v;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Vector3 SwipYZ (Vector3 v) {
|
|
|
|
|
|
float tempZ = v.z;
|
|
|
|
|
|
v.z = v.y;
|
|
|
|
|
|
v.y = tempZ;
|
|
|
|
|
|
return v;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static float Remap (float l, float r, float newL, float newR, float t) {
|
|
|
|
|
|
return l == r ? 0 : Mathf.LerpUnclamped(
|
|
|
|
|
|
newL, newR,
|
|
|
|
|
|
(t - l) / (r - l)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static int MaxAxis (Vector3 v) {
|
|
|
|
|
|
if (Mathf.Abs(v.x) >= Mathf.Abs(v.y)) {
|
|
|
|
|
|
return Mathf.Abs(v.x) >= Mathf.Abs(v.z) ? 0 : 2;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Mathf.Abs(v.y) >= Mathf.Abs(v.z) ? 1 : 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void CopyToClipboard (string containt) {
|
|
|
|
|
|
TextEditor te = new TextEditor { text = containt };
|
|
|
|
|
|
te.SelectAll();
|
|
|
|
|
|
te.Copy();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string GetObj (Mesh m) {
|
|
|
|
|
|
|
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
|
|
sb.Append("g ").Append(m.name).Append("\n");
|
|
|
|
|
|
foreach (Vector3 v in m.vertices) {
|
|
|
|
|
|
sb.Append(string.Format("v {0} {1} {2}\n", v.x, v.y, v.z));
|
|
|
|
|
|
}
|
|
|
|
|
|
sb.Append("\n");
|
|
|
|
|
|
foreach (Vector3 v in m.normals) {
|
|
|
|
|
|
sb.Append(string.Format("vn {0} {1} {2}\n", v.x, v.y, v.z));
|
|
|
|
|
|
}
|
|
|
|
|
|
sb.Append("\n");
|
|
|
|
|
|
foreach (Vector3 v in m.uv) {
|
|
|
|
|
|
sb.Append(string.Format("vt {0} {1}\n", v.x, v.y));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sb.Append("\n");
|
|
|
|
|
|
sb.Append("usemtl ").Append(m.name).Append("\n");
|
|
|
|
|
|
sb.Append("usemap ").Append(m.name).Append("\n");
|
|
|
|
|
|
|
|
|
|
|
|
int[] triangles = m.triangles;
|
|
|
|
|
|
for (int i = 0; i < triangles.Length; i += 3) {
|
|
|
|
|
|
sb.Append(
|
|
|
|
|
|
string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n",
|
|
|
|
|
|
triangles[i] + 1, triangles[i + 1] + 1, triangles[i + 2] + 1)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Texture2D RenderTextureToTexture2D (Camera renderCamera) {
|
|
|
|
|
|
var rTex = renderCamera.targetTexture;
|
|
|
|
|
|
if (!rTex) { return null; }
|
|
|
|
|
|
RenderTexture.active = rTex;
|
|
|
|
|
|
Texture2D texture = new Texture2D(rTex.width, rTex.height, TextureFormat.ARGB32, false, false) {
|
|
|
|
|
|
filterMode = FilterMode.Bilinear
|
|
|
|
|
|
};
|
|
|
|
|
|
var oldColor = renderCamera.backgroundColor;
|
|
|
|
|
|
renderCamera.backgroundColor = Color.clear;
|
|
|
|
|
|
renderCamera.Render();
|
|
|
|
|
|
texture.ReadPixels(new Rect(0, 0, rTex.width, rTex.height), 0, 0, false);
|
|
|
|
|
|
texture.Apply();
|
|
|
|
|
|
renderCamera.backgroundColor = oldColor;
|
|
|
|
|
|
RenderTexture.active = null;
|
|
|
|
|
|
return texture;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Texture2D TrimTexture (Texture2D texture, float alpha = 0.01f, int gap = 0) {
|
|
|
|
|
|
int width = texture.width;
|
|
|
|
|
|
int height = texture.height;
|
|
|
|
|
|
var colors = texture.GetPixels();
|
|
|
|
|
|
int minX = int.MaxValue;
|
|
|
|
|
|
int minY = int.MaxValue;
|
|
|
|
|
|
int maxX = int.MinValue;
|
|
|
|
|
|
int maxY = int.MinValue;
|
|
|
|
|
|
|
|
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
|
|
|
|
for (int x = 0; x < width; x++) {
|
|
|
|
|
|
var c = colors[y * width + x];
|
|
|
|
|
|
if (c.a > alpha) {
|
|
|
|
|
|
minX = Mathf.Min(minX, x);
|
|
|
|
|
|
minY = Mathf.Min(minY, y);
|
|
|
|
|
|
maxX = Mathf.Max(maxX, x);
|
|
|
|
|
|
maxY = Mathf.Max(maxY, y);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Gap
|
|
|
|
|
|
minX = Mathf.Clamp(minX - gap, 0, width - 1);
|
|
|
|
|
|
minY = Mathf.Clamp(minY - gap, 0, height - 1);
|
|
|
|
|
|
maxX = Mathf.Clamp(maxX + gap, 0, width - 1);
|
|
|
|
|
|
maxY = Mathf.Clamp(maxY + gap, 0, height - 1);
|
|
|
|
|
|
|
|
|
|
|
|
int newWidth = maxX - minX + 1;
|
|
|
|
|
|
int newHeight = maxY - minY + 1;
|
|
|
|
|
|
if (newWidth != width || newHeight != height) {
|
|
|
|
|
|
texture.Resize(newWidth, newHeight);
|
|
|
|
|
|
var newColors = new Color[newWidth * newHeight];
|
|
|
|
|
|
for (int y = 0; y < newHeight; y++) {
|
|
|
|
|
|
for (int x = 0; x < newWidth; x++) {
|
|
|
|
|
|
newColors[y * newWidth + x] = colors[(y + minY) * width + (x + minX)];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
texture.SetPixels(newColors);
|
|
|
|
|
|
texture.Apply();
|
|
|
|
|
|
}
|
|
|
|
|
|
return texture;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static bool GetBit (int value, int index) {
|
|
|
|
|
|
if (index < 0 || index > 31) { return false; }
|
|
|
|
|
|
var val = 1 << index;
|
|
|
|
|
|
return (value & val) == val;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static int SetBitValue (int value, int index, bool bitValue) {
|
|
|
|
|
|
if (index < 0 || index > 31) { return value; }
|
|
|
|
|
|
var val = 1 << index;
|
|
|
|
|
|
return bitValue ? (value | val) : (value & ~val);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void SetMaterialFloatOrColor (Material mat, string keyword, float value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (!string.IsNullOrEmpty(keyword)) {
|
|
|
|
|
|
if (keyword[0] == '$' && keyword.Length > 2) {
|
|
|
|
|
|
Color color = Color.white;
|
|
|
|
|
|
switch (keyword[1]) {
|
|
|
|
|
|
case 'r':
|
|
|
|
|
|
color.r = value;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'g':
|
|
|
|
|
|
color.g = value;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'b':
|
|
|
|
|
|
color.b = value;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'a':
|
|
|
|
|
|
color.a = value;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'c':
|
|
|
|
|
|
color.r = value;
|
|
|
|
|
|
color.g = value;
|
|
|
|
|
|
color.b = value;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
mat.SetColor(keyword.Substring(2, keyword.Length - 2), color);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
mat.SetFloat(keyword, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch { }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static string GetPrefabAssetPath (GameObject g) {
|
|
|
|
|
|
#if UNITY_4 || UNITY_5 || UNITY_2017 || UNITY_2018_1 || UNITY_2018_2
|
|
|
|
|
|
return g ? AssetDatabase.GetAssetPath(PrefabUtility.GetPrefabParent(g)) : "";
|
|
|
|
|
|
#else
|
|
|
|
|
|
return g ? PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(g) : "";
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void OverrideMesh (Mesh instance, Mesh data) {
|
|
|
|
|
|
|
|
|
|
|
|
instance.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
instance.vertices = data.vertices;
|
|
|
|
|
|
instance.uv = data.uv;
|
|
|
|
|
|
instance.triangles = data.triangles;
|
|
|
|
|
|
instance.colors = data.colors;
|
|
|
|
|
|
instance.boneWeights = data.boneWeights;
|
|
|
|
|
|
instance.bindposes = data.bindposes;
|
|
|
|
|
|
instance.name = data.name;
|
|
|
|
|
|
|
|
|
|
|
|
instance.RecalculateNormals();
|
|
|
|
|
|
instance.RecalculateTangents();
|
|
|
|
|
|
instance.RecalculateBounds();
|
|
|
|
|
|
|
|
|
|
|
|
instance.UploadMeshData(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void OverrideTexture (Texture2D instance, Texture2D data) {
|
|
|
|
|
|
instance.Resize(data.width, data.height, data.format, false);
|
|
|
|
|
|
instance.SetPixels(data.GetPixels());
|
|
|
|
|
|
instance.Apply();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void OverrideMaterial (Material instance, Material data, string mainTexKeyword) {
|
|
|
|
|
|
instance.shader = data.shader;
|
|
|
|
|
|
instance.SetTexture(mainTexKeyword, data.GetTexture(mainTexKeyword));
|
|
|
|
|
|
instance.CopyPropertiesFromMaterial(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static AnimationClip CopyAnimation (AnimationClip source) {
|
|
|
|
|
|
// Init
|
|
|
|
|
|
var animation = new AnimationClip() {
|
|
|
|
|
|
frameRate = source.frameRate,
|
|
|
|
|
|
name = source.name,
|
|
|
|
|
|
wrapMode = source.wrapMode,
|
|
|
|
|
|
legacy = source.legacy,
|
|
|
|
|
|
hideFlags = source.hideFlags,
|
|
|
|
|
|
localBounds = source.localBounds,
|
|
|
|
|
|
};
|
|
|
|
|
|
// Data
|
|
|
|
|
|
var bindings = AnimationUtility.GetCurveBindings(source);
|
|
|
|
|
|
for (int i = 0; i < bindings.Length; i++) {
|
|
|
|
|
|
var binding = bindings[i];
|
|
|
|
|
|
var curve = AnimationUtility.GetEditorCurve(source, binding);
|
|
|
|
|
|
var keys = new Keyframe[curve.length];
|
|
|
|
|
|
for (int j = 0; j < keys.Length; j++) {
|
|
|
|
|
|
keys[j] = curve.keys[j];
|
|
|
|
|
|
}
|
|
|
|
|
|
animation.SetCurve(binding.path, binding.type, binding.propertyName, new AnimationCurve(keys) {
|
|
|
|
|
|
postWrapMode = curve.postWrapMode,
|
|
|
|
|
|
preWrapMode = curve.preWrapMode,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
return animation;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void ClearChildrenImmediate (Transform tf) {
|
|
|
|
|
|
if (!tf) { return; }
|
|
|
|
|
|
int len = tf.childCount;
|
|
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
|
|
Object.DestroyImmediate(tf.GetChild(0).gameObject, false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void CurveAllLiner (AnimationCurve curve) {
|
|
|
|
|
|
for (int i = 0; i < curve.keys.Length; i++) {
|
|
|
|
|
|
var key = curve.keys[i];
|
|
|
|
|
|
key.inTangent = 0f;
|
|
|
|
|
|
key.outTangent = 0f;
|
|
|
|
|
|
#if UNITY_2018_3_6
|
|
|
|
|
|
key.inWeight = 0f;
|
|
|
|
|
|
key.outWeight = 0f;
|
|
|
|
|
|
key.weightedMode = WeightedMode.Both;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
curve.MoveKey(i, key);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region --- MagicaVoxel ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly Dictionary<byte, Vector4> MAGIC_BYTE_TO_TRANSFORM_MAP = new Dictionary<byte, Vector4>() {
|
|
|
|
|
|
|
|
|
|
|
|
{ 40 , new Vector4(3,0,0,0)},
|
|
|
|
|
|
{ 2 , new Vector4(3,3,0,0)},
|
|
|
|
|
|
{ 24 , new Vector4(3,2,0,0)},
|
|
|
|
|
|
{ 50 , new Vector4(3,1,0,0)},
|
|
|
|
|
|
{ 120, new Vector4(1,0,2,0)},
|
|
|
|
|
|
{ 98 , new Vector4(1,0,3,0)},
|
|
|
|
|
|
{ 72 , new Vector4(1,0,0,0)},
|
|
|
|
|
|
{ 82 , new Vector4(1,0,1,0)},
|
|
|
|
|
|
{ 4 , new Vector4(0,0,0,0)},
|
|
|
|
|
|
{ 22 , new Vector4(0,0,1,0)},
|
|
|
|
|
|
{ 84 , new Vector4(0,0,2,0)},
|
|
|
|
|
|
{ 70 , new Vector4(0,0,3,0)},
|
|
|
|
|
|
{ 52 , new Vector4(0,2,0,0)},
|
|
|
|
|
|
{ 118, new Vector4(0,2,3,0)},
|
|
|
|
|
|
{ 100, new Vector4(0,2,2,0)},
|
|
|
|
|
|
{ 38 , new Vector4(0,2,1,0)},
|
|
|
|
|
|
{ 17 , new Vector4(0,3,0,0)},
|
|
|
|
|
|
{ 89 , new Vector4(0,3,3,0)},
|
|
|
|
|
|
{ 113, new Vector4(0,3,2,0)},
|
|
|
|
|
|
{ 57 , new Vector4(0,3,1,0)},
|
|
|
|
|
|
{ 33 , new Vector4(0,1,0,0)},
|
|
|
|
|
|
{ 9 , new Vector4(0,1,1,0)},
|
|
|
|
|
|
{ 65 , new Vector4(0,1,2,0)},
|
|
|
|
|
|
{ 105, new Vector4(0,1,3,0)},
|
|
|
|
|
|
|
|
|
|
|
|
{ 56 , new Vector4(3,0,0,1)},
|
|
|
|
|
|
{ 34 , new Vector4(3,3,0,1)},
|
|
|
|
|
|
{ 8 , new Vector4(3,2,0,1)},
|
|
|
|
|
|
{ 18 , new Vector4(3,1,0,1)},
|
|
|
|
|
|
{ 104, new Vector4(1,0,2,1)},
|
|
|
|
|
|
{ 66 , new Vector4(1,0,3,1)},
|
|
|
|
|
|
{ 88 , new Vector4(1,0,0,1)},
|
|
|
|
|
|
{ 114, new Vector4(1,0,1,1)},
|
|
|
|
|
|
{ 20 , new Vector4(0,0,0,1)},
|
|
|
|
|
|
{ 86 , new Vector4(0,0,1,1)},
|
|
|
|
|
|
{ 68 , new Vector4(0,0,2,1)},
|
|
|
|
|
|
{ 6 , new Vector4(0,0,3,1)},
|
|
|
|
|
|
{ 36 , new Vector4(0,2,0,1)},
|
|
|
|
|
|
{ 54 , new Vector4(0,2,3,1)},
|
|
|
|
|
|
{ 116, new Vector4(0,2,2,1)},
|
|
|
|
|
|
{ 102, new Vector4(0,2,1,1)},
|
|
|
|
|
|
{ 49 , new Vector4(0,3,0,1)},
|
|
|
|
|
|
{ 25 , new Vector4(0,3,3,1)},
|
|
|
|
|
|
{ 81 , new Vector4(0,3,2,1)},
|
|
|
|
|
|
{ 121, new Vector4(0,3,1,1)},
|
|
|
|
|
|
{ 1 , new Vector4(0,1,0,1)},
|
|
|
|
|
|
{ 73 , new Vector4(0,1,1,1)},
|
|
|
|
|
|
{ 97 , new Vector4(0,1,2,1)},
|
|
|
|
|
|
{ 41 , new Vector4(0,1,3,1)},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly Dictionary<Vector4, byte> TRANSFORM_TO_MAGIC_BYTE_MAP = new Dictionary<Vector4, byte>() {
|
|
|
|
|
|
|
|
|
|
|
|
{new Vector4(3,0,0,0), 40 },
|
|
|
|
|
|
{new Vector4(3,3,0,0), 2 },
|
|
|
|
|
|
{new Vector4(3,2,0,0), 24 },
|
|
|
|
|
|
{new Vector4(3,1,0,0), 50 },
|
|
|
|
|
|
{new Vector4(1,0,2,0), 120},
|
|
|
|
|
|
{new Vector4(1,0,3,0), 98 },
|
|
|
|
|
|
{new Vector4(1,0,0,0), 72 },
|
|
|
|
|
|
{new Vector4(1,0,1,0), 82 },
|
|
|
|
|
|
{new Vector4(0,0,0,0), 4 },
|
|
|
|
|
|
{new Vector4(0,0,1,0), 22 },
|
|
|
|
|
|
{new Vector4(0,0,2,0), 84 },
|
|
|
|
|
|
{new Vector4(0,0,3,0), 70 },
|
|
|
|
|
|
{new Vector4(0,2,0,0), 52 },
|
|
|
|
|
|
{new Vector4(0,2,3,0), 118},
|
|
|
|
|
|
{new Vector4(0,2,2,0), 100},
|
|
|
|
|
|
{new Vector4(0,2,1,0), 38 },
|
|
|
|
|
|
{new Vector4(0,3,0,0), 17 },
|
|
|
|
|
|
{new Vector4(0,3,3,0), 89 },
|
|
|
|
|
|
{new Vector4(0,3,2,0), 113},
|
|
|
|
|
|
{new Vector4(0,3,1,0), 57 },
|
|
|
|
|
|
{new Vector4(0,1,0,0), 33 },
|
|
|
|
|
|
{new Vector4(0,1,1,0), 9 },
|
|
|
|
|
|
{new Vector4(0,1,2,0), 65 },
|
|
|
|
|
|
{new Vector4(0,1,3,0), 105},
|
|
|
|
|
|
|
|
|
|
|
|
{new Vector4(3,0,0,1), 56 },
|
|
|
|
|
|
{new Vector4(3,3,0,1), 34 },
|
|
|
|
|
|
{new Vector4(3,2,0,1), 8 },
|
|
|
|
|
|
{new Vector4(3,1,0,1), 18 },
|
|
|
|
|
|
{new Vector4(1,0,2,1), 104},
|
|
|
|
|
|
{new Vector4(1,0,3,1), 66 },
|
|
|
|
|
|
{new Vector4(1,0,0,1), 88 },
|
|
|
|
|
|
{new Vector4(1,0,1,1), 114},
|
|
|
|
|
|
{new Vector4(0,0,0,1), 20 },
|
|
|
|
|
|
{new Vector4(0,0,1,1), 86 },
|
|
|
|
|
|
{new Vector4(0,0,2,1), 68 },
|
|
|
|
|
|
{new Vector4(0,0,3,1), 6 },
|
|
|
|
|
|
{new Vector4(0,2,0,1), 36 },
|
|
|
|
|
|
{new Vector4(0,2,3,1), 54 },
|
|
|
|
|
|
{new Vector4(0,2,2,1), 116},
|
|
|
|
|
|
{new Vector4(0,2,1,1), 102},
|
|
|
|
|
|
{new Vector4(0,3,0,1), 49 },
|
|
|
|
|
|
{new Vector4(0,3,3,1), 25 },
|
|
|
|
|
|
{new Vector4(0,3,2,1), 81 },
|
|
|
|
|
|
{new Vector4(0,3,1,1), 121},
|
|
|
|
|
|
{new Vector4(0,1,0,1), 1 },
|
|
|
|
|
|
{new Vector4(0,1,1,1), 73 },
|
|
|
|
|
|
{new Vector4(0,1,2,1), 97 },
|
|
|
|
|
|
{new Vector4(0,1,3,1), 41 },
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void VoxMatrixByteToTransform (byte the_Byte_Which_Wasted_My_While_Afternoon, out Vector3 rotation, out Vector3 scale) {
|
|
|
|
|
|
if (MAGIC_BYTE_TO_TRANSFORM_MAP.ContainsKey(the_Byte_Which_Wasted_My_While_Afternoon)) {
|
|
|
|
|
|
var v4 = MAGIC_BYTE_TO_TRANSFORM_MAP[the_Byte_Which_Wasted_My_While_Afternoon];
|
|
|
|
|
|
rotation = new Vector3(v4.x * 90f, v4.y * 90f, v4.z * 90f);
|
|
|
|
|
|
scale = v4.w < 0.5f ? Vector3.one : new Vector3(-1, 1, 1);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
rotation = Vector3.zero;
|
|
|
|
|
|
scale = Vector3.one;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static byte TransformToVoxMatrixByte (Vector3 rot, Vector3 scale) {
|
|
|
|
|
|
var v4 = new Vector4(
|
|
|
|
|
|
(byte)(Mathf.RoundToInt((Mathf.Repeat(rot.x, 360f) / 90f) % 4)),
|
|
|
|
|
|
(byte)(Mathf.RoundToInt((Mathf.Repeat(rot.y, 360f) / 90f) % 4)),
|
|
|
|
|
|
(byte)(Mathf.RoundToInt((Mathf.Repeat(rot.z, 360f) / 90f) % 4)),
|
|
|
|
|
|
(byte)(scale.x > 0f ? 0 : 1)
|
|
|
|
|
|
);
|
|
|
|
|
|
if (TRANSFORM_TO_MAGIC_BYTE_MAP.ContainsKey(v4)) {
|
|
|
|
|
|
return TRANSFORM_TO_MAGIC_BYTE_MAP[v4];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return 4;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|