internal void Write(BinaryWriterEx bw, List <LayoutMember> layout, float uvFactor) { foreach (LayoutMember member in layout) { switch (member.Semantic) { case LayoutSemantic.Position: if (member.Type == LayoutType.Float3) { bw.WriteVector3(Position); } else if (member.Type == LayoutType.Float4) { bw.WriteVector3(Position); bw.WriteSingle(0); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } break; case LayoutSemantic.BoneWeights: if (member.Type == LayoutType.Byte4A) { for (int i = 0; i < 4; i++) { bw.WriteSByte((sbyte)Math.Round(BoneWeights[i] * sbyte.MaxValue)); } } else if (member.Type == LayoutType.Byte4C) { for (int i = 0; i < 4; i++) { bw.WriteSByte((sbyte)Math.Round(BoneWeights[i] * sbyte.MaxValue)); } } else if (member.Type == LayoutType.UVPair) { for (int i = 0; i < 4; i++) { bw.WriteInt16((short)Math.Round(BoneWeights[i] * short.MaxValue)); } } else if (member.Type == LayoutType.Short4toFloat4A) { for (int i = 0; i < 4; i++) { bw.WriteInt16((short)Math.Round(BoneWeights[i] * short.MaxValue)); } } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } break; case LayoutSemantic.BoneIndices: if (member.Type == LayoutType.Byte4B) { for (int i = 0; i < 4; i++) { bw.WriteByte((byte)BoneIndices[i]); } } else if (member.Type == LayoutType.ShortBoneIndices) { for (int i = 0; i < 4; i++) { bw.WriteUInt16((ushort)BoneIndices[i]); } } else if (member.Type == LayoutType.Byte4E) { for (int i = 0; i < 4; i++) { bw.WriteByte((byte)BoneIndices[i]); } } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } break; case LayoutSemantic.Normal: if (member.Type == LayoutType.Float3) { bw.WriteSingle(Normal.X); bw.WriteSingle(Normal.Y); bw.WriteSingle(Normal.Z); } else if (member.Type == LayoutType.Float4) { bw.WriteVector4(Normal); } else if (member.Type == LayoutType.Byte4A) { bw.WriteByte((byte)Math.Round(Normal.X * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.W * 127 + 127)); } else if (member.Type == LayoutType.Byte4B) { bw.WriteByte((byte)Math.Round(Normal.X * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.W * 127 + 127)); } else if (member.Type == LayoutType.Byte4C) { bw.WriteByte((byte)Math.Round(Normal.X * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.W * 127 + 127)); } else if (member.Type == LayoutType.Short4toFloat4A) { bw.WriteInt16((short)Math.Round(Normal.X * 32767)); bw.WriteInt16((short)Math.Round(Normal.Y * 32767)); bw.WriteInt16((short)Math.Round(Normal.Z * 32767)); bw.WriteInt16((short)Math.Round(Normal.W * 32767)); } else if (member.Type == LayoutType.Short4toFloat4B) { bw.WriteUInt16((ushort)Math.Round(Normal.X * 32767 + 32767)); bw.WriteUInt16((ushort)Math.Round(Normal.Y * 32767 + 32767)); bw.WriteUInt16((ushort)Math.Round(Normal.Z * 32767 + 32767)); bw.WriteUInt16((ushort)Math.Round(Normal.W * 32767 + 32767)); } else if (member.Type == LayoutType.Byte4E) { bw.WriteByte((byte)Math.Round(Normal.X * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.W * 127 + 127)); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } break; case LayoutSemantic.UV: Vector3 uv = uvQueue.Dequeue() * uvFactor; if (member.Type == LayoutType.Float2) { bw.WriteSingle(uv.X); bw.WriteSingle(uv.Y); } else if (member.Type == LayoutType.Float3) { bw.WriteVector3(uv); } else if (member.Type == LayoutType.Float4) { bw.WriteSingle(uv.X); bw.WriteSingle(uv.Y); uv = uvQueue.Dequeue() * uvFactor; bw.WriteSingle(uv.X); bw.WriteSingle(uv.Y); } else if (member.Type == LayoutType.Byte4A) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.Byte4B) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.Short2toFloat2) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.Byte4C) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.UV) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.UVPair) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); uv = uvQueue.Dequeue() * uvFactor; bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.Short4toFloat4B) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); bw.WriteInt16((short)Math.Round(uv.Z)); bw.WriteInt16(0); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } break; case LayoutSemantic.Tangent: Vector4 tangent = tangentQueue.Dequeue(); if (member.Type == LayoutType.Float4) { bw.WriteVector4(tangent); } else if (member.Type == LayoutType.Byte4A) { bw.WriteByte((byte)Math.Round(tangent.X * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.W * 127 + 127)); } else if (member.Type == LayoutType.Byte4B) { bw.WriteByte((byte)Math.Round(tangent.X * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.W * 127 + 127)); } else if (member.Type == LayoutType.Byte4C) { bw.WriteByte((byte)Math.Round(tangent.X * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.W * 127 + 127)); } else if (member.Type == LayoutType.Short4toFloat4A) { bw.WriteInt16((short)Math.Round(tangent.X * 32767)); bw.WriteInt16((short)Math.Round(tangent.Y * 32767)); bw.WriteInt16((short)Math.Round(tangent.Z * 32767)); bw.WriteInt16((short)Math.Round(tangent.W * 32767)); } else if (member.Type == LayoutType.Byte4E) { bw.WriteByte((byte)Math.Round(tangent.X * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.W * 127 + 127)); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } break; case LayoutSemantic.Bitangent: if (member.Type == LayoutType.Byte4A) { bw.WriteByte((byte)Math.Round(Bitangent.X * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.W * 127 + 127)); } else if (member.Type == LayoutType.Byte4B) { bw.WriteByte((byte)Math.Round(Bitangent.X * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.W * 127 + 127)); } else if (member.Type == LayoutType.Byte4C) { bw.WriteByte((byte)Math.Round(Bitangent.X * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.W * 127 + 127)); } else if (member.Type == LayoutType.Byte4E) { bw.WriteByte((byte)Math.Round(Bitangent.X * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(Bitangent.W * 127 + 127)); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } break; case LayoutSemantic.VertexColor: FLVER.VertexColor color = colorQueue.Dequeue(); if (member.Type == LayoutType.Float4) { bw.WriteSingle(color.R); bw.WriteSingle(color.G); bw.WriteSingle(color.B); bw.WriteSingle(color.A); } else if (member.Type == LayoutType.Byte4A) { bw.WriteByte((byte)Math.Round(color.A * 255)); bw.WriteByte((byte)Math.Round(color.R * 255)); bw.WriteByte((byte)Math.Round(color.G * 255)); bw.WriteByte((byte)Math.Round(color.B * 255)); } else if (member.Type == LayoutType.Byte4C) { bw.WriteByte((byte)Math.Round(color.R * 255)); bw.WriteByte((byte)Math.Round(color.G * 255)); bw.WriteByte((byte)Math.Round(color.B * 255)); bw.WriteByte((byte)Math.Round(color.A * 255)); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } break; default: throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } } }
private static void WriteUShortNorm(BinaryWriterEx bw, float value) => bw.WriteUInt16((ushort)Math.Round(value * 32767 + 32767));
internal void WriteCells(BinaryWriterEx bw, PARAM parent, int index) { if (parent.Format2D.HasFlag(FormatFlags1.LongDataOffset)) { bw.FillInt64($"RowOffset{index}", bw.Position); } else { bw.FillUInt32($"RowOffset{index}", (uint)bw.Position); } int bitOffset = -1; PARAMDEF.DefType bitType = PARAMDEF.DefType.u8; uint bitValue = 0; for (int i = 0; i < Cells.Count; i++) { Cell cell = Cells[i]; object value = cell.Value; PARAMDEF.Field field = cell.Def; PARAMDEF.DefType type = field.DisplayType; if (type == PARAMDEF.DefType.s8) { bw.WriteSByte((sbyte)value); } else if (type == PARAMDEF.DefType.s16) { bw.WriteInt16((short)value); } else if (type == PARAMDEF.DefType.s32) { bw.WriteInt32((int)value); } else if (type == PARAMDEF.DefType.f32) { bw.WriteSingle((float)value); } else if (type == PARAMDEF.DefType.fixstr) { bw.WriteFixStr((string)value, field.ArrayLength); } else if (type == PARAMDEF.DefType.fixstrW) { bw.WriteFixStrW((string)value, field.ArrayLength * 2); } else if (ParamUtil.IsBitType(type)) { if (field.BitSize == -1) { if (type == PARAMDEF.DefType.u8) { bw.WriteByte((byte)value); } else if (type == PARAMDEF.DefType.u16) { bw.WriteUInt16((ushort)value); } else if (type == PARAMDEF.DefType.u32) { bw.WriteUInt32((uint)value); } else if (type == PARAMDEF.DefType.dummy8) { bw.WriteBytes((byte[])value); } } else { if (bitOffset == -1) { bitOffset = 0; bitType = type == PARAMDEF.DefType.dummy8 ? PARAMDEF.DefType.u8 : type; bitValue = 0; } uint shifted = 0; if (bitType == PARAMDEF.DefType.u8) { shifted = (byte)value; } else if (bitType == PARAMDEF.DefType.u16) { shifted = (ushort)value; } else if (bitType == PARAMDEF.DefType.u32) { shifted = (uint)value; } // Shift left first to clear any out-of-range bits shifted = shifted << (32 - field.BitSize) >> (32 - field.BitSize - bitOffset); bitValue |= shifted; bitOffset += field.BitSize; bool write = false; if (i == Cells.Count - 1) { write = true; } else { PARAMDEF.Field nextField = Cells[i + 1].Def; PARAMDEF.DefType nextType = nextField.DisplayType; int bitLimit = ParamUtil.GetBitLimit(bitType); if (!ParamUtil.IsBitType(nextType) || nextField.BitSize == -1 || bitOffset + nextField.BitSize > bitLimit || (nextType == PARAMDEF.DefType.dummy8 ? PARAMDEF.DefType.u8 : nextType) != bitType) { write = true; } } if (write) { bitOffset = -1; if (bitType == PARAMDEF.DefType.u8) { bw.WriteByte((byte)bitValue); } else if (bitType == PARAMDEF.DefType.u16) { bw.WriteUInt16((ushort)bitValue); } else if (bitType == PARAMDEF.DefType.u32) { bw.WriteUInt32(bitValue); } } } } else { throw new NotImplementedException($"Unsupported field type: {type}"); } } }
public override void Write(HKX hkx, HKXSection section, BinaryWriterEx bw, uint sectionBaseOffset, HKXVariation variation) { bw.WriteUInt16(data); }
internal void Write(BinaryWriterEx bw, List <LayoutMember> layout, float uvFactor) { foreach (LayoutMember member in layout) { if (member.Semantic == LayoutSemantic.Position) { if (member.Type == LayoutType.Float3) { bw.WriteVector3(Position); } else if (member.Type == LayoutType.Float4) { bw.WriteVector3(Position); bw.WriteSingle(0); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } } else if (member.Semantic == LayoutSemantic.BoneWeights) { if (member.Type == LayoutType.Byte4A) { for (int i = 0; i < 4; i++) { bw.WriteSByte((sbyte)Math.Round(BoneWeights[i] * 127)); } } else if (member.Type == LayoutType.Byte4C) { for (int i = 0; i < 4; i++) { bw.WriteByte((byte)Math.Round(BoneWeights[i] * 255)); } } else if (member.Type == LayoutType.UVPair) { for (int i = 0; i < 4; i++) { bw.WriteInt16((short)Math.Round(BoneWeights[i] * 32767)); } } else if (member.Type == LayoutType.Short4toFloat4A) { for (int i = 0; i < 4; i++) { bw.WriteInt16((short)Math.Round(BoneWeights[i] * 32767)); } } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } } else if (member.Semantic == LayoutSemantic.BoneIndices) { if (member.Type == LayoutType.Byte4B) { for (int i = 0; i < 4; i++) { bw.WriteByte((byte)BoneIndices[i]); } } else if (member.Type == LayoutType.ShortBoneIndices) { for (int i = 0; i < 4; i++) { bw.WriteUInt16((ushort)BoneIndices[i]); } } else if (member.Type == LayoutType.Byte4E) { for (int i = 0; i < 4; i++) { bw.WriteByte((byte)BoneIndices[i]); } } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } } else if (member.Semantic == LayoutSemantic.Normal) { if (member.Type == LayoutType.Float3) { bw.WriteVector3(Normal); } else if (member.Type == LayoutType.Float4) { bw.WriteVector3(Normal); bw.WriteSingle(NormalW); } else if (member.Type == LayoutType.Byte4A) { WriteByteNormXYZ(bw, Normal); bw.WriteByte((byte)NormalW); } else if (member.Type == LayoutType.Byte4B) { WriteByteNormXYZ(bw, Normal); bw.WriteByte((byte)NormalW); } else if (member.Type == LayoutType.Short2toFloat2) { bw.WriteByte((byte)NormalW); WriteSByteNormZYX(bw, Normal); } else if (member.Type == LayoutType.Byte4C) { WriteByteNormXYZ(bw, Normal); bw.WriteByte((byte)NormalW); } else if (member.Type == LayoutType.Short4toFloat4A) { WriteShortNormXYZ(bw, Normal); bw.WriteInt16((short)NormalW); } else if (member.Type == LayoutType.Short4toFloat4B) { WriteUShortNormXYZ(bw, Normal); bw.WriteInt16((short)NormalW); } else if (member.Type == LayoutType.Byte4E) { WriteByteNormXYZ(bw, Normal); bw.WriteByte((byte)NormalW); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } } else if (member.Semantic == LayoutSemantic.UV) { Vector3 uv = uvQueue.Dequeue() * uvFactor; if (member.Type == LayoutType.Float2) { bw.WriteSingle(uv.X); bw.WriteSingle(uv.Y); } else if (member.Type == LayoutType.Float3) { bw.WriteVector3(uv); } else if (member.Type == LayoutType.Float4) { bw.WriteSingle(uv.X); bw.WriteSingle(uv.Y); uv = uvQueue.Dequeue() * uvFactor; bw.WriteSingle(uv.X); bw.WriteSingle(uv.Y); } else if (member.Type == LayoutType.Byte4A) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.Byte4B) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.Short2toFloat2) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.Byte4C) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.UV) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.UVPair) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); uv = uvQueue.Dequeue() * uvFactor; bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == LayoutType.Short4toFloat4B) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); bw.WriteInt16((short)Math.Round(uv.Z)); bw.WriteInt16(0); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } } else if (member.Semantic == LayoutSemantic.Tangent) { Vector4 tangent = tangentQueue.Dequeue(); if (member.Type == LayoutType.Float4) { bw.WriteVector4(tangent); } else if (member.Type == LayoutType.Byte4A) { WriteByteNormXYZW(bw, tangent); } else if (member.Type == LayoutType.Byte4B) { WriteByteNormXYZW(bw, tangent); } else if (member.Type == LayoutType.Byte4C) { WriteByteNormXYZW(bw, tangent); } else if (member.Type == LayoutType.Short4toFloat4A) { WriteShortNormXYZW(bw, tangent); } else if (member.Type == LayoutType.Byte4E) { WriteByteNormXYZW(bw, tangent); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } } else if (member.Semantic == LayoutSemantic.Bitangent) { if (member.Type == LayoutType.Byte4A) { WriteByteNormXYZW(bw, Bitangent); } else if (member.Type == LayoutType.Byte4B) { WriteByteNormXYZW(bw, Bitangent); } else if (member.Type == LayoutType.Byte4C) { WriteByteNormXYZW(bw, Bitangent); } else if (member.Type == LayoutType.Byte4E) { WriteByteNormXYZW(bw, Bitangent); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } } else if (member.Semantic == LayoutSemantic.VertexColor) { VertexColor color = colorQueue.Dequeue(); if (member.Type == LayoutType.Float4) { color.WriteFloatRGBA(bw); } else if (member.Type == LayoutType.Byte4A) { color.WriteByteRGBA(bw); } else if (member.Type == LayoutType.Byte4C) { color.WriteByteRGBA(bw); } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } } else { throw new NotImplementedException($"Write not implemented for {member.Type} {member.Semantic}."); } } }
internal override void Write(BinaryWriterEx bw) { if (layout == null) { throw new InvalidOperationException("Params cannot be written without a layout."); } Rows.Sort((r1, r2) => r1.ID.CompareTo(r2.ID)); bw.BigEndian = BigEndian; void WriteFormat() { bw.WriteByte((byte)(BigEndian ? 0xFF : 0x00)); bw.WriteByte(Format2D); bw.WriteByte(Format2E); bw.WriteByte(Format2F); } // DeS, DS1 if ((Format2D & 0x7F) < 3) { bw.ReserveUInt32("StringsOffset"); bw.ReserveUInt16("DataStart"); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ID, 0x20, 0x20); WriteFormat(); } // DS2 else if ((Format2D & 0x7F) == 3) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ID, 0x20, 0x20); WriteFormat(); bw.ReserveUInt32("DataStart"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } // SotFS, BB else if ((Format2D & 0x7F) == 4) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ID, 0x20, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } // DS3, SDT else { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteInt32(0); bw.ReserveInt64("IDOffset"); bw.WritePattern(0x14, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteHeader(bw, Format2D, i); } if ((Format2D & 0x7F) < 3) { bw.FillUInt16("DataStart", (ushort)bw.Position); } else if ((Format2D & 0x7F) == 3) { bw.FillUInt32("DataStart", (uint)bw.Position); } else { bw.FillInt64("DataStart", bw.Position); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteCells(bw, Format2D, i, layout); } bw.FillUInt32("StringsOffset", (uint)bw.Position); if ((Format2D & 0x7F) > 4) { bw.FillInt64("IDOffset", bw.Position); bw.WriteASCII(ID, true); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteName(bw, Format2D, i); } }
internal void WriteCells(BinaryWriterEx bw, byte format2D, int i, Layout layout) { if ((format2D & 0x7F) < 4) { bw.FillUInt32($"RowOffset{i}", (uint)bw.Position); } else { bw.FillInt64($"RowOffset{i}", bw.Position); } for (int j = 0; j < layout.Count; j++) { Cell cell = Cells[j]; Layout.Entry entry = layout[j]; CellType type = entry.Type; object value = cell.Value; if (entry.Name != cell.Name || type != cell.Type) { throw new FormatException("Layout does not match cells."); } void WriteBools(CellType boolType, int fieldSize) { byte[] b = new byte[fieldSize]; int k; for (k = 0; k < fieldSize * 8; k++) { if (j + k >= layout.Count || layout[j + k].Type != boolType) { break; } if ((bool)Cells[j + k].Value) { b[k / 8] |= (byte)(1 << (k % 8)); } } j += k - 1; bw.WriteBytes(b); } if (type == CellType.s8) { bw.WriteSByte((sbyte)value); } else if (type == CellType.u8 || type == CellType.x8) { bw.WriteByte((byte)value); } else if (type == CellType.s16) { bw.WriteInt16((short)value); } else if (type == CellType.u16 || type == CellType.x16) { bw.WriteUInt16((ushort)value); } else if (type == CellType.s32) { bw.WriteInt32((int)value); } else if (type == CellType.u32 || type == CellType.x32) { bw.WriteUInt32((uint)value); } else if (type == CellType.f32) { bw.WriteSingle((float)value); } else if (type == CellType.dummy8) { bw.WriteBytes((byte[])value); } else if (type == CellType.fixstr) { bw.WriteFixStr((string)value, entry.Size); } else if (type == CellType.fixstrW) { bw.WriteFixStrW((string)value, entry.Size); } else if (type == CellType.b8) { WriteBools(type, 1); } else if (type == CellType.b16) { WriteBools(type, 2); } else if (type == CellType.b32) { WriteBools(type, 4); } } }
internal void Write(BinaryWriterEx bw, BufferLayout layout, int vertexSize, int version) { var tangentQueue = new Queue <Vector4>(Tangents); var colorQueue = new Queue <Color>(Colors); var uvQueue = new Queue <Vector3>(UVs); float uvFactor = 1024; foreach (BufferLayout.Member member in layout) { switch (member.Semantic) { case BufferLayout.MemberSemantic.Position: if (member.Type == BufferLayout.MemberType.Float3) { bw.WriteVector3(Position); } else { throw new NotImplementedException(); } break; case BufferLayout.MemberSemantic.BoneWeights: if (member.Type == BufferLayout.MemberType.Byte4C) { for (int i = 0; i < 4; i++) { bw.WriteSByte((sbyte)Math.Round(BoneWeights[i] * sbyte.MaxValue)); } } else if (member.Type == BufferLayout.MemberType.Short4toFloat4A) { for (int i = 0; i < 4; i++) { bw.WriteInt16((short)Math.Round(BoneWeights[i] * short.MaxValue)); } } else { throw new NotImplementedException(); } break; case BufferLayout.MemberSemantic.BoneIndices: if (member.Type == BufferLayout.MemberType.Byte4B) { for (int i = 0; i < 4; i++) { bw.WriteByte((byte)BoneIndices[i]); } } else if (member.Type == BufferLayout.MemberType.ShortBoneIndices) { for (int i = 0; i < 4; i++) { bw.WriteUInt16((ushort)BoneIndices[i]); } } else if (member.Type == BufferLayout.MemberType.Byte4E) { for (int i = 0; i < 4; i++) { bw.WriteByte((byte)BoneIndices[i]); } } else { throw new NotImplementedException(); } break; case BufferLayout.MemberSemantic.Normal: if (member.Type == BufferLayout.MemberType.Float4) { bw.WriteVector4(Normal); } else if (member.Type == BufferLayout.MemberType.Byte4A) { bw.WriteByte((byte)Math.Round(Normal.X * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.W * 127 + 127)); } else if (member.Type == BufferLayout.MemberType.Byte4B) { bw.WriteByte((byte)Math.Round(Normal.X * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.W * 127 + 127)); } else if (member.Type == BufferLayout.MemberType.Byte4C) { bw.WriteByte((byte)Math.Round(Normal.X * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(Normal.W * 127 + 127)); } else if (member.Type == BufferLayout.MemberType.Short4toFloat4B) { bw.WriteInt16((short)Math.Round(Normal.X * 32767 + 32767)); bw.WriteInt16((short)Math.Round(Normal.Y * 32767 + 32767)); bw.WriteInt16((short)Math.Round(Normal.Z * 32767 + 32767)); bw.WriteInt16((short)Math.Round(Normal.W * 32767 + 32767)); } else { throw new NotImplementedException(); } break; case BufferLayout.MemberSemantic.UV: Vector3 uv = uvQueue.Dequeue() * uvFactor; if (member.Type == BufferLayout.MemberType.Float2) { bw.WriteSingle(uv.X); bw.WriteSingle(uv.Y); } else if (member.Type == BufferLayout.MemberType.Float3) { bw.WriteVector3(uv); } else if (member.Type == BufferLayout.MemberType.Byte4A) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == BufferLayout.MemberType.Byte4B) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == BufferLayout.MemberType.Short2toFloat2) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == BufferLayout.MemberType.Byte4C) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == BufferLayout.MemberType.UV) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else if (member.Type == BufferLayout.MemberType.UVPair) { bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); uv = uvQueue.Dequeue() * uvFactor; bw.WriteInt16((short)Math.Round(uv.X)); bw.WriteInt16((short)Math.Round(uv.Y)); } else { throw new NotImplementedException(); } break; case BufferLayout.MemberSemantic.Tangent: Vector4 tangent = tangentQueue.Dequeue(); if (member.Type == BufferLayout.MemberType.Byte4A) { bw.WriteByte((byte)Math.Round(tangent.X * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.W * 127 + 127)); } else if (member.Type == BufferLayout.MemberType.Byte4B) { bw.WriteByte((byte)Math.Round(tangent.X * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.W * 127 + 127)); } else if (member.Type == BufferLayout.MemberType.Byte4C) { bw.WriteByte((byte)Math.Round(tangent.X * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Y * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.Z * 127 + 127)); bw.WriteByte((byte)Math.Round(tangent.W * 127 + 127)); } else { throw new NotImplementedException(); } break; case BufferLayout.MemberSemantic.UnknownVector4A: if (member.Type == BufferLayout.MemberType.Byte4B) { bw.WriteBytes(UnknownVector4); } else if (member.Type == BufferLayout.MemberType.Byte4C) { bw.WriteBytes(UnknownVector4); } else { throw new NotImplementedException(); } break; case BufferLayout.MemberSemantic.VertexColor: Color color = colorQueue.Dequeue(); if (member.Type == BufferLayout.MemberType.Float4) { bw.WriteSingle(color.R); bw.WriteSingle(color.G); bw.WriteSingle(color.B); bw.WriteSingle(color.A); } else if (member.Type == BufferLayout.MemberType.Byte4A) { bw.WriteByte((byte)Math.Round(color.A * 255)); bw.WriteByte((byte)Math.Round(color.R * 255)); bw.WriteByte((byte)Math.Round(color.G * 255)); bw.WriteByte((byte)Math.Round(color.B * 255)); } else if (member.Type == BufferLayout.MemberType.Byte4C) { bw.WriteByte((byte)Math.Round(color.R * 255)); bw.WriteByte((byte)Math.Round(color.G * 255)); bw.WriteByte((byte)Math.Round(color.B * 255)); bw.WriteByte((byte)Math.Round(color.A * 255)); } else { throw new NotImplementedException(); } break; default: throw new NotImplementedException(); } } }
/// <summary> /// Serializes file data to a stream. /// </summary> internal override void Write(BinaryWriterEx bw) { if (AppliedParamdef == null) { throw new InvalidOperationException("Params cannot be written without applying a paramdef."); } bw.BigEndian = BigEndian; void WriteFormat() { bw.WriteByte((byte)(BigEndian ? 0xFF : 0x00)); bw.WriteByte(Format2D); bw.WriteByte(Format2E); bw.WriteByte(Format2F); } // DeS, DS1 if ((Format2D & 0x7F) < 3) { bw.ReserveUInt32("StringsOffset"); bw.ReserveUInt16("DataStart"); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ParamType, 0x20, (byte)((Format2D & 0x7F) < 2 ? 0x20 : 0x00)); WriteFormat(); } // DS2 else if ((Format2D & 0x7F) == 3) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ParamType, 0x20, 0x20); WriteFormat(); bw.ReserveUInt32("DataStart"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } // SotFS, BB else if ((Format2D & 0x7F) == 4) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ParamType, 0x20, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } // DS3, SDT else { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteInt32(0); bw.ReserveInt64("IDOffset"); bw.WritePattern(0x14, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteHeader(bw, Format2D, i); } if ((Format2D & 0x7F) < 2) { bw.WritePattern(0x20, 0x00); } if ((Format2D & 0x7F) < 3) { bw.FillUInt16("DataStart", (ushort)bw.Position); } else if ((Format2D & 0x7F) == 3) { bw.FillUInt32("DataStart", (uint)bw.Position); } else { bw.FillInt64("DataStart", bw.Position); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteCells(bw, Format2D, i); } bw.FillUInt32("StringsOffset", (uint)bw.Position); if ((Format2D & 0x7F) > 4) { bw.FillInt64("IDOffset", bw.Position); bw.WriteASCII(ParamType, true); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteName(bw, Format2D, Format2E, i); } // DeS and BB sometimes (but not always) include some useless padding here }
internal void WriteCells(BinaryWriterEx bw, int i, Layout layout) { bw.FillInt64($"RowOffset{i}", bw.Position); for (int j = 0; j < layout.Count; j++) { Cell cell = Cells[j]; Layout.Entry entry = layout[j]; string type = entry.Type; object value = cell.Value; if (entry.Name != cell.Name || type != cell.Type) { throw new FormatException("Layout does not match cells."); } if (type == "s8") { bw.WriteSByte((sbyte)value); } else if (type == "u8" || type == "x8") { bw.WriteByte((byte)value); } else if (type == "s16") { bw.WriteInt16((short)value); } else if (type == "u16" || type == "x16") { bw.WriteUInt16((ushort)value); } else if (type == "s32") { bw.WriteInt32((int)value); } else if (type == "u32" || type == "x32") { bw.WriteUInt32((uint)value); } else if (type == "f32") { bw.WriteSingle((float)value); } else if (type == "dummy8") { bw.WriteBytes((byte[])value); } else if (type == "fixstr") { bw.WriteFixStr((string)value, entry.Size); } else if (type == "fixstrW") { bw.WriteFixStrW((string)value, entry.Size); } else if (type == "b8") { byte b = 0; int k; for (k = 0; k < 8; k++) { if (j + k >= layout.Count || layout[j + k].Type != "b8") { break; } if ((bool)Cells[j + k].Value) { b |= (byte)(1 << k); } } j += k - 1; bw.WriteByte(b); } else if (type == "b32") { byte[] b = new byte[4]; int k; for (k = 0; k < 32; k++) { if (j + k >= layout.Count || layout[j + k].Type != "b32") { break; } if ((bool)Cells[j + k].Value) { b[k / 8] |= (byte)(1 << (k % 8)); } } j += k - 1; bw.WriteBytes(b); } } }
internal override void Write(BinaryWriterEx bw) { if (layout == null) { throw new InvalidOperationException("Params cannot be written without a layout."); } Rows.Sort((r1, r2) => r1.ID.CompareTo(r2.ID)); bw.BigEndian = false; bw.ReserveInt32("NameOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk1); bw.WriteInt16(Unk2); bw.WriteUInt16((ushort)Rows.Count); if (FixStrID) { bw.WriteFixStr(ID, 0x20); } else { bw.WriteInt32(0); bw.ReserveInt32("IDOffset"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } bw.WriteByte(0); bw.WriteByte(Unk3); bw.WriteByte(Unk4); bw.WriteByte(0); bw.ReserveInt64("DataStart"); bw.WriteInt32(0); bw.WriteInt32(0); for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteHeader(bw, i); } bw.FillInt64("DataStart", bw.Position); for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteCells(bw, i, layout); } bw.FillInt32("NameOffset", (int)bw.Position); if (FixStrID) { if (Unk4 == 6) { bw.WriteShiftJIS(Name, true); } else if (Unk4 == 7) { bw.WriteUTF16(Name, true); } } else { bw.WriteShiftJIS(Name, true); bw.FillInt32("IDOffset", (int)bw.Position); bw.WriteASCII(ID, true); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteName(bw, i, Unk4); } }
protected override void Write(BinaryWriterEx bw) { bw.WriteASCII("FXR\0"); bw.WriteInt16(0); bw.WriteUInt16((ushort)Version); bw.WriteInt32(1); bw.WriteInt32(ID); bw.ReserveInt32("Section1Offset"); bw.WriteInt32(1); bw.ReserveInt32("Section2Offset"); bw.WriteInt32(Section1Tree.Section2s.Count); bw.ReserveInt32("Section3Offset"); bw.ReserveInt32("Section3Count"); bw.ReserveInt32("Section4Offset"); bw.ReserveInt32("Section4Count"); bw.ReserveInt32("Section5Offset"); bw.ReserveInt32("Section5Count"); bw.ReserveInt32("Section6Offset"); bw.ReserveInt32("Section6Count"); bw.ReserveInt32("Section7Offset"); bw.ReserveInt32("Section7Count"); bw.ReserveInt32("Section8Offset"); bw.ReserveInt32("Section8Count"); bw.ReserveInt32("Section9Offset"); bw.ReserveInt32("Section9Count"); bw.ReserveInt32("Section10Offset"); bw.ReserveInt32("Section10Count"); bw.ReserveInt32("Section11Offset"); bw.ReserveInt32("Section11Count"); bw.WriteInt32(1); bw.WriteInt32(0); if (Version == FXRVersion.Sekiro) { bw.ReserveInt32("Section12Offset"); bw.WriteInt32(Section12s.Count); bw.ReserveInt32("Section13Offset"); bw.WriteInt32(Section13s.Count); bw.ReserveInt32("Section14Offset"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } bw.FillInt32("Section1Offset", (int)bw.Position); Section1Tree.Write(bw); bw.Pad(0x10); bw.FillInt32("Section2Offset", (int)bw.Position); Section1Tree.WriteSection2s(bw); bw.Pad(0x10); bw.FillInt32("Section3Offset", (int)bw.Position); List <Section2> section2s = Section1Tree.Section2s; var section3s = new List <Section3>(); for (int i = 0; i < section2s.Count; i++) { section2s[i].WriteSection3s(bw, i, section3s); } bw.FillInt32("Section3Count", section3s.Count); bw.Pad(0x10); bw.FillInt32("Section4Offset", (int)bw.Position); var section4s = new List <Section4>(); Section4Tree.Write(bw, section4s); Section4Tree.WriteSection4s(bw, section4s); bw.FillInt32("Section4Count", section4s.Count); bw.Pad(0x10); bw.FillInt32("Section5Offset", (int)bw.Position); int section5Count = 0; for (int i = 0; i < section4s.Count; i++) { section4s[i].WriteSection5s(bw, i, ref section5Count); } bw.FillInt32("Section5Count", section5Count); bw.Pad(0x10); bw.FillInt32("Section6Offset", (int)bw.Position); section5Count = 0; var section6s = new List <FFXDrawEntityHost>(); for (int i = 0; i < section4s.Count; i++) { section4s[i].WriteSection6s(bw, i, ref section5Count, section6s); } bw.FillInt32("Section6Count", section6s.Count); bw.Pad(0x10); bw.FillInt32("Section7Offset", (int)bw.Position); var section7s = new List <FFXProperty>(); for (int i = 0; i < section6s.Count; i++) { section6s[i].WriteSection7s(bw, i, section7s); } bw.FillInt32("Section7Count", section7s.Count); bw.Pad(0x10); bw.FillInt32("Section8Offset", (int)bw.Position); var section8s = new List <Section8>(); for (int i = 0; i < section7s.Count; i++) { section7s[i].WriteSection8s(bw, i, section8s); } bw.FillInt32("Section8Count", section8s.Count); bw.Pad(0x10); bw.FillInt32("Section9Offset", (int)bw.Position); var section9s = new List <Section9>(); for (int i = 0; i < section8s.Count; i++) { section8s[i].WriteSection9s(bw, i, section9s); } bw.FillInt32("Section9Count", section9s.Count); bw.Pad(0x10); bw.FillInt32("Section10Offset", (int)bw.Position); var section10s = new List <Section10>(); for (int i = 0; i < section6s.Count; i++) { section6s[i].WriteSection10s(bw, i, section10s); } bw.FillInt32("Section10Count", section10s.Count); bw.Pad(0x10); bw.FillInt32("Section11Offset", (int)bw.Position); int section11Count = 0; for (int i = 0; i < section3s.Count; i++) { section3s[i].WriteSection11s(bw, i, ref section11Count); } for (int i = 0; i < section6s.Count; i++) { section6s[i].WriteSection11s(bw, i, ref section11Count); } for (int i = 0; i < section7s.Count; i++) { section7s[i].WriteSection11s(bw, i, ref section11Count); } for (int i = 0; i < section8s.Count; i++) { section8s[i].WriteSection11s(bw, i, ref section11Count); } for (int i = 0; i < section9s.Count; i++) { section9s[i].WriteSection11s(bw, i, ref section11Count); } for (int i = 0; i < section10s.Count; i++) { section10s[i].WriteSection11s(bw, i, ref section11Count); } bw.FillInt32("Section11Count", section11Count); bw.Pad(0x10); if (Version == FXRVersion.Sekiro) { bw.FillInt32("Section12Offset", (int)bw.Position); bw.WriteInt32s(Section12s); bw.Pad(0x10); bw.FillInt32("Section13Offset", (int)bw.Position); bw.WriteInt32s(Section13s); bw.Pad(0x10); bw.FillInt32("Section14Offset", (int)bw.Position); } }