-1

EDIT: I am aware this is the slowest way to draw a square, but I do need to set pixels individually for a separate purpose.


I'm pretty sure what I'm trying to do is create a Frame Buffer. I have the following code:

... /* Other Unrelated (<- I promise) Code */

    switch(message)
{
    /*  Window is being created*/
    case WM_CREATE: 
        return 0;
        break;
    /*  Window is closing*/
    case WM_CLOSE: 
        PostQuitMessage(0);
        return 0;
        break;
    /*  Window needs update*/
    case WM_PAINT: 
        hDC = BeginPaint(hwnd,&paintStruct);
        /*  Draw a Red Square pixel by pixel*/
        for (int x=100;x<300;x++) {
            for (int y = 300;y>100;y--) {
                SetPixel(hDC, x, y, 0x000000FF);
            }
        }

        EndPaint(hwnd, &paintStruct);
        return 0;
        break;
    default:
        break;
}

... /* Other Unrelated (<- I promise) Code*/

The desired result

A red square that doesn't show each pixel being drawn, but rather, just a red square being drawn instantaneously. To break it down, I want the memory to fill up before releasing it to video memory rather than going 1 by 1 to video memory (I hope I'm using the right words here...)


The problem

The opposite of the desired result, I am getting a quick drawing of the square from left right as each pixel is being set.


What I'm looking for

A command to enable output buffering to my window or a function to store pixels then draw them all at once, or any other method that would get me the desired result.

Thank you in advance. I think it would be helpful to say that I have only been programming in the C++ language for 5 days, and that any breaking down or direct answer would be greatly appreciated.

  • 1
    I think you need [`WS_EX_COMPOSITED`](https://msdn.microsoft.com/en-us/library/windows/desktop/ff700543.aspx) (which you would pass to [`CreateWindowEx`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680.aspx)) – Blorgbeard Jan 23 '18 at 21:34
  • Actually you want to **enable** output buffering. – user7860670 Jan 23 '18 at 21:34
  • @VTT okay I'll edit that in, and I'll check that WS_EX_COMPOSITED out blorgbeard. – Corpus Shmorpus Jan 23 '18 at 21:35
  • 4
    No. What you need is FillRect – David Heffernan Jan 23 '18 at 21:36
  • .. I am assuming the red square is example code to demonstrate slow drawing, but if not - yeah, just use FillRect. – Blorgbeard Jan 23 '18 at 21:37
  • @David No, I'm trying to avoid that. I am looking to set pixels individually for a specific purpose. I'm well aware of the "slowness" of what I am doing, but I have a few work-arounds up my sleeve. That is, once I learn assembly ;) – Corpus Shmorpus Jan 23 '18 at 21:37
  • 1
    Then it would be better to set pixels directly using DIB and then just bitblit it. – user7860670 Jan 23 '18 at 21:39
  • 1
    SetPixel is no good. Manipulate the bits of a bitmap yourself. – David Heffernan Jan 23 '18 at 21:40
  • @David Does that have the same effect? – Corpus Shmorpus Jan 23 '18 at 21:41
  • 1
    No, it's much faster. SetPixel is actually very slow. – Blorgbeard Jan 23 '18 at 21:44
  • 2
    Get a pointer to the bits of a bitmap. Manipulate them yourself. Then you are just writing directly to memory. The question was very confusing because FillRect is the correct way to do what you show there, but if course, what you showed in the question is not what you want to do. You want to have a different colour for each pixel. A quite different problem. Better to ask about the problem rather than your solution. – David Heffernan Jan 23 '18 at 21:48
  • @David Well said. I made an edit earlier which sums it up, I don't think I can make a random hex number without making it slower and expanding my code ample amounts. I'll stick with the edit – Corpus Shmorpus Jan 23 '18 at 21:49
  • @Blorgbeard Your first comment worked, would you mind adding an answer? – Corpus Shmorpus Jan 23 '18 at 21:55
  • You really don't want to do that. – David Heffernan Jan 23 '18 at 22:00
  • I don't really think that comment is going to work for your real use-case now that we know more about it. I honestly don't want to put my name on an answer saying that the right way to set a lot of pixels is to enable WS_EX_COMPOSITED. You can add an answer yourself if that's what you're going with, though. – Blorgbeard Jan 23 '18 at 22:02
  • 1
    Search for "memory device context" or even better "buffered paint API". I believe "Old New Thing" blog has some example code for the latter. That's the way the Windows common controls do their buffering. – zett42 Jan 23 '18 at 22:03
  • 1
    @MegaFirm You'd have so much more control at the per-pixel level efficiently by creating a DIB and blitting it as others suggested. It effectively serves as your back buffer. Quick snippet I use: https://paste.ofcode.org/AHdAPzYicUTPXXW9eS7UL6. Once you create that, you can manipulate everything through the `pixels` field directly without those expensive `SetPixel/GetPixel` calls. –  Jan 24 '18 at 01:20

1 Answers1

2

You need to create a memory HDC, and a bitmap, select the bitmap in to memory, draw on memory, then BitBlt the memory dc on to the final HDC. Example:

case WM_PAINT:
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);

    HDC memdc = CreateCompatibleDC(hdc);
    HBITMAP bitmap = CreateCompatibleBitmap(hdc, 300, 300);
    HBITMAP oldbmp = (HBITMAP)SelectObject(memdc, bitmap);

    for(int x = 100; x<300; x++)
        for(int y = 300; y>100; y--)
            SetPixelV(memdc, x, y, 0x000000FF);
    BitBlt(hdc, 0, 0, w, h, memdc, 0, 0, SRCCOPY);

    //cleanup:
    SelectObject(memdc, oldbmp);
    DeleteDC(memdc);
    DeleteObject(bitmap);
    EndPaint(hWnd, &ps);
    return 0;
}

Note that you have access to all GDI functions. In this example you can use FillRect instead:

RECT rc{ 100, 100, 300, 300 };
SetDCBrushColor(memdc, RGB(255, 0, 0));
FillRect(memdc, &rc, (HBRUSH)GetStockObject(DC_BRUSH));

Or use GetDIBits to manipulate the bitmap.

Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • 2
    Calling `SetPixel` and ignoring the return value doesn't make sense. It's the return value that makes the operation slow to being with. If you don't care about the current color of the pixel, call [SetPixelV](https://msdn.microsoft.com/en-us/library/windows/desktop/dd145079.aspx) instead. – IInspectable Jan 24 '18 at 09:56
  • I tried this and got a whole mess of errors. https://drive.google.com/file/d/1CroIgckAmyMGEmR2qRFLUMdDHbXWezeo/view?usp=sharing – Corpus Shmorpus Jan 26 '18 at 21:39
  • `SetPixelV` is from Gdi32 library, it's a standard library, the same library as `SetPixel` which you used earlier. Also you just post a picture of part of you error. If you want to keep this a secret then why bother asking questions. – Barmak Shemirani Jan 27 '18 at 01:09