2010-07-14 39 views
6

thời gian cho một câu hỏi khác ngoài tường. Tôi đang viết một trình tải MD2 cho dự án động cơ 3D nhỏ của tôi. Trong ngôn ngữ cũ của tôi (C) tôi có thể định nghĩa một cấu trúc và sau đó đọc() từ một tệp mở trực tiếp vào cấu trúc. Tôi có một cấu trúc tổ chức thông tin tiêu đề từ tập tin MD2, như sau:Đọc các byte thành một cấu trúc trong C#

[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; 
} 

Trong mã độc giả của tôi, tôi muốn làm một cái gì đó như:

// 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)); 

Tôi nhận ra điều này là không đúng , vì nó phá vỡ an toàn loại hơi kỳ quặc, nhưng bạn có được ý tưởng về những gì tôi muốn thực hiện. Tôi có thể làm điều này với các cuộc gọi riêng biệt để đọc.ReadInt32(), nhưng tôi tò mò nếu có anyway để có được điều này để làm việc theo cách tôi muốn sử dụng các cuộc gọi thư viện bình thường.

Tôi đã xem xét một chút về phương thức Marshal.Copy(), nhưng có vẻ như là để đi giữa bộ nhớ được quản lý và không được quản lý, điều đó không thực sự là những gì tôi đang làm ở đây.

Mọi đề xuất?

+0

Trông như ai đó đánh bại bạn với nó: http://gpwiki.org/index.php/C_sharp:MD2_loader_in_CSharp – Jess

Trả lời

3

Cấu trúc trong C và cấu trúc trong C# là hai điều hoàn toàn khác nhau. Một cấu trúc trong C được sử dụng cho cả kiểu giá trị và kiểu tham chiếu, trong khi cấu trúc trong C# chỉ được sử dụng cho các kiểu giá trị.

Loại giá trị phải đại diện cho một giá trị duy nhất, nhưng những gì bạn có nhiều giá trị, do đó bạn nên sử dụng một lớp thay thế. Kích thước tối đa được đề xuất cho cấu trúc trong .NET là 16 byte và bạn có nhiều hơn bốn lần dữ liệu.

Một lớp với các thuộc tính và một constructor mà phải mất một mảng byte sẽ trông như thế này:

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); 
    } 

} 
+0

Tôi đã tiếp tục và sử dụng phương pháp này, tôi đồng ý hoàn toàn với sự phân biệt của bạn giữa giá trị và loại tham chiếu . Giải pháp của bạn là thiết kế tốt hơn, chắc chắn, tôi đã chỉ tò mò nếu có một phương pháp đơn giản để mô phỏng phong cách cũ của tôi làm việc. :-) –

+0

-1 ... hoàn toàn bỏ qua các câu trả lời thích hợp mà trỏ đến đó được chính xác được hỗ trợ cho các lý do interop. – TomTom

+0

@Chris: Có thể, nhưng không đơn giản. Bạn sẽ cần phải sử dụng các thuộc tính xác định chính xác cách các thành viên được tổ chức trong cấu trúc để đảm bảo rằng không có đệm và chúng nằm đúng thứ tự. Sau đó, bạn cần phải sử dụng bộ thu gom rác để ghim dữ liệu trong bộ nhớ, và marshalling hoặc mã không an toàn để sao chép dữ liệu vào cấu trúc. – Guffa

0

Nó có thể phức tạp một chút trong C#, nhưng bạn có thể thiết lập mọi thứ nơi bạn có thể ghi nhớ các byte từ một mảng byte vào cấu trúc.

1

Những gì bạn có thể làm là đọc các byte thành bộ đệm có kích thước phù hợp, sử dụng fixed (int* = &md2hdr.FourCC) để có được con trỏ đến đầu cấu trúc của bạn, chuyển con trỏ đến cấu trúc của bạn tới byte* và sao chép byte theo cách thủ công.

5

Đọc dòng byte để mảng byte, tên nó packet, và cố gắng sau:

GCHandle pinned = GCHandle.Alloc(packet, GCHandleType.Pinned); 
MD2_Header h = (MD2_Header)Marshal.PtrToStructure(pinned.AddrOfPinnedObject(), typeof(MD2_Header)); 
pinned.Free(); 
+0

circumvents này các GC một cách khá đáng kể, một cái gì đó tôi muốn tránh. –

3

Bạn có thể sử dụng Marshal.PtrToStructure để sao chép từ một con trỏ trực tiếp vào cấu trúc của bạn trong một shot. By

byte[] data = reader.ReadBytes(...); 
fixed (byte* bytes = data) 
{ 
    Classic.Util.MD2_Header md2hdr = 
      (Classic.Util.MD2_Header)Marshal.PtrToStructure(
       Marshal.UnsafeAddrOfPinnedArrayElement(data, 0), 
       typeof(Classic.Util.MD2_Header) 
     ); 
} 
+0

Đây là một chút sạch hơn so với giải pháp của Yossarian, nhưng vẫn còn liên quan đến rất nhiều lúng túng với GC Tôi thà tránh. Ngoài ra, một phần "cố định" yêu cầu biên dịch với tham số/không an toàn. –

+0

@ Chris D .: Khá nhiều lần bạn đang rối tung với byte và cố gắng sao chép bộ nhớ trực tiếp, bạn ~ nên ~ ở trong/không an toàn. Điều đó đang được nói, bạn có thể thực hiện điều này bằng nhiều cách khác, nhưng đây có lẽ là câu trả lời trực tiếp nhất cho câu hỏi của bạn, IMO ... –

1

Bạn có thể sử dụng marshaling để xử lý việc sao chép. Không cần phải viết mã để xử lý nó.

//create object 
Classic.Util.MD2_Header md2hdr = new Classic.Util.MD2_Header(); 
Classic.Util.MD2_Header another = new Classic.Util.MD2_Header(); 
byte[] mem = new byte[Marshal.SizeOf(typeof(MD2_Header))]; 

//allocate unmanaged memory 
IntPtr hmem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Classic.Util.MD2_Header))); 

//copy structure to unmanaged memory 
Marshal.StructureToPtr(md2hdr, hmem, false); 

//copy to managed memory 
Marshal.Copy(hmem, mem, 0, mem.Length); 

//copy unmanaged memory to structure 
another = (Classic.Util.MD2_Header)Marshal.PtrToStructure(hmem, typeof(Classic.Util.MD2_Header)); 

//free unmanaged memory 
Marshal.FreeHGlobal(hmem); 
+0

Định dạng màu là tự động nếu JS lib SO đang sử dụng nhận dạng mã của bạn. Có vẻ như bạn đang thiết lập một số văn bản để in đậm ở đây, có thể là ném nó đi ... –

+0

Về mặt kỹ lưỡng, tôi đã xem xét src của nhận xét của bạn và bạn đang làm sai. Đối với nguồn, trên SO, tất cả những gì bạn phải làm là phải ngắt dòng trước mã và thụt lề dòng mã của bạn theo bốn dấu cách. Phần còn lại là tự động. Tuy nhiên, bạn không thể tạo ra một số dòng nhất định. –

+0

Ban đầu, tôi đã in đậm chữ đậm nhưng đặt ở đó sau khi tôi không thể tô màu để tô sáng các phần chính. Tôi sẽ cố gắng sửa nó để lấy màu ngay bây giờ. Cảm ơn. :) –

1

Tôi biết bạn đã có câu trả lời và đó là câu trả lời hay.

Tôi nghĩ bạn có thể nhận được một số giá trị từ một bài đăng trên blog mà tôi đã thực hiện trên một số tùy chọn có sẵn trong .NET để đạt được điều này.

Structure from binary data

Và một bài tương ứng cho điều ngược lại

Binary data from a structure

+1

Cảm ơn các liên kết này, chúng rất tốt. –

Các vấn đề liên quan