time for another off the wall question. I am writing an MD2 loader for my small 3D engine project. In my old language (C) I could define a structure and then read() from an open file directly into the structure. I have a structure to hold the header information from the MD2 file, as follows:
[StructLayout(LayoutKind.Sequential)]
public struct MD2_Header
{
public int FourCC;
public int Version;
public int TextureWidth;
public int TextureHeight;
public int FrameSizeInBytes;
public int NbrTextures;
public int NbrVertices;
public int NbrTextureCoords;
public int NbrTriangles;
public int NbrOpenGLCmds;
public int NbrFrames;
public int TextureOffset;
public int TexCoordOffset;
public int TriangleOffset;
public int FrameOffset;
public int OpenGLCmdOffset;
public int EndOffset;
}
In my reader code, I would like to do something like:
// Suck the MD2 header into a structure, it is 68 bytes long.
Classic.Util.MD2_Header md2hdr = new Classic.Util.MD2_Header();
md2hdr = reader.ReadBytes(sizeof(Classic.Util.MD2_Header));
I realize this is not correct, as it breaks type safety somewhat oddly, but you get the idea of what I want to accomplish. I could do this with separate calls to reader.ReadInt32(), but I am curious if there is anyway to get this to work the way I am wanting using normal library calls.
I have looked a little into the Marshal.Copy() method, but it seems to be for going between managed and unmanaged memory, which is not really what I am doing here.
Any suggestions?
Read the byte stream to byte array, name it packet
, and try following:
GCHandle pinned = GCHandle.Alloc(packet, GCHandleType.Pinned);
MD2_Header h = (MD2_Header)Marshal.PtrToStructure(pinned.AddrOfPinnedObject(), typeof(MD2_Header));
pinned.Free();
A structure in C and a structure in C# are two completely different things. A structure in C is used both for value types and reference types, while a structure in C# is only used for value types.
A value type should represent a single value, but what you have is plenty of values, so you should use a class instead. The recommended maximum size for a structure in .NET is 16 bytes, and you have more than four times as much data.
A class with properties and a constructor that takes a byte array would look like this:
public class MD2_Header {
public int FourCC { get; set; }
public int Version { get; set; };
public int TextureWidth { get; set; };
public int TextureHeight { get; set; };
public int FrameSizeInBytes { get; set; };
public int NbrTextures { get; set; };
public int NbrVertices { get; set; };
public int NbrTextureCoords { get; set; };
public int NbrTriangles { get; set; };
public int NbrOpenGLCmds { get; set; };
public int NbrFrames { get; set; };
public int TextureOffset { get; set; };
public int TexCoordOffset { get; set; };
public int TriangleOffset { get; set; };
public int FrameOffset { get; set; };
public int OpenGLCmdOffset { get; set; };
public int EndOffset { get; set; };
public MD2_Header(byte[] values) {
FourCC = BitConverter.ToInt32(values, 0);
Version = BitConverter.ToInt32(values, 4);
TextureWidth = BitConverter.ToInt32(values, 8);
TextureHeight = BitConverter.ToInt32(values, 12);
FrameSizeInBytes = BitConverter.ToInt32(values, 16);
NbrTextures = BitConverter.ToInt32(values, 20);
NbrVertices = BitConverter.ToInt32(values, 24);
NbrTextureCoords = BitConverter.ToInt32(values, 28);
NbrTriangels = BitConverter.ToInt32(values, 32);
NbrOpenGLCmds = BitConverter.ToInt32(values, 36);
NbrFrames = BitConverter.ToInt32(values, 40);
TextureOffset = BitConverter.ToInt32(values, 44);
TexCoordOffset = BitConverter.ToInt32(values, 48);
TriangleOffset = BitConverter.ToInt32(values, 52);
FrameOffset = BitConverter.ToInt32(values, 56);
OpenGLCmdOffset = BitConverter.ToInt32(values, 60);
EndOffset = BitConverter.ToInt32(values, 64);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With