-1

The program window wont update when I try to draw a rectangle. It isn't the program not responding because I can still draw the background, but the rectangle wont update and I don't know what to change. There are no errors popping up, and the only warning is:

Warning C28251 Inconsistent annotation for 'WinMain': this instance has no annotations.

This program is in two .cpp files, the first one doesn't create a window (make sure to set that in properties), and the second one does create a window.

Note: the first .cpp file is called render.cpp and is included in the second file.

Here is the code for debugging:

#include <Windows.h>

struct Render_State
{
    int width;
    int hight;
    void* memory;
    BITMAPINFO bitmap_info;
};

Render_State render_state;

void render_backround(HWND hwnd, int colour)
{
    if (WM_PAINT)
    {
        PAINTSTRUCT ps;

        HDC hdc = BeginPaint(hwnd, &ps);

        unsigned int* pixel = (unsigned int*)render_state.memory;
        for (int y = 0; y < render_state.hight; y += 1)
        {
            for (int x = 0; x < render_state.width; x += 1)
            {
                *pixel++ = colour;
            }
        }

        // render
        StretchDIBits(hdc, 0, 0, render_state.width, render_state.hight, 0, 0,
            render_state.width,
            render_state.hight,
            render_state.memory, &render_state.bitmap_info, DIB_RGB_COLORS, SRCCOPY); {}
        EndPaint(hwnd, &ps);
    }
}

void clear_screen(HWND hwnd, int colour)
{
    if (WM_PAINT)
    {
        PAINTSTRUCT ps;

        HDC hdc = BeginPaint(hwnd, &ps);

        unsigned int* pixel = (unsigned int*)render_state.memory;
        for (int y = 0; y < render_state.hight; y += 1)
        {
            for (int x = 0; x < render_state.width; x += 1)
            {
                *pixel++ = colour;
            }
        }
        // render
        StretchDIBits(hdc, 0, 0, render_state.width, render_state.hight, 0, 0, render_state.width,
            render_state.hight,
            render_state.memory, &render_state.bitmap_info, DIB_RGB_COLORS, SRCCOPY); {}
        EndPaint(hwnd, &ps);
    }
}

void draw_rect(HWND hwnd, int X, int Y, int X2, int Y2, int colour)
{
    if (WM_PAINT)
    {
        PAINTSTRUCT ps;

        HDC hdc = BeginPaint(hwnd, &ps);

        for (int y = Y; y < Y2; y++)
        {
            //  unsigned int* pixel = (unsigned int*)render_state.memory;
            size_t pixel = size_t(render_state.memory) + static_cast<size_t>(X) + static_cast<size_t> (y) * static_cast<size_t> (render_state.width);

            for (int x = X; x < X2; x++)
            {
                pixel += 0xf5500;
            }
        }
        // render
        StretchDIBits(hdc, X, Y, X2, Y2, X, Y, render_state.width, render_state.hight,
            render_state.memory, &render_state.bitmap_info, DIB_RGB_COLORS, SRCCOPY); {}
        EndPaint(hwnd, &ps);
    }
}
#include <Windows.h>

bool running = true;

#include "renderer.cpp"
LRESULT CALLBACK windows_callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LRESULT result = 0;
    switch (uMsg)
    {
    case WM_CLOSE:
    case WM_DESTROY:
    {
        PostQuitMessage(0);
    }
    break;

    case WM_SIZE:
    {
        RECT rect;
        GetClientRect(hwnd, &rect);
        render_state.width = rect.right - rect.left;
        render_state.hight = rect.bottom - rect.top;
        int size = render_state.width * render_state.hight * sizeof(unsigned int);
        if (render_state.memory) VirtualFree(render_state.memory, 0, MEM_RELEASE);
        render_state.memory = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        render_state.bitmap_info.bmiHeader.biSize = sizeof(render_state.bitmap_info.bmiHeader);
        render_state.bitmap_info.bmiHeader.biWidth = render_state.width;
        render_state.bitmap_info.bmiHeader.biHeight = render_state.hight;
        render_state.bitmap_info.bmiHeader.biPlanes = 1;
        render_state.bitmap_info.bmiHeader.biBitCount = 32;
        render_state.bitmap_info.bmiHeader.biCompression = BI_RGB;
         //render_backround(hwnd, 0xf2000);
        //clear_screen(hwnd, 0xff5500);
        draw_rect(hwnd, 3, 5, 50, 50, 0xff5500);
    }
    break;

    default:
    {
        result = DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    }
    return result;
}

int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    //compile window
    CHAR clsName[] = "test";
    WNDCLASSA window_class = {};
    window_class.style = CS_HREDRAW | CS_VREDRAW;
    window_class.lpszClassName = clsName;
    window_class.lpfnWndProc = windows_callback;
    //register clases
    ATOM atom = RegisterClassA(&window_class);
    if (0 == atom)
    {
        DWORD err = GetLastError();
        return 1;
    }

    // create window
    HWND window = CreateWindow(clsName, "game", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT,
        CW_USEDEFAULT, 720, 360, 0, 0, hInstance, 0);
    if (NULL == window)
    {
        DWORD err = GetLastError();
        return 1;
    }
    MSG message;
    HDC hdc = GetDC(window);

    // Main message loop:
    while (GetMessage(&message, nullptr, 0, 0))
    {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }
    //simulate

    //render
    StretchDIBits(hdc, 0, 0, render_state.width, render_state.hight, 0, 0, render_state.width,
        render_state.hight,
        render_state.memory, &render_state.bitmap_info, DIB_RGB_COLORS, SRCCOPY); {}
}
  • 3
    `if (WM_PAINT)` looks weird because `WM_PAINT` is a constant and it will always be true. What do you actually want to do here? – MikeCAT Mar 02 '21 at 13:11
  • you don't handle WM_PAINT in your switch in windows_callback – engf-010 Mar 02 '21 at 13:14
  • if (WM_Paint) is for when the program receves a paint mesage from the program – user14699592 Mar 02 '21 at 13:16
  • explane please. – user14699592 Mar 02 '21 at 13:16
  • If you are actually trying to draw a rectangle, then why make this mess instead of, you know, using [`Rectangle`](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-rectangle)? – IWonderWhatThisAPIDoes Mar 02 '21 at 13:27
  • 1
    If you want anything to be drawn ,you MUST properly handle WM_PAINT in your WNDPROC (in your case windows_callback ). If you don't do this properly (by calling BeginPaint(...) and EndPaint(...)) ,Windows keeps sending WM_PAINT until it's handled. – engf-010 Mar 02 '21 at 13:39
  • its a challenge and i didn't know you could do that – user14699592 Mar 02 '21 at 13:40
  • @engf-010 could you explane whith a full answer haw to handle WM_PAINT. – user14699592 Mar 02 '21 at 13:52
  • Well not really ,it all depends what must be drawn (your task) and this must be done after BeginPaint and before EndPaint. Basically you're doing the right thing in render_background(...) ,it just isn't called. Call render_background(...) in your switch-statement when case WM_PAINT. – engf-010 Mar 02 '21 at 13:58
  • @engf-010 thats not the problem background draws but rect doesn't – user14699592 Mar 02 '21 at 14:08
  • In short: all drawing must be done between BeginPaint and EndPaint and those MUST be called in reaction on WM_PAINT. I can't tell you more than that. Triggering WM_PAINT can be done by calling the InvalidateRect function. – engf-010 Mar 02 '21 at 14:15
  • What is `if (WM_PAINT)`? And this is C not C++. Win32 API is a little harder than your knowledge. – i486 Mar 02 '21 at 20:25
  • [Get Started with Win32 and C++](https://learn.microsoft.com/en-us/windows/win32/learnwin32/learn-to-program-for-windows). – IInspectable Mar 02 '21 at 20:40
  • @i486 this is c++ i only instaled a c++ compiler – user14699592 Mar 03 '21 at 06:54
  • @IInspectable thanks for the link will check it out! – user14699592 Mar 03 '21 at 06:55
  • @user14699592 C++ compiler includes C compiler and your program above is C only. – i486 Mar 03 '21 at 08:08
  • @i486 ok is it posible to still program in c++ in the same program? – user14699592 Mar 03 '21 at 08:41
  • the totorial said it was c++ so is he lying? – user14699592 Mar 03 '21 at 10:59
  • @i48 I'm not aware of a C compiler that would understand `nullptr`. Likewise, I'm not aware of any C++ compiler that includes a C compiler. – IInspectable Mar 03 '21 at 13:47
  • @IInspectable For example, Borland C++ compiler has option to treat `.c` files as C language and `.cpp` for C++. I.e. C++ features are not allowed for .c file. My note was because of wrong `c++` tag of the question. – i486 Mar 03 '21 at 13:51
  • @i48 MSVC also has the option to compile files with arbitrary file extension as C. That doesn't mean that a C compiler were included in the C++ compiler. They are distinct binaries (c1.dll and c1xx.dll). And you haven't explained yet which C compiler were to understand `nullptr`. If you cannot, then maybe you are wrong rather than the question tags. – IInspectable Mar 03 '21 at 13:57
  • @IInspectable If you look at the whole product "C++ compiler" (IDE, etc.) then the C compiler is included inside (as module, separate executable, etc.) About `nullptr` - from all lines of code do you get this keyword as evidence that code is in C++ and not C? Will `GetMessage` work with `NULL` (or even `0`) instead of `nullptr`? Yes, it will. Then the above code is pure C. It is correct to put `NULL` in the place of `nullptr` and I hope you understand it. If you want to be picky is another matter. – i486 Mar 03 '21 at 14:21
  • @i48 The OP has posted C++ code, and is interested in a solution that compiles with a C++ compiler. The [tag:c++] tag communicates this accurately. – IInspectable Mar 03 '21 at 14:32
  • i wasnt the one who said this was c code just making it clear. – user14699592 Mar 05 '21 at 11:19

2 Answers2

1

In the draw_rect function, pixel is an unsigned int type.

for (int x = X; x < X2; ++x)
{
     pixel += 0xf5500;
}

pixel += 0xf5500 will only increase the size of pixel, because pixel is not an address.

This is the reason why square cannot be drawn =>render_state.memory has no color data.

You need to declare pixel as a pointer variable. As you declared in the render_backround function.

size_t* pixel = (size_t*)render_state.memory;

for (int y = 0; y < Y2; y += 1)
{
    for (int x = 0; x < X2; x += 1)
    {
        *pixel++ = colour;
    }
}   

The whole draw_rect code,

 void draw_rect(HWND hwnd, int X, int Y, int X2, int Y2, int colour)
{
    if (WM_PAINT)
    {
        PAINTSTRUCT ps;

        HDC hdc = BeginPaint(hwnd, &ps);
     
        size_t* pixel = (size_t*)render_state.memory;

        for (int y = 0; y < Y2; y += 1)
        {
            for (int x = 0; x < X2; x += 1)
            {
                *pixel++ = colour;
            }
        }     
        render_state.bitmap_info.bmiHeader.biWidth = X2;
        render_state.bitmap_info.bmiHeader.biHeight = Y2;
        StretchDIBits(hdc, X, Y, X2, Y2, X, Y, X2, Y2,
            render_state.memory, &render_state.bitmap_info, DIB_RGB_COLORS, SRCCOPY);
        EndPaint(hwnd, &ps);
    }
}

Note: Responsible only for your current code examples. As stated in the comment section, you can re-read the drawing of win32 window, especially the WindowProc callback function.

Strive Sun
  • 5,988
  • 1
  • 9
  • 26
0

As stated in comments, the problem is that you are not handling the WM_PAINT message in your windows_callback() at all. You need to do something more like this instead:

renderer.h

#ifndef renderer_H
#define renderer_H

#include <Windows.h>

struct Render_State
{
    int width;
    int hight;
    void* memory;
    BITMAPINFO bitmap_info;
};

void render_background(HDC hdc, Render_State &state, int colour);
void clear_screen(HDC hdc, Render_State &state, int colour);
void draw_rect(HDC hdc, Render_State &state, int X, int Y, int X2, int Y2, int colour);

#endif

renderer.cpp

#include "renderer.h"

void render_background(HDC hdc, Render_State &state, int colour)
{
    unsigned int* pixel = static_cast<unsigned int*>(state.memory);
    for (int y = 0; y < state.hight; ++y)
    {
        for (int x = 0; x < state.width; ++x)
        {
            *pixel++ = colour;
        }
    }

    // render
    StretchDIBits(hdc,
        0, 0, state.width, state.hight,
        0, 0, state.width, state.hight,
        state.memory, &state.bitmap_info,
        DIB_RGB_COLORS, SRCCOPY);
} 

void clear_screen(HDC hdc, Render_State &state, int colour)
{
    render_background(hdc, state, colour);
}

void draw_rect(HDC hdc, Render_State &state, int X, int Y, int X2, int Y2, int colour)
{
    for (int y = Y; y < Y2; ++y)
    {
        //  unsigned int* pixel = static_cast<unsigned int*>(state.memory);
        size_t pixel = size_t(state.memory) + static_cast<size_t>(X) + static_cast<size_t>(y) * static_cast<size_t>(state.width);
                
        for (int x = X; x < X2; ++x)
        {
            pixel += 0xf5500;
        }
    }

    // render
    StretchDIBits(hdc,
        X, Y, X2, Y2,
        X, Y, state.width, state.hight,
        state.memory, &state.bitmap_info,
        DIB_RGB_COLORS, SRCCOPY);
}
#include <Windows.h>
#include "renderer.h"

bool running = true;
Render_State render_state = {};

LRESULT CALLBACK windows_callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_CLOSE:
            DestroyWindow(hwnd);
            return 0;

        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
   
        case WM_SIZE:
        {
            RECT rect;
            GetClientRect(hwnd, &rect);
            render_state.width = rect.right - rect.left;
            render_state.hight = rect.bottom - rect.top;
            int size = render_state.width * render_state.hight * sizeof(unsigned int);
            if (render_state.memory) VirtualFree(render_state.memory, 0, MEM_RELEASE);
            render_state.memory = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
            render_state.bitmap_info.bmiHeader.biSize = sizeof(render_state.bitmap_info.bmiHeader);
            render_state.bitmap_info.bmiHeader.biWidth = render_state.width;
            render_state. bitmap_info.bmiHeader.biHeight = render_state.hight;
            render_state. bitmap_info.bmiHeader.biPlanes = 1;
            render_state. bitmap_info.bmiHeader.biBitCount = 32;
            render_state .bitmap_info.bmiHeader.biCompression = BI_RGB;
            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
        }
   
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);

            // render_background(hdc, render_state, white);
            // clear_screen(hdc, render_state, 0xff5500);
            draw_rect(hdc, render_state, 30, 50, 500, 500, 0xff5500);

            EndPaint(hwnd, &ps);
            return 0;
        }
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    //compile window
    CHAR clsName[] = "test";
    WNDCLASSA window_class = {};
    window_class.style = CS_HREDRAW | CS_VREDRAW;
    window_class.lpszClassName = clsName;
    window_class.lpfnWndProc = windows_callback;

    //register class
    if (!RegisterClassA(&window_class))
    {
        DWORD err = GetLastError();
        return 1;
    }

    // create window
    HWND window = CreateWindow(clsName, "game", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, 
        CW_USEDEFAULT, 720, 360, 0, 0, hInstance, 0);
    if (!window)
    {
        DWORD err = GetLastError();
        return 1;
    }

    // Main message loop:
    MSG message;
    while (GetMessage(&message, nullptr, 0, 0))
    {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }

    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • thanks so much this probably too you a long time ill tell you if it works – user14699592 Mar 03 '21 at 06:52
  • im getting an error Error LNK2001 unresolved external symbol "void __cdecl draw_rect(struct HDC__ *,struct Render_State &,int,int,int,int,int)" (?draw_rect@@YAXPEAUHDC__@@AEAURender_State@@HHHHH@Z) – user14699592 Mar 10 '21 at 11:19
  • and unresolved external simbal which is kinda the same – user14699592 Mar 10 '21 at 11:20
  • it works if I comment out all the draw_ functions eg draw_rect(); – user14699592 Mar 10 '21 at 11:23
  • also could you explaine the workings of this code im trying to learn as much as i can. – user14699592 Mar 10 '21 at 11:25
  • @user14699592 The main file is including `renderer.h`, which declares `draw_rect()`, and the `WM_PAINT` handler is actually calling `draw_rect()`, but the linker can't find the implementation of `draw_rect()` to satisfy the call. Which means you are likely not compiling `renderer.cpp` into an object file and linking it into your EXE. – Remy Lebeau Mar 10 '21 at 15:43
  • it is not compiled into a program no – user14699592 Mar 12 '21 at 08:53
  • that is the whole point it is to make it faster and easier to program – user14699592 Mar 12 '21 at 08:54
  • @user14699592 well, then that explains the error. You have to compile and link `renderer.cpp` in order to use its implemented functions in other source files. – Remy Lebeau Mar 12 '21 at 08:55
  • if this is the only way you'll answer the problem i don't think i could accept – user14699592 Mar 12 '21 at 08:56
  • the answer because, it changes my program to something I don't want . – user14699592 Mar 12 '21 at 08:58
  • @user14699592 then you clearly don't understand how the compiler and linker work together to produce an executable. I suggest you get yourself some [good C++ books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Remy Lebeau Mar 12 '21 at 08:59
  • so there is no way to have a {.cpp } file that doesn't render? – user14699592 Mar 14 '21 at 10:37
  • your answers are quite vague please explane what you mean by compiling it because it doesnt seem likly that turning 'render.cpp' into a comand window would help. – user14699592 Mar 14 '21 at 11:07
  • @user14699592 you have to tell the *compiler* to process every `.cpp` source file in your project, not just the main `.cpp` source file. That will produce a binary object file for each source file. You then have to tell the *linker* to link all of those object files together to produce the final executable. Now, how you do this depends on which particular compiler/linker you are using, but it basically comes down to either 1) issuing appropriate commands to them on the command line, either manually or via a makefile; 2) using an IDE to handle everything for you. – Remy Lebeau Mar 14 '21 at 17:55
  • @user14699592 "unresolved external" errors happen when you fail to link every object file that is required. Every function that is called, every class/struct that is used, is referenced by the object files. The linker is the one that searches through them all and fills in the details about which reference refers to which thing. This is what allows you to implement a function/class in one source file and use it in another source file, like your example is doing for the drawing functions. – Remy Lebeau Mar 14 '21 at 17:59
  • sadly this doesn't work is it something I have done please test it to see if it works for you – user14699592 Mar 30 '21 at 15:36