Skip to content

Instantly share code, notes, and snippets.

@Nikspace2
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nikspace2/7e9904522341ff3587fa to your computer and use it in GitHub Desktop.
Save Nikspace2/7e9904522341ff3587fa to your computer and use it in GitHub Desktop.
Qubicle Updater for PicaVoxel
using PicaVoxel;
using System.IO;
using UnityEditor;
using UnityEngine;
/// <summary>
/// Custom Inspector for the .qb files to import faster.
/// It's not optimized it checks every time you select an object in the Project Panel but i don't know any other way to do it :D
/// I used your QubicleImportWindow. But i like it more this way. Check it out.
/// </summary>
[CustomEditor(typeof(Object), true)]
public class QubicleFileInspector : Editor
{
// PicaVoxel QubicleImportW Values
static float voxelSize = 0.1f;
static string objectName = "Qubicle Import";
static string ext = "qb";
static bool showImport = false;
static Object m_lastObject = null;
private void OnEnable()
{
voxelSize = 0.1f;
objectName = "Qubicle Import";
}
/// <summary>
/// Override what the inspector shows
/// </summary>
public override void OnInspectorGUI()
{
#region Checkc File Extension
// check if the object changes
bool objectChanged = false;
if(m_lastObject != target)
{
showImport = false;
m_lastObject = target;
objectChanged = true;
}
// nothing to do
if(null == target)
{
return;
}
// only read contents when the object changes
if(objectChanged)
{
// Print the path of the created asset
string assetPath = AssetDatabase.GetAssetPath(target);
if(!string.IsNullOrEmpty(assetPath))
{
// get the file extension
string extension = Path.GetExtension(assetPath);
if(string.IsNullOrEmpty(extension))
{
extension = string.Empty;
}
else
{
extension = extension.ToLower();
}
if(ext.Equals(extension))
{
showImport = true;
}
}
}
#endregion Checkc File Extension
// Show Importer GUI
if(showImport)
{
GUI.enabled = true;
ImporterStyles.ShowTitle("Qubicle Import");
EditorGUILayout.Space();
objectName = EditorGUILayout.TextField("Volume name: ", objectName);
EditorGUILayout.Space();
voxelSize = EditorGUILayout.FloatField("Voxel size: ", voxelSize);
EditorGUILayout.Space();
if(ImporterStyles.BigOrangeButton("Import in Scene"))
QubicleImporter.QubicleImport(AssetDatabase.GetAssetPath(target), objectName, voxelSize);
GUI.enabled = false;
}
}
}
/// <summary>
/// Custom Editor Styles
/// Because we've got style baby.
/// </summary>
public static class ImporterStyles
{
static GUIStyle whiteBoldButtonStyle;
static GUIStyle topLanguageBox;
public static GUIStyle WhiteBoldButtonStyle
{
get
{
if(whiteBoldButtonStyle == null)
{
whiteBoldButtonStyle = new GUIStyle("button");
whiteBoldButtonStyle.normal.textColor = Color.white;
whiteBoldButtonStyle.active.textColor = Color.white;
whiteBoldButtonStyle.fontStyle = FontStyle.Bold;
}
return whiteBoldButtonStyle;
}
}
public static bool BigOrangeButton(string content)
{
GUI.backgroundColor = new Color(0.87f, 0.45f, 0.14f);
bool result = GUILayout.Button(content, WhiteBoldButtonStyle, GUILayout.Height(30));
GUI.backgroundColor = new Color(1f, 1f, 1f);
return result;
}
public static void ShowTitle(string title)
{
EditorGUILayout.BeginHorizontal("box", GUILayout.Height(20));
GUILayout.FlexibleSpace();
GUILayout.Label(title, EditorStyles.boldLabel);
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
}
}
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Just a reference MonoBehaviour to keep the selected values
/// on the custom Inspector.
/// </summary>
public class QubicleUpdater : MonoBehaviour
{
public Object qubicleFile;
public Dictionary<int, string> qubicleVolumes;
public uint selectedVolume = 0;
}
using PicaVoxel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
/// <summary>
/// The Qubicle Updater main file
/// </summary>
[RequireComponent(typeof(Volume))]
[CustomEditor(typeof(QubicleUpdater))]
public class QubicleUpdaterEditor : Editor
{
private QubicleUpdater quibicleUpdater;
public bool changeName = true;
public bool changePivotPoint = true;
public bool changeTransform = true;
private void OnEnable()
{
quibicleUpdater = (QubicleUpdater)target;
}
private void CleanVales()
{
quibicleUpdater.selectedVolume = 0;
}
public override void OnInspectorGUI()
{
quibicleUpdater.qubicleFile = (UnityEngine.Object)EditorGUILayout.ObjectField("Qubicle File :", quibicleUpdater.qubicleFile, typeof(UnityEngine.Object));
EditorGUI.BeginDisabledGroup((Path.GetExtension(AssetDatabase.GetAssetPath(quibicleUpdater.qubicleFile)) != ".qb"));
if(GUILayout.Button("Refresh File"))
{
ReadQubicle();
}
EditorGUI.EndDisabledGroup();
if(quibicleUpdater.qubicleFile == null)
{
CleanVales();
return;
}
else
{
ReadQubicle();
}
if(quibicleUpdater.qubicleVolumes.Count != 0)
{
quibicleUpdater.selectedVolume = (uint)EditorGUILayout.Popup("Quibicle Volume", (int)quibicleUpdater.selectedVolume, quibicleUpdater.qubicleVolumes.Values.ToArray());
}
changeName = EditorGUILayout.Toggle("Change Name : ", changeName);
changePivotPoint = EditorGUILayout.Toggle("Change Pivot Point : ", changePivotPoint);
changeTransform = EditorGUILayout.Toggle("Change Transform Point : ", changeTransform);
if(GUILayout.Button("Update Volume"))
{
UpdateQubicle();
}
EditorGUILayout.Space();
}
public void ReadQubicle()
{
float voxelSize = quibicleUpdater.GetComponent<Volume>().VoxelSize;
string fn = AssetDatabase.GetAssetPath(quibicleUpdater.qubicleFile);
using(BinaryReader stream = new BinaryReader(new FileStream(fn, FileMode.Open)))
{
UpdateQubicle(false, stream, Path.GetFileNameWithoutExtension(fn), voxelSize);
}
}
public void UpdateQubicle()
{
float voxelSize = quibicleUpdater.GetComponent<Volume>().VoxelSize;
string fn = AssetDatabase.GetAssetPath(quibicleUpdater.qubicleFile);
using(BinaryReader stream = new BinaryReader(new FileStream(fn, FileMode.Open)))
{
UpdateQubicle(true, stream, Path.GetFileNameWithoutExtension(fn), voxelSize);
}
}
private void UpdateQubicle(bool isUpdateing, BinaryReader stream, string volumeName, float voxelSize)
{
quibicleUpdater.qubicleVolumes = new Dictionary<int, string>();
#region Qubicle Fields
uint sizex = 0;
uint sizey = 0;
uint sizez = 0;
// uint version;
uint colorFormat;
uint zAxisOrientation;
uint compressed;
// uint visibilityMaskEncoded;
uint numMatrices;
uint i;
uint j;
uint x;
uint y;
uint z;
int posX;
int posY;
int posZ;
uint[, ,] matrix;
List<uint[, ,]> matrixList = new List<uint[, ,]>();
uint index;
uint data;
uint count;
const uint CODEFLAG = 2;
const uint NEXTSLICEFLAG = 6;
#endregion Qubicle Fields
//version = stream.ReadUInt32();
stream.ReadUInt32();
colorFormat = stream.ReadUInt32();
zAxisOrientation = stream.ReadUInt32();
compressed = stream.ReadUInt32();
//visibilityMaskEncoded = stream.ReadUInt32();
stream.ReadUInt32();
numMatrices = stream.ReadUInt32();
for(i = 0; i < numMatrices; i++) // for each matrix stored in file
{
// Your Importer code
#region ReadAllMatrices
// read matrix name
byte nameLength = stream.ReadByte();
string name = new string(stream.ReadChars(nameLength));
// read matrix size
sizex = stream.ReadUInt32();
sizey = stream.ReadUInt32();
sizez = stream.ReadUInt32();
// read matrix position (in this example the position is irrelevant)
posX = stream.ReadInt32();
posY = stream.ReadInt32();
posZ = stream.ReadInt32();
// create matrix and add to matrix list
matrix = new uint[sizex, sizey, sizez];
matrixList.Add(matrix);
if(compressed == 0) // if uncompressd
{
for(z = 0; z < sizez; z++)
for(y = 0; y < sizey; y++)
for(x = 0; x < sizex; x++)
matrix[x, y, z] = stream.ReadUInt32();
}
else // if compressed
{
z = 0;
while(z < sizez)
{
index = 0;
while(true)
{
data = stream.ReadUInt32();
if(data == NEXTSLICEFLAG)
break;
else if(data == CODEFLAG)
{
count = stream.ReadUInt32();
data = stream.ReadUInt32();
for(j = 0; j < count; j++)
{
x = index % sizex; // mod = modulo e.g. 12 mod 8 = 4
y = index / sizex; // div = integer division e.g. 12 div 8 = 1
index++;
matrix[x, y, z] = data;
}
}
else
{
x = index % sizex;
y = index / sizex;
index++;
matrix[x, y, z] = data;
}
}
z++;
}
}
#endregion ReadAllMatrices
if(!isUpdateing)
{
// Add them matrices to the list
quibicleUpdater.qubicleVolumes.Add((int)i, (name != "") ? name : volumeName);
}
else
{
// Update to the selected matrix
if(i == quibicleUpdater.selectedVolume)
{
/// NOTE
// I skipped the splitting because it never worked for me even at your Importer i always get ArgumentException
// so i changed MAX_VOLUME_DIMENSION to be able to import bigger matrices.
// Single volume
var newObject = quibicleUpdater.gameObject;
//newObject.transform.localPosition = Vector3.zero;
if(newObject != null)
{
// Change the Name if we want.
if(changeName)
newObject.name = name != "" ? name : volumeName;
Volume voxelVolume = newObject.GetComponent<Volume>();
voxelVolume.Material = PicaVoxel.EditorUtility.PicaVoxelDiffuseMaterial;
// Here is that it would be nice a method like
// voxelVolume.Replace(newFrame); or something like that.
// or something that deletes the necessary Chucks and replace the ones that are needed.
// The only reason i am not doing it my self is that i want it to be independent. I don't want to change your code.
// That my dirty method
DeleteOldFrame(newObject.GetComponent<Volume>());
voxelVolume.GenerateBasic(FillMode.None);
voxelVolume.XSize = Convert.ToInt32(sizex);
voxelVolume.YSize = Convert.ToInt32(sizey);
voxelVolume.ZSize = Convert.ToInt32(sizez);
voxelVolume.Frames[0].XSize = Convert.ToInt32(sizex);
voxelVolume.Frames[0].YSize = Convert.ToInt32(sizey);
voxelVolume.Frames[0].ZSize = Convert.ToInt32(sizez);
voxelVolume.Frames[0].Voxels = new Voxel[sizex * sizey * sizez];
voxelVolume.VoxelSize = voxelSize;
if(zAxisOrientation == 0)
{
// Change the PivotPoint if we want.
if(changePivotPoint)
{
voxelVolume.Pivot = new Vector3(sizex, 0, 0) * voxelSize;
voxelVolume.UpdatePivot();
}
}
for(z = 0; z < sizez; z++)
for(y = 0; y < sizey; y++)
for(x = 0; x < sizex; x++)
{
Color col = QubicleImporter.UIntToColor(matrix[x, y, z], colorFormat);
if(matrix[x, y, z] != 0)
voxelVolume.Frames[0].Voxels[(zAxisOrientation == 0 ? sizex - 1 - x : x) + sizex * (y + sizey * z)] = new Voxel()
{
Active = true,
Color = col,
Value = 128
};
}
voxelVolume.UpdateAllChunks();
voxelVolume.SaveForSerialize();
// Change the Transform if we want.
if(changeTransform)
{
newObject.transform.position = (new Vector3((zAxisOrientation == 0 ? -posX : posX), posY, posZ) * voxelSize);
}
}
}
}
}
}
/// <summary>
/// Delete old Frames from the Volume
/// </summary>
/// <param name="volume"></param>
private void DeleteOldFrame(Volume volume)
{
for(int i = volume.Frames.Count - 1; i >= 0; i--)
{
DestroyImmediate(volume.Frames[i].gameObject);
volume.Frames.RemoveAt(i);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment