Hello I am following along with the handmade hero game and I am getting this error: "Unhandled exception at 0x013B56B2 in win32_handmade.exe: 0xC000041D: An unhandled exception was encountered during a user callback."
I am not sure what is causing this because I have the exact same code that he had and when I build in a .bat I get no errors.
Visual Studio is saying that the error is occurring at line 62 which is where the second internal void is at, but the error has been occurring no matter what is there.
#include <windows.h>
#include <stdint.h>
#define internal static
#define local_persist static
#define global_variable static
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
// TODO(casey): This is a global for now.
global_variable bool Running;
global_variable BITMAPINFO BitmapInfo;
global_variable void *BitmapMemory;
global_variable int BitmapWidth;
global_variable int BitmapHeight;
global_variable int BytesPerPixel = 4;
internal void
RenderWeirdGradient(int BlueOffset, int GreenOffset)
{
int Width = BitmapWidth;
int Height = BitmapHeight;
int Pitch = Width * BytesPerPixel;
uint8 *Row = (uint8 *)BitmapMemory;
for (int Y = 0;
Y < BitmapHeight;
++Y)
{
uint32 *Pixel = (uint32 *)Row;
for (int X = 0;
X < BitmapWidth;
++X)
{
uint8 Blue = (X + BlueOffset);
uint8 Green = (Y + GreenOffset);
*Pixel++ = ((Green << 8) | Blue);
}
Row += Pitch;
}
}
internal void
Win32ResizeDIBSection(int Width, int Height)
{
// TODO(casey): Bulletproof this.
// Maybe don't free first, free after, then free first if that fails.
if (BitmapMemory)
{
VirtualFree(BitmapMemory, 0, MEM_RELEASE);
}
BitmapWidth = Width;
BitmapHeight = Height;
BitmapInfo.bmiHeader.biSize = sizeof(BitmapInfo.bmiHeader);
BitmapInfo.bmiHeader.biWidth = BitmapWidth;
BitmapInfo.bmiHeader.biHeight = -BitmapHeight;
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = 32;
BitmapInfo.bmiHeader.biCompression = BI_RGB;
// NOTE(casey): Thank you to Chris Hecker of Spy Party fame
// for clarifying the deal with StretchDIBits and BitBlt!
// No more DC for us.
int BitmapMemorySize = (BitmapWidth*BitmapHeight)*BytesPerPixel;
BitmapMemory = VirtualAlloc(0, BitmapMemorySize, MEM_COMMIT,
PAGE_READWRITE);
// TODO(casey): Probably clear this to black
}
internal void
Win32UpdateWindow(HDC DeviceContext, RECT *ClientRect, int X, int Y, int
Width, int Height)
{
int WindowWidth = ClientRect->right - ClientRect->left;
int WindowHeight = ClientRect->bottom - ClientRect->top;
StretchDIBits(DeviceContext,
/*
X, Y, Width, Height,
X, Y, Width, Height,
*/
0, 0, BitmapWidth, BitmapHeight,
0, 0, WindowWidth, WindowHeight,
BitmapMemory,
&BitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
}
LRESULT CALLBACK
Win32MainWindowCallback(HWND Window,
UINT Message,
WPARAM WParam,
LPARAM LParam)
{
LRESULT Result = 0;
switch (Message)
{
case WM_SIZE:
{
RECT ClientRect;
GetClientRect(Window, &ClientRect);
int Width = ClientRect.right - ClientRect.left;
int Height = ClientRect.bottom - ClientRect.top;
Win32ResizeDIBSection(Width, Height);
} break;
case WM_CLOSE:
{
// TODO(casey): Handle this with a message to the user?
Running = false;
} break;
case WM_ACTIVATEAPP:
{
OutputDebugStringA("WM_ACTIVATEAPP\n");
} break;
case WM_DESTROY:
{
// TODO(casey): Handle this as an error - recreate window?
Running = false;
} break;
case WM_PAINT:
{
PAINTSTRUCT Paint;
HDC DeviceContext = BeginPaint(Window, &Paint);
int X = Paint.rcPaint.left;
int Y = Paint.rcPaint.top;
int Width = Paint.rcPaint.right - Paint.rcPaint.left;
int Height = Paint.rcPaint.bottom - Paint.rcPaint.top;
RECT ClientRect;
GetClientRect(Window, &ClientRect);
Win32UpdateWindow(DeviceContext, &ClientRect, X, Y, Width, Height);
EndPaint(Window, &Paint);
} break;
default:
{
// OutputDebugStringA("default\n");
Result = DefWindowProc(Window, Message, WParam, LParam);
} break;
}
return(Result);
}
int CALLBACK
WinMain(HINSTANCE Instance,
HINSTANCE PrevInstance,
LPSTR CommandLine,
int ShowCode)
{
WNDCLASS WindowClass = {};
// TODO(casey): Check if HREDRAW/VREDRAW/OWNDC still matter
WindowClass.lpfnWndProc = Win32MainWindowCallback;
WindowClass.hInstance = Instance;
// WindowClass.hIcon;
WindowClass.lpszClassName = "HandmadeHeroWindowClass";
if (RegisterClassA(&WindowClass))
{
HWND Window =
CreateWindowExA(
0,
WindowClass.lpszClassName,
"Handmade Hero",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
Instance,
0);
if (Window)
{
int XOffset = 0;
int YOffset = 0;
Running = true;
while (Running)
{
MSG Message;
while (PeekMessage(&Message, 0, 0, 0, PM_REMOVE))
{
if (Message.message == WM_QUIT)
{
Running = false;
}
TranslateMessage(&Message);
DispatchMessageA(&Message);
}
RenderWeirdGradient(XOffset, YOffset);
HDC DeviceContext = GetDC(Window);
RECT ClientRect;
GetClientRect(Window, &ClientRect);
int WindowWidth = ClientRect.right - ClientRect.left;
int WindowHeight = ClientRect.bottom - ClientRect.top;
Win32UpdateWindow(DeviceContext, &ClientRect, 0, 0, WindowWidth,
WindowHeight);
ReleaseDC(Window, DeviceContext);
++XOffset;
YOffset += 2;
}
}
else
{
// TODO(casey): Logging
}
}
else
{
// TODO(casey): Logging
}
return(0);
}
For who asked for the callstack here it is in better formating since it won't work well as a comment.
win32_handmade.exe!Win32ResizeDIBSection(int Width, int Height) Line 62 C++
win32_handmade.exe!WIN32MainWindowCallback(HWND__ * Window, unsigned int Message, unsigned int WParam, long LParam) Line 118 C++
[External Code]
win32_handmade.exe!WinMain(HINSTANCE__ * hInstance, HINSTANCE__ * PrevInstance, char * CommandLine, int ShowCode) Line 184 C++
[External Code]
Related
I wanted to write a turtle in c++, but the angles at the turn are not accurate.
I tried to create a Koch curve, but the result was bad
Hereis a larger picture of this, it looks like the angles are wrong
This is my program:
#include <windows.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include "turtle.h"
#define MAX_LOADSTRING 100
// Global Variables:
#define HIBA_00 TEXT("Error:Program initialisation process.")
HINSTANCE hInstGlob;
int OwniCmdShow;
char szClassName[] = "WindowsApp";
HWND Form1;
LRESULT CALLBACK WndProc0(HWND, UINT, WPARAM, LPARAM);
RECT rc;
HDC hdcMem;
HBITMAP hbmMem, hbmOld;
HBRUSH hbrBkGnd;
HDC hdc;
PAINTSTRUCT ps;
void DB_prepare_puffer(void);
void DB_start_drawing(void);
void DB_end_drawing(void);
void draw(void);
void screen_clear(void);
void print(int n);
int depth = 4;
float length = 1000;
turtle t;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("StdWinClassName");
MSG msg;
WNDCLASS wndclass0;
OwniCmdShow = iCmdShow;
hInstGlob = hInstance;
wndclass0.style = CS_HREDRAW | CS_VREDRAW;
wndclass0.lpfnWndProc = WndProc0;
wndclass0.cbClsExtra = 0;
wndclass0.cbWndExtra = 0;
wndclass0.hInstance = hInstance;
wndclass0.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass0.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass0.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass0.lpszMenuName = NULL;
wndclass0.lpszClassName = TEXT("WIN0");
if (!RegisterClass(&wndclass0))
{
MessageBox(NULL, HIBA_00, TEXT("Program Start"), MB_ICONERROR); return 0;
}
Form1 = CreateWindow(TEXT("WIN0"),
TEXT("Form1"),
(WS_OVERLAPPED | WS_SYSMENU | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX),
0,
0,
1920,
1050,
NULL,
NULL,
hInstance,
NULL);
DB_prepare_puffer();
ShowWindow(Form1, OwniCmdShow);
UpdateWindow(Form1);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc0(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc_lokal;
PAINTSTRUCT ps_lokal;
switch (message) {
case WM_CREATE:
break;
case WM_MOUSEMOVE:
break;
case WM_ERASEBKGND:
return (LRESULT)1;
break;
case WM_PAINT:
hdc_lokal = BeginPaint(hwnd, &ps_lokal);
EndPaint(hwnd, &ps_lokal);
t.init();
draw();
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hwnd, message, wParam, lParam);
break;
}
return NULL;
}
void DB_prepare_puffer(void)
{
GetClientRect(Form1, &rc);
hdc = GetDC(Form1);
hbmMem = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top);
}
void DB_start_drawing(void)
{
GetClientRect(Form1, &rc);
hdc = GetDC(Form1);
BeginPaint(Form1, &ps);
hdcMem = CreateCompatibleDC(hdc);
hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
hbrBkGnd = CreateSolidBrush(RGB(255, 255, 255));
FillRect(hdcMem, &rc, hbrBkGnd);
DeleteObject(hbrBkGnd);
}
void DB_end_drawing(void)
{
BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, hbmOld);
DeleteDC(hdcMem);
EndPaint(Form1, &ps);
}
void draw(void)
{
DB_start_drawing();
screen_clear();
int i = 0;
depth = 5;
length = 1200;
while (i < depth) {
length = length / 3;
i++;
}
t.right(270);
print(depth);
DB_end_drawing();
}
//************************
//clear screen
//************************
void screen_clear(void)
{
HBRUSH hBrush;
RECT rect;
HDC hdc;
hdc = hdcMem;
hBrush = CreateSolidBrush(RGB(255, 255, 255));
SelectObject(hdc, hBrush);
SetRect(&rect, 0, 0, 1500, 900);
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
void print(int m) {
int n = m;
if (n == 0) {
t.forward(length, hdcMem);
}
if (n != 0){
n -= 1;
print(n);
t.left(60);
print(n);
t.right(120);
print(n);
t.left(60);
print(n);
}
}
this is the turtle.h file:
#pragma once
#define _USE_MATH_DEFINES
#include "resource.h"
#include <windows.h>
#include <cmath>
class turtle {
public:
void init();
void right(double _angle);
void left(double _angle);
void forward(int distance, HDC hdc);
double angle = 0;
POINT pos;
protected:
private:
};
And this is the turtle.cpp:
#pragma once
#include "turtle.h"
void turtle::init()
{
pos.x = 40;
pos.y = 800;
angle = 0;
}
void turtle::left(double _angle) {
angle -= _angle;
}
void turtle::right(double _angle) {
angle += _angle;
}
void turtle::forward(int distance, HDC hdc) {
MoveToEx(hdc, pos.x, pos.y, NULL);
double cos_angle = cos(angle * M_PI / (double)180);
double sin_angle = sin(angle * M_PI / (double)180);
POINT endpoint;
endpoint.x = (0 - (double)distance * sin_angle) + pos.x;
endpoint.y = (0 + (double)distance * cos_angle) + pos.y;
LineTo(hdc, endpoint.x, endpoint.y);
pos = endpoint;
}
In Python, however, this code worked (essentially the same as the c++ code):
from turtle import *
color('blue', 'white')
speed(100000000)
penup()
back(600)
pendown()
begin_fill()
depth = 0
length = 300
i = 0
def print(n):
if n == 0:
forward(length )
if n != 0:
n -= 1
print(n)
left(60)
print(n)
right(120)
print(n)
left(60)
print(n)
i = 0
depth = 5
length = 300
while i < depth:
length = length / 3
i += 1
print(depth)
(Result)
I hope you can help me.
Thanks
It will work with this code because the previously calculated position is stored more accurately.
turtle.cpp:
#pragma once
#include "turtle.h"
void turtle::init()
{
pos.x = 40;
pos.y = 800;
angle = 0;
}
void turtle::left(double _angle) {
angle -= _angle;
}
void turtle::right(double _angle) {
angle += _angle;
}
void turtle::forward(double distance, HDC hdc) {
MoveToEx(hdc, pos.x, pos.y, NULL);
double cos_angle = cos(angle * M_PI / (double)180);
double sin_angle = sin(angle * M_PI / (double)180);
DPOINT endpoint;
endpoint.x = (0 - distance * sin_angle) + pos.x;
endpoint.y = (0 + distance * cos_angle) + pos.y;
LineTo(hdc, endpoint.x, endpoint.y);
pos = endpoint;
}
And insert this code to turtle.h:
`
typedef struct DPOINT {
double x;
double y;
};
`
And change the 'pos' variable type to 'DPOINT'
CreateWindow.h
#pragma once
#include <Windows.h>
#include <iostream>
#include <stdint.h>
#include <cmath>
#include <vector>
#include <sstream>
using namespace std;
struct returncursorposdemcical
{
float x, y;
};
struct CustomImage
{
vector<vector<unsigned>> CImage;
int long height, width;
};
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
class window
{
public:
window();
window(const window&) = delete;
window& operator = (const window&) = delete;
~window();
bool windowpro();
void stretchbit();
void backgroundcolor(int R, int G, int B);
private:
};
CreateWindow.cpp
#include "../Header/CreateWindow.h"
WNDCLASS WindowClass = {};
HWND CreateMyWindow;
HDC mydc;
int BitmapWidth;
int BitmapHeight;
RECT ClientRect;
int ClientWidth;
int ClientHeight;
long int buffer_sizes;
void* buffer_memory;
BITMAPINFO buffer_bitmap;
HINSTANCE myhinstance;
window::window()
{
WindowClass.lpszClassName = "Game_Engine";
WindowClass.lpfnWndProc = WindowProc;
WindowClass.hInstance = myhinstance;
WindowClass.hCursor = LoadCursor(0, IDC_CROSS);
RegisterClass(&WindowClass);
CreateMyWindow = CreateWindowEx(0, "Game_Engine", "Program",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
0, 0, GetModuleHandle(nullptr), 0);
mydc = GetDC(CreateMyWindow);
ShowWindow(CreateMyWindow, SW_SHOWMAXIMIZED);
}
window::~window()
{
std::cout << "destroy";
ReleaseDC(CreateMyWindow, mydc);
UnregisterClass("Game_Engine", myhinstance);
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
case WM_MOUSEMOVE:
{
}
case WM_MOUSELEAVE:
{
}
case WM_SIZE:
{
GetClientRect(CreateMyWindow, &ClientRect);
ClientWidth = ClientRect.right - ClientRect.left;
ClientHeight = ClientRect.bottom - ClientRect.top;
BitmapWidth = ClientWidth;
BitmapHeight = ClientHeight;
buffer_sizes = BitmapWidth * BitmapHeight * sizeof(unsigned int);
if (buffer_memory) {
VirtualFree(buffer_memory, 0, MEM_RELEASE);
}
buffer_memory = VirtualAlloc(0, buffer_sizes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
buffer_bitmap.bmiHeader.biSize = sizeof(buffer_bitmap.bmiHeader);
buffer_bitmap.bmiHeader.biWidth = BitmapWidth;
buffer_bitmap.bmiHeader.biHeight = -BitmapHeight;
buffer_bitmap.bmiHeader.biPlanes = 1;
buffer_bitmap.bmiHeader.biBitCount = 24;
buffer_bitmap.bmiHeader.biCompression = BI_RGB;
}
return 0;
case WM_PAINT:
{
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
bool window::windowpro()
{
MSG msg = { };
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) {
return false;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return true;
}
void window::backgroundcolor(int R, int G, int B)
{
unsigned int* pixel = (unsigned int*)buffer_memory;
for (int y = 0; y < BitmapHeight; y++) {
for (int x = 0; x < BitmapWidth; x++)
{
*pixel++ = (R << 16) + (G << 8) + B;
}
}
}
void window::stretchbit()
{
StretchDIBits(mydc, 0, 0, BitmapWidth, BitmapHeight, 0, 0, ClientWidth, ClientHeight, buffer_memory,&buffer_bitmap,DIB_RGB_COLORS,SRCCOPY);
}
Source.cpp
#include "../WindowStartup/Header/CreateWindow.h"
int main()
{
window mywindow;
bool running = true;
while (running == true)
{
mywindow.backgroundcolor(225, 225, 225);
mywindow.stretchbit();
if (!mywindow.windowpro())
{
running = false;
}
}
return 0;
}
I tried to double buffer it, but it didn't work, I tried using bitblit, but it's the same result. Also, when the window resizing, it's not fully painted. And when the window it's not at the full size, it does not look strippy, so my speculation is that either my program is writing the data to bitmap to slow for the refresh rate, or the bitmap it's copying to screen to slow. Sorry for my bad English, English it's not my first language, and I am new to program.
I fixed, all you have to do is change biBitcounts to 32, I don't know why that works, might be some to do with ARGB, although I am only using RGB which is 24bits or 3 bytes, if someone could explain this why I need to change biBitcounts to 32, that would be nice. Also thanks for all the people in the comment that are trying to help me.
This code in my windowless framework is an area like just button,but some code I wanted to run it only once until the mouse move on the area next time.
All those code are in WM_MOUSEMOVE.
int ClickAreaPtInfo(HWND hWnd, int x, int y, int sizex, int sizey, LPARAM lParam,int &value)
{
POINT pt;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
RECT rect;
GetClientRect(hWnd, &rect);
RECT rc = { x,y,x + sizex,y + sizey };
if (PtInRect(&rc, pt))
{
value = 1;
return -1;
}
else
{
value = 0;
return -1;
}
return -1;
}
int _CreateMouseEvent(HWND hWnd, int x, int y, int sizex, int sizey, LPARAM lParam,RUNFUN function(), const wchar_t* Panelid, const wchar_t* CtlName)
{
int val = 0;
int msg = 0;
//int ist = 0; int istprev = 0;
RECT winrc;
GetClientRect(hWnd, &winrc);
RECT rc;
RectTypeConvert(rc,x, y, sizex, sizey);
if (Panelid == PanelID)
{
int nst = 1;
//OutputDebugString(L"HOVER!\n");
msg = 1;
ClickAreaPtInfo(hWnd, x, y, sizex, sizey, lParam, val);
if (val == 1)
{
if (ClickMsg == 1) //Click(Get from WM_LBUTTONUP)
{
ClickMsg = 0;
function();
}
else
{
//It must be run for only once until the mouse leave next time,or it will lead to a lot of resource occupation
if (CtlName == L"Button") //HOVER
{
if (nst == 1)
{
HDC hdc = GetDC(hWnd);
CreateSimpleButtonEx(hWnd, hdc, x, y, sizex, sizey, UICOLOR_GREENSEA, 1, ButtonText);
ReleaseDC(hWnd, hdc);
nst = 0;
return 0;
}
else
{
nst = 0;
return 0;
}
return 0;
}
if (CtlName == L"CloseButton") ///HOVER
{
if (nst == 1)
{
HDC hdc = GetDC(hWnd);
CreateRect(hWnd, hdc, x, y, sizex, sizey, UICOLOR_PEACHRED);
PanelDrawCloseBtn(hWnd, hdc, rc.right - 40, 0, 40, 40, 12, UICOLOR_WHITE);
ReleaseDC(hWnd, hdc);
nst = 0;
return 0;
}
else
{
nst = 0;
return 0;
}
return 0;
}
else
{
return 0;
}
}
}
if (val == 0) //Leave
{
nst = 1;
InvalidateRect(hWnd, &rc, 0); //It must be run for only once until the mouse leave next time,or it will lead to a lot of resource(CPU) occupation
}
}
if (Panelid == PrevPanelID)
{
msg = 1;
}
else
{
msg = 0;
}
return 0;
}
then handle CreateMouseEvent in WM_MOUSEMOVE:
case WM_MOUSEMOVE:
{
CreateMouseEvent(hWnd, 20, 60, 140, 40, lParam, test, L"Init",L"Button");
CreateMouseEvent(hWnd, 20, 120, 140, 40, lParam, test3, L"Init", L"Button");
CreateMouseEvent(hWnd, 20, 180, 140, 40, lParam, btn3, L"Init",L"Button");
CreateMouseEvent(hWnd, rc.right - 40, 0, 40, 40, lParam, CloseWindow, L"Init",L"CloseButton");
break;
}
And I will also give a picture to this question!
http://db.vertexstudio.xyz/lnk/PanelPic/debuginf.png
any solution?thanks!
Some of your problems have already been mentioned above.
There are some variables that are not defined in your example, neither type nor value, but I can extrapolate some at least.
Also, in several places, you try to directly compare a C style string pointer (not a std::string!) to another C style string pointer.
if (Panelid == PanelID) is one place
if (CtlName == L"Button") //HOVER === is another
if (CtlName == L"CloseButton") ///HOVER another
You can use something like int _wcsnicmp( const wchar_t *string1,const wchar_t *string2, size_t count); or whatever your compiler supports. Optionally, you could just use std::wstring.
As for the click, you need to save the rect you get with GetClientRect(hWnd, &winrc); It needs persistence, ie saved outside of the function and accessible. Then compare to this rectangle and act accordingly.
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); {}
}
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.
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;
}
first I write some UINT as color in UINT** framebuffer,then create a BITMAPINFO by CreateDIBSection, but after run the program the window are black instead of some color I set,what's wrong?
PAINTSTRUCT ps;
HDC hdc;
static int s_widthClient, s_heightClient;
static BITMAPINFO s_bitmapInfo;
static HDC s_hdcBackbuffer;
static HBITMAP s_hBitmap;
static HBITMAP s_hOldBitmap;
static void* s_pData;
switch (message)
{
case WM_CREATE:
{
RECT rc;
GetClientRect(hWnd, &rc);
s_widthClient = rc.right - rc.left;
s_heightClient = rc.bottom - rc.top;
Tiny3DDevice pDevice(s_widthClient, s_heightClient, s_pData);
pDevice.Test();
BITMAPINFOHEADER bmphdr = { 0 };
bmphdr.biSize = sizeof(BITMAPINFOHEADER);
bmphdr.biWidth = s_widthClient;
bmphdr.biHeight = -s_heightClient;
bmphdr.biPlanes = 1;
bmphdr.biBitCount = 32;
bmphdr.biSizeImage = s_heightClient * s_widthClient * 4;
s_hdcBackbuffer = CreateCompatibleDC(nullptr);
HDC hdc = GetDC(hWnd);
//s_hBitmap = CreateCompatibleBitmap(hdc, s_widthClient, s_heightClient);
s_hBitmap = CreateDIBSection(nullptr, (PBITMAPINFO)&bmphdr, DIB_RGB_COLORS,
reinterpret_cast<void**>(&pDevice.m_pFramebuffer), nullptr, 0);
s_hOldBitmap = (HBITMAP)SelectObject(s_hdcBackbuffer, s_hBitmap);
ReleaseDC(hWnd, hdc);
}
break;
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
//BitBlt(s_hdcBackbuffer, 0, 0, s_widthClient, s_heightClient, nullptr, 0, 0, WHITENESS);
////draw text
//SetTextColor(s_hdcBackbuffer, RGB(0, 0, 0));
//SetBkMode(s_hdcBackbuffer, TRANSPARENT);
//TextOut(s_hdcBackbuffer, 0, 5, text.c_str(), text.size());
BitBlt(ps.hdc, 0, 0, s_widthClient, s_heightClient, s_hdcBackbuffer, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
}
break;
and the Tiny3DDevice:
class Tiny3DDevice
{
public:
Tiny3DDevice(int width, int height, void *fb);
~Tiny3DDevice();
public:
void Test();
public:
int m_width;
int m_height;
UINT** m_pFramebuffer;
};
Tiny3DDevice::Tiny3DDevice(int width, int height, void *fb)
{
m_width = width;
m_height = height;
m_pFramebuffer = new UINT*[width];
for (int i = 0; i < width; ++i)
{
m_pFramebuffer[i] = new UINT[height];
}
}
void Tiny3DDevice::Test()
{
ZCFLOAT3 color(0.5f, 0.5f, 0.5f);
for (int i = 0; i < m_width; ++i)
for (int j = 0; j < m_height; ++j)
{
//m_pFramebuffer[i][j] = MathUtil::ColorToUINT(color);
m_pFramebuffer[i][j] = 0x3fbcefff;
}
}
what is wrong ? How should I write data in m_framebuffer? Any idea ?.
you need code like this
PVOID pv;
if (s_hBitmap = CreateDIBSection(nullptr, (PBITMAPINFO)&bmphdr, DIB_RGB_COLORS, &pv, 0, 0))
{
RtlFillMemoryUlong((PULONG)pv, bmphdr.biSizeImage, 0x3fbcefff);
}
you not need allocate pv(pDevice.m_pFramebuffer in your code), because it allocated in CreateDIBSection. you just need fill it. your code of Tiny3DDevice completely wrong and senseless.
use static vars for s_hdcBackbuffer, etc - nightmare
BITMAPINFOHEADER bmphdr = { 0 };
nobody try use this :) ?
BITMAPINFOHEADER bmphdr = { };