Skip to content

Instantly share code, notes, and snippets.

@ajweeks
Last active January 31, 2016 15:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ajweeks/9174d37b13e7fd82b30a to your computer and use it in GitHub Desktop.
Save ajweeks/9174d37b13e7fd82b30a to your computer and use it in GitHub Desktop.
Eighth of Devember

Devember Day 08

I kind of managed to get an hour of programming in today, but only sort of. If you haven't heard about it, there's this daily livestream called Handmade Hero, where Casey Muratori explains how to make a game, from scratch, in c++. No engines, no frameworks, not even OpenGL or DirectX. I watched the livestreams from the beginning of the series, but I never followed along. Recently I decided to start at the first episode and follow along, line by line. I think the only realistic way for me to actually meet the devember challenge, as well as catch up to where Casey is right now - episode 220 at the time of this writing - is to include time I spend watching his recorded livestreams. They are about an hour long, with 30-60 minutes of Q and A afterwards. I usualy take probably an extra 10 or 15 minutes than the actual length of the video, since I pause and try some things on my own. That extra time will only increase as the complexity of the project also increases.

Unfortunately I only began the video about an hour before I had to leave for the evening, and now it's 11:39 pm. But I did manage to spend almost an hour following episode 5. So far we've got a window up, and a game loop running catching window events. I'll attach the code along with this entry once again. The entire project so far is that one .cpp file. You can just compile and run it.

We set up a Bitmap that we can render into in the last episode and are drawing some simple shapes using each pixel's coords plus an offset that is incremented each frame.

Anyway, that's it for today. Not sure what I'll work on tomorrow, probably finish off that episode and spend some time messing around with the code to better understand it. See you then!

Previous Entry | All Entries | Next Entry

#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;
struct win32_offscreen_buffer {
BITMAPINFO Info;
void *Memory;
int Width;
int Height;
int Pitch;
int BytesPerPixel;
};
// TODO(AJ): Relocate globals
global_variable BOOL Running;
global_variable win32_offscreen_buffer GlobalBackbuffer;
internal void
RenderWeirdGradient(win32_offscreen_buffer *Buffer, int XOffset, int YOffset)
{
// TODO(AJ): Should we pass buffer in by value or by ref?
int Width = Buffer->Width;
int Height = Buffer->Height;
uint8 *Row = (uint8 *)Buffer->Memory; // Only casted so we can do pointer arithmetic easier
for (int y = 0; y < Height; ++y)
{
uint32 *Pixel = (uint32 *)Row; // uint32 so we can increment pixel by pixel (each 32 bits big)
for (int x = 0; x < Width; ++x)
{
/*
Pixel in memory: BB GG RR xx // Little Endian
in Register: xx RR GG BB
*/
uint8 Red = XOffset + YOffset + x + y;
uint8 Green = YOffset + y;
uint8 Blue = XOffset + x;
*Pixel++ = ((Red << 16) | (Green << 8) | (Blue));
}
Row += Buffer->Pitch;
}
}
internal void
Win32ResizeDIBSection(win32_offscreen_buffer *Buffer, int Width, int Height)
{
// TODO(AJ): Bullet proof this, maybe don't free first, free after, then free first if it fails
if (Buffer->Memory)
{
VirtualFree(Buffer->Memory, 0, MEM_RELEASE);
}
Buffer->Width = Width;
Buffer->Height = Height;
Buffer->Info.bmiHeader.biSize = sizeof(Buffer->Info.bmiHeader);
Buffer->Info.bmiHeader.biWidth = Buffer->Width;
Buffer->Info.bmiHeader.biHeight = -Buffer->Height;
Buffer->Info.bmiHeader.biPlanes = 1;
Buffer->Info.bmiHeader.biBitCount = 32;
Buffer->Info.bmiHeader.biCompression = BI_RGB;
int BitmapMemorySize = (Buffer->Width * Buffer->Height) * Buffer->BytesPerPixel;
Buffer->Memory = VirtualAlloc(0, BitmapMemorySize, MEM_COMMIT, PAGE_READWRITE);
// TODO(AJ): Probably want to clear this to black
Buffer->Pitch = Width * Buffer->BytesPerPixel;
}
// Does this function "paint" the Bitmap to the window?
internal void
Win32DisplayBufferInWindow(HDC DeviceContext, RECT ClientRect,
win32_offscreen_buffer Buffer,
int X, int Y, int Width, int Height)
{
int WindowWidth = ClientRect.right - ClientRect.left;
int WindowHeight = ClientRect.bottom - ClientRect.top;
StretchDIBits(DeviceContext,
0, 0, Buffer.Width, Buffer.Height,
0, 0, WindowWidth, WindowHeight,
Buffer.Memory,
&Buffer.Info,
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;
} break;
case WM_DESTROY:
{
// TODO(AJ): Handle this with as an error - Recreate window?
Running = false;
} break;
case WM_CLOSE:
{
// TODO(AJ): Handle this with a message to the user
Running = false;
} break;
case WM_ACTIVATEAPP:
{
OutputDebugStringA("WM_ACTIVATEAPP\n");
} 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);
Win32DisplayBufferInWindow(DeviceContext, ClientRect, GlobalBackbuffer, 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 = {};
WindowClass.style = CS_HREDRAW|CS_VREDRAW;
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)
{
Running = true;
int XOffset = 0;
int YOffset = 0;
while(Running)
{
MSG Message;
while(PeekMessageA(&Message, 0, 0, 0, PM_REMOVE))
{
if (Message.message == WM_QUIT)
{
Running = false;
}
TranslateMessage(&Message);
DispatchMessageA(&Message);
}
RenderWeirdGradient(GlobalBackbuffer, XOffset, YOffset);
HDC DeviceContext = GetDC(Window);
RECT ClientRect;
GetClientRect(Window, &ClientRect);
int WindowWidth = ClientRect.right - ClientRect.left;
int WindowHeight = ClientRect.bottom - ClientRect.top;
Win32DisplayBufferInWindow(DeviceContext, ClientRect, GlobalBackbuffer, 0, 0, WindowWidth, WindowHeight);
ReleaseDC(Window, DeviceContext);
++XOffset;
if (XOffset % 500 < 250) --YOffset;
else ++YOffset;
}
}
else
{
// TODO(AJ): Logging
}
}
else
{
// TODO(AJ): Logging
}
return(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment