public override void StreamWriteData(BinaryWriter outstream) { outstream.Write(this.vert_count); outstream.Write(Headers.Count); foreach (GeometryHeader head in this.Headers) { outstream.Write(head.ItemSize); outstream.Write((uint)head.ItemType); } List <Vector3> verts = this.verts; int vert_pos = 0; List <Vector3> normals = this.normals.ToList(); int norm_pos = 0; List <GeometryWeightGroups> unknown_15s = this.weight_groups; int unknown_15s_pos = 0; List <Vector3> binormals = this.binormals; int binormals_pos = 0; List <Vector3> tangents = this.tangents; int tangents_pos = 0; List <byte[]> unknown_data = this.unknown_item_data; int unknown_data_pos = 0; foreach (GeometryHeader head in this.Headers) { if (head.ItemType == GeometryChannelTypes.POSITION) { for (int x = 0; x < this.vert_count; x++) { Vector3 vert = verts[vert_pos]; outstream.Write(vert.X); outstream.Write(vert.Y); outstream.Write(vert.Z); vert_pos++; } } else if (head.ItemType == GeometryChannelTypes.NORMAL) { for (int x = 0; x < this.vert_count; x++) { Vector3 norm = normals[norm_pos]; outstream.Write(norm.X); outstream.Write(norm.Y); outstream.Write(norm.Z); norm_pos++; } } else if (head.ItemType == GeometryChannelTypes.COLOR) { for (int x = 0; x < this.vert_count; x++) { this.vertex_colors[x].StreamWrite(outstream); } } else if (head.ItemType == GeometryChannelTypes.BINORMAL) { for (int x = 0; x < this.vert_count; x++) { if (this.binormals.Count != this.vert_count) { outstream.Write(0.0f); outstream.Write(0.0f); outstream.Write(0.0f); } else { Vector3 binormal_entry = binormals[x]; outstream.Write(binormal_entry.X); outstream.Write(binormal_entry.Y); outstream.Write(binormal_entry.Z); binormals_pos++; } } } else if (head.ItemType == GeometryChannelTypes.TANGENT) { for (int x = 0; x < this.vert_count; x++) { if (this.tangents.Count != this.vert_count) { outstream.Write(0.0f); outstream.Write(0.0f); outstream.Write(0.0f); } else { Vector3 tangent_entry = tangents[x]; outstream.Write(tangent_entry.X); outstream.Write(tangent_entry.Y); outstream.Write(tangent_entry.Z); tangents_pos++; } } } else if (head.ItemType == GeometryChannelTypes.BLENDINDICES) { for (int x = 0; x < this.vert_count; x++) { if (this.weight_groups.Count != this.vert_count) { outstream.Write(0.0f); outstream.Write(0.0f); } else { GeometryWeightGroups unknown_15_entry = unknown_15s[x]; unknown_15_entry.StreamWrite(outstream); unknown_15s_pos++; } } } else if (head.ItemType == GeometryChannelTypes.BLENDWEIGHT) { if (head.ItemSize == 4) { Log.Default.Warn("Section {0} has four weights", this.HashName.String); } for (int x = 0; x < this.vert_count; x++) { Vector3 weight = this.weights.Count != this.vert_count ? Vector3.UnitX : weights[x]; outstream.Write(weight.X); outstream.Write(weight.Y); if (head.ItemSize == 3) { outstream.Write(weight.Z); } else if (head.ItemSize == 4) { outstream.Write(weight.Z); outstream.Write(0.0f); } else if (head.ItemSize != 2) { throw new Exception("Cannot write bad header BLENDWEIGHT s=" + head.ItemSize); } } } else if (head.ItemType >= GeometryChannelTypes.TEXCOORD0 && head.ItemType <= GeometryChannelTypes.TEXCOORD7) { int idx = head.ItemType - GeometryChannelTypes.TEXCOORD0; for (int x = 0; x < this.vert_count; x++) { Vector2 uv = UVs[idx][x]; outstream.Write(uv.X); outstream.Write(-uv.Y); } } else { outstream.Write(unknown_data[unknown_data_pos]); unknown_data_pos++; } } outstream.Write(this.HashName.Hash); if (this.remaining_data != null) { outstream.Write(this.remaining_data); } }
public Geometry(BinaryReader instream, SectionHeader section) : this() { this.SectionId = section.id; // Count of everysingle item in headers (Verts, Normals, UVs, UVs for normalmap, Colors, Unknown 20, Unknown 21, etc) this.vert_count = instream.ReadUInt32(); //Count of all headers for items in this section uint header_count = instream.ReadUInt32(); UInt32 calc_size = 0; for (int x = 0; x < header_count; x++) { GeometryHeader header = new GeometryHeader(); header.ItemSize = instream.ReadUInt32(); header.ItemType = (GeometryChannelTypes)instream.ReadUInt32(); calc_size += header.ItemSizeBytes; this.Headers.Add(header); } foreach (GeometryHeader head in this.Headers) { //Console.WriteLine("Header type: " + head.item_type + " Size: " + head.item_size); if (head.ItemType == GeometryChannelTypes.POSITION) { verts.Capacity = (int)vert_count + 1; for (int x = 0; x < this.vert_count; x++) { Vector3 vert = new Vector3(); vert.X = instream.ReadSingle(); vert.Y = instream.ReadSingle(); vert.Z = instream.ReadSingle(); this.verts.Add(vert); } } else if (head.ItemType == GeometryChannelTypes.NORMAL) { normals.Capacity = (int)vert_count + 1; for (int x = 0; x < this.vert_count; x++) { Vector3 norm = new Vector3(); norm.X = instream.ReadSingle(); norm.Y = instream.ReadSingle(); norm.Z = instream.ReadSingle(); this.normals.Add(norm); } } else if (head.ItemType == GeometryChannelTypes.COLOR0) { vertex_colors.Capacity = (int)vert_count + 1; for (int x = 0; x < this.vert_count; x++) { this.vertex_colors.Add(new GeometryColor(instream)); } } //Below is unknown data else if (head.ItemType == GeometryChannelTypes.BINORMAL0) { binormals.Capacity = (int)vert_count + 1; for (int x = 0; x < this.vert_count; x++) { Vector3 binormal_entry = new Vector3(); binormal_entry.X = instream.ReadSingle(); binormal_entry.Y = instream.ReadSingle(); binormal_entry.Z = instream.ReadSingle(); this.binormals.Add(binormal_entry); } } else if (head.ItemType == GeometryChannelTypes.TANGENT0) { tangents.Capacity = (int)vert_count + 1; for (int x = 0; x < this.vert_count; x++) { Vector3 tangent_entry = new Vector3(); tangent_entry.X = instream.ReadSingle(); tangent_entry.Y = instream.ReadSingle(); tangent_entry.Z = instream.ReadSingle(); this.tangents.Add(tangent_entry); } } //Weight Groups else if (head.ItemType == GeometryChannelTypes.BLENDINDICES0) { weight_groups.Capacity = (int)vert_count + 1; for (int x = 0; x < this.vert_count; x++) { GeometryWeightGroups unknown_15_entry = new GeometryWeightGroups(instream); this.weight_groups.Add(unknown_15_entry); } } //Weights else if (head.ItemType == GeometryChannelTypes.BLENDWEIGHT0) { if (head.ItemSize == 4) { Log.Default.Warn("Section {0} has four weights", this.SectionId); } weights.Capacity = (int)vert_count + 1; for (int x = 0; x < this.vert_count; x++) { Vector3 unknown_17_entry = new Vector3(); unknown_17_entry.X = instream.ReadSingle(); unknown_17_entry.Y = instream.ReadSingle(); if (head.ItemSize == 3) { unknown_17_entry.Z = instream.ReadSingle(); } else if (head.ItemSize == 4) { unknown_17_entry.Z = instream.ReadSingle(); var tmp = instream.ReadSingle(); if (tmp != 0) { Log.Default.Warn("Nonzero fourth weight in {0} vtx {1} (is {2})", this.SectionId, x, tmp); } } else if (head.ItemSize != 2) { throw new Exception("Bad BLENDWEIGHT0 item size " + head.ItemSize); } this.weights.Add(unknown_17_entry); } } else if (head.ItemType >= GeometryChannelTypes.TEXCOORD0 && head.ItemType <= GeometryChannelTypes.TEXCOORD7) { int idx = head.ItemType - GeometryChannelTypes.TEXCOORD0; for (int x = 0; x < vert_count; x++) { // Previously, the Y was only inverted on the TEXCOORD0 channel, and // not on the TEXCOORD1 channel. I assume that was incorrect, TODO check? Vector2 uv = new Vector2 { X = instream.ReadSingle(), Y = -instream.ReadSingle() }; UVs[idx].Add(uv); } } else { this.unknown_item_data.Add( instream.ReadBytes((int)(head.ItemSizeBytes * this.vert_count))); } } this.HashName = new HashName(instream.ReadUInt64()); this.remaining_data = null; long sect_end = section.offset + 12 + section.size; if (sect_end > instream.BaseStream.Position) { // If exists, this contains hashed name for this geometry (see hashlist.txt) remaining_data = instream.ReadBytes((int)(sect_end - instream.BaseStream.Position)); } }