/// <summary> /// Writes the buffer vertex to a stream /// </summary> /// <param name="writer">Output stream</param> public void Write(EndianWriter writer) { Position.Write(writer, IOType.Float); Normal.Write(writer, IOType.Float); writer.WriteUInt16(Index); writer.WriteUInt16((ushort)(Weight * ushort.MaxValue)); }
/// <summary> /// Writes the buffer mesh to a stream /// </summary> /// <param name="writer">Output stream</param> public uint Write(EndianWriter writer, uint imageBase) { uint vtxAddr = 0; if (Vertices != null) { vtxAddr = writer.Position + imageBase; foreach (BufferVertex vtx in Vertices) { vtx.Write(writer); } } uint cornerAddr = 0; if (Corners != null) { cornerAddr = writer.Position + imageBase; foreach (BufferCorner c in Corners) { c.Write(writer); } } uint triangleAddr = 0; if (TriangleList != null) { triangleAddr = writer.Position + imageBase; foreach (uint t in TriangleList) { writer.WriteUInt32(t); } } uint address = writer.Position + imageBase; writer.WriteUInt16((ushort)(Vertices == null ? 0 : Vertices.Length)); writer.WriteUInt16((ushort)(ContinueWeight ? 1u : 0u)); writer.WriteUInt32((uint)(Corners == null ? 0 : Corners.Length)); writer.WriteUInt32((uint)(TriangleList == null ? 0 : TriangleList.Length)); if (Material == null) { writer.Write(new byte[32]); } else { Material.Write(writer); } writer.WriteUInt32(vtxAddr); writer.WriteUInt32(cornerAddr); writer.WriteUInt32(triangleAddr); return(address); }
internal static void DefaultWrite(this IPoly poly, EndianWriter writer) { foreach (ushort i in poly.Indices) { writer.WriteUInt16(i); } }
/// <summary> /// Writes the strip to a byte stream /// </summary> /// <param name="writer">Output stream</param> /// <param name="userAttribs">Amount of user attributes</param> /// <param name="hasUV">Whether the polygons carry uv data</param> /// <param name="HDUV">Whether the uv data repeats at 1024, not 256</param> /// <param name="hasNormal">Whether the polygons carry normal data</param> /// <param name="hasColor">Whether the polygons carry color data</param> public void Write(EndianWriter writer, byte userAttribs, bool hasUV, bool HDUV, bool hasNormal, bool hasColor) { short length = (short)Math.Min(Corners.Length, short.MaxValue); writer.WriteInt16(Reversed ? (short)-length : length); bool flag1 = userAttribs > 0; bool flag2 = userAttribs > 1; bool flag3 = userAttribs > 2; float multiplier = HDUV ? 1024 : 256; for (int i = 0; i < length; i++) { Corner c = Corners[i]; writer.WriteUInt16(c.Index); if (hasUV) { (c.Texcoord * multiplier).Write(writer, IOType.Short); } if (hasNormal) { c.Normal.Write(writer, IOType.Float); } else if (hasColor) { c.Color.Write(writer, IOType.ARGB8_16); } if (flag1 && i > 1) { writer.WriteUInt16(c.UserFlag1); if (flag2) { writer.WriteUInt16(c.UserFlag2); if (flag3) { writer.WriteUInt16(c.UserFlag3); } } } } }
/// <summary> /// Updates any changes made to the object data. /// </summary> /// <param name="reader"> /// The EndianWriter to write to. /// It should point to the same stream that was used to load the object data, as seeking will be done automatically. /// </param> public virtual void Update(EndianWriter writer) { // Strength info long chunkStartOffset = _entry.ObjectAddress + (long)TableOffset.ObjectPool; writer.SeekTo(chunkStartOffset + StrengthInfoOffset); _healthInfo.WriteTo(writer); // BSP Zone writer.SeekTo(chunkStartOffset + 0x18); writer.WriteUInt16(_zone); // Position1 writer.SeekTo(chunkStartOffset + PositionOffset1); writer.WriteFloat(_positionMain.X); writer.WriteFloat(_positionMain.Y); writer.WriteFloat(_positionMain.Z); // Calculate extra position vectors Vector3 position2 = Vector3.Add(_position2Delta, _positionMain); Vector3 position3 = Vector3.Add(_position3Delta, _positionMain); Vector3 position4 = Vector3.Add(_position4Delta, _positionMain); // Position2 writer.SeekTo(chunkStartOffset + PositionOffset2); writer.WriteFloat(position2.X); writer.WriteFloat(position2.Y); writer.WriteFloat(position2.Z); // Position3 writer.SeekTo(chunkStartOffset + PositionOffset3); writer.WriteFloat(position3.X); writer.WriteFloat(position3.Y); writer.WriteFloat(position3.Z); // Position4 writer.SeekTo(chunkStartOffset + PositionOffset4); writer.WriteFloat(position4.X); writer.WriteFloat(position4.Y); writer.WriteFloat(position4.Z); }
/// <summary> /// Write the chunk to a stream /// </summary> /// <param name="writer">Output stream</param> public virtual void Write(EndianWriter writer) { writer.WriteUInt16((ushort)((byte)Type | (ushort)(Attributes << 8))); }
/// <summary> /// Writes the buffer corner to a stream /// </summary> /// <param name="writer">Output stream</param> public void Write(EndianWriter writer) { writer.WriteUInt16(VertexIndex); Color.Write(writer, IOType.ARGB8_32); Texcoord.Write(writer, IOType.Float); }
private void WriteChunks(SerializingContainer2 sc) { EndianWriter writer = sc.ms.Writer; if (EmbeddedFiles.Count > 0) { writer.WriteUInt32(didx); writer.WriteInt32(EmbeddedFiles.Count * 12); var dataChunk = new MemoryStream(); foreach ((uint id, byte[] bytes) in EmbeddedFiles) { dataChunk.WriteZeros((int)(dataChunk.Position.Align(16) - dataChunk.Position)); //files must be 16-byte aligned in the data chunk writer.WriteUInt32(id); //writing to DIDX writer.WriteInt32((int)dataChunk.Position); //Writing to DIDX writer.WriteInt32(bytes.Length); //Writing to DIDX dataChunk.WriteFromBuffer(bytes); //Writing to DATA } writer.WriteUInt32(data); writer.WriteInt32((int)dataChunk.Length); writer.WriteFromBuffer(dataChunk.ToArray()); } if (sc.Game == MEGame.ME2 && ME2STMGFallback != null) { writer.WriteUInt32(stmg); writer.WriteInt32(ME2STMGFallback.Length); writer.WriteFromBuffer(ME2STMGFallback); } if (sc.Game == MEGame.ME3 && InitStateManagement != null) { writer.WriteUInt32(stmg); var lenPos = sc.ms.Position; writer.WriteUInt32(0); writer.WriteFloat(InitStateManagement.VolumeThreshold); writer.WriteUInt16(InitStateManagement.MaxVoiceInstances); writer.WriteInt32(InitStateManagement.StateGroups.Count); foreach ((uint _, WwiseStateManagement.StateGroup stateGroup) in InitStateManagement.StateGroups) { writer.WriteUInt32(stateGroup.ID); writer.WriteUInt32(stateGroup.DefaultTransitionTime); writer.WriteInt32(stateGroup.CustomTransitionTimes.Count); foreach (var transTime in stateGroup.CustomTransitionTimes) { writer.WriteUInt32(transTime.FromStateID); writer.WriteUInt32(transTime.ToStateID); writer.WriteUInt32(transTime.TransitionTime); } } writer.WriteInt32(InitStateManagement.SwitchGroups.Count); foreach ((uint _, WwiseStateManagement.SwitchGroup switchGroup) in InitStateManagement.SwitchGroups) { writer.WriteUInt32(switchGroup.ID); writer.WriteUInt32(switchGroup.GameParamID); writer.WriteInt32(switchGroup.Points.Count); foreach (var point in switchGroup.Points) { writer.WriteFloat(point.GameParamValue); writer.WriteUInt32(point.SwitchID); writer.WriteUInt32(point.CurveShape); } } writer.WriteInt32(InitStateManagement.GameParameterDefaultValues.Count); foreach ((uint id, float defaultValue) in InitStateManagement.GameParameterDefaultValues) { writer.WriteUInt32(id); writer.WriteFloat(defaultValue); } var endPos = sc.ms.Position; sc.ms.JumpTo(lenPos); writer.WriteInt32((int)(endPos - lenPos - 4)); sc.ms.JumpTo(endPos); } if (HIRCObjects.Count > 0) { writer.WriteUInt32(hirc); var lengthPos = sc.ms.Position; writer.WriteUInt32(0); writer.WriteInt32(HIRCObjects.Count); foreach ((uint _, HIRCObject h) in HIRCObjects) { writer.WriteFromBuffer(h.ToBytes(sc.Game)); } var endPos = sc.ms.Position; sc.ms.JumpTo(lengthPos); writer.WriteInt32((int)(endPos - lengthPos - 4)); sc.ms.JumpTo(endPos); } if (ReferencedBanks.Count > 0) { writer.WriteUInt32(stid); var lengthPos = sc.ms.Position; writer.WriteUInt32(0); writer.WriteUInt32(1); writer.WriteInt32(ReferencedBanks.Count); foreach ((uint id, string name) in ReferencedBanks) { writer.WriteUInt32(id); writer.WriteByte((byte)name.Length); writer.WriteStringASCII(name); } var endPos = sc.ms.Position; sc.ms.JumpTo(lengthPos); writer.WriteInt32((int)(endPos - lengthPos - 4)); sc.ms.JumpTo(endPos); } if (FXPR_Chunk != null) { writer.WriteUInt32(fxpr); writer.WriteInt32(FXPR_Chunk.Length); writer.WriteFromBuffer(FXPR_Chunk); } if (ENVS_Chunk != null) { writer.WriteUInt32(envs); writer.WriteInt32(ENVS_Chunk.Length); writer.WriteFromBuffer(ENVS_Chunk); } }
public override uint Write(EndianWriter writer, uint imageBase, bool DX, Dictionary <string, uint> labels) { VertexSet[] sets = VertexData.Values.ToArray(); uint[] vtxAddresses = new uint[VertexData.Count]; for (int i = 0; i < sets.Length; i++) { VertexSet vtxSet = sets[i]; vtxAddresses[i] = writer.Position + imageBase; IOType outputType = vtxSet.DataType.ToStructType(); switch (vtxSet.Attribute) { case VertexAttribute.Position: case VertexAttribute.Normal: foreach (Vector3 vec in vtxSet.Vector3Data) { vec.Write(writer, outputType); } break; case VertexAttribute.Color0: case VertexAttribute.Color1: foreach (Color col in vtxSet.ColorData) { col.Write(writer, outputType); } break; case VertexAttribute.Tex0: case VertexAttribute.Tex1: case VertexAttribute.Tex2: case VertexAttribute.Tex3: case VertexAttribute.Tex4: case VertexAttribute.Tex5: case VertexAttribute.Tex6: case VertexAttribute.Tex7: foreach (Vector2 uv in vtxSet.UVData) { (uv * 256).Write(writer, outputType); } break; case VertexAttribute.PositionMatrixId: case VertexAttribute.Null: default: throw new FormatException($"Vertex set had an invalid or unavailable type: {vtxSet.Attribute}"); } } uint vtxAddr = writer.Position + imageBase; // writing vertex attributes for (int i = 0; i < sets.Length; i++) { VertexSet vtxSet = sets[i]; writer.Write(new byte[] { (byte)vtxSet.Attribute, (byte)vtxSet.StructSize }); writer.WriteUInt16((ushort)vtxSet.DataLength); uint structure = (uint)vtxSet.StructType; structure |= (uint)((byte)vtxSet.DataType << 4); writer.WriteUInt32(structure); writer.WriteUInt32(vtxAddresses[i]); writer.WriteUInt32((uint)(vtxSet.DataLength * vtxSet.StructSize)); } // empty vtx attribute byte[] nullVtx = new byte[16]; nullVtx[0] = 0xFF; writer.Write(nullVtx); // writing geometry data uint[] WriteMeshData(Mesh[] meshes) { uint[] result = new uint[meshes.Length * 4]; IndexAttributes indexAttribs = IndexAttributes.HasPosition; for (int i = 0, ri = 0; i < meshes.Length; i++, ri += 4) { Mesh m = meshes[i]; IndexAttributes?t = m.IndexAttributes; if (t.HasValue) { indexAttribs = t.Value; } // writing parameters result[ri] = writer.Position + imageBase; result[ri + 1] = (uint)m.Parameters.Length; foreach (IParameter p in m.Parameters) { p.Write(writer); } // writing polygons uint addr = writer.Position; foreach (Poly p in m.Polys) { p.Write(writer, indexAttribs); } result[ri + 2] = addr + imageBase; result[ri + 3] = writer.Position - addr; } return(result); } uint[] opaqueMeshStructs = WriteMeshData(OpaqueMeshes); uint[] transparentMeshStructs = WriteMeshData(TransparentMeshes); // writing geometry properties uint opaqueAddress = writer.Position + imageBase; foreach (uint i in opaqueMeshStructs) { writer.Write(i); } uint transparentAddress = writer.Position + imageBase; foreach (uint i in transparentMeshStructs) { writer.Write(i); } uint address = writer.Position + imageBase; labels.AddLabel(Name, address); writer.WriteUInt32(vtxAddr); writer.WriteUInt32(0); writer.WriteUInt32(opaqueAddress); writer.WriteUInt32(transparentAddress); writer.WriteUInt16((ushort)OpaqueMeshes.Length); writer.WriteUInt16((ushort)TransparentMeshes.Length); MeshBounds.Write(writer); return(address); }
public override uint Write(EndianWriter writer, uint imageBase, bool DX, Dictionary <string, uint> labels) { // writing positions uint posAddress; if (labels.ContainsKey(PositionName)) { posAddress = labels[PositionName]; } else { posAddress = writer.Position + imageBase; labels.AddLabel(PositionName, posAddress); foreach (Vector3 p in Positions) { p.Write(writer, IOType.Float); } } // writing normals uint nrmAddress = 0; if (Normals != null) { if (labels.ContainsKey(NormalName)) { nrmAddress = labels[NormalName]; } else { nrmAddress = writer.Position + imageBase; labels.AddLabel(NormalName, nrmAddress); foreach (Vector3 p in Normals) { p.Write(writer, IOType.Float); } } } // writing meshsets uint meshAddress; if (labels.ContainsKey(MeshName)) { meshAddress = labels[MeshName]; } else { // writing meshset data foreach (Mesh m in Meshes) { m.WriteData(writer, imageBase, labels); } meshAddress = writer.Position + imageBase; labels.AddLabel(MeshName, meshAddress); foreach (Mesh m in Meshes) { m.WriteMeshset(writer, DX, labels); } } // writing materials uint materialAddress; if (labels.ContainsKey(MaterialName)) { materialAddress = labels[MaterialName]; } else { materialAddress = writer.Position + imageBase; labels.AddLabel(MaterialName, materialAddress); foreach (Material m in Materials) { m.Write(writer); } } // writing the attach uint outAddress = writer.Position + imageBase; labels.AddLabel(Name, outAddress); writer.WriteUInt32(posAddress); writer.WriteUInt32(nrmAddress); writer.WriteUInt32((uint)Positions.Length); writer.WriteUInt32(meshAddress); writer.WriteUInt32(materialAddress); writer.WriteUInt16((ushort)Meshes.Length); writer.WriteUInt16((ushort)Materials.Length); MeshBounds.Write(writer); if (DX) { writer.WriteUInt32(0); } return(outAddress); }
/// <summary> /// Writes the landtable to a stream /// </summary> /// <param name="writer">Output stream</param> /// <param name="imageBase">Image base for all addresses</param> /// <param name="labels">C struct labels</param> /// <returns></returns> public uint Write(EndianWriter writer, uint imageBase, Dictionary <string, uint> labels) { // sort the landentries HashSet <Attach> attaches = new(); ushort visCount = 0; if (Format > LandtableFormat.SADX && Format != LandtableFormat.Buffer) { List <LandEntry> visual = new(); List <LandEntry> basic = new(); foreach (LandEntry le in Geometry) { if (le.Attach.Format == AttachFormat.BASIC) { basic.Add(le); } else { visual.Add(le); } attaches.Add(le.Attach); } Geometry.Clear(); Geometry.AddRange(visual); Geometry.AddRange(basic); visCount = (ushort)visual.Count; } else { foreach (LandEntry le in Geometry) { attaches.Add(le.Attach); } } foreach (LandEntryMotion lem in GeometryAnimations) { NJObject[] models = lem.Model.GetObjects(); foreach (NJObject mdl in models) { if (mdl.Attach != null) { attaches.Add(mdl.Attach); } } } // writing all attaches if (Format == LandtableFormat.Buffer) { foreach (var atc in attaches) { atc.WriteBuffer(writer, imageBase, labels); } } else { foreach (var atc in attaches) { atc.Write(writer, imageBase, false, labels); } } var t = labels.GroupBy(x => x.Value).Where(x => x.Count() > 1).ToList(); // write the landentry models foreach (LandEntry le in Geometry) { le.WriteModel(writer, imageBase, labels); } // write the landentry motion models foreach (LandEntryMotion lem in GeometryAnimations) { lem.Model.Write(writer, imageBase, labels); } Dictionary <Action, uint> actionAddresses = new(); // write the landentry motion animations foreach (LandEntryMotion lem in GeometryAnimations) { actionAddresses.Add(lem.MotionAction, lem.MotionAction.Write(writer, imageBase, Format == LandtableFormat.SADX, Format == LandtableFormat.Buffer, labels)); } // writing the geometry list uint geomAddr = 0; if (Geometry.Count > 0) { if (labels.ContainsKey(GeoName)) { geomAddr = labels[GeoName]; } else { geomAddr = writer.Position + imageBase; labels.AddLabel(GeoName, geomAddr); foreach (LandEntry le in Geometry) { le.Write(writer, Format, labels); } } } // writing the animation list uint animAddr = 0; if (GeometryAnimations.Count > 0) { if (labels.ContainsKey(GeoAnimName)) { animAddr = labels[GeoAnimName]; } else { animAddr = writer.Position + imageBase; labels.AddLabel(GeoAnimName, animAddr); foreach (LandEntryMotion lem in GeometryAnimations) { lem.Write(writer, actionAddresses, labels); } } } // write the texture name uint texNameAddr = 0; if (TextureFileName != null) { texNameAddr = writer.Position + imageBase; writer.Write(Encoding.ASCII.GetBytes(TextureFileName)); writer.Write(new byte[1]); } // write the landtable struct itself uint address = writer.Position + imageBase; writer.WriteUInt16((ushort)Geometry.Count); if (Format < LandtableFormat.SA2) // sa1 + sadx { writer.WriteUInt16((ushort)GeometryAnimations.Count); writer.WriteUInt32((uint)Attributes); writer.WriteSingle(DrawDistance); writer.WriteUInt32(geomAddr); writer.WriteUInt32(animAddr); writer.WriteUInt32(texNameAddr); writer.WriteUInt32(TexListPtr); writer.WriteUInt64(0); // two unused pointers } else // sa2 + sa2b { writer.WriteUInt16(visCount); writer.WriteUInt64(0); // todo: figure out what these do writer.WriteSingle(DrawDistance); writer.WriteUInt32(geomAddr); writer.WriteUInt32(animAddr); writer.WriteUInt32(texNameAddr); writer.WriteUInt32(TexListPtr); } labels.AddLabel(Name, address); return(address); }
public void Write(EndianWriter writer) { writer.WriteUInt16((ushort)((Indices.Length & 0x7FFF) | (Reversed ? 0x8000 : 0))); this.DefaultWrite(writer); }