|
|
|
#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); |
|
} |