diff --git a/bounce_cpp/hyrax.ico b/bounce_cpp/hyrax.ico new file mode 100644 index 0000000..b330db1 Binary files /dev/null and b/bounce_cpp/hyrax.ico differ diff --git a/bounce_cpp/hyrax.jpeg b/bounce_cpp/hyrax.jpeg new file mode 100644 index 0000000..89aca4f Binary files /dev/null and b/bounce_cpp/hyrax.jpeg differ diff --git a/bounce_cpp/main.cpp b/bounce_cpp/main.cpp index 0d64c55..088e03d 100644 --- a/bounce_cpp/main.cpp +++ b/bounce_cpp/main.cpp @@ -1,275 +1,367 @@ -#include +/* +Anytime I edit any C++ Code, in specifically Win32 code i get acute seizures cause of the naming +conventions. I hope that whoever came up with these fuckass names gets fucked by a femboy. idk. + +Anyways this is under the AGPL3.0 License so do whatever you want under that license terms. + +Quick description of the app: + - A hyrax picture which bounces around your desktop, like bonzi buddy but not destructive, more of a fun thing which you can open + when you get bored. + - Run the exe youll find out. + +This is not malware or a virus, its purely for fun and entertainment purpouses. + +rattatwinko - 04/05/26 +*/ + +#include +#include #include -#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; +// consts +static constexpr double GRAVITY = 1200.0; +static constexpr double RESTITUTION = 0.6; +static constexpr double AIR_DRAG = 0.999; +static constexpr double GROUND_FRICTION = 0.8; +static constexpr double REST_THRESHOLD = 5.0; +static constexpr UINT TIMER_MS = 10; +static constexpr int IMAGE_RESOURCE = 111; +static constexpr int RESIZE_BORDER = 12; // make wider so easier grab - DWORD size = SizeofResource(NULL, hRes); - if (size == 0) return NULL; +// globals +static ULONG_PTR g_gdiplusToken = 0; +static Image* g_image = nullptr; +static int g_winW = 640; +static int g_winH = 480; +static LARGE_INTEGER g_freq = {}; - HGLOBAL hData = LoadResource(NULL, hRes); - if (!hData) return NULL; +// physics states +static double g_x = 200.0, g_y = 50.0; +static double g_vx = 0.0, g_vy = 0.0; +static double g_lastTime = 0.0; + +// resize status +static bool g_resizing = false; +static bool g_dragging = false; +static int g_dragOffsetX = 0; +static int g_dragOffsetY = 0; +static POINT g_lastMouse = {}; +static double g_lastMouseTime = 0.0; + +// helper definitions +static double Now() { + LARGE_INTEGER t; + QueryPerformanceCounter(&t); + return static_cast(t.QuadPart) / static_cast(g_freq.QuadPart); +} + +static Image* LoadImageFromResource(HINSTANCE hInst, int resId) { + HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(resId), RT_RCDATA); + if (!hRes) return nullptr; + + DWORD size = SizeofResource(hInst, hRes); + if (!size) return nullptr; + + HGLOBAL hData = LoadResource(hInst, hRes); + if (!hData) return nullptr; void* pData = LockResource(hData); - if (!pData) return NULL; + if (!pData) return nullptr; - HGLOBAL hBuffer = GlobalAlloc(GMEM_MOVEABLE, size); - if (!hBuffer) return NULL; + HGLOBAL hBuf = GlobalAlloc(GMEM_MOVEABLE, size); + if (!hBuf) return nullptr; - void* pBuffer = GlobalLock(hBuffer); - if (!pBuffer) { - GlobalFree(hBuffer); - return NULL; - } + void* pBuf = GlobalLock(hBuf); + if (!pBuf) { GlobalFree(hBuf); return nullptr; } - memcpy(pBuffer, pData, size); - GlobalUnlock(hBuffer); + memcpy(pBuf, pData, size); + GlobalUnlock(hBuf); - IStream* stream = NULL; - HRESULT hr = CreateStreamOnHGlobal(hBuffer, TRUE, &stream); - if (FAILED(hr) || !stream) { - GlobalFree(hBuffer); - return NULL; + IStream* stream = nullptr; + if (FAILED(CreateStreamOnHGlobal(hBuf, TRUE, &stream)) || !stream) { + GlobalFree(hBuf); + return nullptr; } Image* img = Image::FromStream(stream); stream->Release(); if (!img || img->GetLastStatus() != Ok) { - if (img) delete img; - return NULL; + delete img; + return nullptr; } return img; } +// physics "engine" +static void StepPhysics(double dt) { + const int screenW = GetSystemMetrics(SM_CXSCREEN); + const int screenH = GetSystemMetrics(SM_CYSCREEN); -double x = 200.0, y = 50.0; -double vx = 0.0, vy = 0.0; + g_vy += GRAVITY * dt; + g_vx *= AIR_DRAG; + g_vy *= AIR_DRAG; -double gravity = 1200.0; -double restitution = 0.6; -double air_drag = 0.999; -double ground_friction = 0.8; + g_x += g_vx * dt; + g_y += g_vy * dt; -int win_w = 640; -int win_h = 480; + // left/ right monitor borders + if (g_x < 0.0) { + g_x = 0.0; + g_vx = -g_vx * RESTITUTION; + } + else if (g_x > screenW - g_winW) { + g_x = static_cast(screenW - g_winW); + g_vx = -g_vx * RESTITUTION; + } -int dragging = 0; -int offset_x = 0, offset_y = 0; + // top + if (g_y < 0.0) { + g_y = 0.0; + g_vy = -g_vy * RESTITUTION; + } -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; + // bottom + if (g_y > screenH - g_winH) { + g_y = static_cast(screenH - g_winH); + g_vy = -g_vy * RESTITUTION; + g_vx *= GROUND_FRICTION; + if (fabs(g_vy) < REST_THRESHOLD) + g_vy = 0.0; + } } - -LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { +// win api window proc +static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { + // init the window case WM_CREATE: { - QueryPerformanceFrequency(&freq); + QueryPerformanceFrequency(&g_freq); - GdiplusStartupInput gdiplusStartupInput; - GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + GdiplusStartupInput si; + GdiplusStartup(&g_gdiplusToken, &si, nullptr); - img = LoadImageFromResource(111); + HINSTANCE hInst = reinterpret_cast(lParam)->hInstance; + g_image = LoadImageFromResource(hInst, IMAGE_RESOURCE); - 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); + if (g_image) { + g_winW = static_cast(g_image->GetWidth()); + g_winH = static_cast(g_image->GetHeight()); + SetWindowPos(hwnd, nullptr, 0, 0, g_winW, g_winH, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); } - SetTimer(hwnd, 1, 10, NULL); + g_lastTime = Now(); + g_lastMouseTime = g_lastTime; - last_time = now_time(); - last_mouse_time = last_time; + SetTimer(hwnd, 1, TIMER_MS, nullptr); break; } + // drag start case WM_LBUTTONDOWN: { - dragging = 1; - offset_x = LOWORD(lParam); - offset_y = HIWORD(lParam); + g_dragging = true; + g_dragOffsetX = GET_X_LPARAM(lParam); + g_dragOffsetY = GET_Y_LPARAM(lParam); + g_vx = g_vy = 0.0; - vx = vy = 0; - - GetCursorPos(&last_mouse); - last_mouse_time = now_time(); + GetCursorPos(&g_lastMouse); + g_lastMouseTime = Now(); 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); + // drag move + case WM_MOUSEMOVE: { + if (!g_dragging) break; - double now = now_time(); - double dt = now - last_mouse_time; + POINT p; + GetCursorPos(&p); - if (dt > 0) { - vx = (p.x - last_mouse.x) / dt; - vy = (p.y - last_mouse.y) / dt; - } + const double now = Now(); + const double dt = now - g_lastMouseTime; - 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); + if (dt > 0.0) { + g_vx = (p.x - g_lastMouse.x) / dt; + g_vy = (p.y - g_lastMouse.y) / dt; } - break; + g_lastMouse = p; + g_lastMouseTime = now; + + g_x = p.x - g_dragOffsetX; + g_y = p.y - g_dragOffsetY; + + SetWindowPos(hwnd, nullptr, static_cast(g_x), static_cast(g_y), + 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + break; + } + + // drag end case WM_LBUTTONUP: - dragging = 0; + g_dragging = false; ReleaseCapture(); break; + + // while dragging nutz accross fohead disable OS from doing shit + case WM_ENTERSIZEMOVE: + g_resizing = true; + break; + case WM_EXITSIZEMOVE: { + g_resizing = false; + g_vx = g_vy = 0.0; + + // sync gx/y with resized cords + RECT r; + GetWindowRect(hwnd, &r); + g_x = static_cast(r.left); + g_y = static_cast(r.top); + + g_lastTime = Now(); // after everything is clean then redraw + break; + } + + // weird asf logic + case WM_NCHITTEST: { + POINT p = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + RECT r; + GetWindowRect(hwnd, &r); + + const bool left = p.x < r.left + RESIZE_BORDER; + const bool right = p.x >= r.right - RESIZE_BORDER; + const bool top = p.y < r.top + RESIZE_BORDER; + const bool bottom = p.y >= r.bottom - RESIZE_BORDER; + + if (top && left) return HTTOPLEFT; + if (top && right) return HTTOPRIGHT; + if (bottom && left) return HTBOTTOMLEFT; + if (bottom && right) return HTBOTTOMRIGHT; + if (left) return HTLEFT; + if (right) return HTRIGHT; + if (top) return HTTOP; + if (bottom) return HTBOTTOM; + return HTCLIENT; + } + + // sync dimensions after resizing + case WM_SIZE: + g_winW = LOWORD(lParam); + g_winH = HIWORD(lParam); + InvalidateRect(hwnd, nullptr, FALSE); + break; + + // cursor, bunch of this dont work + case WM_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT) { + SetCursor(LoadCursor(nullptr, g_dragging ? IDC_SIZEALL : IDC_HAND)); + return TRUE; + } + return DefWindowProcW(hwnd, msg, wParam, lParam); + + // phyisks tick case WM_TIMER: { - double now = now_time(); - double dt = now - last_time; - last_time = now; + const double now = Now(); + const double dt = now - g_lastTime; + g_lastTime = 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); + if (!g_dragging && !g_resizing) { + StepPhysics(dt); + SetWindowPos(hwnd, nullptr, static_cast(g_x), static_cast(g_y), + 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } break; } + // pablo picasso case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); - Graphics g(hdc); + // db to avoid me floppin on the floor like a fish (cause of flashing lights) + HDC memDC = CreateCompatibleDC(hdc); + HBITMAP memBmp = CreateCompatibleBitmap(hdc, g_winW, g_winH); + HGDIOBJ old = SelectObject(memDC, memBmp); - if (img) - g.DrawImage(img, 0, 0, win_w, win_h); + Graphics g(memDC); + g.SetInterpolationMode(InterpolationModeHighQualityBicubic); + + if (g_image) + g.DrawImage(g_image, 0, 0, g_winW, g_winH); + + BitBlt(hdc, 0, 0, g_winW, g_winH, memDC, 0, 0, SRCCOPY); + + SelectObject(memDC, old); + DeleteObject(memBmp); + DeleteDC(memDC); EndPaint(hwnd, &ps); break; } + // escape destroy case WM_KEYDOWN: if (wParam == VK_ESCAPE) DestroyWindow(hwnd); + else if (wParam == VK_SPACE) + DestroyWindow(hwnd); break; + // consuela case WM_DESTROY: - if (img) delete img; - GdiplusShutdown(gdiplusToken); + KillTimer(hwnd, 1); + delete g_image; + g_image = nullptr; + GdiplusShutdown(g_gdiplusToken); PostQuitMessage(0); break; + + default: + return DefWindowProcW(hwnd, msg, wParam, lParam); } - return DefWindowProcW(hwnd, msg, wParam, lParam); + return 0; } - -static int WINAPI wWinMain( - HINSTANCE hInstance, - HINSTANCE, - PWSTR, - int nCmdShow -) { - - if (IsDebuggerPresent()) - return 0; - - WNDCLASSW wc = { 0 }; +// right around the entry point (reference to asshair guy) +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int nCmdShow) { + WNDCLASSW wc = {}; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.lpszClassName = L"Hyrax"; - wc.hCursor = LoadCursor(NULL, IDC_HAND); - + wc.hCursor = LoadCursor(nullptr, IDC_HAND); RegisterClassW(&wc); HWND hwnd = CreateWindowExW( WS_EX_TOPMOST, - L"Hyrax", - L"", + L"Hyrax", L"", WS_POPUP, - (int)x, (int)y, - win_w, win_h, - NULL, NULL, hInstance, NULL + static_cast(g_x), static_cast(g_y), + g_winW, g_winH, + nullptr, nullptr, hInstance, nullptr ); + if (!hwnd) + return 1; + ShowWindow(hwnd, nCmdShow); + UpdateWindow(hwnd); MSG msg; - while (GetMessageW(&msg, NULL, 0, 0)) { + while (GetMessageW(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); } - return 0; + return static_cast(msg.wParam); } \ No newline at end of file