| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Numerics;
- using System.Runtime.InteropServices;
- using System.Text;
- namespace SharpGLTF
- {
- /// <summary>
- /// Function for converting data into binary buffers
- /// Specs see https://github.com/CesiumGS/3d-tiles/tree/main/specification/Metadata#binary-table-format
- /// </summary>
- public static class BinaryTable
- {
- public static List<byte> GetBytesForArray<T>(List<List<T>> values)
- {
- var bytes = new List<byte>();
- foreach (var value in values)
- {
- var b = GetBytes(value);
- bytes.AddRange(b);
- }
- return bytes;
- }
- /// <summary>
- /// Converts a list of primitive types into a byte array
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="values"></param>
- /// <returns>byte array</returns>
- public static byte[] GetBytes<T>(IReadOnlyList<T> values)
- {
- Guard.IsTrue(values.Count > 0, nameof(values), "values must have at least one element");
- if (typeof(T) == typeof(string))
- {
- var res = string.Join("", values);
- return Encoding.UTF8.GetBytes(res);
- }
- else if (typeof(T) == typeof(Vector2))
- {
- return Vector2ToBytes(values);
- }
- else if (typeof(T) == typeof(Vector3))
- {
- return Vector3ToBytes(values);
- }
- else if (typeof(T) == typeof(Vector4))
- {
- return Vector4ToBytes(values);
- }
- else if(typeof(T) == typeof(Matrix4x4))
- {
- return Matrix4x4ToBytes(values);
- }
- else if (typeof(T).IsPrimitive)
- {
- if (typeof(T) == typeof(bool))
- {
- var bits = new BitArray(values.Cast<bool>().ToArray());
- byte[] ret = new byte[(bits.Length - 1) / 8 + 1];
- bits.CopyTo(ret, 0);
- return ret;
- }
- var size = GetSize<T>();
- var result = new byte[values.Count * size];
- Buffer.BlockCopy(values.ToArray(), 0, result, 0, result.Length);
- return result;
- }
- else
- {
- // other types (like datetime, mat2, mat3) are not implemented
- // see https://github.com/CesiumGS/3d-tiles/tree/main/specification/Metadata#binary-table-format
- throw new NotImplementedException();
- }
- }
- private static byte[] Matrix4x4ToBytes<T>(IReadOnlyList<T> values)
- {
- var result = new byte[values.Count * 64];
- for (int i = 0; i < values.Count; i++)
- {
- var mat = (Matrix4x4)(object)values[i];
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M11), 0, result, i * 64, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M12), 0, result, i * 64 + 4, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M13), 0, result, i * 64 + 8, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M14), 0, result, i * 64 + 12, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M21), 0, result, i * 64 + 16, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M22), 0, result, i * 64 + 20, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M23), 0, result, i * 64 + 24, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M24), 0, result, i * 64 + 28, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M31), 0, result, i * 64 + 32, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M32), 0, result, i * 64 + 36, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M33), 0, result, i * 64 + 40, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M34), 0, result, i * 64 + 44, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M41), 0, result, i * 64 + 48, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M42), 0, result, i * 64 + 52, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M43), 0, result, i * 64 + 56, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(mat.M44), 0, result, i * 64 + 60, 4);
- }
- return result;
- }
- private static byte[] Vector2ToBytes<T>(IReadOnlyList<T> values)
- {
- var result = new byte[values.Count * 8];
- for (int i = 0; i < values.Count; i++)
- {
- var vec = (Vector2)(object)values[i];
- Buffer.BlockCopy(BitConverter.GetBytes(vec.X), 0, result, i * 8, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(vec.Y), 0, result, i * 8 + 4, 4);
- }
- return result;
- }
- private static byte[] Vector3ToBytes<T>(IReadOnlyList<T> values)
- {
- var result = new byte[values.Count * 12];
- for (int i = 0; i < values.Count; i++)
- {
- var vec = (Vector3)(object)values[i];
- Buffer.BlockCopy(BitConverter.GetBytes(vec.X), 0, result, i * 12, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(vec.Y), 0, result, i * 12 + 4, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(vec.Z), 0, result, i * 12 + 8, 4);
- }
- return result;
- }
- private static byte[] Vector4ToBytes<T>(IReadOnlyList<T> values)
- {
- var result = new byte[values.Count * 16];
- for (int i = 0; i < values.Count; i++)
- {
- var vec = (Vector4)(object)values[i];
- Buffer.BlockCopy(BitConverter.GetBytes(vec.X), 0, result, i * 16, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(vec.Y), 0, result, i * 16 + 4, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(vec.Z), 0, result, i * 16 + 8, 4);
- Buffer.BlockCopy(BitConverter.GetBytes(vec.W), 0, result, i * 16 + 12, 4);
- }
- return result;
- }
- public static List<int> GetStringOffsets(List<string> values)
- {
- var offsets = new List<int>() { 0 };
- foreach (var value in values)
- {
- var length = Encoding.UTF8.GetBytes(value).Length;
- offsets.Add(offsets.Last() + length);
- }
- return offsets;
- }
- public static List<int> GetStringOffsets(List<List<string>> values)
- {
- var offsets = new List<int>() {};
- foreach (var arr in values)
- {
- var arrOffsets = GetStringOffsets(arr);
- var last = offsets.LastOrDefault();
- foreach (var offset in arrOffsets)
- {
- if(!offsets.Contains(last + offset))
- {
- offsets.Add(last + offset);
- }
- }
- }
- return offsets;
- }
- public static List<int> GetArrayOffsets<T>(List<List<T>> values)
- {
- var offsets = new List<int>() { 0 };
- foreach (var value in values)
- {
- offsets.Add(offsets.Last() + value.Count);
- }
- return offsets;
- }
- public static int GetSize<T>()
- {
- #if NETSTANDARD2_0
- var isValueType = typeof(T).IsValueType;
- #else
- var isValueType = !System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences<T>();
- #endif
-
- Guard.IsTrue(isValueType, nameof(T), "T must be a value type");
- var type = typeof(T);
- var size = Marshal.SizeOf<T>();
- return size;
- }
- }
- }
|