diff --git a/VisualC/demo/Demo.vcxproj.filters b/VisualC/demo/Demo.vcxproj.filters
new file mode 100644
index 0000000..5c66dd8
--- /dev/null
+++ b/VisualC/demo/Demo.vcxproj.filters
@@ -0,0 +1,13 @@
+
+
+
+
+ {daa19be2-a3d5-40c0-aaff-83bf3bca32d9}
+
+
+
+
+ SourceFiles
+
+
+
\ No newline at end of file
diff --git a/VisualC/demo/demo.vcxproj b/VisualC/demo/demo.vcxproj
new file mode 100644
index 0000000..44985f1
--- /dev/null
+++ b/VisualC/demo/demo.vcxproj
@@ -0,0 +1,186 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {AF97B7A7-FA7A-40FC-8E16-AE23F5D136E9}
+ HelloWorld
+ Win32Proj
+ demo
+
+
+
+ Application
+ v143
+ Unicode
+ true
+
+
+ Application
+ v143
+ Unicode
+ true
+
+
+ Application
+ v143
+ Unicode
+
+
+ Application
+ v143
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>16.0.29103.76
+
+
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+ MinimumRecommendedRules.ruleset
+
+
+
+
+ true
+ MinimumRecommendedRules.ruleset
+
+
+
+
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ false
+ MinimumRecommendedRules.ruleset
+
+
+
+
+ false
+ MinimumRecommendedRules.ruleset
+
+
+
+
+
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+ Level3
+ $(SolutionDir)\..
+
+
+ true
+ Windows
+ MachineX86
+ $(CoreLibraryDependencies);%(AdditionalDependencies)
+ %(AdditionalLibraryDirectories)
+
+
+
+
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level3
+ $(SolutionDir)\..
+
+
+ true
+ Windows
+ $(CoreLibraryDependencies);%(AdditionalDependencies)
+ %(AdditionalLibraryDirectories)
+
+
+
+
+ MaxSpeed
+ true
+ WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+ Level3
+ ProgramDatabase
+ $(SolutionDir)\..
+
+
+ true
+ Windows
+ true
+ true
+ MachineX86
+ %(AdditionalLibraryDirectories)
+
+
+
+
+ MaxSpeed
+ true
+ WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+
+ Level3
+ ProgramDatabase
+ $(SolutionDir)\..
+
+
+ true
+ Windows
+ true
+ true
+ %(AdditionalLibraryDirectories)
+
+
+
+
+
+
+
+ {65d14e02-ec19-49eb-8e43-f33b4b0f8286}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/VisualC/demo/main.cpp b/VisualC/demo/main.cpp
new file mode 100644
index 0000000..8e90c01
--- /dev/null
+++ b/VisualC/demo/main.cpp
@@ -0,0 +1,190 @@
+#ifndef UNICODE
+#define UNICODE
+#endif
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "util/arg.h"
+
+LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+static HWND sHwnd;
+static COLORREF redColor = RGB(255, 0, 0);
+static COLORREF blueColor = RGB(0, 0, 255);
+static COLORREF greenColor = RGB(0, 255, 0);
+SFT sft;
+
+int width;
+int height;
+
+void SetWindowHandle(HWND hwnd)
+{
+ sHwnd = hwnd;
+}
+
+void SetPixel(int x, int y, COLORREF& color)
+{
+ if (sHwnd == NULL)
+ {
+ exit(0);
+ }
+
+ HDC hdc = GetDC(sHwnd);
+ SetPixel(hdc, x, y, color);
+ ReleaseDC(sHwnd, hdc);
+ return;
+}
+
+void RenderText()
+{
+ unsigned long cp;
+ SFT_Glyph gid, prevGid = 0;
+ SFT_Image image;
+ SFT_GMetrics mtx;
+ SFT_Kerning kerning;
+
+ // Text start position in pixels
+ int xOffset = 10;
+ int yOffet = 100;
+
+ // TODO: use stored text to dispaly
+ for (cp = 32; cp < 127; ++cp)
+ {
+ if (sft_lookup(&sft, cp, &gid) < 0)
+ continue;
+ if (sft_gmetrics(&sft, gid, &mtx) < 0)
+ continue;
+
+ image.width = mtx.minWidth;
+ image.height = mtx.minHeight;
+ image.pixels = malloc((size_t)image.width * (size_t)image.height);
+
+ sft_render(&sft, gid, image);
+
+ sft_kerning(&sft, prevGid, gid, &kerning);
+
+ xOffset += (int)(mtx.leftSideBearing + kerning.xShift);
+
+ for (int h = 0; h < image.height; h++)
+ {
+ for (int w = 0; w < image.width; w++)
+ {
+ char pixelWeight = 255 - ((char*)image.pixels)[image.width * h + w];
+ COLORREF grayColor = RGB(pixelWeight, pixelWeight, pixelWeight);
+ SetPixel(xOffset + w, yOffet + (int)mtx.yOffset + h, grayColor);
+ }
+ }
+
+ xOffset += (int)mtx.advanceWidth;
+
+ free(image.pixels);
+
+ prevGid = gid;
+ }
+}
+
+static void Die(const char* msg)
+{
+ fprintf(stderr, "%s\n", msg);
+ exit(1);
+}
+
+int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
+{
+ // Load and setup font
+ SFT_Font* font;
+ const char* filename;
+ double size;
+
+ filename = "../../resources/FiraGO-Regular.ttf";
+ size = 20.0;
+
+ if (!(font = sft_loadfile(filename)))
+ Die("Can't load font file.");
+
+ memset(&sft, 0, sizeof sft);
+ sft.font = font;
+ sft.xScale = size;
+ sft.yScale = size;
+ sft.flags = SFT_DOWNWARD_Y;
+
+ // Register the window class.
+ const wchar_t CLASS_NAME[] = L"Sample Window Class";
+
+ WNDCLASS wc = { };
+
+ wc.lpfnWndProc = WindowProc;
+ wc.lpszClassName = CLASS_NAME;
+ wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+
+ RegisterClass(&wc);
+
+ // Create the window.
+ HWND hwnd = CreateWindowEx(
+ 0, // Optional window styles.
+ CLASS_NAME, // Window class
+ L"Font rendering program", // Window text
+ WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME, // Window style, To prevent maximing ~WS_MAXIMIZEBOX AND window resizing ~WS_THICKFRAME
+
+ // Size and position
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+
+ NULL, // Parent window
+ NULL, // Menu
+ hInstance, // Instance handle
+ NULL // Additional application data
+ );
+
+ if (hwnd == NULL)
+ {
+ return 0;
+ }
+
+ ShowWindow(hwnd, nCmdShow);
+ UpdateWindow(hwnd);
+
+ // TODO: use window size to render text inside window dimensions
+ RECT rect;
+ if (GetWindowRect(hwnd, &rect))
+ {
+ width = rect.right - rect.left;
+ height = rect.bottom - rect.top;
+ }
+
+ // Run the message loop.
+ MSG msg = { };
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ sft_freefont(font);
+
+ return 0;
+}
+
+LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+
+ case WM_PAINT:
+ SetWindowHandle(hwnd);
+ RenderText();
+
+ return 0;
+ }
+
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+