|
|
@@ -0,0 +1,193 @@ |
|
|
|
#include <windows.h> |
|
|
|
#include <stdint.h> |
|
|
|
|
|
|
|
#define internal static // for functions |
|
|
|
#define local_persist static // for static variables in a scope |
|
|
|
#define global static // for global variables |
|
|
|
|
|
|
|
struct Win32OffscreenBuffer { |
|
|
|
BITMAPINFO info; |
|
|
|
void *memory; |
|
|
|
int width; |
|
|
|
int height; |
|
|
|
int bytesPerPixel; |
|
|
|
}; |
|
|
|
|
|
|
|
struct Win32WindowDimensions { |
|
|
|
int width; |
|
|
|
int height; |
|
|
|
}; |
|
|
|
|
|
|
|
global bool running; |
|
|
|
global Win32OffscreenBuffer globalBackBuffer; |
|
|
|
|
|
|
|
typedef uint8_t uint8; |
|
|
|
typedef uint16_t uint16; |
|
|
|
typedef uint32_t uint32; |
|
|
|
typedef uint64_t uint64; |
|
|
|
typedef int8_t int8; |
|
|
|
typedef int16_t int16; |
|
|
|
typedef int32_t int32; |
|
|
|
typedef int64_t int64; |
|
|
|
|
|
|
|
internal void renderWeirdGradient(Win32OffscreenBuffer buffer, int xOffset, int yOffset) { |
|
|
|
int bytesPerPixel = 4; |
|
|
|
int pitch = buffer.width*bytesPerPixel; |
|
|
|
uint8 *row = (uint8*)buffer.memory; |
|
|
|
for (int y = 0; y < buffer.height; y++) { |
|
|
|
uint32 *pixel = (uint32*)row; |
|
|
|
for (int x = 0; x < buffer.width; x++) { |
|
|
|
uint8 blue = x + xOffset; |
|
|
|
uint8 green = y + yOffset; |
|
|
|
*pixel++ = (green << 8) | blue; |
|
|
|
} |
|
|
|
row += pitch; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
internal void resizeDIBSection(Win32OffscreenBuffer *buffer, int width, int height) { |
|
|
|
if (buffer->memory) { |
|
|
|
VirtualFree(buffer->memory, NULL, MEM_RELEASE); |
|
|
|
} |
|
|
|
|
|
|
|
buffer->width = width; |
|
|
|
buffer->height = height; |
|
|
|
buffer->bytesPerPixel = 4; |
|
|
|
|
|
|
|
buffer->info = { |
|
|
|
.bmiHeader = { |
|
|
|
.biSize = sizeof(buffer->info.bmiHeader), |
|
|
|
.biWidth = buffer->width, |
|
|
|
.biHeight = -buffer->height, |
|
|
|
.biPlanes = 1, |
|
|
|
.biBitCount = 32, |
|
|
|
.biCompression = BI_RGB, |
|
|
|
}, |
|
|
|
}; |
|
|
|
|
|
|
|
int bitmapSize = buffer->width*buffer->height*buffer->bytesPerPixel; |
|
|
|
buffer->memory = VirtualAlloc(NULL, bitmapSize, MEM_COMMIT, PAGE_READWRITE); |
|
|
|
} |
|
|
|
|
|
|
|
Win32WindowDimensions win32GetWindowDimensions(HWND window) { |
|
|
|
Win32WindowDimensions result; |
|
|
|
RECT clientRect; |
|
|
|
GetClientRect(window, &clientRect); |
|
|
|
result.width = clientRect.right - clientRect.left; |
|
|
|
result.height = clientRect.bottom - clientRect.top; |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
void win32DrawBufferInWindow(Win32OffscreenBuffer buffer, HWND window) { |
|
|
|
Win32WindowDimensions winDims = win32GetWindowDimensions(window); |
|
|
|
StretchDIBits( |
|
|
|
GetDC(window), |
|
|
|
0, 0, winDims.width, winDims.height, |
|
|
|
0, 0, buffer.width, buffer.height, |
|
|
|
buffer.memory, |
|
|
|
&buffer.info, |
|
|
|
DIB_RGB_COLORS, |
|
|
|
SRCCOPY |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
LRESULT mainWindowCallback( |
|
|
|
HWND window, |
|
|
|
UINT message, |
|
|
|
WPARAM wParam, |
|
|
|
LPARAM lParam |
|
|
|
) { |
|
|
|
LRESULT result = 0; |
|
|
|
switch (message) { |
|
|
|
case WM_SIZE: { |
|
|
|
} break; |
|
|
|
|
|
|
|
case WM_DESTROY: { |
|
|
|
//OutputDebugStringA("WM_DESTROY\n"); |
|
|
|
} break; |
|
|
|
|
|
|
|
case WM_CLOSE: { |
|
|
|
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; |
|
|
|
win32DrawBufferInWindow(globalBackBuffer, window); |
|
|
|
EndPaint(window, &paint); |
|
|
|
} break; |
|
|
|
|
|
|
|
case WM_ACTIVATEAPP: { |
|
|
|
running = false; |
|
|
|
} break; |
|
|
|
|
|
|
|
default: { |
|
|
|
result = DefWindowProcA(window, message, wParam, lParam); |
|
|
|
//OutputDebugStringA("default\n"); |
|
|
|
} break; |
|
|
|
} |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
int APIENTRY WinMain( |
|
|
|
HINSTANCE instance, |
|
|
|
HINSTANCE prevInstance, |
|
|
|
PSTR commandLine, |
|
|
|
int commandShow |
|
|
|
) { |
|
|
|
WNDCLASS windowClass = { |
|
|
|
.style = CS_VREDRAW | CS_HREDRAW, |
|
|
|
.lpfnWndProc = &mainWindowCallback, |
|
|
|
.hInstance = instance, |
|
|
|
.lpszClassName = "HandmadeHeroWindowClass", |
|
|
|
}; |
|
|
|
|
|
|
|
resizeDIBSection(&globalBackBuffer, 1280, 720); |
|
|
|
|
|
|
|
if (RegisterClass(&windowClass)) { |
|
|
|
HWND window = CreateWindowExA( |
|
|
|
NULL, |
|
|
|
windowClass.lpszClassName, |
|
|
|
"Handmade Hero", |
|
|
|
WS_OVERLAPPEDWINDOW | WS_VISIBLE, |
|
|
|
CW_USEDEFAULT, |
|
|
|
CW_USEDEFAULT, |
|
|
|
CW_USEDEFAULT, |
|
|
|
CW_USEDEFAULT, |
|
|
|
NULL, |
|
|
|
NULL, |
|
|
|
instance, |
|
|
|
NULL |
|
|
|
); |
|
|
|
if (window) { |
|
|
|
MSG message; |
|
|
|
running = true; |
|
|
|
int xOffset = 0; |
|
|
|
int yOffset = 0; |
|
|
|
while (running) { |
|
|
|
while(PeekMessageA(&message, NULL, NULL, NULL, PM_REMOVE)) { |
|
|
|
if (message.message == WM_QUIT) { |
|
|
|
running = false; |
|
|
|
} |
|
|
|
TranslateMessage(&message); |
|
|
|
DispatchMessage(&message); |
|
|
|
} |
|
|
|
renderWeirdGradient(globalBackBuffer, xOffset, yOffset); |
|
|
|
win32DrawBufferInWindow(globalBackBuffer, window); |
|
|
|
xOffset++; |
|
|
|
yOffset++; |
|
|
|
} |
|
|
|
} else { |
|
|
|
// failed |
|
|
|
} |
|
|
|
} else { |
|
|
|
// failed |
|
|
|
} |
|
|
|
return(0); |
|
|
|
} |
|
|
|
|
|
|
|
|