Thread: How to clear the image before redrawing it?

  1. #1
    Registered User
    Join Date
    Sep 2011
    Posts
    4

    How to clear the image before redrawing it?

    Hello. I am reading a book and there was an exercise after a chapter, and I can't solve it... I need to modify the GameLoop so that the image will move around the window (in my understanding - the previously drawn image would be deleted, while the new one would be drawn). I tried putting the GameEnd release codes on the end of the drawing code, but apparently it didn't work...

    It also would be nice if you'd explain it in a few words if it isn't self-explanatory, I want to understand it.

    Code:
    #include <windows.h>
    #include <iostream>
    #include <time.h>
    using namespace std;
    
    const string APPTITLE = "Game Loop";
    HWND window;
    HDC device;
    bool gameover = false;
    
    
    /**
     ** Loads and draws a bitmap from a file and then frees the memory
     **/
    void DrawBitmap(char *filename, int x, int y)
    {
        //load the bitmap image
        HBITMAP image = (HBITMAP)LoadImage(0,"c.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
    
        //read the bitmap's properties
        BITMAP bm;
        GetObject(image, sizeof(BITMAP), &bm);
    
        //create a device context for the bitmap
        HDC hdcImage = CreateCompatibleDC(device);
        SelectObject(hdcImage, image);
    
        //draw the bitmap to the window (bit block transfer)
        BitBlt( 
            device,                  //destination device context
            x, y,                    //x,y location on destination
            bm.bmWidth, bm.bmHeight, //width,height of source bitmap
            hdcImage,                  //source bitmap device context
            0, 0,                    //start x,y on source bitmap
            SRCCOPY);                //blit method
    
        //delete the device context and bitmap
        DeleteDC(hdcImage);
        DeleteObject((HBITMAP)image);
    }
    
    /**
     ** Startup and loading code goes here
     **/
    bool Game_Init()
    {
        //start up the random number generator
        srand(time(NULL));
    
        return 1;
    }
    
    /**
     ** Update function called from inside game loop
     **/
    void Game_Run()
    {
        if (gameover == true) return;
    
        //get the drawing surface
        RECT rect;
        GetClientRect(window, &rect);
    
        //draw bitmap at random location
        int x = rand() % (rect.right - rect.left);
        int y = rand() % (rect.bottom - rect.top);
        DrawBitmap("c.bmp", x, y);
    }
    
    /**
     ** Shutdown code
     **/
    void Game_End()
    {
        //free the device
        ReleaseDC(window, device);
    }
    
    /**
     ** Window callback function
     **/
    LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message) 
        {
            case WM_DESTROY:
                gameover = true;
                PostQuitMessage(0);
                break;
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    
    /**
     ** MyRegiserClass function sets program window properties
     **/
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
        //create the window class structure
        WNDCLASSEX wc;
        wc.cbSize = sizeof(WNDCLASSEX); 
    
        //fill the struct with info
        wc.style         = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc   = (WNDPROC)WinProc;
        wc.cbClsExtra     = 0;
        wc.cbWndExtra     = 0;
        wc.hInstance     = hInstance;
        wc.hIcon         = NULL;
        wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
        wc.lpszMenuName  = NULL;
        wc.lpszClassName = APPTITLE.c_str();
        wc.hIconSm       = NULL;
    
        //set up the window with the class info
        return RegisterClassEx(&wc);
    }
    
    /**
     ** Helper function to create the window and refresh it
     **/
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
        //create a new window
        window = CreateWindow(
           APPTITLE.c_str(),              //window class
           APPTITLE.c_str(),              //title bar
           WS_OVERLAPPEDWINDOW,   //window style
           CW_USEDEFAULT,         //x position of window
           CW_USEDEFAULT,         //y position of window
           640,                   //width of the window
           480,                   //height of the window
           NULL,                  //parent window
           NULL,                  //menu
           hInstance,             //application instance
           NULL);                 //window parameters
    
        //was there an error creating the window?
        if (window == 0) return 0;
    
        //display the window
        ShowWindow(window, nCmdShow);
        UpdateWindow(window);
    
        //get device context for drawing
        device = GetDC(window);
    
        return 1;
    }
    
    /**
     ** Entry point function
     **/
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
        MSG msg;
    
        //create window
        MyRegisterClass(hInstance);
        if (!InitInstance (hInstance, nCmdShow)) return 0;
    
        //initialize the game
        if (!Game_Init()) return 0;
    
        // main message loop
        while (!gameover)
        {
            //process Windows events
            if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            
            //process game loop
            Game_Run();
        }
    
        //free game resources
        Game_End();
    
        return msg.wParam;
    }

  2. #2
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    A lot to cover in one post...

    Let me know how you go and post any issues.

    You need to copy the image from your 'device' HDC to the screen DC.

    This is done in response to a WM_PAINT msg.

    In your callback;

    Code:
    //paint handler, should not contain more than a sinlge BitBlt()
    CASE WM_PAINT:
    	
    PAINTSTRUCT ps = {0};
    
    //get the area to draw and the screen HDC
    HDC hdcPaint = BeginPaint(hWnd, &ps);
    
    //copy the device HDC to the screen HDC using the minimum rectangle we can
    BitBlt(hdcPaint, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, device, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
    
    //clean up 
    EndPaint(hWnd, &ps);
    
    //return ? //forget what shoud be returned to show we processed the paint
    break;
    Another issue is your DrawBitmap() method. It is more like a 'LoadBitmap' function, called once (like srand).

    You should only load the image once, not every time.
    You should only create the compatible DC once, not every time.

    These things should be done in the WM_CREATE or WM_INITDIALOG msg.

    You should move the GetDC() to this msg as well.
    You should ReleaseDC() any DC you 'get' and delete any DC you create.
    Every time you use SelectObject() you should catch the returned GDI object.

    You should clean up hdcImage, image etc in the Game_End() method.

    Code:
    void DrawBitmap(char *filename, int x, int y)
    {
    	static rect rcLastImagePos = {0}; //holds where we last drew the image
    
    	//clear last image by colouring the area white
    	FillRect(device, rcLastImagePos , GetStockObject(device, WHITE_BRUSH));
    
    	//update the position of the image
    	rcLastImagePos.left = x;
    	rcLastImagePos.top = y;
    	rcLastImagePos.right = rcLastImagePos.left + bm.bmWidth; //will need to pass the bitmap dimensions into this method or make global (not recommended)
    	rcLastImagePos.bottom = rcLastImagePos.top + bm.bmHeight;
    	
        	//draw the bitmap to the window (bit block transfer)
        	BitBlt( 
            	device,                  //destination device context
           		x, y,                    //x,y location on destination
            	bm.bmWidth, bm.bmHeight, //width,height of source bitmap
            	hdcImage,                  //source bitmap device context
            	0, 0,                    //start x,y on source bitmap
            	SRCCOPY);                //blit method
    
    ///////// EDIT! Forgot this bit....... ////
    
                  //generate a WM_PAINT msg
                  InvalidateRect(hWnd, &rcLastImagePos, FALSE); //not the correct area, but will let you work that out....
                  //send directly to the callback, bypassing the OS queue
                  UpdateWindow(hWnd);
    }
    Last edited by novacain; 09-05-2011 at 02:27 AM. Reason: Forgot some important code!
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Stop PictureBox from redrawing?
    By h3ro in forum C# Programming
    Replies: 0
    Last Post: 09-06-2009, 10:09 AM
  2. redrawing a symbol on keypress.
    By rickyoswaldiow in forum Windows Programming
    Replies: 3
    Last Post: 10-22-2006, 08:24 AM
  3. Redrawing
    By maxorator in forum Windows Programming
    Replies: 6
    Last Post: 11-05-2005, 01:34 AM
  4. How redrawing works
    By ChadJohnson in forum Windows Programming
    Replies: 5
    Last Post: 07-14-2005, 11:01 PM
  5. Redrawing the Screen.
    By Ranedhel in forum C++ Programming
    Replies: 2
    Last Post: 07-15-2003, 04:57 PM