Add rendering to screen using win32 blits

This commit is contained in:
Doyle Thai 2017-04-04 14:16:22 +10:00
parent 076f5977a3
commit 1c4c6d3dca
3 changed files with 111 additions and 15 deletions

View File

@ -83,6 +83,7 @@
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<AdditionalDependencies>msimg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

View File

@ -41,7 +41,7 @@ REM Include directories
set IncludeFlags=
REM Link libraries
set LinkLibraries=user32.lib gdi32.lib
set LinkLibraries=user32.lib gdi32.lib msimg32.lib
REM incrmenetal:no, turn incremental builds off
REM opt:ref, try to remove functions from libs that are referenced at all

View File

@ -9,6 +9,15 @@
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
FILE_SCOPE HBITMAP bitmap;
FILE_SCOPE BITMAPINFO bitmapInfo;
const i32 WIDTH = 64;
const i32 HEIGHT = 32;
const i32 RESOLUTION = WIDTH * HEIGHT;
FILE_SCOPE void *bitmapMemory;
FILE_SCOPE bool globalRunning = false;
@ -52,13 +61,14 @@ inline FILE_SCOPE LARGE_INTEGER getWallClock()
return result;
}
#define ErrorBox(text, title) MessageBox(nullptr, text, title, MB_OK);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX wc =
{
sizeof(WNDCLASSEX),
CS_HREDRAW | CS_VREDRAW,
CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
mainWindowProcCallback,
0, // int cbClsExtra
0, // int cbWndExtra
@ -72,34 +82,34 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
};
if (!RegisterClassEx(&wc)) {
// TODO(doyle): Logging, couldn't register class
ASSERT(INVALID_CODE_PATH);
ErrorBox(L"RegisterClassEx() failed.", nullptr);
return -1;
}
globalRunning = true;
// NOTE: Regarding Window Sizes
// If you specify a window size, e.g. 800x600, Windows regards the 800x600
// region to be inclusive of the toolbars and side borders. So in actuality,
// when you blit to the screen blackness, the area that is being blitted to
// is slightly smaller than 800x600. Windows provides a function to help
// calculate the size you'd need by accounting for the window style.
RECT r = {};
r.right = 450;
r.bottom = 200;
RECT rect = {};
rect.right = 128;
rect.bottom = 64;
DWORD windowStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
AdjustWindowRect(&r, windowStyle, FALSE);
DWORD windowStyle =
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
AdjustWindowRect(&rect, windowStyle, FALSE);
globalRunning = true;
HWND mainWindow = CreateWindowEx(
WS_EX_COMPOSITED, wc.lpszClassName, L"dchip-8", windowStyle,
CW_USEDEFAULT, CW_USEDEFAULT, r.right - r.left, r.bottom - r.top,
nullptr, nullptr, hInstance, nullptr);
CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left,
rect.bottom - rect.top, nullptr, nullptr, hInstance, nullptr);
if (!mainWindow)
{
// TODO(doyle): Logging, couldn't create root window
ASSERT(INVALID_CODE_PATH);
ErrorBox(L"CreateWindowEx() failed.", nullptr);
return -1;
}
@ -109,6 +119,66 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
f32 targetSecondsPerFrame = 1 / targetFramesPerSecond;
f32 frameTimeInS = 0.0f;
{
BITMAPINFOHEADER header = {};
header.biSize = sizeof(BITMAPINFOHEADER);
header.biWidth = WIDTH;
header.biHeight = HEIGHT;
header.biPlanes = 1;
header.biBitCount = 32;
header.biCompression = BI_RGB; // uncompressed bitmap
header.biSizeImage = 0;
header.biXPelsPerMeter = 0;
header.biYPelsPerMeter = 0;
header.biClrUsed = 0;
header.biClrImportant = 0;
bitmapInfo.bmiHeader = header;
const i32 numPixels = header.biWidth * header.biHeight;
const i32 bytesPerPixel = header.biBitCount / 8;
#if 0
bitmapMemory = calloc(1, numPixels * bytesPerPixel);
if (!bitmapMemory)
{
ErrorBox(L"malloc() failed.", nullptr);
return -1;
}
#else
HDC deviceContext = GetDC(mainWindow);
bitmap = CreateDIBSection(deviceContext, &bitmapInfo, DIB_RGB_COLORS,
&bitmapMemory, NULL, NULL);
ReleaseDC(mainWindow, deviceContext);
if (!bitmapMemory)
{
ErrorBox(L"CreateDIBSection() failed.", nullptr);
return -1;
}
#endif
u32 *bitmapBuffer = (u32 *)bitmapMemory;
for (i32 i = 0; i < numPixels; i++)
{
// NOTE: Win32 AlphaBlend requires the RGB components to be
// premultiplied with alpha.
f32 normA = 1.0f;
f32 normR = (normA * 0.0f);
f32 normG = (normA * 0.0f);
f32 normB = (normA * 1.0f);
u8 r = (u8)(normR * 255.0f);
u8 g = (u8)(normG * 255.0f);
u8 b = (u8)(normB * 255.0f);
u8 a = (u8)(normA * 255.0f);
u32 color = (a << 24) | (r << 16) | (g << 8) | (b << 0);
bitmapBuffer[i] = color;
}
}
MSG msg;
while (globalRunning)
{
@ -119,10 +189,35 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
DispatchMessage(&msg);
}
RECT clientRect = {};
GetClientRect(mainWindow, &clientRect);
LONG clientWidth = clientRect.right - clientRect.left;
LONG clientHeight = clientRect.bottom - clientRect.top;
BLENDFUNCTION blend = {};
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
HDC deviceContext = GetDC(mainWindow);
HDC alphaBlendDC = CreateCompatibleDC(deviceContext);
SelectObject(alphaBlendDC, bitmap);
AlphaBlend(deviceContext, 0, 0, WIDTH, HEIGHT, alphaBlendDC, 0, 0,
WIDTH, HEIGHT, blend);
StretchBlt(deviceContext, 0, 0, clientWidth, clientHeight,
deviceContext, 0, 0, WIDTH, HEIGHT, SRCCOPY);
DeleteDC(alphaBlendDC);
ReleaseDC(mainWindow, deviceContext);
////////////////////////////////////////////////////////////////////////
// Frame Limiting
////////////////////////////////////////////////////////////////////////
LARGE_INTEGER endWorkTime = getWallClock();
f32 workTimeInS =
getTimeFromQueryPerfCounter(startFrameTime, endWorkTime);
if (workTimeInS < targetSecondsPerFrame)
{
DWORD remainingTimeInMs =