public Shape() { MatrixGroups = new List <MatrixGroup>(); VertexDescription = new VertexDescription(); ShapeMaterial = null; VertexData = new MeshVertexHolder(); Indices = new List <int>(); }
public Shape() { Attributes = new List <ShapeVertexAttribute>(); VertexData = new MeshVertexHolder(); Indexes = new List <int>(); VertexDescription = new VertexDescription(); MatrixDataTable = new List <SkinDataTable>(); OverrideVertPos = new List <Vector3>(); OverrideNormals = new List <Vector3>(); m_glBufferIndexes = new int[15]; for (int i = 0; i < m_glBufferIndexes.Length; i++) { m_glBufferIndexes[i] = -1; } m_glIndexBuffer = GL.GenBuffer(); }
public void ReadSHP1FromStream(EndianBinaryReader reader, long tagStart, MeshVertexHolder compressedVertexData) { ShapeCount = reader.ReadInt16(); Trace.Assert(reader.ReadUInt16() == 0xFFFF); // Padding int shapeOffset = reader.ReadInt32(); // Another index remap table. int remapTableOffset = reader.ReadInt32(); Trace.Assert(reader.ReadInt32() == 0); int attributeOffset = reader.ReadInt32(); // Offset to the Matrix Table which holds a list of ushorts used for ?? int matrixTableOffset = reader.ReadInt32(); // Offset to the array of primitive's data. int primitiveDataOffset = reader.ReadInt32(); int matrixDataOffset = reader.ReadInt32(); int packetLocationOffset = reader.ReadInt32(); reader.BaseStream.Position = tagStart + remapTableOffset; ShapeRemapTable = new List <short>(); for (int i = 0; i < ShapeCount; i++) { ShapeRemapTable.Add(reader.ReadInt16()); } for (int s = 0; s < ShapeCount; s++) { // Shapes can have different attributes for each shape. (ie: Some have only Position, while others have Pos & TexCoord, etc.) Each // shape (which has a consistent number of attributes) it is split into individual packets, which are a collection of geometric primitives. // Each packet can have individual unique skinning data. reader.BaseStream.Position = tagStart + shapeOffset + (0x28 * s) /* 0x28 is the size of one Shape entry*/; long shapeStart = reader.BaseStream.Position; Shape shape = new Shape(); shape.MatrixType = reader.ReadByte(); Trace.Assert(reader.ReadByte() == 0xFF); // Padding // Number of Packets (of data) contained in this Shape ushort packetCount = reader.ReadUInt16(); // Offset from the start of the Attribute List to the attributes this particular batch uses. ushort batchAttributeOffset = reader.ReadUInt16(); ushort firstMatrixIndex = reader.ReadUInt16(); ushort firstPacketIndex = reader.ReadUInt16(); Trace.Assert(reader.ReadUInt16() == 0xFFFF); // Padding float boundingSphereDiameter = reader.ReadSingle(); Vector3 bboxMin = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); Vector3 bboxMax = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); // Determine which Attributes this particular shape uses. reader.BaseStream.Position = tagStart + attributeOffset + batchAttributeOffset; List <ShapeVertexAttribute> attributes = new List <ShapeVertexAttribute>(); do { ShapeVertexAttribute attribute = new ShapeVertexAttribute((VertexArrayType)reader.ReadInt32(), (VertexDataType)reader.ReadInt32()); if (attribute.ArrayType == VertexArrayType.NullAttr) { break; } attributes.Add(attribute); } while (true); shape.BoundingSphereDiameter = boundingSphereDiameter; shape.BoundingBox = new FAABox(bboxMin, bboxMax); shape.Attributes = attributes; Shapes.Add(shape); int numVertexRead = 0; for (ushort p = 0; p < packetCount; p++) { // The packets are all stored linearly and then they point to the specific size and offset of the data for this particular packet. reader.BaseStream.Position = tagStart + packetLocationOffset + ((firstPacketIndex + p) * 0x8); /* 0x8 is the size of one Packet entry */ int packetSize = reader.ReadInt32(); int packetOffset = reader.ReadInt32(); // Read Matrix Data for Packet reader.BaseStream.Position = tagStart + matrixDataOffset + (firstMatrixIndex + p) * 0x08; /* 0x8 is the size of one Matrix Data */ ushort matrixUnknown0 = reader.ReadUInt16(); ushort matrixCount = reader.ReadUInt16(); uint matrixFirstIndex = reader.ReadUInt32(); Shape.SkinDataTable matrixData = new Shape.SkinDataTable(matrixUnknown0); shape.MatrixDataTable.Add(matrixData); matrixData.FirstRelevantVertexIndex = shape.VertexData.Position.Count; // Read Matrix Table data. The Matrix Table is skinning information for the packet which indexes into the DRW1 section for more info. reader.BaseStream.Position = tagStart + matrixTableOffset + (matrixFirstIndex * 0x2); /* 0x2 is the size of one Matrix Table entry */ for (int m = 0; m < matrixCount; m++) { matrixData.MatrixTable.Add(reader.ReadUInt16()); } // Read the Primitive Data reader.BaseStream.Position = tagStart + primitiveDataOffset + packetOffset; uint numPrimitiveBytesRead = 0; while (numPrimitiveBytesRead < packetSize) { // The game pads the chunk out with zeros, so if there's a primitive with type zero (invalid) then we early out of the loop. GXPrimitiveType type = (GXPrimitiveType)reader.ReadByte(); if (type == 0 || numPrimitiveBytesRead >= packetSize) { break; } // The number of vertices this primitive has indexes for ushort vertexCount = reader.ReadUInt16(); numPrimitiveBytesRead += 0x3; // 2 bytes for vertex count, one byte for GXPrimitiveType. List <MeshVertexIndex> primitiveVertices = new List <MeshVertexIndex>(); for (int v = 0; v < vertexCount; v++) { MeshVertexIndex newVert = new MeshVertexIndex(); primitiveVertices.Add(newVert); // Each vertex has an index for each ShapeAttribute specified by the Shape that we belong to. So we'll loop through // each index and load it appropriately (as vertices can have different data sizes). foreach (ShapeVertexAttribute curAttribute in attributes) { int index = 0; uint numBytesRead = 0; switch (curAttribute.DataType) { case VertexDataType.Unsigned8: case VertexDataType.Signed8: index = reader.ReadByte(); numBytesRead = 1; break; case VertexDataType.Unsigned16: case VertexDataType.Signed16: index = reader.ReadUInt16(); numBytesRead = 2; break; case VertexDataType.Float32: case VertexDataType.None: default: System.Console.WriteLine("Unknown Data Type {0} for ShapeAttribute!", curAttribute.DataType); break; } // We now have the index into the datatype this array points to. We can now inspect the array type of the // attribute to get the value out of the correct source array. switch (curAttribute.ArrayType) { case VertexArrayType.Position: newVert.Position = index; break; case VertexArrayType.PositionMatrixIndex: newVert.PosMtxIndex = index; break; case VertexArrayType.Normal: newVert.Normal = index; break; case VertexArrayType.Color0: newVert.Color0 = index; break; case VertexArrayType.Color1: newVert.Color1 = index; break; case VertexArrayType.Tex0: newVert.Tex0 = index; break; case VertexArrayType.Tex1: newVert.Tex1 = index; break; case VertexArrayType.Tex2: newVert.Tex2 = index; break; case VertexArrayType.Tex3: newVert.Tex3 = index; break; case VertexArrayType.Tex4: newVert.Tex4 = index; break; case VertexArrayType.Tex5: newVert.Tex5 = index; break; case VertexArrayType.Tex6: newVert.Tex6 = index; break; case VertexArrayType.Tex7: newVert.Tex7 = index; break; default: System.Console.WriteLine("Unsupported ArrayType {0} for ShapeAttribute!", curAttribute.ArrayType); break; } numPrimitiveBytesRead += numBytesRead; } } // All vertices have now been loaded into the primitiveIndexes array. We can now convert them if needed // to triangle lists, instead of triangle fans, strips, etc. var triangleList = ConvertTopologyToTriangles(type, primitiveVertices); for (int i = 0; i < triangleList.Count; i++) { shape.Indexes.Add(numVertexRead); numVertexRead++; var tri = triangleList[i]; if (tri.Position >= 0) { shape.VertexData.Position.Add(compressedVertexData.Position[tri.Position]); } if (tri.Normal >= 0) { shape.VertexData.Normal.Add(compressedVertexData.Normal[tri.Normal]); } if (tri.Binormal >= 0) { shape.VertexData.Binormal.Add(compressedVertexData.Binormal[tri.Binormal]); } if (tri.Color0 >= 0) { shape.VertexData.Color0.Add(compressedVertexData.Color0[tri.Color0]); } if (tri.Color1 >= 0) { shape.VertexData.Color1.Add(compressedVertexData.Color1[tri.Color1]); } if (tri.Tex0 >= 0) { shape.VertexData.Tex0.Add(compressedVertexData.Tex0[tri.Tex0]); } if (tri.Tex1 >= 0) { shape.VertexData.Tex1.Add(compressedVertexData.Tex1[tri.Tex1]); } if (tri.Tex2 >= 0) { shape.VertexData.Tex2.Add(compressedVertexData.Tex2[tri.Tex2]); } if (tri.Tex3 >= 0) { shape.VertexData.Tex3.Add(compressedVertexData.Tex3[tri.Tex3]); } if (tri.Tex4 >= 0) { shape.VertexData.Tex4.Add(compressedVertexData.Tex4[tri.Tex4]); } if (tri.Tex5 >= 0) { shape.VertexData.Tex5.Add(compressedVertexData.Tex5[tri.Tex5]); } if (tri.Tex6 >= 0) { shape.VertexData.Tex6.Add(compressedVertexData.Tex6[tri.Tex6]); } if (tri.Tex7 >= 0) { shape.VertexData.Tex7.Add(compressedVertexData.Tex7[tri.Tex7]); } // We pre-divide the index here just to make life simpler. For some reason the index is multiplied by three // and it's not entirely clear why. Might be related to doing skinning on the GPU and offsetting the correct // number of floats in a matrix? if (tri.PosMtxIndex >= 0) { shape.VertexData.PositionMatrixIndexes.Add(tri.PosMtxIndex / 3); } else { shape.VertexData.PositionMatrixIndexes.Add(0); } } } // Set the last relevant vertex for this packet. matrixData.LastRelevantVertexIndex = shape.VertexData.Position.Count; } shape.UploadBuffersToGPU(false); } }
public void LoadVTX1FromStream(EndianBinaryReader reader, long chunkStart, int chunkSize) { int vertexFormatOffset = reader.ReadInt32(); int[] vertexDataOffsets = new int[13]; for (int i = 0; i < 13; i++) { vertexDataOffsets[i] = reader.ReadInt32(); } reader.BaseStream.Position = chunkStart + vertexFormatOffset; VertexFormats = new List <VertexFormat>(); VertexFormat curFormat = null; do { curFormat = new VertexFormat(); curFormat.ArrayType = (VertexArrayType)reader.ReadInt32(); curFormat.ComponentCount = reader.ReadInt32(); curFormat.DataType = (VertexDataType)reader.ReadInt32(); curFormat.ColorDataType = (VertexColorType)curFormat.DataType; curFormat.DecimalPoint = reader.ReadByte(); reader.ReadBytes(3); // Padding VertexFormats.Add(curFormat); }while (curFormat.ArrayType != VertexArrayType.NullAttr); // Remove the last one because it simply the NullAttr that defines the end of the list. VertexFormats.RemoveAt(VertexFormats.Count - 1); VertexData = new MeshVertexHolder(); // Retrieve the data from the 13 possible types of data using the above VertexFormats as a guide to the data. for (int k = 0; k < vertexDataOffsets.Length; k++) { // If this data isn't included in the file, it'll list zero as its offset. if (vertexDataOffsets[k] == 0) { continue; } // Get the total length of this block of data. This is used to try and automate a lot of the data loading. int totalLength = GetVertexDataLength(vertexDataOffsets, k, chunkSize); reader.BaseStream.Position = chunkStart + vertexDataOffsets[k]; VertexFormat vertexFormat = null; switch (k) { // Position Data case 0: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Position); VertexData.Position = LoadVertexAttribute <Vector3>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Position, vertexFormat.DataType, VertexColorType.None); break; // Normal Data case 1: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Normal); VertexData.Normal = LoadVertexAttribute <Vector3>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Normal, vertexFormat.DataType, VertexColorType.None); break; // Normal Binormal Tangent Data (presumed) case 2: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.NormalBinormalTangent); VertexData.Binormal = LoadVertexAttribute <Vector3>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.NormalBinormalTangent, vertexFormat.DataType, VertexColorType.None); break; // Color 0 Data case 3: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Color0); VertexData.Color0 = LoadVertexAttribute <WLinearColor>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Color0, VertexDataType.None, vertexFormat.ColorDataType); break; // Color 1 Data (presumed) case 4: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Color1); VertexData.Color1 = LoadVertexAttribute <WLinearColor>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Color1, VertexDataType.None, vertexFormat.ColorDataType); break; // Tex 0 Data case 5: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Tex0); VertexData.Tex0 = LoadVertexAttribute <Vector2>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Tex0, vertexFormat.DataType, VertexColorType.None); break; // Tex 1 Data case 6: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Tex1); VertexData.Tex1 = LoadVertexAttribute <Vector2>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Tex1, vertexFormat.DataType, VertexColorType.None); break; // Tex 2 Data case 7: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Tex2); VertexData.Tex2 = LoadVertexAttribute <Vector2>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Tex2, vertexFormat.DataType, VertexColorType.None); break; // Tex 3 Data case 8: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Tex3); VertexData.Tex3 = LoadVertexAttribute <Vector2>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Tex3, vertexFormat.DataType, VertexColorType.None); break; // Tex 4 Data case 9: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Tex4); VertexData.Tex4 = LoadVertexAttribute <Vector2>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Tex4, vertexFormat.DataType, VertexColorType.None); break; // Tex 5 Data case 10: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Tex5); VertexData.Tex5 = LoadVertexAttribute <Vector2>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Tex5, vertexFormat.DataType, VertexColorType.None); break; // Tex 6 Data case 11: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Tex6); VertexData.Tex6 = LoadVertexAttribute <Vector2>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Tex6, vertexFormat.DataType, VertexColorType.None); break; // Tex 7 Data case 12: vertexFormat = VertexFormats.Find(x => x.ArrayType == VertexArrayType.Tex7); VertexData.Tex7 = LoadVertexAttribute <Vector2>(reader, totalLength, vertexFormat.DecimalPoint, VertexArrayType.Tex7, vertexFormat.DataType, VertexColorType.None); break; default: Console.WriteLine("Unsupported VertexFormat Index: {0}", k); break; } } }