using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
namespace OpenVIII.Battle.Dat
{
///
/// Section 1b: Bones
///
///
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = ByteSize)]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "UnassignedReadonlyField")]
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public class Bone
{
#region Fields
public const int ByteSize = 16 + UnkSize;
public const int UnkSize = 32;
///
/// Bone Size
///
[field: FieldOffset(2)]
public readonly short BoneSize;
///
/// Parent ID
///
[field: FieldOffset(0)]
public readonly ushort ParentId;
///
/// Unknown Often Empty Bytes
///
[MarshalAs(UnmanagedType.ByValArray, SizeConst = UnkSize)]
[field: FieldOffset(16)]
public readonly byte[] Unk;
///
/// rotation X * 360f
///
[field: FieldOffset(4)]
private readonly short _rotX;
///
/// rotation Y * 360f
///
[field: FieldOffset(6)]
private readonly short _rotY;
///
/// rotation Z * 360f
///
[field: FieldOffset(8)]
private readonly short _rotZ;
[field: FieldOffset(10)]
private readonly short _unk4;
[field: FieldOffset(12)]
private readonly short _unk5;
[field: FieldOffset(14)]
private readonly short _unk6;
#endregion Fields
#region Constructors
private Bone(BinaryReader br)
{
if (br.BaseStream.Position + ByteSize >= br.BaseStream.Length) return;
(ParentId, BoneSize, _rotX, _rotY, _rotZ, _unk4, _unk5, _unk6, Unk) = (br.ReadUInt16(), br.ReadInt16(),
br.ReadInt16(), br.ReadInt16(), br.ReadInt16(), br.ReadInt16(), br.ReadInt16(), br.ReadInt16(),
br.ReadBytes(UnkSize));
}
private Bone()
{
}
#endregion Constructors
#region Properties
public (float X, float Y, float Z) Rot =>
(_rotX / 4096.0f * 360.0f, _rotY / 4096.0f * 360.0f, _rotZ / 4096.0f * 360.0f);
public float Size => BoneSize / DatFile.ScaleHelper;
public (float A, float B, float C) UnkV => (_unk4 / 4096.0f, _unk5 / 4096.0f, _unk6 / 4096.0f);
#endregion Properties
#region Methods
public static IReadOnlyList CreateInstances(BinaryReader br, ushort cBones)
{
if (br.BaseStream.Position + ByteSize * cBones < br.BaseStream.Length)
return Enumerable.Range(0, cBones)
.Select(_ => Extended.ByteArrayToClass(br.ReadBytes(ByteSize))).ToList()
.AsReadOnly();
throw new InvalidDataException($"{nameof(Bone)}::{nameof(CreateInstances)} Stream to short to read {cBones} bones");
}
#endregion Methods
}
}