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;
+}