This is my personal code and study progress of the handmade hero project.
- Setup the directory structure
- Make a command line with
shell.batstartup script to set path andcl - Use
devenvto debug in visual studio WinMain: Entry of a Windows GUI programMessageBox: Show a message box
- Using
WNDCLASSstruct andRegisterClass - Opening a window
CreateWindow - Get a window handle with
GetModuleHandle WndProcand handling messages andDefWindowProc- Making a loop and getting messages with
GetMessage,TranslateMessage,DispatchMessage - Drawing in
WM_PAINwithBeginPaint,EndPaint,PatBlt
- Closing window with
PostQuitMessageand handling it with arunningvariable - #define
global_variable,local_persistand internal tostatic - Resize Buffer on recieving
WM_SIZE - Using
GetClientRectto get window dimensions - Allocating the buffer using
CreateDIBSectionusingBITMAPINFOstruct - Drawing the buffer using
StretchDIBits - Creating a Device Context using
CreateCompatibleDC - Using
DeleteObjectto release the buffer when reallocated
at the end of day 3 I wanted to use the buffer to get something on the screen so I experimented a little on my own, the following is just some tinkering and will most likely be scrapped on Day 004
- Created a
RenderPixel(int x, int y, int r, int g, int b)function - It uses the windows
COLORREFdefinition which is a uint32 - The color value is passed using the windows
RGB()macro - Used it to render a simple sine function across the screen
- Set
biHeightto negative width to get a top-down coordinate where (0,0) is at top-left corner
// Definition
internal void
RenderPixel(int x, int y, int r = 255, int g = 255, int b = 255) {
int width = paint.rcPaint.right - paint.rcPaint.left; // ignore this way of getting the width, will be changed later
((COLORREF*)bitmapData)[y * width + x] = RGB(r, g, b);
}
// Sine function draw, placed in Win32UpdateWindow
for (int i = 0; i < width; ++i)
{
/* amplitude*sin(angle in radians) */
int y = 100*sin(i*3.1415/180); // sin function from math.h
y = (height/2) - y; // negative y is up in top-down coords -> (0,0) at upper-left corner
RenderPixel(i, y);
}- Using
VirtualAllocto allocate the bitmap memory ourselves instead ofCreateDIBSection - Using
VirtualFreeto free memory allocated - Learn about
VirtualProtectwhich helps in debugging use-after-free errors - Setting
biHeightto negative to get top-left origin (I found this already during #Tangent #1) - Pass (0,0) for x and y in
StretchDIBitsand window dimensions in dest dimensions, bitmap dimensions in src dimensions - Render a simple gradient. Pixel has the form
0x00RRGGBBwhere a padding byte is left for memory alignment - Use
PeekMessageinstead ofGetMessageso it doesn't block - Draw the gradient and pass changing offsets to animate it in the main loop
- Call
Win32UpdateWindowin the main loop to update and draw.- Handle deviceContext with
GetDC(window)andReleaseDC(window, deviceContext) GetClientRectto get windowRECTand dimensions
- Handle deviceContext with
HREDRAWandVREDRAWare used to tell Windows to redraw the whole window- Pulled the bitmap global variables into
win32_offscreen_bufferstruct - Pull the
GetClientRectcalls and calculation into a function that returnswin32_window_dimensionsstruct - Create the back buffer just once with constant width and height, move it out of
WM_SIZE - The stack grows down starting from WinMain, we can change it's size by specifying the
/F<num_of_bytes>argument in the build command OWNDCis used to have a single persistent Device ContextHDCper WindowHWNDto use across the program
As the new buffer had constant size and was being stretched it had some visual artifacts of black lines showing for the stretched color data, I looked into it and found about Stretch Modes which are set using SetStretchBltMode, COLORONCOLOR (or STRETCH_DELETESCANS) is used to preserve color in bitmaps so I've gone ahead and set it and it fixed the problem.