Loading a BMP....it should work.

This is a discussion on Loading a BMP....it should work. within the Game Programming forums, part of the General Programming Boards category; I've done this about a billion times and yet this time its not working right. This is insane. Here is ...

  1. #1
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596

    Loading a BMP....it should work.

    I've done this about a billion times and yet this time its not working right.

    This is insane. Here is the code.

    This header is just the two headers in the SDK merged together.

    Code:
     
    struct VoxelRGB
    {
    __int8 red;
    __int8 green;
    __int8 blue;
    };
     
    struct BMPHeader
    {
    __int16 Type;
    __int32 Size;
    __int32 Reserved;
    __int32 Offset;
    __int32 HeaderSize;
    __int32 Width;
    __int32 Height;
    __int16 Planes;
    __int16 BitsPerPixel;
    __int32 Compression;
    __int32 ImageSize;
    __int32 XPixelsPerMeter;
    __int32 YPixelsPerMeter;
    __int32 ColorsUsed;
    __int32 ColorsImportant;
    };
     
     
    BMPHeader ColorMapInfo;
    ...
    ...
    void LoadBMPColorMap(std::string File,VoxelRGB *Map,BMPHeader bmpinfo);
     
    ...
    ...
     
    void Setup(void)
    {
    LoadBMPColorMap("blah blah blah",ColorMap,ColorMapInfo);
    }
     
    void LoadBMPColorMap(std::string File,VoxelRGB *Map,BMPHeader bmpinfo)
    {
    FILE *fp;
    fp=fopen(File.c_str(),"rb");
    fread(&bmpinfo,sizeof(BMPHeader),1,fp);
    char txt[10];
     
    //Just to be sure
    memset(txt,0,10);
     
    //Problem here??
    sprintf(txt,"%lu",bmpinfo.Size);
    MessageBox(0,txt,0,0);
     
    fclose(fp);
    }
    The Type field is correct with 0x4D42 which means it's reading the first __int16 right. Then it proceeds to tell me that the Size is only 3 bytes??? Stupid. I opened this file in QuickBasic 7.1 and read the Size member and it was correct. The file is good but for some stupid reason my code doesn't work. Either I'm not using sprintf() right which is showing erroneous values or something else is wrong.
    I even commented out all dynamic memory allocation prior to this function. The only thing happening is the loading of the bmpheader, but it doesn't work?

    I've tried _read,_open, fread, fopen, etc. All have the same result. WTH is going on?
    I feel stupid for asking this.

    Structure alignment is 8 bytes, but I have changed it and the same thing happens. The file is 256x256 in 32 bit color. Something somewhere is fragging my structure alignment.

    I even took out the code that loaded the image data into the VoxelRGB map. It made no difference and it didn't work because the width was being reported well into the billions. Trying to access memory using y*width+x when width is near 3 billion...well Windows doesn't like that. Clearly an alignment problem somewhere.

    But if the first __int16 is correct, how can the member immediately following that one be off?? Weird.

    Sorry I can't post the entire program here....it's enormous.
    Last edited by VirtualAce; 08-09-2004 at 01:46 PM.

  2. #2
    erstwhile
    Join Date
    Jan 2002
    Posts
    2,227
    Two suggestions:
    1. Use the predefined window types for bitmaps (BITMAPFILEHEADER, BITMAPINFOHEADER etc.) as that's what they're there for.
    2. Match the data types with what you're after - most of those you've declared in your BMPHeader struct should be unsigned (check the types of the members in your struct against those for the corresponding wingdi.h struct members).
    CProgramming FAQ
    Caution: this person may be a carrier of the misinformation virus.

  3. #3
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,499
    Looks like you need
    #pragma pack(1)
    to me

    Try printing what sizeof(BMPHeader) is and compare with the supposed value
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  4. #4
    erstwhile
    Join Date
    Jan 2002
    Posts
    2,227
    Quote Originally Posted by Salem
    Looks like you need
    #pragma pack(1)
    to me

    Try printing what sizeof(BMPHeader) is and compare with the supposed value
    That's a better idea: I just checked wingdi.h and BITMAPFILHEADER (the one with the corresponding 'size' member) is effectively declared after a #pragma pack(2). Wish I'd checked that before.
    CProgramming FAQ
    Caution: this person may be a carrier of the misinformation virus.

  5. #5
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    Yeppers it worked. I was looking for PACKED which is what I use in DJGPP and forgot all about pragma. Thanks a million Salem.

    I'm not using the Windows stuff because it is so convoluted. Although I could use Windows structures I don't want to load the bitmap via the GDI because it takes more code just to get to the raw image data. Much easier to load it myself.

    About the unsigned data types, I didn't read enough to see that those sized integer types are signed by default. I will correct.

    I'm using them because they are guaranteed to work on all systems because they default to the correct WORD size for the system they are used on. That's the reason for using them.
    Last edited by VirtualAce; 08-09-2004 at 07:44 PM.

  6. #6
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    >> I'm not using the Windows stuff because it is so convoluted. Although I could use Windows structures I don't want to load the bitmap via the GDI because it takes more code just to get to the raw image data. Much easier to load it myself. <<

    You're right about the GDI api being convoluted but getting raw pixels from an image isn't too bad.

    Code:
    int main(void)
    {
    	DIBSECTION ds;
    	HANDLE     hDib;
    
    	hDib = LoadImage(NULL, TEXT("Test.bmp"), IMAGE_BITMAP,
    	                 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
    
    	GetObject(hDib, sizeof(DIBSECTION), &ds);
    
    	printf("Height = %d, Width = %d, bpp = %d\n", ds.dsBm.bmHeight, ds.dsBm.bmWidth, ds.dsBm.bmBitsPixel);
    
    	/* Raw pixel data for image is at ds.dsBm.bmBits. Use it as needed. */
    	printf("Assuming a 24bpp image, Pixel 1 is %06.6x\n", *((UINT32 *) ds.dsBm.bmBits) & 0xffffff);
    
    	DeleteObject(hDib);
    	getchar();
    	return 0;
    }
    Last edited by anonytmouse; 08-10-2004 at 01:26 AM.

  7. #7
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    That's bad. Here's my code.

    Code:
    #pragma pack(1)
    struct BMPHeader
    {
      WORD   Type;
      DWORD  Size;
      DWORD  Reserved;
      DWORD  Offset;
      DWORD  HeaderSize;
      DWORD  Width;
      DWORD  Height;
      WORD   Planes;
      WORD   BitsPerPixel;
      DWORD  Compression;
      DWORD  ImageSize;
      DWORD  XPixelsPerMeter;
      DWORD  YPixelsPerMeter;
      DWORD  ColorsUsed;
      DWORD  ColorsImportant;
    };
    
    void LoadBMPColorMap(std::string File,VoxelRGB *Map,BMPHeader &bmpinfo)
    {
    
      WORD handle=_open(File.c_str(),_O_BINARY | _O_RDONLY);
      _read(handle,&bmpinfo,sizeof(BMPHeader));
    
    
      DWORD size=(bmpinfo.Width*bmpinfo.Height)*3;
    
    
      DWORD bytes=_read(handle,Map,size);
      
      _close(handle);
    
    }
    Then to access the BMP you simply access the red, green, and blue components of the bitmap array you declared. Form that into a DWORD or COLORREF using D3DCOLOR_XRGB or one of its many variants and you are done.

  8. #8
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,499
    Don't forget to undo the #pragma pack() at the end of the structure, otherwise all following structures will be packed as well (with perhaps the loss of performance and increased code size to cope with them)
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  9. #9
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    MSVC states that the pragma only affects the structure immediately following the pragma. After that it is switched off.

    EDIT: Actually I reread it and it says it has no effect on declarations...so you are right it is still packed.
    Last edited by VirtualAce; 08-11-2004 at 07:44 AM.

  10. #10
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,262
    That's pretty sharp. The easiest way to avoid alignment issues (And possible incompatibility) is to read each part of the structure individually, although I think speed is more important for you.

    Also you're tieing yourself to 24-bit BMPs there. Time for some error handling?

  11. #11
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Quote Originally Posted by Bubba
    That's bad. Here's my code.
    To state that his code is bad is a bit harsh.

    His code is much more portable (works with different color depths) and it's shorter.
    When using your function, you also have to know the size of the bitmap beforehand, to create the buffer for the function to fill in.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  12. #12
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,596
    You're right about the GDI api being convoluted but getting raw pixels from an image isn't too bad
    That's what I meant by bad....not his code. Getting raw pixels from Windows GDI is bad because it's so convoluted just to get to the RAW data.....but his code his perfect, just that I do not want to use GDI to do it. Several books I've read also agree that using GDI for any bitmap manipulation, loading, saving, etc., is not the best.

    And yes I'm tying myself directly into 24/32-bit BMPs because I have no need for any other functionality or image formats in BMP.

    No error checking at all because it is slower and I need levels to load up fast. Very soon I'm going to totally revamp the BMP loader and not even use BMP format. I've come up with my own compression scheme that will both save space and preserve the image 100%.

    No I would never say his code is bad and that's not what I meant...so very sorry for the misunderstanding. Easy to get misunderstood here.

    The size of my images in the game are all powers of 2. I have no need for loading images of other sizes. There is a lot assumed in the program but then....that is because putting in all that functionality when I don't need it is wasteful. Many games do this and only support certain size BMPs and/or texture sizes. Many of them are hardcoded into the game and the editors for the games take this into account.

    I'm not trying to write an official BMP loader that takes every single thing into account. I could careless about all that...and this is not a BMP library for others to use or anything.
    Last edited by VirtualAce; 08-14-2004 at 04:46 AM.

  13. #13
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Quote Originally Posted by Bubba
    No I would never say his code is bad and that's not what I meant...so very sorry for the misunderstanding.
    Hehe, OK

    I understand that you don't want to use the GDI when loading bitmaps to create textures.

    Just for the record, I use D3DXCreateTextureFromFile because I'm lazy and it lets me use PNG images which are smaller and allows an alpha channel to be used. To write a PNG loader requires a little more code.
    This makes level loading a bit slower, of course.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. how come... (bmp loading)
    By Homunculus in forum Windows Programming
    Replies: 4
    Last Post: 03-21-2006, 08:00 PM
  2. Loading a bitmap (Without using glaux)
    By Shamino in forum Game Programming
    Replies: 7
    Last Post: 03-16-2006, 08:43 AM
  3. Writing BMP file... doesn't work correctly
    By tin in forum Game Programming
    Replies: 3
    Last Post: 12-28-2005, 03:40 AM
  4. Loading a bmp file
    By Ganoosh in forum C++ Programming
    Replies: 4
    Last Post: 10-04-2005, 12:51 AM
  5. BMP Loading Questions, More OpenGL!!! :D
    By Shamino in forum Game Programming
    Replies: 13
    Last Post: 05-08-2005, 02:31 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21