diff --git a/.gitignore b/.gitignore index 1c9a181..bd3cdaf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,10 @@ +################################################################################ +# MANUAL ENTRIES +################################################################################ +tags +*.swp +*.swo + ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. diff --git a/dchip-8.vcxproj b/dchip-8.vcxproj index 2ed25ab..63e7779 100644 --- a/dchip-8.vcxproj +++ b/dchip-8.vcxproj @@ -68,13 +68,22 @@ - + + $(SolutionDir)\bin\ + $(SolutionDir)\bin\ + Level3 Disabled true + true + false + MultiThreaded + + Windows + @@ -110,6 +119,7 @@ + diff --git a/dchip-8.vcxproj.filters b/dchip-8.vcxproj.filters index 6a1782f..9120b0a 100644 --- a/dchip-8.vcxproj.filters +++ b/dchip-8.vcxproj.filters @@ -14,4 +14,9 @@ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + Source Files + + \ No newline at end of file diff --git a/src/.clang-format b/src/.clang-format new file mode 100644 index 0000000..82ec7e2 --- /dev/null +++ b/src/.clang-format @@ -0,0 +1,46 @@ +{ + ColumnLimit: 80, + TabWidth: 4, + IndentWidth: 4, # 1 tab + UseTab: ForIndentation, + BreakBeforeBraces: Allman, + PointerBindsToType: false, + ### + AlwaysBreakAfterDefinitionReturnType: false, + AlwaysBreakTemplateDeclarations: true, + AlwaysBreakBeforeMultilineStrings: true, + IndentFunctionDeclarationAfterType: false, + # + AccessModifierOffset: -4, # 1 tab + AlignAfterOpenBracket: true, + AlignConsecutiveAssignments: true, + AlignTrailingComments: true, + # + AllowAllParametersOfDeclarationOnNextLine: true, + AllowShortBlocksOnASingleLine: false, + AllowShortIfStatementsOnASingleLine: true, + AllowShortLoopsOnASingleLine: false, + # + BinPackArguments: true, + BinPackParameters: true, + # + BreakConstructorInitializersBeforeComma: true, + ConstructorInitializerIndentWidth: 0, + # + IndentCaseLabels: true, + # + MaxEmptyLinesToKeep: 1, + NamespaceIndentation: None, + # + SpaceBeforeAssignmentOperators: true, + SpaceInEmptyParentheses: false, + SpacesBeforeTrailingComments: 1, + SpacesInAngles: false, + SpacesInCStyleCastParentheses: false, + SpacesInParentheses: false, + SpacesInSquareBrackets: false, + # + Cpp11BracedListStyle: true, + Standard: Cpp11, + # +} diff --git a/src/Common.h b/src/Common.h new file mode 100644 index 0000000..5011a99 --- /dev/null +++ b/src/Common.h @@ -0,0 +1,128 @@ +#ifndef COMMON_H +#define COMMON_H + +#include "stdint.h" + +#define LOCAL_PERSIST static +#define GLOBAL_VAR static +#define FILE_SCOPE static + +typedef uint32_t u32; +typedef uint16_t u16; + +typedef int64_t i64; +typedef int32_t i32; +typedef int16_t i16; + +typedef float f32; +typedef unsigned char u8; + +#define INVALID_CODE_PATH 0 + +#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) + +#ifdef DEBUG_MODE + #define ASSERT(expr) if (!(expr)) { (*((int *)0)) = 0; } +#else + #define ASSERT(expr) +#endif + +#define MATH_ABS(x) (((x) < 0) ? (-(x)) : (x)) + +typedef union v2 { + struct { f32 x, y; }; + struct { f32 w, h; }; +} v2; + +inline FILE_SCOPE v2 V2(f32 x, f32 y) +{ + v2 result = {}; + result.x = x; + result.y = y; + + return result; +} + +inline FILE_SCOPE v2 V2i(i32 x, i32 y) +{ + v2 result = V2((f32)x, (f32)y); + return result; +} + +inline FILE_SCOPE i32 common_strcmp(const char *a, const char *b) +{ + while ((*a) == (*b)) + { + if (!(*a)) return 0; + a++; + b++; + } + + return (((*a) < (*b)) ? -1 : 1); +} + +inline FILE_SCOPE i32 common_wstrcmp(const wchar_t *a, const wchar_t *b) +{ + while ((*a) == (*b)) + { + if (!(*a)) return 0; + a++; + b++; + } + + return (((*a) < (*b)) ? -1 : 1); +} + +inline FILE_SCOPE void common_wstrcat(const wchar_t *a, i32 lenA, + const wchar_t *b, i32 lenB, wchar_t *out, + i32 outLen) +{ + ASSERT((lenA + lenB) < outLen); + + i32 outIndex = 0; + for (i32 i = 0; i < lenA; i++) + out[outIndex++] = a[i]; + + for (i32 i = 0; i < lenB; i++) + out[outIndex++] = b[i]; + + ASSERT(outIndex <= outLen); +} + +inline FILE_SCOPE wchar_t common_wcharAsciiToLowercase(wchar_t character) +{ + if (character >= L'A' && character <= L'Z') + { + i32 shiftOffset = L'a' - L'A'; + character += (wchar_t)shiftOffset; + } + + return character; +} + +inline FILE_SCOPE i32 common_wstrlen(const wchar_t *a) +{ + i32 result = 0; + while ((*a)) + { + result++; + a++; + } + + return result; +} + +inline FILE_SCOPE i32 common_strlen(const char *a) +{ + i32 result = 0; + while ((*a)) + { + result++; + a++; + } + + return result; +} + + +#endif diff --git a/src/build.bat b/src/build.bat new file mode 100644 index 0000000..41ceab6 --- /dev/null +++ b/src/build.bat @@ -0,0 +1,54 @@ +@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or +@REM vcvarsall.bat to setup command-line compiler. + +@echo OFF +set ProjectName=dchip-8 + +ctime -begin %ProjectName%.ctm + +REM Build tags file +ctags -R + +REM Check if build tool is on path +REM >nul, 2>nul will remove the output text from the where command +where cl.exe >nul 2>nul +if %errorlevel%==1 call msvc86.bat + +REM Drop compilation files into build folder +IF NOT EXIST ..\bin mkdir ..\bin +pushd ..\bin + +REM EHa- disable exception handling (we don't use) +REM GR- disable c runtime type information (we don't use) + +REM MD use dynamic runtime library +REM MT use static runtime library, so build and link it into exe + +REM Oi enable intrinsics optimisation, let us use CPU intrinsics if there is one +REM instead of generating a call to external library (i.e. CRT). + +REM Zi enables debug data, Z7 combines the debug files into one. + +REM W4 warning level 4 +REM WX treat warnings as errors +REM wd4100 ignore: unused argument parameters +REM wd4201 ignore: nonstandard extension used: nameless struct/union +REM wd4189 ignore: local variable is initialised but not referenced + +set CompileFlags=-EHa- -GR- -Oi -MT -Z7 -W4 -WX -wd4100 -wd4201 -wd4189 + +REM Include directories +set IncludeFlags= + +REM Link libraries +set LinkLibraries=user32.lib gdi32.lib + +REM incrmenetal:no, turn incremental builds off +REM opt:ref, try to remove functions from libs that are referenced at all +set LinkFlags=-incremental:no -opt:ref + +cl %CompileFlags% ..\src\%ProjectName%.cpp %IncludeFlags% /link -subsystem:WINDOWS,5.1 %LinkLibraries% %LinkFlags% /nologo /OUT:"%ProjectName%.exe" + +popd +ctime -end %ProjectName%.ctm + diff --git a/src/ctime.exe b/src/ctime.exe new file mode 100644 index 0000000..b5fa4db Binary files /dev/null and b/src/ctime.exe differ diff --git a/src/dchip-8.cpp b/src/dchip-8.cpp new file mode 100644 index 0000000..95406b5 --- /dev/null +++ b/src/dchip-8.cpp @@ -0,0 +1,146 @@ +#define UNICODE +#define _UNICODE + +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif + +#include "Common.h" + +#include +#include + +FILE_SCOPE bool globalRunning = false; + +FILE_SCOPE LRESULT CALLBACK mainWindowProcCallback(HWND window, UINT msg, + WPARAM wParam, LPARAM lParam) +{ + LRESULT result = 0; + switch (msg) + { + case WM_CLOSE: + case WM_DESTROY: + { + globalRunning = false; + } + break; + + default: + { + result = DefWindowProc(window, msg, wParam, lParam); + } + break; + } + + return result; +} + +GLOBAL_VAR LARGE_INTEGER globalQueryPerformanceFrequency; +inline FILE_SCOPE f32 getTimeFromQueryPerfCounter(LARGE_INTEGER start, + LARGE_INTEGER end) +{ + f32 result = (f32)(end.QuadPart - start.QuadPart) / + globalQueryPerformanceFrequency.QuadPart; + return result; +} + +inline FILE_SCOPE LARGE_INTEGER getWallClock() +{ + LARGE_INTEGER result; + QueryPerformanceCounter(&result); + + return result; +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, int nShowCmd) +{ + WNDCLASSEX wc = + { + sizeof(WNDCLASSEX), + CS_HREDRAW | CS_VREDRAW, + mainWindowProcCallback, + 0, // int cbClsExtra + 0, // int cbWndExtra + hInstance, + LoadIcon(NULL, IDI_APPLICATION), + LoadCursor(NULL, IDC_ARROW), + GetSysColorBrush(COLOR_3DFACE), + L"", // LPCTSTR lpszMenuName + L"dchip-8Class", + NULL, // HICON hIconSm + }; + + if (!RegisterClassEx(&wc)) { + // TODO(doyle): Logging, couldn't register class + ASSERT(INVALID_CODE_PATH); + return -1; + } + + // 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; + + DWORD windowStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE; + AdjustWindowRect(&r, 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); + + if (!mainWindow) + { + // TODO(doyle): Logging, couldn't create root window + ASSERT(INVALID_CODE_PATH); + return -1; + } + + QueryPerformanceFrequency(&globalQueryPerformanceFrequency); + LARGE_INTEGER startFrameTime; + const f32 targetFramesPerSecond = 16.0f; + f32 targetSecondsPerFrame = 1 / targetFramesPerSecond; + f32 frameTimeInS = 0.0f; + + MSG msg; + while (globalRunning) + { + startFrameTime = getWallClock(); + while (PeekMessage(&msg, mainWindow, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + LARGE_INTEGER endWorkTime = getWallClock(); + f32 workTimeInS = + getTimeFromQueryPerfCounter(startFrameTime, endWorkTime); + + if (workTimeInS < targetSecondsPerFrame) + { + DWORD remainingTimeInMs = + (DWORD)((targetSecondsPerFrame - workTimeInS) * 1000); + Sleep(remainingTimeInMs); + } + + LARGE_INTEGER endFrameTime = getWallClock(); + frameTimeInS = + getTimeFromQueryPerfCounter(startFrameTime, endFrameTime); + f32 msPerFrame = 1000.0f * frameTimeInS; + + wchar_t windowTitleBuffer[128] = {}; + _snwprintf_s(windowTitleBuffer, ARRAY_COUNT(windowTitleBuffer), + ARRAY_COUNT(windowTitleBuffer), L"dchip-8 | %5.2f ms/f", + msPerFrame); + SetWindowText(mainWindow, windowTitleBuffer); + } + + return 0; +}