0

I am working with the win32 API, and I wrote a simple program to draw 100 random pixels ten times a second. However, when I compile and run the code, the screen only refreshes just around once a second. I would debug it but I am working on a locked down device and my IDE doesn't have debugging. I have changed all variables I can find referencing the timer function and nothing is working. I am compiling using gcc. Here is the code:

#include <windows.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
const int ID_TIMER = 1;

void DrawRandom(HDC hdc);


//Double buffering implementation 
static void Paint(HDC hdc, RECT* prc){
    //Declares our varibles
    HDC hdcMem;
    HBITMAP hbmMem, hbmOld;
    HBRUSH hbrBkGnd;
    POINT Border;
    //Creates creates compatible device context
    hdcMem = CreateCompatibleDC(hdc);

    //Create bitmap big enough for our display
    hbmMem = CreateCompatibleBitmap(hdc, prc->right, prc->bottom);

    //Select the bitmap into the offscreen DC
    hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);

    //Erase the background
    hbrBkGnd = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
    FillRect(hdcMem, prc, hbrBkGnd);
    DeleteObject(hbrBkGnd);

    //Gets the size of our border
    Border.x = prc->right;
    Border.y = prc->bottom;

    
    //Draws random pixels
    DrawRandom(hdcMem);

    //BLT the changes to the screen dc
    BitBlt(hdc, 0, 0, prc->right, prc->bottom, hdcMem, 0, 0, SRCCOPY);

    //Memory manegment
    SelectObject(hdcMem, hbmOld);
    DeleteObject(hbmMem);
    DeleteDC(hdcMem);
}
//Sets up our window
int WINAPI 
WinMain (HINSTANCE hInstance, HINSTANCE hPrevInst, LPTSTR lpCmdLine, int nShowCmd) {
    
    MSG  msg;
    WNDCLASSW wc = {0};

    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpszClassName = L"Cube!";
    wc.hInstance     = hInstance;
    wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    wc.lpfnWndProc   = WndProc;
    wc.hCursor       = LoadCursor(0, IDC_ARROW);

    

    RegisterClassW(&wc);
    CreateWindowW(wc.lpszClassName, L"Cube",
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                100, 100, 300, 250, NULL, NULL, hInstance, NULL);

    while (GetMessage(&msg, NULL, 0, 0)) {
    
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }


    return (int) msg.wParam;
}
//Calls our buffer and initilizes timer
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam) {
    
    switch(msg) {
         //Initilizes timer
        case WM_CREATE:
        {
            UINT ret;

            ret = SetTimer(hwnd, ID_TIMER, 50, NULL);
        }
        break;
        case WM_ERASEBKGND:
            //Disables auto clear
            return (LRESULT)1; 
        break;
        //Makes sure the window closes
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        //This is what initilizes the contents of the window
        case WM_PAINT:
        {
            RECT rcClient;
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            
            GetClientRect(hwnd, &rcClient);
            Paint(hdc, &rcClient);

            EndPaint(hwnd, &ps);
        }
        break;
        //This is where the main update loop is
        case WM_TIMER:
        {
            RECT rcClient;
            HDC hdc = GetDC(hwnd);

            GetClientRect(hwnd, &rcClient);

            Paint(hdc, &rcClient);
        }
        break;
        //Kills the timer
        case WM_DESTROY:
            KillTimer(hwnd, ID_TIMER);
            PostQuitMessage(0);
        break;
        //Make sures the program closes
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

void DrawRandom(HDC hdc){
    srand(time(NULL));
    for(int i = 0;i < 100;i++){
        int x = rand() % 400;
        int y = rand() % 400;

        SetPixel(hdc, x, y, RGB(0,0,0));
    }
}
  • 5
    move your `srand(time(NULL))` to `WinMain`. By reseeding the random number generator you're getting _the same_ results for every timer call that happens in the same *second* – Chad Aug 24 '23 at 14:10
  • Note also that creating a bitmap is a rather expensive operation. That should not be done any more often than necessary, usually only in response to window size changes (`WM_SIZE`). – IInspectable Aug 24 '23 at 14:36
  • @IInspectable what would you recommend instead, I am only using set pixel as a way to learn about low level computer graphics and this is what I was recommended for double buffering. – Mason Cooreman Aug 24 '23 at 15:41
  • Create the bitmap only once and keep reusing it. Whenever you receive a `WM_SIZE` (or [`WM_EXITSIZEMOVE`](https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-exitsizemove)) message, check to see if the client area changed. If it has, destroy the old bitmap and create a new one of the appropriate size. – IInspectable Aug 24 '23 at 16:04
  • 1
    Side note: [rand() Considered Harmful](https://learn.microsoft.com/en-us/events/goingnative-2013/rand-considered-harmful) – Jesper Juhl Aug 24 '23 at 18:10
  • `time(NULL)` is a *horribly bad* seed, regardless of the generator you use. – Jesper Juhl Aug 24 '23 at 18:12
  • 1
    Never have I walked away from a Stephan T. Lavavej talk bored or without having learned something new. Now I know that `mt19937` is actually fast, and 1729 is the smallest taxicab number. – IInspectable Aug 24 '23 at 19:22
  • 1
    @JesperJuhl that was a super interesting video, I just implemented that as a test but in the future ill make sure to use mt19937 and random_device – Mason Cooreman Aug 26 '23 at 20:58

1 Answers1

5

srand(time(NULL)) seeds the pseudo-random number generator rand() Seeding it means it sets the initial starting value.

Since you call srand(time(NULL)) inside your DrawRandom() function, that means the subsequent calls to rand() will have the same values any time DrawRandom() is called and time(NULL) returns the same value. time(NULL) is giving you seconds resolution, which is why you see your changes only happening once per second.

Chad
  • 18,706
  • 4
  • 46
  • 63