Skip to content

Instantly share code, notes, and snippets.

@msmshazan
Last active Apr 24, 2017
Embed
What would you like to do?
Win32 app wrapper
#include "main.h"
#include "resource.h"
global_variable bool32 GlobalRunning = 1;
global_variable win32_offscreen_buffer GlobalBackBuffer;
global_variable WINDOWPLACEMENT GlobalWindowPosition = { sizeof(GlobalWindowPosition) };
global_variable HWND hDlgCurrent = NULL;
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
internal void
Win32DisplayBufferInWindow(win32_offscreen_buffer *Buffer, HDC DeviceContext,
int WindowWidth, int WindowHeight)
{
// TODO: Centering / black bars?
if ((WindowWidth >= Buffer->Width * 2) &&
(WindowHeight >= Buffer->Height * 2)) {
StretchDIBits(DeviceContext,
0, 0, 2 * Buffer->Width, 2 * Buffer->Height,
0, 0, Buffer->Width, Buffer->Height,
Buffer->Memory, &Buffer->Info,
DIB_RGB_COLORS, SRCCOPY);
}
else {
#if 1
int OffsetX = 0;
int OffsetY = 0;
PatBlt(DeviceContext, 0, 0, WindowWidth, OffsetY, BLACKNESS);
PatBlt(DeviceContext, 0, OffsetY + Buffer->Height, WindowWidth, WindowHeight, BLACKNESS);
PatBlt(DeviceContext, 0, 0, OffsetX, WindowHeight, BLACKNESS);
PatBlt(DeviceContext, OffsetX + Buffer->Width, 0, WindowWidth, WindowHeight, BLACKNESS);
// NOTE: For prototyping purposes, we're going to always blit
// 1-to-1 pixels to make sure we don't introduce artifacts with
// stretching while we are learning to code the renderer!
StretchDIBits(DeviceContext,
/*
X, Y, Width, Height,
X, Y, Width, Height,
*/
OffsetX, OffsetY, Buffer->Width, Buffer->Height,
0, 0, Buffer->Width, Buffer->Height,
Buffer->Memory, &Buffer->Info,
DIB_RGB_COLORS, SRCCOPY);
#else
r32 HeightOverWidth = (r32)Buffer->Height / (r32)Buffer->Width;
s32 Width = WindowWidth;
s32 Height = (s32)(Width * HeightOverWidth);
StretchDIBits(DeviceContext,
0, 0, Width, Height,
0, 0, Buffer->Width, Buffer->Height,
Buffer->Memory, &Buffer->Info,
DIB_RGB_COLORS, SRCCOPY);
#endif
}
}
internal void
Win32ResizeDIBSection(win32_offscreen_buffer* Buffer, int Width, int Height)
{
// TODO: Bulletproof this.
// Maybe don't free first, free after, then free first if that fails.
if (Buffer->Memory) {
VirtualFree(Buffer->Memory, 0, MEM_RELEASE);
}
Buffer->Width = Width;
Buffer->Height = Height;
int BytesPerPixel = 4;
Buffer->BytesPerPixel = BytesPerPixel;
// NOTE: When the biHeight field is negative, this is the clue to
// Windows to treat this bitmap as top-down, not bottom-up, meaning that
// the first tree bytes of the image are the color for the top left pixel
// in the bitmap, not the bottom left.
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;
Buffer->Pitch = Align16(Width * BytesPerPixel);
int BitmapMemorySize = Buffer->Pitch * Buffer->Height;
Buffer->Memory = VirtualAlloc(0, BitmapMemorySize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
// TODO: Probably clear this to black
}
internal win32_window_dimension
Win32GetWindowDimension(HWND Window)
{
win32_window_dimension Result;
RECT ClientRect;
GetClientRect(Window, &ClientRect);
Result.Width = ClientRect.right - ClientRect.left;
Result.Height = ClientRect.bottom - ClientRect.top;
return Result;
}
BOOL CALLBACK QuitDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_INITDIALOG:
hDlgCurrent = hwnd;
ShowWindow(hwnd, SW_SHOW);
return TRUE;
case WM_DESTROY:
hDlgCurrent = NULL;
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
EndDialog(hwnd, IDOK);
GlobalRunning = false;
break;
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
}
break;
}
return FALSE;
}
BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_INITDIALOG:
hDlgCurrent = hwnd;
ShowWindow(hwnd, SW_SHOW);
return TRUE;
case WM_DESTROY:
hDlgCurrent = NULL;
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
EndDialog(hwnd, IDOK);
break;
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
}
break;
}
return FALSE;
}
LRESULT CALLBACK
Win32MainWindowCallback(HWND Window,
UINT Message,
WPARAM WParam,
LPARAM LParam)
{
LRESULT Result = 0;
switch (Message) {
case WM_CLOSE:
{
// TODO: Handle this with a message to the user?
GlobalRunning = false;
printf("WM_CLOSE\n");
} break;
case WM_ACTIVATEAPP:
{
OutputDebugString("WM_ACTIVATEAPP\n");
#if 1
if (WParam == TRUE) {
SetLayeredWindowAttributes(Window, RGB(0, 0, 0), 255, LWA_ALPHA);
}
else {
SetLayeredWindowAttributes(Window, RGB(0, 0, 0), 80, LWA_ALPHA);
}
#endif
} break;
case WM_COMMAND: {
HWND dialog;
int wmId = LOWORD(WParam);
// Parse the menu selections:
switch (wmId)
{
case ID_INFO_ABOUT:
CreateDialog(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DIALOG1), Window, AboutDlgProc);
break;
case ID_FILE_EXIT:
CreateDialog(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DIALOG2), Window, QuitDlgProc);
break;
}
}break;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:
{
assert(!"Keybord input came in through a non-dispatch message");
} break;
case WM_SIZE:
{
}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;
win32_window_dimension Dimension = Win32GetWindowDimension(Window);
Win32DisplayBufferInWindow(&GlobalBackBuffer, DeviceContext, Dimension.Width, Dimension.Height);
EndPaint(Window, &Paint);
} break;
default:
{
Result = DefWindowProc(Window, Message, WParam, LParam);
}break;
}
return Result;
}
internal void
ToggleFullscreen(HWND Window) {
// NOTE: This follows Raymond Chen's prescription
// for fullscreen toggling, see:
// http://blogs.msdn.com/b/oldnewthing/archive/2010/04/12/9994016.aspx
DWORD Style = GetWindowLong(Window, GWL_STYLE);
if (Style & WS_OVERLAPPEDWINDOW) {
MONITORINFO MonitorInfo = { sizeof(MonitorInfo) };
if (GetWindowPlacement(Window, &GlobalWindowPosition) &&
GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTOPRIMARY), &MonitorInfo))
{
SetWindowLong(Window, GWL_STYLE, Style & ~WS_OVERLAPPEDWINDOW);
SetWindowPos(Window, HWND_TOP,
MonitorInfo.rcMonitor.left, MonitorInfo.rcMonitor.top,
MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left,
MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top,
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}
else {
SetWindowLong(Window, GWL_STYLE, Style | WS_OVERLAPPEDWINDOW);
SetWindowPlacement(Window, &GlobalWindowPosition);
SetWindowPos(Window, 0, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}
int CALLBACK WinMain(HINSTANCE Instance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow) {
WNDCLASS wc;
ATOM atom;
RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
DWORD style = WS_OVERLAPPEDWINDOW ;
DWORD exstyle = WS_EX_APPWINDOW ;
HWND window;
HDC dc;
/* Win32 */
memset(&wc, 0, sizeof(wc));
wc.style = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.lpfnWndProc = Win32MainWindowCallback;
wc.hInstance = GetModuleHandle(0);
wc.hCursor = (HCURSOR)LoadImage(Instance,MAKEINTRESOURCE(IDC_POINTER),IMAGE_CURSOR,0,0,LR_DEFAULTSIZE);
wc.lpszClassName = "WindowClass";
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wc.hIcon = LoadIcon(Instance, MAKEINTRESOURCE(IDI_ICON1)); // Make sure to pass instance of app
atom = RegisterClass(&wc);
window = CreateWindowEx(exstyle, wc.lpszClassName, "Win32 programming",
style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
rect.right - rect.left, rect.bottom - rect.top,
NULL, NULL, wc.hInstance, NULL);
dc = GetDC(window);
if (window) {
char X = 0;
Win32ResizeDIBSection(&GlobalBackBuffer, 1920, 1080);
while (GlobalRunning)
{
InvalidateRect(window, NULL, FALSE);
MSG Message;
while(PeekMessage(&Message, 0, 0, 0, PM_REMOVE)) {
if (Message.message == WM_QUIT) {
GlobalRunning = false;
}
if (!IsDialogMessage(hDlgCurrent, &Message)) {
switch (Message.message) {
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP: {
uint32 VKCode = (uint32)Message.wParam;
// NOTE: Since we are comparing WasDown to IsDown,
// we MUST use == or != to convert these bit tests to actual
// 0 or 1 values.
bool WasDown = ((Message.lParam & (1 << 30)) != 0);
bool IsDown = ((Message.lParam & (1 << 31)) == 0);
if (WasDown != IsDown) {
if (VKCode == 'W') {
}
else if (VKCode == 'A') {
}
else if (VKCode == 'S') {
}
else if (VKCode == 'D') {
}
else if (VKCode == 'Q') {
}
else if (VKCode == 'E') {
}
else if (VKCode == VK_UP) {
}
else if (VKCode == VK_LEFT) {
}
else if (VKCode == VK_RIGHT) {
}
else if (VKCode == VK_DOWN) {
}
else if (VKCode == VK_ESCAPE) {
GlobalRunning = false;
}
else if (VKCode == VK_SPACE) {
}
if (IsDown) {
bool32 AltKeyWasDown = (Message.lParam & (1 << 29));
if ((VKCode == VK_F4) && AltKeyWasDown) {
GlobalRunning = false;
}
if ((VKCode == VK_RETURN) && AltKeyWasDown) {
if (Message.hwnd) {
ToggleFullscreen(Message.hwnd);
}
}
}
}
} break;
default: {
TranslateMessage(&Message);
DispatchMessage(&Message);
}break;
}
}
}
// All Non- Win32 code go here :-)
memset(GlobalBackBuffer.Memory, X, GlobalBackBuffer.BytesPerPixel*GlobalBackBuffer.Height*GlobalBackBuffer.Width);
X += 1;
}
ReleaseDC(window, dc);
}
UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment