diff --git a/bounce_cpp.slnx b/bounce_cpp.slnx
new file mode 100644
index 0000000..220e9fa
--- /dev/null
+++ b/bounce_cpp.slnx
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/bounce_cpp/Resource.aps b/bounce_cpp/Resource.aps
new file mode 100644
index 0000000..1235c37
Binary files /dev/null and b/bounce_cpp/Resource.aps differ
diff --git a/bounce_cpp/Resource.rc b/bounce_cpp/Resource.rc
new file mode 100644
index 0000000..816f46b
Binary files /dev/null and b/bounce_cpp/Resource.rc differ
diff --git a/bounce_cpp/bounce_cpp.vcxproj b/bounce_cpp/bounce_cpp.vcxproj
new file mode 100644
index 0000000..2aecb3d
--- /dev/null
+++ b/bounce_cpp/bounce_cpp.vcxproj
@@ -0,0 +1,147 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 18.0
+ Win32Proj
+ {61c6f079-9b1c-4d66-b9c7-4646f87181a6}
+ bouncecpp
+ 10.0
+
+
+
+ Application
+ true
+ v145
+ Unicode
+
+
+ Application
+ false
+ v145
+ true
+ Unicode
+
+
+ Application
+ true
+ v145
+ Unicode
+
+
+ Application
+ false
+ v145
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp20
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp20
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp20
+
+
+ Windows
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp20
+ MultiThreaded
+
+
+ Windows
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bounce_cpp/bounce_cpp.vcxproj.filters b/bounce_cpp/bounce_cpp.vcxproj.filters
new file mode 100644
index 0000000..cefc746
--- /dev/null
+++ b/bounce_cpp/bounce_cpp.vcxproj.filters
@@ -0,0 +1,43 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
+
+ Resource Files
+
+
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/bounce_cpp/bounce_cpp.vcxproj.user b/bounce_cpp/bounce_cpp.vcxproj.user
new file mode 100644
index 0000000..88a5509
--- /dev/null
+++ b/bounce_cpp/bounce_cpp.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/bounce_cpp/hyrax.bmp b/bounce_cpp/hyrax.bmp
new file mode 100644
index 0000000..600bba5
Binary files /dev/null and b/bounce_cpp/hyrax.bmp differ
diff --git a/bounce_cpp/icon1.ico b/bounce_cpp/icon1.ico
new file mode 100644
index 0000000..5d06b9f
Binary files /dev/null and b/bounce_cpp/icon1.ico differ
diff --git a/bounce_cpp/main.cpp b/bounce_cpp/main.cpp
new file mode 100644
index 0000000..0d64c55
--- /dev/null
+++ b/bounce_cpp/main.cpp
@@ -0,0 +1,275 @@
+#include
+#include
+#include
+#include
+#include
+
+#pragma comment(lib, "gdiplus.lib")
+
+using namespace Gdiplus;
+
+Image* LoadImageFromResource(int resId) {
+ HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(resId), RT_RCDATA);
+ if (!hRes) return NULL;
+
+ DWORD size = SizeofResource(NULL, hRes);
+ if (size == 0) return NULL;
+
+ HGLOBAL hData = LoadResource(NULL, hRes);
+ if (!hData) return NULL;
+
+ void* pData = LockResource(hData);
+ if (!pData) return NULL;
+
+ HGLOBAL hBuffer = GlobalAlloc(GMEM_MOVEABLE, size);
+ if (!hBuffer) return NULL;
+
+ void* pBuffer = GlobalLock(hBuffer);
+ if (!pBuffer) {
+ GlobalFree(hBuffer);
+ return NULL;
+ }
+
+ memcpy(pBuffer, pData, size);
+ GlobalUnlock(hBuffer);
+
+ IStream* stream = NULL;
+ HRESULT hr = CreateStreamOnHGlobal(hBuffer, TRUE, &stream);
+ if (FAILED(hr) || !stream) {
+ GlobalFree(hBuffer);
+ return NULL;
+ }
+
+ Image* img = Image::FromStream(stream);
+ stream->Release();
+
+ if (!img || img->GetLastStatus() != Ok) {
+ if (img) delete img;
+ return NULL;
+ }
+
+ return img;
+}
+
+
+double x = 200.0, y = 50.0;
+double vx = 0.0, vy = 0.0;
+
+double gravity = 1200.0;
+double restitution = 0.6;
+double air_drag = 0.999;
+double ground_friction = 0.8;
+
+int win_w = 640;
+int win_h = 480;
+
+int dragging = 0;
+int offset_x = 0, offset_y = 0;
+
+POINT last_mouse;
+double last_mouse_time = 0.0;
+double last_time = 0.0;
+
+LARGE_INTEGER freq;
+
+ULONG_PTR gdiplusToken;
+Image* img = NULL;
+
+
+double now_time() {
+ LARGE_INTEGER t;
+ QueryPerformanceCounter(&t);
+ return (double)t.QuadPart / (double)freq.QuadPart;
+}
+
+
+LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch (msg) {
+
+ case WM_CREATE: {
+ QueryPerformanceFrequency(&freq);
+
+ GdiplusStartupInput gdiplusStartupInput;
+ GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+
+ img = LoadImageFromResource(111);
+
+ if (!img || img->GetLastStatus() != Ok) {
+ // MessageBoxA(NULL, "Image failed to load", "Error", MB_OK);
+ }
+ else {
+ win_w = 640;
+ win_h = 480;
+ SetWindowPos(hwnd, NULL, 0, 0, win_w, win_h, SWP_NOMOVE);
+ }
+
+ SetTimer(hwnd, 1, 10, NULL);
+
+ last_time = now_time();
+ last_mouse_time = last_time;
+ break;
+ }
+
+ case WM_LBUTTONDOWN: {
+ dragging = 1;
+ offset_x = LOWORD(lParam);
+ offset_y = HIWORD(lParam);
+
+ vx = vy = 0;
+
+ GetCursorPos(&last_mouse);
+ last_mouse_time = now_time();
+
+ SetCapture(hwnd);
+ break;
+ }
+
+ case WM_SETCURSOR:
+ if (dragging)
+ SetCursor(LoadCursor(NULL, IDC_SIZEALL));
+ else
+ SetCursor(LoadCursor(NULL, IDC_HAND));
+ return TRUE;
+
+ case WM_MOUSEMOVE:
+ if (dragging) {
+ POINT p;
+ GetCursorPos(&p);
+
+ double now = now_time();
+ double dt = now - last_mouse_time;
+
+ if (dt > 0) {
+ vx = (p.x - last_mouse.x) / dt;
+ vy = (p.y - last_mouse.y) / dt;
+ }
+
+ last_mouse = p;
+ last_mouse_time = now;
+
+ x = p.x - offset_x;
+ y = p.y - offset_y;
+
+ SetWindowPos(hwnd, NULL, (int)x, (int)y, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER);
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ dragging = 0;
+ ReleaseCapture();
+ break;
+
+ case WM_TIMER: {
+ double now = now_time();
+ double dt = now - last_time;
+ last_time = now;
+
+ int screen_w = GetSystemMetrics(SM_CXSCREEN);
+ int screen_h = GetSystemMetrics(SM_CYSCREEN);
+
+ if (!dragging) {
+ vy += gravity * dt;
+
+ vx *= air_drag;
+ vy *= air_drag;
+
+ x += vx * dt;
+ y += vy * dt;
+
+ if (x <= 0) {
+ x = 0;
+ vx = -vx * restitution;
+ }
+ else if (x >= screen_w - win_w) {
+ x = screen_w - win_w;
+ vx = -vx * restitution;
+ }
+
+ if (y >= screen_h - win_h) {
+ y = screen_h - win_h;
+ vy = -vy * restitution;
+ vx *= ground_friction;
+
+ if (fabs(vy) < 5)
+ vy = 0;
+ }
+
+ if (y <= 0) {
+ y = 0;
+ vy = -vy * restitution;
+ }
+
+ SetWindowPos(hwnd, NULL, (int)x, (int)y, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER);
+ }
+ break;
+ }
+
+ case WM_PAINT: {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwnd, &ps);
+
+ Graphics g(hdc);
+
+ if (img)
+ g.DrawImage(img, 0, 0, win_w, win_h);
+
+ EndPaint(hwnd, &ps);
+ break;
+ }
+
+ case WM_KEYDOWN:
+ if (wParam == VK_ESCAPE)
+ DestroyWindow(hwnd);
+ break;
+
+ case WM_DESTROY:
+ if (img) delete img;
+ GdiplusShutdown(gdiplusToken);
+ PostQuitMessage(0);
+ break;
+ }
+
+ return DefWindowProcW(hwnd, msg, wParam, lParam);
+}
+
+
+static int WINAPI wWinMain(
+ HINSTANCE hInstance,
+ HINSTANCE,
+ PWSTR,
+ int nCmdShow
+) {
+
+ if (IsDebuggerPresent())
+ return 0;
+
+ WNDCLASSW wc = { 0 };
+ wc.lpfnWndProc = WndProc;
+ wc.hInstance = hInstance;
+ wc.lpszClassName = L"Hyrax";
+ wc.hCursor = LoadCursor(NULL, IDC_HAND);
+
+ RegisterClassW(&wc);
+
+ HWND hwnd = CreateWindowExW(
+ WS_EX_TOPMOST,
+ L"Hyrax",
+ L"",
+ WS_POPUP,
+ (int)x, (int)y,
+ win_w, win_h,
+ NULL, NULL, hInstance, NULL
+ );
+
+ ShowWindow(hwnd, nCmdShow);
+
+ MSG msg;
+ while (GetMessageW(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/bounce_cpp/resource.h b/bounce_cpp/resource.h
new file mode 100644
index 0000000..74fc674
--- /dev/null
+++ b/bounce_cpp/resource.h
@@ -0,0 +1,17 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Resource.rc
+//
+#define IDR_RCDATA1 111
+#define IDI_ICON1 114
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 115
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif