/// <summary> /// Writes the parameters and primitives to a stream /// </summary> /// <param name="writer">The ouput stream</param> /// <param name="indexFlags">The index flags</param> public void WriteData(BinaryWriter writer, GCIndexAttributeFlags indexFlags) { paramAddress = (uint)writer.BaseStream.Length; foreach (GCParameter param in parameters) { param.Write(writer); } primitiveAddress = (uint)writer.BaseStream.Length; foreach (GCPrimitive prim in primitives) { prim.Write(writer, indexFlags); } primitiveSize = (uint)writer.BaseStream.Length - primitiveAddress; }
/// <summary> /// Read a mesh from a file /// </summary> /// <param name="file">The files contents</param> /// <param name="address">The address at which the mesh is located</param> /// <param name="imageBase">The imagebase (used for when reading from an exe)</param> /// <param name="index">Indexattribute parameter of the previous mesh</param> public GCMesh(byte[] file, int address, uint imageBase, GCIndexAttributeFlags indexFlags) { // getting the addresses and sizes int parameters_offset = (int)(ByteConverter.ToInt32(file, address) - imageBase); int parameters_count = ByteConverter.ToInt32(file, address + 4); int primitives_offset = (int)(ByteConverter.ToInt32(file, address + 8) - imageBase); int primitives_size = ByteConverter.ToInt32(file, address + 12); // reading the parameters parameters = new List <GCParameter>(); for (int i = 0; i < parameters_count; i++) { parameters.Add(GCParameter.Read(file, parameters_offset)); parameters_offset += 8; } // getting the index attribute parameter GCIndexAttributeFlags?flags = IndexFlags; if (flags.HasValue) { indexFlags = flags.Value; } // reading the primitives primitives = new List <GCPrimitive>(); int end_pos = primitives_offset + primitives_size; while (primitives_offset < end_pos) { // if the primitive isnt valid if (file[primitives_offset] == 0) { break; } primitives.Add(new GCPrimitive(file, primitives_offset, indexFlags, out primitives_offset)); } }
/// <summary> /// Read a primitive object from a file /// </summary> /// <param name="file">The files contents as a byte array</param> /// <param name="address">The starting address of the primitive</param> /// <param name="indexFlags">How the indices of the loops are structured</param> public GCPrimitive(byte[] file, int address, GCIndexAttributeFlags indexFlags, out int end) { primitiveType = (GCPrimitiveType)file[address]; bool wasBigEndian = ByteConverter.BigEndian; ByteConverter.BigEndian = true; ushort vtxCount = ByteConverter.ToUInt16(file, address + 1); // checking the flags bool hasFlag(GCIndexAttributeFlags flag) { return(indexFlags.HasFlag(flag)); } // position always exists bool has_color = hasFlag(GCIndexAttributeFlags.HasColor); bool has_normal = hasFlag(GCIndexAttributeFlags.HasNormal); bool has_uv = hasFlag(GCIndexAttributeFlags.HasUV); //whether any of the indices use 16 bits instead of 8 bool pos16bit = hasFlag(GCIndexAttributeFlags.Position16BitIndex); bool col16bit = hasFlag(GCIndexAttributeFlags.Color16BitIndex); bool nrm16bit = hasFlag(GCIndexAttributeFlags.Normal16BitIndex); bool uv16bit = hasFlag(GCIndexAttributeFlags.UV16BitIndex); int tmpaddr = address + 3; loops = new List <Loop>(); for (ushort i = 0; i < vtxCount; i++) { Loop l = new Loop(); // reading position, which should always exist if (pos16bit) { l.PositionIndex = ByteConverter.ToUInt16(file, tmpaddr); tmpaddr += 2; } else { l.PositionIndex = file[tmpaddr]; tmpaddr++; } // reading normals if (has_normal) { if (nrm16bit) { l.NormalIndex = ByteConverter.ToUInt16(file, tmpaddr); tmpaddr += 2; } else { l.NormalIndex = file[tmpaddr]; tmpaddr++; } } // reading colors if (has_color) { if (col16bit) { l.Color0Index = ByteConverter.ToUInt16(file, tmpaddr); tmpaddr += 2; } else { l.Color0Index = file[tmpaddr]; tmpaddr++; } } // reading uvs if (has_uv) { if (uv16bit) { l.UV0Index = ByteConverter.ToUInt16(file, tmpaddr); tmpaddr += 2; } else { l.UV0Index = file[tmpaddr]; tmpaddr++; } } loops.Add(l); } end = tmpaddr; ByteConverter.BigEndian = wasBigEndian; }
/// <summary> /// Write the contents /// </summary> /// <param name="writer">The output stream</param> /// <param name="indexFlags">How the indices of the loops are structured</param> public void Write(BinaryWriter writer, GCIndexAttributeFlags indexFlags) { writer.Write((byte)primitiveType); byte[] bytes = BitConverter.GetBytes((ushort)loops.Count); // writing count as big endian writer.Write(bytes[1]); writer.Write(bytes[0]); // checking the flags bool hasFlag(GCIndexAttributeFlags flag) { return(indexFlags.HasFlag(flag)); } // position always exists bool has_color = hasFlag(GCIndexAttributeFlags.HasColor); bool has_normal = hasFlag(GCIndexAttributeFlags.HasNormal); bool has_uv = hasFlag(GCIndexAttributeFlags.HasUV); bool is_position_16bit = hasFlag(GCIndexAttributeFlags.Position16BitIndex); bool is_color_16bit = hasFlag(GCIndexAttributeFlags.Color16BitIndex); bool is_normal_16bit = hasFlag(GCIndexAttributeFlags.Normal16BitIndex); bool is_uv_16bit = hasFlag(GCIndexAttributeFlags.UV16BitIndex); foreach (Loop v in loops) { // Position should always exist if (is_position_16bit) { bytes = BitConverter.GetBytes(v.PositionIndex); // writing big endian writer.Write(bytes[1]); writer.Write(bytes[0]); } else { writer.Write((byte)v.PositionIndex); } if (has_normal) { if (is_normal_16bit) { bytes = BitConverter.GetBytes(v.NormalIndex); // writing big endian writer.Write(bytes[1]); writer.Write(bytes[0]); } else { writer.Write((byte)v.NormalIndex); } } if (has_color) { if (is_color_16bit) { bytes = BitConverter.GetBytes(v.Color0Index); // writing big endian writer.Write(bytes[1]); writer.Write(bytes[0]); } else { writer.Write((byte)v.Color0Index); } } if (has_uv) { if (is_uv_16bit) { bytes = BitConverter.GetBytes(v.UV0Index); // writing big endian writer.Write(bytes[1]); writer.Write(bytes[0]); } else { writer.Write((byte)v.UV0Index); } } } }
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 uint vertexAddress = ByteConverter.ToUInt32(file, address) - imageBase; //uint gap = ByteConverter.ToUInt32(file, address + 4); int opaqueAddress = (int)(ByteConverter.ToInt32(file, address + 8) - imageBase); int translucentAddress = (int)(ByteConverter.ToInt32(file, address + 12) - imageBase); int opaqueCount = ByteConverter.ToInt16(file, address + 16); int translucentCount = ByteConverter.ToInt16(file, address + 18); Bounds = new BoundingSphere(file, address + 20); // reading vertex data vertexData = new List <GCVertexSet>(); GCVertexSet vertexSet = new GCVertexSet(file, vertexAddress, imageBase); while (vertexSet.attribute != GCVertexAttribute.Null) { vertexData.Add(vertexSet); vertexAddress += 16; vertexSet = new GCVertexSet(file, vertexAddress, imageBase); } // reading geometry GCIndexAttributeFlags indexFlags = GCIndexAttributeFlags.HasPosition; opaqueMeshes = new List <GCMesh>(); for (int i = 0; i < opaqueCount; i++) { GCMesh mesh = new GCMesh(file, opaqueAddress, imageBase, indexFlags); GCIndexAttributeFlags?t = mesh.IndexFlags; if (t.HasValue) { indexFlags = t.Value; } opaqueMeshes.Add(mesh); opaqueAddress += 16; } translucentMeshes = new List <GCMesh>(); for (int i = 0; i < translucentCount; i++) { GCMesh mesh = new GCMesh(file, translucentAddress, imageBase, indexFlags); GCIndexAttributeFlags?t = mesh.IndexFlags; if (t.HasValue) { indexFlags = t.Value; } translucentMeshes.Add(mesh); translucentAddress += 16; } }
/// <summary> /// Writes the attaches contents into a byte array /// </summary> /// <param name="imageBase">The files imagebase</param> /// <param name="DX">Unused</param> /// <param name="labels">The files labels</param> /// <param name="address"></param> /// <returns></returns> public override byte[] GetBytes(uint imageBase, bool DX, Dictionary <string, uint> labels, out uint address) { byte[] output; using (MemoryStream strm = new MemoryStream()) { BinaryWriter writer = new BinaryWriter(strm); writer.Write(new byte[16]); // address placeholders writer.Write((ushort)opaqueMeshes.Count); writer.Write((ushort)translucentMeshes.Count); writer.Write(Bounds.GetBytes()); // writing vertex data foreach (GCVertexSet vtx in vertexData) { vtx.WriteData(writer); } uint vtxAddr = (uint)writer.BaseStream.Length + imageBase; // writing vertex attributes foreach (GCVertexSet vtx in vertexData) { vtx.WriteAttribute(writer, imageBase); } writer.Write((byte)255); writer.Write(new byte[15]); // empty vtx attribute // writing geometry data GCIndexAttributeFlags indexFlags = GCIndexAttributeFlags.HasPosition; foreach (GCMesh m in opaqueMeshes) { GCIndexAttributeFlags?t = m.IndexFlags; if (t.HasValue) { indexFlags = t.Value; } m.WriteData(writer, indexFlags); } foreach (GCMesh m in translucentMeshes) { GCIndexAttributeFlags?t = m.IndexFlags; if (t.HasValue) { indexFlags = t.Value; } m.WriteData(writer, indexFlags); } // writing geometry properties uint opaqueAddress = (uint)writer.BaseStream.Length + imageBase; foreach (GCMesh m in opaqueMeshes) { m.WriteProperties(writer, imageBase); } uint translucentAddress = (uint)writer.BaseStream.Length + imageBase; foreach (GCMesh m in translucentMeshes) { m.WriteProperties(writer, imageBase); } // replacing the placeholders writer.Seek(0, SeekOrigin.Begin); writer.Write(vtxAddr); writer.Write(0); writer.Write(opaqueAddress); writer.Write(translucentAddress); writer.Seek(0, SeekOrigin.End); output = strm.ToArray(); } address = 0; labels.Add(Name, imageBase); return(output); }
/// <summary> /// Creates an index attribute parameter based on existing flags /// </summary> /// <param name="flags"></param> public IndexAttributeParameter(GCIndexAttributeFlags flags) : base(ParameterType.IndexAttributeFlags) { IndexAttributes = flags; }
/// <summary> /// Creates an empty index attribute parameter /// </summary> public IndexAttributeParameter() : base(ParameterType.IndexAttributeFlags) { //this always exists IndexAttributes &= GCIndexAttributeFlags.HasPosition; }