public GFSubMesh(H3DSubMesh SubMesh, H3DMesh Parent, List <PICAVertex> Vertices, string Name) : this() { this.Name = Name; BoneIndicesCount = (byte)SubMesh.BoneIndicesCount; BoneIndices = new byte[SubMesh.BoneIndicesCount]; for (int i = 0; i < SubMesh.BoneIndicesCount; i++) { BoneIndices[i] = (byte)SubMesh.BoneIndices[i]; } Indices = SubMesh.Indices; PrimitiveMode = SubMesh.PrimitiveMode; VertexStride = Parent.VertexStride; Attributes = Parent.Attributes; foreach (PICAFixedAttribute Old in Parent.FixedAttributes) { PICAFixedAttribute New = new PICAFixedAttribute() { Name = Old.Name, Value = Old.Value }; FixedAttributes.Add(New); } List <PICAVertex> NewVertices = new List <PICAVertex>(); Dictionary <ushort, ushort> OldNewIndexMap = new Dictionary <ushort, ushort>(); ushort[] NewIndices = new ushort[Indices.Length]; for (int i = 0; i < NewIndices.Length; i++) { if (OldNewIndexMap.ContainsKey(Indices[i])) { NewIndices[i] = OldNewIndexMap[Indices[i]]; } else { PICAVertex Vertex = Vertices[Indices[i]]; ushort NewIndex = (ushort)NewVertices.Count; NewVertices.Add(Vertex); NewIndices[i] = NewIndex; OldNewIndexMap.Add(Indices[i], NewIndex); } } Indices = NewIndices; IsIdx8Bits = /*NewIndices.Length <= 0x100*/ false; RawBuffer = VerticesConverter.GetBuffer(NewVertices, Attributes); }
public void Write(BinaryWriter Writer) { long StartPosition = Writer.BaseStream.Position; new GFSection(MagicStr).Write(Writer); GFNV1 FNV = new GFNV1(); FNV.Hash(Name); Writer.Write(FNV.HashCode); Writer.WritePaddedString(Name, 0x40); Writer.Write(0u); Writer.Write(BBoxMinVector); Writer.Write(BBoxMaxVector); Writer.Write((uint)SubMeshes.Count); Writer.Write(BoneIndicesPerVertex); Writer.Write(0xfffffffffffffffful); Writer.Write(0xfffffffffffffffful); for (int Index = 0; Index < SubMeshes.Count; Index++) { GFSubMesh SM = SubMeshes[Index]; PICACommandWriter CmdWriter; /* Enable commands */ CmdWriter = new PICACommandWriter(); ulong BufferFormats = 0; ulong BufferAttributes = 0; ulong BufferPermutation = 0; int AttributesTotal = 0; //Normal Attributes for (int Attr = 0; Attr < SM.Attributes.Count; Attr++) { PICAAttribute Attrib = SM.Attributes[Attr]; int Shift = AttributesTotal++ *4; ulong AttribFmt; AttribFmt = (ulong)Attrib.Format; AttribFmt |= (ulong)((Attrib.Elements - 1) & 3) << 2; BufferFormats |= AttribFmt << Shift; BufferPermutation |= (ulong)Attrib.Name << Shift; BufferAttributes |= (ulong)Attr << Shift; } BufferAttributes |= (ulong)(SM.VertexStride & 0xff) << 48; BufferAttributes |= (ulong)SM.Attributes.Count << 60; //Fixed Attributes foreach (PICAFixedAttribute Attrib in SM.FixedAttributes) { BufferFormats |= 1ul << (48 + AttributesTotal); BufferPermutation |= (ulong)Attrib.Name << AttributesTotal++ *4; } BufferFormats |= (ulong)(AttributesTotal - 1) << 60; CmdWriter.SetCommand(PICARegister.GPUREG_VSH_INPUTBUFFER_CONFIG, 0xa0000000u | (uint)(AttributesTotal - 1), 0xb); CmdWriter.SetCommand(PICARegister.GPUREG_VSH_NUM_ATTR, (uint)(AttributesTotal - 1), 1); CmdWriter.SetCommand(PICARegister.GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW, (uint)(BufferPermutation >> 0)); CmdWriter.SetCommand(PICARegister.GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH, (uint)(BufferPermutation >> 32)); CmdWriter.SetCommand(PICARegister.GPUREG_ATTRIBBUFFERS_LOC, true, 0x03000000u, //Base Address (Place holder) (uint)(BufferFormats >> 0), (uint)(BufferFormats >> 32), 0x99999999u, //Attributes Buffer Address (Place holder) (uint)(BufferAttributes >> 0), (uint)(BufferAttributes >> 32)); for (int Attr = 0; Attr < SM.FixedAttributes.Count; Attr++) { PICAFixedAttribute Attrib = SM.FixedAttributes[Attr]; float Scale = Attrib.Name == PICAAttributeName.Color || Attrib.Name == PICAAttributeName.BoneWeight ? GFMesh.Scales[1] : 1; PICAFixedAttribute ScaledAttribute = new PICAFixedAttribute() { Name = Attrib.Name, Value = new PICAVectorFloat24(Attrib.Value.X, Attrib.Value.Y, Attrib.Value.Z, Attrib.Value.W) / Scale }; CmdWriter.SetCommand(PICARegister.GPUREG_FIXEDATTRIB_INDEX, true, (uint)(SM.Attributes.Count + Attr), ScaledAttribute.Value.Word0, ScaledAttribute.Value.Word1, ScaledAttribute.Value.Word2); } CmdWriter.WriteEnd(); WriteCmdsBuff(Writer, CmdWriter.GetBuffer(), Index * 3); /* Disable commands */ CmdWriter = new PICACommandWriter(); //Assuming that the Position isn't used as Fixed Attribute since this doesn't make sense. CmdWriter.SetCommand(PICARegister.GPUREG_ATTRIBBUFFER0_OFFSET, true, 0, 0, 0); for (int Attr = 1; Attr < 12; Attr++) { CmdWriter.SetCommand(PICARegister.GPUREG_ATTRIBBUFFER0_CONFIG2 + Attr * 3, 0); if (SM.FixedAttributes?.Any(x => (int)x.Name == Attr) ?? false) { CmdWriter.SetCommand(PICARegister.GPUREG_FIXEDATTRIB_INDEX, true, (uint)Attr, 0, 0, 0); } } CmdWriter.WriteEnd(); WriteCmdsBuff(Writer, CmdWriter.GetBuffer(), Index * 3 + 1); /* Index commands */ CmdWriter = new PICACommandWriter(); uint IdxFmtAddr = SM.IsIdx8Bits ? 0x01999999u : 0x81999999u; CmdWriter.SetCommand(PICARegister.GPUREG_RESTART_PRIMITIVE, true); CmdWriter.SetCommand(PICARegister.GPUREG_INDEXBUFFER_CONFIG, IdxFmtAddr); CmdWriter.SetCommand(PICARegister.GPUREG_NUMVERTICES, (uint)SM.Indices.Length); CmdWriter.SetCommand(PICARegister.GPUREG_START_DRAW_FUNC0, false, 1); CmdWriter.SetCommand(PICARegister.GPUREG_DRAWELEMENTS, true); CmdWriter.SetCommand(PICARegister.GPUREG_START_DRAW_FUNC0, true, 1); CmdWriter.SetCommand(PICARegister.GPUREG_VTX_FUNC, true); CmdWriter.SetCommand(PICARegister.GPUREG_PRIMITIVE_CONFIG, (uint)SM.PrimitiveMode << 8, 8); CmdWriter.SetCommand(PICARegister.GPUREG_PRIMITIVE_CONFIG, (uint)SM.PrimitiveMode << 8, 8); CmdWriter.WriteEnd(); WriteCmdsBuff(Writer, CmdWriter.GetBuffer(), Index * 3 + 2); } foreach (GFSubMesh SM in SubMeshes) { FNV = new GFNV1(); FNV.Hash(SM.Name); Writer.Write(FNV.HashCode); Writer.Write(GetPaddedLen4(SM.Name.Length)); Writer.WritePaddedString(SM.Name, GetPaddedLen4(SM.Name.Length)); Writer.Write(SM.BoneIndicesCount); byte[] BoneIndices = new byte[0x1f]; SM.BoneIndices.CopyTo(BoneIndices, 0); Writer.Write(BoneIndices); int VerticesCount = 0; if (SM.VertexStride != 0) { VerticesCount = SM.RawBuffer.Length / SM.VertexStride; } int VtxBuffLen = SM.RawBuffer.Length; int IdxBuffLen = SM.Indices.Length * (SM.IsIdx8Bits ? 1 : 2); Writer.Write(VerticesCount); Writer.Write(SM.Indices.Length); Writer.Write(GetPaddedLen16(VtxBuffLen)); Writer.Write(GetPaddedLen16(IdxBuffLen)); } foreach (GFSubMesh SM in SubMeshes) { long Position = Writer.BaseStream.Position; Writer.Write(SM.RawBuffer); int VertexBufferPaddingLength = GetPaddedLen16(SM.RawBuffer.Length) - SM.RawBuffer.Length; Writer.Write(new byte[VertexBufferPaddingLength]); /*while (((Writer.BaseStream.Position - Position) & 3) != 0) * { * Writer.Write((byte)0); * }*/ Position = Writer.BaseStream.Position; foreach (ushort Idx in SM.Indices) { if (SM.IsIdx8Bits) { Writer.Write((byte)Idx); } else { Writer.Write(Idx); } } /*while (((Writer.BaseStream.Position - Position) & 0xf) != 0) * { * Writer.Write((byte)0); * }*/ int IndexBufferLength = SM.Indices.Length * (SM.IsIdx8Bits ? 1 : 2); int IndexBufferPaddingLength = GetPaddedLen16(IndexBufferLength) - IndexBufferLength; Writer.Write(new byte[IndexBufferPaddingLength]); } Writer.Align(0x10, 0); Writer.Write(0ul); Writer.Write(0ul); long EndPosition = Writer.BaseStream.Position; Writer.BaseStream.Seek(StartPosition + 8, SeekOrigin.Begin); Writer.Write((uint)(EndPosition - StartPosition - 0x10)); Writer.BaseStream.Seek(EndPosition, SeekOrigin.Begin); }