public GCAttach(byte[] file, int address, uint imageBase, Dictionary <int, string> labels) { if (labels.ContainsKey(address)) { Name = labels[address]; } else { Name = "attach_" + address.ToString("X8"); } // The struct is 36/0x24 bytes long. VertexData = new VertexData(); GeometryData = new GeometryData(); uint vertex_attribute_offset = ByteConverter.ToUInt32(file, address) - imageBase; int unknown_1 = ByteConverter.ToInt32(file, address + 4); int opaque_geometry_data_offset = (int)(ByteConverter.ToInt32(file, address + 8) - imageBase); int translucent_geometry_data_offset = (int)(ByteConverter.ToInt32(file, address + 12) - imageBase); int opaque_geometry_count = ByteConverter.ToInt16(file, address + 16); int translucent_geometry_count = ByteConverter.ToInt16(file, address + 18); Bounds = new BoundingSphere(file, address + 20); VertexData.Load(file, vertex_attribute_offset, imageBase); if (opaque_geometry_count > 0) { GeometryData.Load(file, opaque_geometry_data_offset, imageBase, opaque_geometry_count, GeometryType.Opaque); } if (translucent_geometry_count > 0) { GeometryData.Load(file, translucent_geometry_data_offset, imageBase, translucent_geometry_count, GeometryType.Translucent); } }
public void ExportOBJ(string file_name) { StringWriter writer = new StringWriter(); if (VertexData.CheckAttribute(GXVertexAttribute.Position)) { for (int i = 0; i < VertexData.Positions.Count; i++) { Vector3 pos = VertexData.Positions[i]; writer.WriteLine($"v {pos.X} {pos.Y} {pos.Z}"); } } if (VertexData.CheckAttribute(GXVertexAttribute.Normal)) { for (int i = 0; i < VertexData.Normals.Count; i++) { Vector3 nrm = VertexData.Normals[i]; writer.WriteLine($"vn {nrm.X} {nrm.Y} {nrm.Z}"); } } if (VertexData.CheckAttribute(GXVertexAttribute.Tex0)) { for (int i = 0; i < VertexData.TexCoord_0.Count; i++) { Vector2 tex = VertexData.TexCoord_0[i]; writer.WriteLine($"vt {tex.X} {tex.Y}"); } } int mesh_index = 0; foreach (Mesh m in GeometryData.OpaqueMeshes) { writer.WriteLine($"o mesh_{ mesh_index++ }"); foreach (Primitive p in m.Primitives) { List <Vertex> triangles = p.ToTriangles(); if (triangles == null) { continue; } for (int i = 0; i < triangles.Count; i += 3) { int pos_1 = (int)triangles[i].PositionIndex; int pos_2 = (int)triangles[i + 1].PositionIndex; int pos_3 = (int)triangles[i + 2].PositionIndex; string empty = ""; int tex_1 = 0; int tex_2 = 0; int tex_3 = 0; int nrm_1 = 0; int nrm_2 = 0; int nrm_3 = 0; bool has_tex = VertexData.TexCoord_0.Count > 0; bool has_nrm = VertexData.Normals.Count > 0; if (has_tex) { tex_1 = (int)triangles[i].UVIndex; tex_2 = (int)triangles[i + 1].UVIndex; tex_3 = (int)triangles[i + 2].UVIndex; } if (has_nrm) { nrm_1 = (int)triangles[i].NormalIndex; nrm_2 = (int)triangles[i + 1].NormalIndex; nrm_3 = (int)triangles[i + 2].NormalIndex; } string v1 = $"{pos_1 + 1}{(has_tex ? "/" + tex_1.ToString() : empty) }{(!has_tex ? "/" : empty) + (has_nrm ? "/" + nrm_1.ToString() : empty)}"; string v2 = $"{pos_2 + 1}{(has_tex ? "/" + tex_2.ToString() : empty) }{(!has_tex ? "/" : empty) + (has_nrm ? "/" + nrm_2.ToString() : empty)}"; string v3 = $"{pos_3 + 1}{(has_tex ? "/" + tex_3.ToString() : empty) }{(!has_tex ? "/" : empty) + (has_nrm ? "/" + nrm_3.ToString() : empty)}"; writer.WriteLine($"f { v1 } { v2 } { v3 }"); } } } foreach (Mesh m in GeometryData.TranslucentMeshes) { foreach (Primitive p in m.Primitives) { List <Vertex> triangles = p.ToTriangles(); if (triangles == null) { continue; } for (int i = 0; i < triangles.Count; i += 3) { int pos_1 = (int)triangles[i].PositionIndex; int pos_2 = (int)triangles[i + 1].PositionIndex; int pos_3 = (int)triangles[i + 2].PositionIndex; writer.WriteLine($"f {pos_1 + 1} {pos_2 + 1} {pos_3 + 1}"); } } } File.WriteAllText(file_name, writer.ToString()); }