Results 1 to 5 of 5

Thread: Double buffering a rectangular area

  1. #1
    Administrator James's Avatar
    Join Date
    May 2010
    Location
    on the intraweb
    Posts
    3,180

    Default Double buffering a rectangular area

    Here is what I'm trying to do. I have credits that are scrolling in a certain part of my main window.
    I'm running into 1 of 2 issues.

    1. If I invalidate hWnd (main window), and it repaints, it causes everything to flicker, and causes some lag.
    2. If I only redraw it once, then the area doesn't repaint and it smears the text as it's scrolling.

    Objective:
    I'm trying to get only a portion of my main window to update not the whole window. I'm not sure how to do this.
    I'm assuming I would use RECT like I'm using, but I'm not sure how to only redraw that part of the window properly.

    Here is my code.

    Main.cpp

    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
    hInst = hInstance;


    //Main window
    hWnd = CreateWindow("mainDialog", "SEAL Reeemiiiiix", WS_POPUP | WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, ((getImageWidth(L"main.png"))+ 5), ((getImageHeight(L"main.png")) + 26), NULL, NULL, hInstance, NULL);


    //My scrolling credits
    scrollingCredits = CreateWindow("Static", "", WS_CHILDWINDOW | WS_VISIBLE | ES_READONLY | SS_OWNERDRAW, 10, 300, 300, 80, hWnd, (HMENU)IDB_SCROLLINGCREDITS, hInstance, NULL);


    if (!hWnd)
    {
    return FALSE;
    }


    CenterWindow(hWnd);
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);


    return TRUE;
    }


    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    static RECT pRect = {10, 300, 260, 380};


    switch(message)
    {
    case WM_DRAWITEM:
    {
    if(wParam == IDB_SCROLLINGCREDITS)
    {
    StartScrolling(wParam, lParam);
    }
    }
    break;


    case WM_CREATE:
    {
    //scrollingCredits
    SetTimer(hWnd, 1, 100, NULL);
    }
    break;


    case WM_ERASEBKGND:
    {
    //This minimizes some flickering
    return true;
    }
    break;


    case WM_TIMER:
    {
    InvalidateRect( scrollingCredits, NULL, FALSE );
    InvalidateRect( hWnd, &pRect, FALSE );
    }
    break;


    case WM_PAINT:
    {
    HDC hdcMem;
    HGDIOBJ hOld;
    HGDIOBJ hbmMem;
    static bool painted = false;
    hdc = BeginPaint(hWnd, &ps);


    // Create an off-screen DC for double-buffering
    GetClientRect( scrollingCredits, &pRect );
    hdcMem = CreateCompatibleDC(hdc);
    hbmMem = CreateCompatibleBitmap(hdc, 300, 80);


    hOld = SelectObject(hdcMem, hbmMem);


    //drawStuff(hdcMem, L"main.png", 0, 0);
    BitBlt(hdc, 10, 300, (getImageWidth(L"main.png")), (getImageHeight(L"main.png")), hdcMem, 10, 300, SRCCOPY);

    if(!painted)
    {
    painted = true;

    drawStuff(hdc, L"main.png", 0, 0);
    }


    //-------------------------------------
    //Delete our variables to free memory
    //-------------------------------------
    SelectObject(hdcMem, hOld);
    DeleteObject(hbmMem);
    DeleteDC (hdcMem);


    EndPaint(hWnd, &ps);
    }
    break;


    default:
    {
    return DefWindowProc(hWnd, message, wParam, lParam);
    }
    }
    return 0;
    }


    Here is the scrolling source code:

    //Disable unnecessary warnings
    #pragma warning(disable: 4267)


    //Our Window variable
    HWND scrollingCredits;


    char szCredit[][100] =
    {
    " Property of:",
    " ",
    "Midwest Palliative and Hospice CareCenter",
    "",
    " Created By:",
    " James"
    };


    const int nCreditLines = ( sizeof(szCredit) / 100 );
    const int nWaitTime = 100;
    const int x_dif = 10;
    const int y_end = (nCreditLines * (x_dif+1) );
    const int y_start = -90;


    void RollCredits( HDC dc )
    {
    static DWORD dwTime = 0;
    static int y_mod = y_start;


    if( dwTime <= GetTickCount() )
    {
    y_mod++;
    dwTime = (GetTickCount()+100);
    }


    if( y_mod == y_end)
    {
    y_mod = y_start;
    dwTime = (GetTickCount()+nWaitTime);
    }


    for( int i = 0; i < nCreditLines; i++)
    {
    int y = ((i * x_dif)) - y_mod;


    TextOut( dc , 0 ,y , szCredit[i], strlen(szCredit[i]) );
    }
    }


    void StartScrolling(WPARAM wParam, LPARAM lParam)
    {
    LPDRAWITEMSTRUCT pDrawItem = (LPDRAWITEMSTRUCT)lParam;


    if( wParam == IDB_SCROLLINGCREDITS )
    {
    static HFONT hFont = 0;


    if( hFont == 0 )
    {
    if( (hFont = CreateFont( 9,0,0,0,400,0,0,0, OEM_CHARSET,0,0,0,DEFAULT_PITCH | FF_SCRIPT,"terminal")) == 0 )
    {
    MessageBox( 0, "Failed to create font!\n", "Errr", 0 );
    PostQuitMessage(0);
    }
    }


    SelectObject( pDrawItem->hDC, hFont );


    SetBkMode( pDrawItem->hDC, TRANSPARENT);


    RollCredits( pDrawItem->hDC );
    }
    }


    Also here is my window rendering code (although I don't think this is relevant)

    void drawStuff(HDC hdc, const WCHAR *image, int x, int y)
    {
    Graphics gr(hdc);
    Image *img = new Image(image, false);
    gr.DrawImage(img, x, y, img->GetWidth(), img->GetHeight());


    delete img;
    }


    The smearing I am referring to is in the attachment.

    Any assistance is appreciated.
    Attached Thumbnails Attached Thumbnails smear.png  

  2. #2
    Developer Sor's Avatar
    Join Date
    Aug 2010
    Location
    The Medieval City of Bruges
    Posts
    747

    Default

    I notice you're creating and destroying the off-screen DC each time you draw. It makes more sense to create the DC once but large enough to draw the entire screen.
    Also you could use WS_CLIPCHILDREN to avoid updating the parts of the main window that clip with child windows and see if that helps.
    Morpheus Script (MoH) => You try to shoot yourself in the foot only to discover that MorpheusScript already shot your foot for you.

  3. #3
    Administrator James's Avatar
    Join Date
    May 2010
    Location
    on the intraweb
    Posts
    3,180

    Default

    The problem is though that even if I created a device context once, it still doesn't fix the issue with the window updating without flickering. I tried using WS_CLIPCHILDREN, but I couldn't see any effect int he app. It still caused flickering, even when I drew everything once outside of the main window with the scrolling text area.

    I appreciate the response though.

  4. #4
    Über Prodigy & Developer Razo[R]apiD's Avatar
    Join Date
    May 2010
    Location
    Poland, Lublin
    Posts
    3,257

    Default

    Save the context in global variable like Sor suggested. Free it in WM_DESTROY.

    Try not to invalidate the main window in WM_TIMER, it should get WM_PAINT when system knows it needs it. Invalidate just the static control.
    Another thing is that you might be redrawing in wrong order.

    First invalidate the window, then invalidate the control in that window.

  5. #5
    Über Prodigy & Developer Razo[R]apiD's Avatar
    Join Date
    May 2010
    Location
    Poland, Lublin
    Posts
    3,257

    Default

    Or even get rid of WM_DRAWITEM, and redraw the content of it in WM_TIMER (first clear old content with background redraw, and then paint fresh content on top of it)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •