Thread: Loading a Bitmap w/ DirectX

  1. #1
    Registered User
    Join Date
    Mar 2011
    Posts
    216

    Loading a Bitmap w/ DirectX

    Hi, I'm trying to load a 24 bit image, and then render it on the primary surface via DirectX. The application compiles fine, but quits with an appcrash error. What is wrong?

    Game.cpp
    Code:
    /*************************************************************************/
    // Called in this order
    
    // Code to initialize game - called once
    
    #include "main.h" // your header file
    
    // Global varables for this source file
    
    LPDIRECTDRAW7        lpdd              = NULL;  // dd object
    LPDIRECTDRAWSURFACE7 lpddsprimary      = NULL;  // dd primary surface
    LPDIRECTDRAWSURFACE7 lpddssecondary    = NULL;  // dd back surface
    LPDIRECTDRAWSURFACE7 lpoffscreen       = NULL;  // offscreen working surface
    LPDIRECTDRAWPALETTE  lpddpal           = NULL;  // a pointer to the created dd palette
    DDSURFACEDESC2       ddsd;                      // a direct draw surface description struct
    DDSCAPS2             ddscaps;                   // a direct draw surface capabilities struct
    HRESULT              ddrval;                    // result back from dd calls
    
    UCHAR                *primary_buffer = NULL;    // primary video buffer
    
    
    int Game_Init(void *parms)
    {
        // this function is where you do all the initialization 
        // for your game
    
        log_file = fopen("log.txt","w");
    
        debug("Initializing Game...\n\n\n");
       
        // create object and test for error
        if (DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL) == DD_OK)
                debug("-> DirectDraw Object Created Successfully\n\n");
                
        else
        {
                debug("***Error creating DDraw object***\n\n\n");
                return(0);
        }
    
        // set cooperation level to windowed mode normal
        if (lpdd->SetCooperativeLevel(g_hwnd,
               DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN | 
               DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT) == DD_OK)
                debug("-> Cooperation Level Set\n\n");
        else
        {
                debug("***Couldn't set cooperation level***\n\n\n");
                return(0);
        }
    
        // set the display mode
        if (lpdd->SetDisplayMode(WINDOW_WIDTH,WINDOW_HEIGHT,BITS,0,0) == DD_OK)
                debug("-> Display Mode Set\n\n");
        else
        {
                debug("***Failed to set display mode***\n\n\n");
                return(0);
        }
    
        // Create the primary surface
        memset(&ddsd,0,sizeof(ddsd));
        ddsd.dwSize         = sizeof(ddsd);
        ddsd.dwFlags        = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
        ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
    
        // For secondary surface
        ddsd.dwBackBufferCount = 1;
    
        if (lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL) == DD_OK)
                debug("-> Primary Surface Created at lpddsprimary\n\n");
        else
        {
                debug("***Error Creating Primary Surface***\n\n\n");
                return(0);
        }
       
        ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
       
        if (lpddsprimary->GetAttachedSurface(&ddscaps,&lpddssecondary) == DD_OK)
                debug("-> Secondary Surface Created at lpddssecondary off of lpddsprimary\n\n");
        else
        {        
                debug("***Error Creating Secondary Surface***\n\n\n");
                return(0);
        }
       
        // For Offscreen surface
       
        ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
       
        // set dimensions
       
        ddsd.dwWidth = 600;
        ddsd.dwHeight = 400;
       
        ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
       
        // create offscreen surface
        if (lpdd->CreateSurface(&ddsd,&lpoffscreen,NULL) == DD_OK)
                debug("-> Offscreen Surface Created at lpoffscreen\n\n");
        else
        {
                debug("***Error Creating Offscreen Surface***\n\n\n");
                return(0);
        }
        
        if(!Load_Bitmap_File(&bitmap, "image.bmp"))
        {        
                debug("***Couldn't Load Bitmap***");
                return(0);
        }
        else debug("-> Loaded bitmap");
        
        debug("Done\n\n\n");
    
    // return success
    return(1);
    } // end Game_Init
    
    
    
    /**************************************************************************/
    
    
    
    // Main Game - loops
    
    // this is the workhorse of your game it will be called
    // continuously in real-time this is like main() in C
    // all the calls for you game go here!
    
    
    
    int Game_Main(void *parms)
    {
             // check of user is trying to exit
             if (KEY_DOWN(VK_ESCAPE) || KEY_DOWN(VK_SPACE))
                PostMessage(g_hwnd, WM_DESTROY,0,0);
                
             // set up the surface description to lock the surface
             memset(&ddsd,0,sizeof(ddsd)); 
             ddsd.dwSize = sizeof(ddsd);
    
             // lock the primary surface, note in a real game you would
             lpddsprimary->Lock(NULL,&ddsd, 
                       DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);
    
             // get video pointer
             primary_buffer = (UCHAR *)ddsd.lpSurface;
    
             // copy each bitmap line into primary buffer 
             // taking into consideration non-linear video 
             // cards and the memory pitch lPitch
             for (int y = 0; y < WINDOW_HEIGHT; y++)
             {
                 // copy the line
                 memcpy(&primary_buffer[y*ddsd.lPitch], // dest address
                 &bitmap.buffer[y*WINDOW_WIDTH*4],   // src address
                 WINDOW_WIDTH*4);                         // bytes to copy
             } // end for y
    
             // unlock the surface
             lpddsprimary->Unlock(NULL);
    
    
             // return success
             return(1);
    } // end Game_Main
    
    
    
    /*************************************************************************/
    
    
    
    // Called before WM_DESTROY
    
    
    
    int Game_Shutdown(void *parms)
    {
        // this function is where you shutdown your game and
        // release all resources that you allocated
    
        debug("Shutting Game down...\n\n\n");
        
        // release attached surface first
        if (lpddssecondary!=NULL)
        lpddssecondary->Release();
    
        debug("-> Released Secondary Surface\n\n");
    
        // first release the primary surface
        if (lpddsprimary!=NULL)
           lpddsprimary->Release();
    
        debug("-> Released Primary Surface\n\n");
    
        // release offscreen surface
        if (lpoffscreen!=NULL)
           lpoffscreen->Release();
       
        debug("-> Released Offscreen Surface\n\n");
       
        // release the directdraw object
        if (lpdd!=NULL)
           lpdd->Release();
       
        debug("-> Released DirectDraw Object\n\n");
        
        if(!Unload_Bitmap_File(&bitmap))
           debug("***Failed to unload bitmap***");
           
        else debug("-> Unloaded bitmap\n\n");
    
        debug("Done\n");
       
        fclose(log_file);
    
    // return success
    return(1);
    } // end Game_Shutdown
    Dexterous.cpp

    Code:
    #include "main.h"
    
    void debug(char *text)
    {
         fprintf(log_file,"%s",text);
    }
    
    
    /***************************************************************************/
    
    
    int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
    {
         // this function opens a bitmap file and loads the data into bitmap
    
         int file_handle,  // the file handle
             index;        // looping index
             
         char *buffer;
    
         UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
         OFSTRUCT file_data;        // the file data information
    
         // open the file if it exists
         if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
            return(0);
    
         // now load the bitmap file header
         _lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));
    
         // test if this is a bitmap file
         if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
         {
            // close the file
            _lclose(file_handle);
    
            // return error
            return(0);
         } // end if
    
         // now we know this is a bitmap, so read in all the sections
    
         // first the bitmap infoheader
    
         // now load the bitmap file header
         _lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));
    
    
         // finally the image data itself
         _lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);
    
         // now read in the image, if the image is 16, 24, or 32 bit then simply read it
         if (bitmap->bitmapinfoheader.biBitCount == 16 || bitmap->bitmapinfoheader.biBitCount == 24 || bitmap->bitmapinfoheader.biBitCount == 32)
         {
            // allocate the memory for the image
            if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
            {
               // close the file
               _lclose(file_handle);
    
               // return error
               return(0);
            } // end if
    
         // now read it in
         _lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);
    
       } // end if
       else
       {
            debug("***8-bit image***");
            return(0);
       } // end if
    
    
       // write the file info out 
       sprintf(buffer,"-> Bitmap Information\n\n\tfilename:%s \n\tsize=%d \n\twidth=%d \n\theight=%d \n\tbitsperpixel=%d \n\tcolors=%d \n\timpcolors=%d\n\n",
            filename,
            bitmap->bitmapinfoheader.biSizeImage,
            bitmap->bitmapinfoheader.biWidth,
            bitmap->bitmapinfoheader.biHeight,
    		bitmap->bitmapinfoheader.biBitCount,
            bitmap->bitmapinfoheader.biClrUsed,
            bitmap->bitmapinfoheader.biClrImportant);
            
       debug(buffer);
    
    
       // close the file
       _lclose(file_handle);
    
       // flip the bitmap
       Flip_Bitmap(bitmap->buffer, 
                   bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8), 
                   bitmap->bitmapinfoheader.biHeight);
    
       // return success
       return(1);
    
    } // end Load_Bitmap_File
    
    ///////////////////////////////////////////////////////////
    
    int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
    {
        // this function releases all memory associated with "bitmap"
        if (bitmap->buffer)
        {
           // release memory
           free(bitmap->buffer);
    
           // reset pointer
           bitmap->buffer = NULL;
    
        } // end if
    
        // return success
        return(1);
    
    } // end Unload_Bitmap_File
    
    ///////////////////////////////////////////////////////////
    
    
    int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
    {
        // this function is used to flip upside down .BMP images
    
        UCHAR *buffer; // used to perform the image processing
        int index;     // looping index
    
        // allocate the temporary buffer
        if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
           return(0);
    
        // copy image to work area
        memcpy(buffer,image,bytes_per_line*height);
    
        // flip vertically
        for (index=0; index < height; index++)
            memcpy(&image[((height-1) - index)*bytes_per_line], &buffer[index*bytes_per_line], bytes_per_line);
    
        // release the memory
        free(buffer);
    
        // return success
        return(1);
    
    } // end Flip_Bitmap
    main.h

    Code:
    // Compiler Includes
    
    #include <windows.h>   // include important windows stuff
    #include <windowsx.h> 
    #include <mmsystem.h>
    #include <iostream> // include important C/C++ stuff
    #include <conio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <memory.h>
    #include <string.h>
    #include <stdarg.h>
    #include <stdio.h>
    #include <math.h>
    #include <io.h>
    #include <fcntl.h>
    
    #include <ddraw.h>
    
    
    // Project Includes
    
    
    // Defines
    
    #define WINDOW_TITLE "Dexterous"
    
    #define WINDOW_WIDTH 1280
    #define WINDOW_HEIGHT 1024
    
    #define BITS 24
    
    #define _RGB24BIT(r,g,b) ((b) + ((g) << 8) + ((r) << 16))
    #define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))
    
    #define BITMAP_ID     0x4D42      // universal id for a bitmap
    
    
    // Macros
    
    // these read the keyboard asynchronously
    #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
    #define KEY_UP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
    
    // Typedefs
    
    // container structure for bitmaps .BMP file
    typedef struct BITMAP_FILE_TAG
    {
            BITMAPFILEHEADER bitmapfileheader;  // this contains the bitmapfile header
            BITMAPINFOHEADER bitmapinfoheader;  // this is all the info including the palette
            UCHAR            *buffer;           // this is a pointer to the data
    
    } BITMAP_FILE, *BITMAP_FILE_PTR;
    
    
    // Prototypes
    
    int Game_Init(void *parms=NULL);
    int Game_Shutdown(void *parms=NULL);
    int Game_Main(void *parms=NULL);
    
    void debug(char *text);
    
    int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename);
    int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap);
    int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height);
    
    
    // Global Variables
    
    extern HWND g_hwnd; // save the window handle
    extern HINSTANCE g_hInstance; // save the instance
    
    extern FILE *log_file;
    
    extern BITMAP_FILE          bitmap;            // a bitmap file
    There is also another file, title Windows.cpp. That file is definately not the problem, since it's only initializing the standard window and calling the game functions.

    Help is very appreciated, thanks!

    P.S. I have this feeling the error or bug is in Game_Main, specifically where it tries to copy memory onto the primary surface...

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    I'm assuming you are using Visual Studios for this? Just hit F5 and step through it and it will tell you why it crashes.


    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,949
    Quote Originally Posted by binks View Post
    Code:
    // Compiler Includes
    
    #include <windows.h>   // include important windows stuff
    #include <windowsx.h> 
    #include <mmsystem.h>
    #include <iostream> // include important C/C++ stuff
    #include <conio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <memory.h>
    #include <string.h>
    #include <stdarg.h>
    #include <stdio.h>
    #include <math.h>
    #include <io.h>
    #include <fcntl.h>
    
    #include <ddraw.h>
    ummm.....what?

    Right off the bat the code you are using is nonstandard, outdated and broken. Find different example code to work from. This code is simply not worth the effort.
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    The DirectDraw interfaces have been deprecated and are no longer supported. It would be wise to discontinue using them.

    Once you get a valid IDirect3DDevice9 interface pointer loading textures via D3DX is a snap.

    Code:
    IDirect3DTexture9 *pTexture = 0;
    if (FAILED(D3DXCreateTextureFromFile(pDevice,"mytexture.bmp",pTexture)))
    {
        // Texture failed to load
    }
    If you do not want to use D3DX then you will need to:
    • Write the loading code for the file format
    • Create an IDirect3DTexture9 interface pointer via IDirect3DDevice9::CreateTexture().
    • Get the IDirect3DSurface9 interface pointer from the texture via IDirect3DTexture9::GetSurfaceLevel()
    • Lock the surface via IDirect3DSurface9::LockRect()
    • Copy the image data to the surface via memcpy while taking into account the pitch of the surface
    • Unlock the surface via IDirect3DSurface9::UnlockRect()
    • Release the surface since GetSurfaceLevel() increases the ref count on IDirect3DTexture9
    Last edited by VirtualAce; 09-16-2011 at 09:02 PM.

  5. #5
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    When I compile with debugging information included, I get this from my compiler. (dev-c++)

    An Access Violation (Segmentation Fault) raised in your program
    That's the only information it gives...

    I rather use the old DirectDraw (directx 7) interfaces, since I'm just learning the reins of DX. But what is pDevice? A pointer to an offscreen surface?

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I rather use the old DirectDraw (directx 7) interfaces, since I'm just learning the reins of DX. But what is pDevice? A pointer to an offscreen surface?
    What you would rather do is a moot point. It is a fact that DirectX7 interfaces are deprecated and thus are no longer supported. This means that driver manufacturers do not care if they break old interfaces due to new features b/c they have been marked deprecated. Most of them probably still work but it is a bad idea to write software that relies on them since this may not always be the case.

    I suggest you buy a book on Direct3D before continuing.

  7. #7
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    I blew that buying a book on DirectDraw

  8. #8
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well a book on DirectX7 today should not cost more than a few bucks and most are out of print according to Amazon. Spend $19.99 or so and get you a good book on Direct3D. I can't even get half a tank of gas in my car for $19.99 so that is pretty cheap by today's standards.

  9. #9
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    Well, thanks for the advice I'll try looking

    But for now, I really just want to solve this mystery. The error i got is because of a messed up pointer. So perhaps it is trying to allocate to much in Game_Main().

    I just think the problem is unrelated to DirectX, and more related to a bug in the memory functions called. Perhaps a value is wrong? or a pointer isn't initialized correctly...

  10. #10
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    Does anyone know if my memcpy/memset functions are correct. All I'm trying to do it is copy the bitmap data, onto the primary surface to display. Is there a problem with allocating memory for the screen, 1280 x 1024 x 4 (32 bits) Remember it's a 24 bit image, but it won't let me select the screen res in 24 bits (reports error)

    It doesn't make any sense to me why it won't run correctly?

  11. #11
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well I do not know because I do not have to allocate memory for the screen in any of my graphics applications. I have not done DirectDraw in nearly 10 years so I remember next to nothing about it.

    Go download the latest Direct3D SDK. It shows in the SDK how to get Direct3D up and running. Once you do that you can then create a texture, lock the surface, and do a memcpy to it.
    The important thing about Direct3D surfaces is that you must take the surface pitch into account. The pitch is the number of bytes in one row of the surface so this must be converted to the pixel data type you are using for the surface. This varies depending on the surface format. If the surface format is D3DFMT_A8R8G8B8 or some other 32-bits per pixel format then a simple block memcpy will do. If it is not then you will need to take into account the leftover bytes on the row.
    Last edited by VirtualAce; 09-19-2011 at 07:31 PM.

  12. #12
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    As a matter of interest, many of the better libraries for handling different image formats help with the handling of stride/pitch with very reasonable methods. (Intel's JPEG library and "libpng" for example.) Many allow you to request orientation and process the image by rows so you can adjust the stride/pitch as you load the image; with those methods and a properly formatted chunk of memory you are only a single `memcpy' call away.

    Soma

  13. #13
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    I just need a fix for the current code I have. I understand you guys are trying to supply a good solution, but this code bug doesn't make any sense. If someone could just take a look, it's well commented, so it really shouldn't be hard to find the bug for an experienced programmer. Is there a step I'm missing in the process of loading the bitmap? Is the video mode correct? Am I copying memory to the primary surface correctly for the selected video mode?

    Thanks, but more libraries and SDK's is not what I'm looking for as a solution.
    Last edited by binks; 09-20-2011 at 03:39 PM.

  14. #14
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I'm afraid I cannot help you any further since I do not remember much about DirectDraw 7. The one thing I do remember is that I am glad I am no longer using it.

  15. #15
    Registered User
    Join Date
    Mar 2011
    Posts
    216
    Thanks anyways, hopefully someone else can reply and help.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. loading a bitmap
    By hadi0x7c7 in forum C Programming
    Replies: 4
    Last Post: 06-04-2010, 03:12 PM
  2. Loading a bitmap
    By Homunculus in forum C++ Programming
    Replies: 19
    Last Post: 11-05-2007, 01:24 PM
  3. Loading Bitmap under VC++
    By abu in forum Windows Programming
    Replies: 1
    Last Post: 05-14-2004, 01:07 AM
  4. Loading bitmap in dll
    By Mithoric in forum Windows Programming
    Replies: 2
    Last Post: 12-22-2003, 01:53 PM
  5. No one can seem to help me, loading bitmap
    By Shadow12345 in forum C++ Programming
    Replies: 7
    Last Post: 12-28-2002, 01:22 PM