internal override void WriteContent(EndianBinaryWriter writer, IOContext context) { writer.OffsetPositions.Clear(); var start = writer.Position; // -- header -- // Write relocation table last (lowest priority) writer.PushBaseOffset(start + 0x10); writer.ScheduleWriteOffsetAligned(-1, 16, () => { // Encode & write relocation table var encodedRelocationTable = RelocationTableEncoding.Encode(writer.OffsetPositions.Select(x => ( int )x).ToList(), ( int )writer.BaseOffset); writer.WriteBytes(encodedRelocationTable); var end = writer.Position; writer.SeekBegin(start + 4); writer.WriteInt32(encodedRelocationTable.Length); writer.SeekBegin(end); }); writer.WriteInt32(0); writer.WriteInt16(Group); writer.WriteInt16(PlayGroup); writer.WriteInt16(FirstMotion); writer.WriteInt16(Flags); // -- motion data header -- if (mControllerDefinitions == null) { mControllerDefinitions = Motions.Where(x => x != null) .SelectMany(x => x.Controllers) .Select(x => x.GetDefinition()) .Distinct() //.OrderBy( x => x.NodeIndex ) .ToList(); } if (mMotionDefinitions == null) { mMotionDefinitions = BuildMotionDefinitions(); } writer.WriteInt16(( short )Motions.Count); writer.WriteInt16(( short )mControllerDefinitions.Count); writer.ScheduleWriteOffsetAligned(16, () => { writer.ScheduleWriteObjectOffsetsAligned(mMotionDefinitions, 4); }); // -- controller definitions -- writer.WriteObjects(mControllerDefinitions); // write all the things writer.PerformScheduledWrites(); writer.PopBaseOffset(); }
private void BuildHeaderFinalPass(ref BinaryHeader header) { header.RelocationTable.Offset = GetAlignedAddress() + BinaryHeader.SIZE; header.RelocationTable.Value = RelocationTableEncoding.Encode(mAddressLocations, BinaryHeader.SIZE); header.RelocationTableSize = header.RelocationTable.Value.Length; mPosition += header.RelocationTableSize; header.FileSize = mPosition; }
protected override void Write(EndianBinaryWriter writer, IOContext context = null) { // Skip header writer.PushBaseOffset(); var start = writer.Position; writer.Write(( int )ResourceDescriptor.FileType); writer.Write(( uint )ResourceDescriptor.Identifier); writer.Write(0); // dummy data size writer.ScheduleWriteOffsetAligned(-1, 16, () => { // Write data size var relocationTableStart = writer.Position; writer.SeekBegin(start + 8); writer.Write(( int )relocationTableStart - start); // Encode & write relocation table writer.SeekBegin(relocationTableStart); var encodedRelocationTable = RelocationTableEncoding.Encode(writer.OffsetPositions.Select(x => ( int )x).ToList(), ( int )writer.BaseOffset); writer.Write(encodedRelocationTable); // Write relocation table size var relocationTableEnd = writer.Position; writer.SeekBegin(start + 16); writer.Write(encodedRelocationTable.Length); writer.SeekBegin(relocationTableEnd); }); writer.Write(0); // dummy relocation table size // Write resource content WriteContent(writer, context); writer.PerformScheduledWrites(); // Seek back to the end and align to 64 bytes writer.PopBaseOffset(); }
internal override void WriteContent(EndianBinaryWriter writer, IOContext context) { if (!context.IsFieldObject) { // TODO: implement this properly writer.OffsetPositions.Clear(); } var start = writer.Position; if (!context.IsFieldObject) { // Relocation table needs this base offset writer.PushBaseOffset(start + 16); // Write relocation table last (lowest priority) writer.ScheduleWriteOffsetAligned(-1, 16, () => { // Encode & write relocation table var encodedRelocationTable = RelocationTableEncoding.Encode(writer.OffsetPositions.Select(x => ( int )x).ToList(), ( int )writer.BaseOffset); writer.Write(encodedRelocationTable); // Kind of a hack here, but we need to write the relocation table size after the offset // Seeing as we have the offset positions required to encode the relocation table only at the very end // I can't really think of a better solution var end = writer.Position; writer.SeekBegin(start + 4); writer.Write(encodedRelocationTable.Length); writer.SeekBegin(end); }); } else { writer.Write(0); writer.Write(0); } writer.Align(16); writer.ScheduleWriteOffsetAligned(16, () => { writer.Write(Nodes.Count); writer.Align(16); for (int i = 0; i < Nodes.Count; i++) { writer.WriteObject(Nodes[i], (i, Nodes)); } }); writer.ScheduleWriteOffsetAligned(16, () => { writer.Write(Materials.Count); for (int i = 0; i < Materials.Count; i++) { writer.WriteObject(Materials[i], i); } }); var morpherMeshCount = Nodes.Where(x => x.Geometry != null && x.Geometry.Meshes?.Count > 0) .Sum(x => x.Geometry.Meshes.Count(y => MeshTypeTraits.HasMorphers(y.Type))); writer.Write(morpherMeshCount); writer.ScheduleWriteOffsetAligned(16, () => { // NDNM is a special case as we stored the data in the nodes themselves. bool noNodeNames = Nodes.All(x => x.Name == null); if (!noNodeNames) { WriteExtension(writer, ModelExtensionIdentifier.NodeName, () => { for (int i = 0; i < Nodes.Count; i++) { writer.Write(Nodes[i].Name, StringBinaryFormat.NullTerminated); writer.Align(4); writer.Write(i); } }); } foreach (var extension in Extensions) { WriteExtension(writer, extension.Identifier, () => writer.WriteObject(extension)); } // Write dummy end extension writer.Write(0); writer.Write(0); writer.Align(16); }); if (!context.IsFieldObject) { // TODO(TGE): implement this properly writer.PerformScheduledWrites(); } }