using System; namespace NW4RTools.Models { public abstract class VertexDataBase { public UInt32 Index; public VertexSettings.CompCount ComponentCount; public VertexSettings.CompType ComponentType; public byte Fraction /* Not used for colours */, EntrySize; public UInt16 EntryCount; // Todo, decode data when reading public byte[] RawData; public float[][] Data; public VertexDataBase() { } public virtual float[] GetEntry(int index) { float[] ret = new float[GetRealCount()]; float scale = 1.0f / (1 << Fraction); InputStream ins = new InputStream(RawData); ins.Seek(index * EntrySize); for (int i = 0; i < ret.Length; i++) { switch (ComponentType) { case VertexSettings.CompType.UInt8: ret[i] = (float)ins.ReadByte() * scale; break; case VertexSettings.CompType.Int8: ret[i] = (float)ins.ReadSByte() * scale; break; case VertexSettings.CompType.UInt16: ret[i] = (float)ins.ReadUInt16() * scale; break; case VertexSettings.CompType.Int16: ret[i] = (float)ins.ReadInt16() * scale; break; case VertexSettings.CompType.Float32: ret[i] = ins.ReadFloat(); break; default: throw new NotImplementedException(String.Format("unimplemented type {0}", (int)ComponentType)); } } return ret; } public void Parse() { if (Data != null) return; Data = new float[EntryCount][]; for (int i = 0; i < EntryCount; i++) { Data[i] = GetEntry(i); } } public virtual void Save() { int elementCount = Data[0].Length; float scale = 1.0f / (1 << Fraction); var output = new OutputStream(); switch (ComponentType) { case VertexSettings.CompType.UInt8: foreach (var array in Data) { for (int i = 0; i < elementCount; i++) { output.WriteByte((byte)(array[i] / scale)); } } break; case VertexSettings.CompType.Int8: foreach (var array in Data) { for (int i = 0; i < elementCount; i++) { output.WriteSByte((sbyte)(array[i] / scale)); } } break; case VertexSettings.CompType.UInt16: foreach (var array in Data) { for (int i = 0; i < elementCount; i++) { output.WriteUInt16((ushort)(array[i] / scale)); } } break; case VertexSettings.CompType.Int16: foreach (var array in Data) { for (int i = 0; i < elementCount; i++) { output.WriteInt16((short)(array[i] / scale)); } } break; case VertexSettings.CompType.Float32: foreach (var array in Data) { for (int i = 0; i < elementCount; i++) { output.WriteFloat(array[i]); } } break; default: throw new NotImplementedException(String.Format("unimplemented type {0}", (int)ComponentType)); } RawData = output.GetBuffer(); } public abstract int GetRealCount(); } public class VertexPosData : VertexDataBase { public Vec3 Minimum, Maximum; public VertexPosData() { } public override int GetRealCount() { switch (ComponentCount) { case VertexSettings.CompCount.Position2: return 2; case VertexSettings.CompCount.Position3: return 3; default: return -1; } } } public class VertexNrmData : VertexDataBase { public VertexNrmData() { } public override int GetRealCount() { switch (ComponentCount) { case VertexSettings.CompCount.Normal3: return 3; default: return -1; } } } public class VertexClrData : VertexDataBase { public VertexClrData() { } public override int GetRealCount() { switch (ComponentCount) { case VertexSettings.CompCount.Color3: return 3; case VertexSettings.CompCount.Color4: return 4; default: return -1; } } public override float[] GetEntry(int index) { float[] ret = new float[GetRealCount()]; InputStream ins = new InputStream(RawData); ins.Seek(index * EntrySize); byte r, g, b, a; // todo: better solution instead of this cast switch ((VertexSettings.CompClrType)ComponentType) { case VertexSettings.CompClrType.RGB565: ushort v565 = ins.ReadUInt16(); r = (byte)((v565 & 0xF800) >> 8); g = (byte)((v565 & 0x07E0) >> 3); b = (byte)((v565 & 0x001F) << 3); a = 255; break; case VertexSettings.CompClrType.RGB8: r = ins.ReadByte(); g = ins.ReadByte(); b = ins.ReadByte(); a = 255; break; case VertexSettings.CompClrType.RGBX8: r = ins.ReadByte(); g = ins.ReadByte(); b = ins.ReadByte(); a = 255; ins.Skip(1); break; case VertexSettings.CompClrType.RGBA4: ushort vA4 = ins.ReadUInt16(); r = (byte)((vA4 & 0xF000) >> 8); g = (byte)((vA4 & 0x0F00) >> 4); b = (byte)(vA4 & 0x00F0); a = (byte)((vA4 & 0x000F) << 4); break; case VertexSettings.CompClrType.RGBA6: byte v1 = ins.ReadByte(); byte v2 = ins.ReadByte(); byte v3 = ins.ReadByte(); r = (byte)(v1 & 0xF8); g = (byte)(((v1 & 7) << 6) | ((v2 & 0xF0) >> 2)); b = (byte)(((v2 & 0xF) << 4) | ((v3 & 0xC) >> 4)); a = (byte)((v3 & 0x3F) << 2); break; case VertexSettings.CompClrType.RGBA8: r = ins.ReadByte(); g = ins.ReadByte(); b = ins.ReadByte(); a = ins.ReadByte(); break; default: throw new NotImplementedException(String.Format("unimplemented type {0}", (int)ComponentType)); } // this is the easiest way I can think of to handle this atm // just use floats for EVERYTHING ret[0] = r * (1.0f / 256); ret[1] = g * (1.0f / 256); ret[2] = b * (1.0f / 256); if (ret.Length > 3) ret[3] = a * (1.0f / 256); return ret; } public override void Save() { throw new NotImplementedException(); } } public class VertexTexCoordData : VertexDataBase { public Vec2 Minimum, Maximum; public VertexTexCoordData() { } public override int GetRealCount() { switch (ComponentCount) { case VertexSettings.CompCount.TexCoord1: return 1; case VertexSettings.CompCount.TexCoord2: return 2; default: return -1; } } } }