Skip to content

Instantly share code, notes, and snippets.

@maluoi
Created July 26, 2023 02:30
Show Gist options
  • Save maluoi/d99aa64708099166f5c228a78adfa39f to your computer and use it in GitHub Desktop.
Save maluoi/d99aa64708099166f5c228a78adfa39f to your computer and use it in GitHub Desktop.
A quick format for writing a simple StereoKit mesh to a fairly slim file.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using StereoKit;
class BinMesh {
const uint binMeshIdentifier = 0x06b8d800; // a nice blue color
const uint binMeshVersion = 0x00000001; // and then a version, should never make it to 255!
struct Header {
public uint identifier;
public ushort vertexCount;
public ushort indexCount;
public byte paletteCount;
public Vec3 meshOffset;
public Vec3 meshScale;
};
public static byte[] Make(Mesh m)
{
Vertex[] verts = m.GetVerts();
uint [] inds = m.GetInds();
Bounds b = m.Bounds;
Dictionary<Color32, int> palette = verts.Aggregate(new Dictionary<Color32, int>(), (dict, vert) => {
if (!dict.ContainsKey(vert.col)) dict.Add(vert.col, dict.Count);
return dict;
});
byte[] buffer = new byte[
sizeof(uint) + sizeof(ushort) + sizeof(ushort) + sizeof(byte) + sizeof(float)*3 + sizeof(float)*3 + // Header
(sizeof(short) * 3 + sizeof(byte)) * verts.Length + // Verts
sizeof(byte) * inds.Length + // Indices
sizeof(byte) * palette.Count * 4 // Palette
];
BinaryWriter w = new BinaryWriter(new MemoryStream(buffer));
Header h = new Header {
identifier = binMeshIdentifier | binMeshVersion,
vertexCount = (ushort)verts.Length,
indexCount = (ushort)inds.Length,
paletteCount = (byte)palette.Count,
meshOffset = b.center,
meshScale = b.dimensions,
};
w.Write(h.identifier);
w.Write(h.vertexCount);
w.Write(h.indexCount);
w.Write(h.paletteCount);
w.Write(h.meshOffset.x); w.Write(h.meshOffset.y); w.Write(h.meshOffset.z);
w.Write(h.meshScale .x); w.Write(h.meshScale .y); w.Write(h.meshScale .z);
// Write the palette first
foreach (Color32 c in palette.OrderBy(x => x.Value).Select(x => x.Key))
{
w.Write(c.r);
w.Write(c.g);
w.Write(c.b);
w.Write(c.a);
}
// Quantized verts
for (int i = 0; i < verts.Length; i++)
{
Vec3 v = verts[i].pos - b.center;
short x = (short)((verts[i].pos.x/b.dimensions.x) * short.MaxValue);
short y = (short)((verts[i].pos.y/b.dimensions.y) * short.MaxValue);
short z = (short)((verts[i].pos.z/b.dimensions.z) * short.MaxValue);
w.Write(x);
w.Write(y);
w.Write(z);
w.Write((byte)palette[verts[i].col]);
}
// And finally the indices
for (int i = 0; i < inds.Length; i++)
w.Write((byte)inds[i]);
w.Close();
return buffer;
}
public static Mesh From(byte[] buffer)
{
Header h = new Header();
BinaryReader r = new BinaryReader(new MemoryStream(buffer));
h.identifier = r.ReadUInt32();
if (h.identifier != (binMeshIdentifier | binMeshVersion))
return null;
h.vertexCount = r.ReadUInt16();
h.indexCount = r.ReadUInt16();
h.paletteCount = r.ReadByte();
h.meshOffset = new Vec3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
h.meshScale = new Vec3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
// Read the palette
Color32[] palette = new Color32[h.paletteCount];
for (int i = 0; i < h.paletteCount; i++)
palette[i] = new Color32(r.ReadByte(), r.ReadByte(), r.ReadByte(), r.ReadByte());
// Read the verts
Vertex[] verts = new Vertex[h.vertexCount];
for (int i = 0; i < h.vertexCount; i++)
{
verts[i].pos.x = (r.ReadInt16() / (float)short.MaxValue) * h.meshScale.x + h.meshOffset.x;
verts[i].pos.y = (r.ReadInt16() / (float)short.MaxValue) * h.meshScale.y + h.meshOffset.y;
verts[i].pos.z = (r.ReadInt16() / (float)short.MaxValue) * h.meshScale.z + h.meshOffset.z;
verts[i].col = palette[r.ReadByte()];
}
// Read the indices
uint[] inds = new uint[h.indexCount];
for (int i = 0; i < h.indexCount; i++)
inds[i] = r.ReadByte();
r.Close();
// calculate normals
for (int i = 0; i < inds.Length; i += 3)
{
uint i1 = inds[i ];
uint i2 = inds[i+1];
uint i3 = inds[i+2];
// Length of cross product is twice the area of the triangle it's
// from, so if we don't 'normalize' it, then we get trangle area
// weighting on our normals for free!
Vec3 normal = Vec3.Cross(verts[i3].pos - verts[i2].pos, verts[i1].pos - verts[i2].pos);
verts[i1].norm += normal;
verts[i2].norm += normal;
verts[i3].norm += normal;
}
for (int i = 0; i < verts.Length; i++) verts[i].norm = verts[i].norm.Normalized;
Mesh result = new Mesh();
result.SetData(verts, inds);
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment