Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8630078345 | |||
| fc4dfd6f43 | |||
| 4951a79124 | |||
| 8185fc3032 | |||
| 74b56773d9 |
Binary file not shown.
Binary file not shown.
@@ -23,7 +23,8 @@
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{61c6f079-9b1c-4d66-b9c7-4646f87181a6}</ProjectGuid>
|
||||
<RootNamespace>bouncecpp</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>hyrax</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
@@ -109,6 +110,8 @@
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>gdiplus.lib;
|
||||
winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -125,13 +128,18 @@
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>gdiplus.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="physics.cpp" />
|
||||
<ClCompile Include="sound_handler.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="physics.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="sound_handler.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Resource.rc" />
|
||||
@@ -140,6 +148,21 @@
|
||||
<Image Include="..\..\..\..\Downloads\hyrax.ico" />
|
||||
<Image Include="..\..\..\..\Downloads\hyrax.jpeg" />
|
||||
<Image Include="hyrax.bmp" />
|
||||
<Image Include="hyrax_scream.jpeg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Media Include="hyrax1.wav" />
|
||||
<Media Include="hyrax2.wav" />
|
||||
<Media Include="hyrax3.wav" />
|
||||
<Media Include="hyrax4.wav" />
|
||||
<Media Include="hyrax5.wav" />
|
||||
<Media Include="hyrax6.wav" />
|
||||
<Media Include="hyrax7.wav" />
|
||||
<Media Include="hyrax8.wav" />
|
||||
<Media Include="hyrax9.wav" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\..\..\downloads\wave3.bin" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -18,11 +18,23 @@
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="physics.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sound_handler.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="physics.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sound_handler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Resource.rc">
|
||||
@@ -39,5 +51,42 @@
|
||||
<Image Include="..\..\..\..\Downloads\hyrax.ico">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
<Image Include="hyrax_scream.jpeg">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Media Include="hyrax1.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
<Media Include="hyrax2.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
<Media Include="hyrax3.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
<Media Include="hyrax4.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
<Media Include="hyrax5.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
<Media Include="hyrax6.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
<Media Include="hyrax7.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
<Media Include="hyrax8.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
<Media Include="hyrax9.wav">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Media>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\..\..\downloads\wave3.bin">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.0 MiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 207 KiB |
+287
-182
@@ -1,275 +1,380 @@
|
||||
#include <windows.h>
|
||||
#include <gdiplus.h>
|
||||
#include <cstring>
|
||||
#include <math.h>
|
||||
#include <objidl.h>
|
||||
/*
|
||||
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.
|
||||
|
||||
#pragma comment(lib, "gdiplus.lib")
|
||||
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.
|
||||
- you can click and it will awawa
|
||||
|
||||
This is not malware or a virus, its purely for fun and entertainment purpouses.
|
||||
|
||||
rattatwinko - 04/05/26
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <gdiplus.h>
|
||||
#include <objidl.h>
|
||||
#include <mmsystem.h>
|
||||
#include <math.h>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include "resource.h"
|
||||
#include "sound_handler.h"
|
||||
#include "physics.h"
|
||||
|
||||
using namespace Gdiplus;
|
||||
|
||||
Image* LoadImageFromResource(int resId) {
|
||||
HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(resId), RT_RCDATA);
|
||||
if (!hRes) return NULL;
|
||||
// consts
|
||||
static constexpr UINT TIMER_MS = 10;
|
||||
static constexpr int IMAGE_RESOURCE = 111;
|
||||
static constexpr int RESIZE_BORDER = 12; // make wider so easier grab
|
||||
static constexpr int DRAG_THRESHOLD = 5; // pixels before its a drag not a click
|
||||
|
||||
DWORD size = SizeofResource(NULL, hRes);
|
||||
if (size == 0) return NULL;
|
||||
// globals
|
||||
static ULONG_PTR g_gdiplusToken = 0;
|
||||
static Image* g_image = nullptr; // normal hyrax
|
||||
static Image* g_imageScream = nullptr; // awawa hyrax
|
||||
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 object (initial position 200,50 with zero velocity)
|
||||
static physics g_physics(200.0, 50.0, 0.0, 0.0);
|
||||
|
||||
// resize / drag status
|
||||
static bool g_resizing = false;
|
||||
static bool g_dragging = false;
|
||||
static bool g_didDrag = false;
|
||||
static int g_dragOffsetX = 0;
|
||||
static int g_dragOffsetY = 0;
|
||||
static POINT g_lastMouse = {};
|
||||
static POINT g_clickOrigin = {};
|
||||
static double g_lastMouseTime = 0.0;
|
||||
static double g_lastTime = 0.0;
|
||||
|
||||
static bool g_screaming = false;
|
||||
static std::unique_ptr<sound_handler> g_sound;
|
||||
|
||||
// helper definitions
|
||||
static double Now() {
|
||||
LARGE_INTEGER t;
|
||||
QueryPerformanceCounter(&t);
|
||||
return static_cast<double>(t.QuadPart) / static_cast<double>(g_freq.QuadPart);
|
||||
}
|
||||
|
||||
// load any image from any rc resource type
|
||||
static Image* LoadImageFromResource(HINSTANCE hInst, int resId, LPCWSTR resType) {
|
||||
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(resId), resType);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
// 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);
|
||||
srand(static_cast<unsigned>(time(nullptr)));
|
||||
|
||||
GdiplusStartupInput gdiplusStartupInput;
|
||||
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
|
||||
GdiplusStartupInput si;
|
||||
GdiplusStartup(&g_gdiplusToken, &si, nullptr);
|
||||
|
||||
img = LoadImageFromResource(111);
|
||||
HINSTANCE hInst = reinterpret_cast<CREATESTRUCT*>(lParam)->hInstance;
|
||||
|
||||
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);
|
||||
g_image = LoadImageFromResource(hInst, IDR_RCDATA1, RT_RCDATA);
|
||||
g_imageScream = LoadImageFromResource(hInst, IDB_BITMAP1, L"JPG");
|
||||
|
||||
if (g_image) {
|
||||
g_winW = 480;
|
||||
g_winH = 480;
|
||||
SetWindowPos(hwnd, nullptr, 0, 0, g_winW, g_winH,
|
||||
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
SetTimer(hwnd, 1, 10, NULL);
|
||||
// sound handler
|
||||
g_sound = std::make_unique<sound_handler>(
|
||||
hInst,
|
||||
std::initializer_list<int>{
|
||||
IDR_WAVE1, IDR_WAVE2, IDR_WAVE3,
|
||||
IDR_WAVE4, IDR_WAVE5, IDR_WAVE6,
|
||||
IDR_WAVE7, IDR_WAVE8, IDR_WAVE9
|
||||
}
|
||||
);
|
||||
|
||||
last_time = now_time();
|
||||
last_mouse_time = last_time;
|
||||
g_lastTime = Now();
|
||||
g_lastMouseTime = g_lastTime;
|
||||
|
||||
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_didDrag = false;
|
||||
g_dragOffsetX = GET_X_LPARAM(lParam);
|
||||
g_dragOffsetY = GET_Y_LPARAM(lParam);
|
||||
g_physics.resetVelocity(); // stop all motion
|
||||
|
||||
vx = vy = 0;
|
||||
|
||||
GetCursorPos(&last_mouse);
|
||||
last_mouse_time = now_time();
|
||||
GetCursorPos(&g_lastMouse);
|
||||
g_clickOrigin = 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;
|
||||
}
|
||||
if (abs(p.x - g_clickOrigin.x) > DRAG_THRESHOLD ||
|
||||
abs(p.y - g_clickOrigin.y) > DRAG_THRESHOLD)
|
||||
g_didDrag = true;
|
||||
|
||||
last_mouse = p;
|
||||
last_mouse_time = now;
|
||||
const double now = Now();
|
||||
const double dt = now - g_lastMouseTime;
|
||||
|
||||
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) {
|
||||
double vx = (p.x - g_lastMouse.x) / dt;
|
||||
double vy = (p.y - g_lastMouse.y) / dt;
|
||||
g_physics.setVelocity(vx, vy);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
dragging = 0;
|
||||
ReleaseCapture();
|
||||
break;
|
||||
g_lastMouse = p;
|
||||
g_lastMouseTime = now;
|
||||
|
||||
case WM_TIMER: {
|
||||
double now = now_time();
|
||||
double dt = now - last_time;
|
||||
last_time = now;
|
||||
g_physics.setPos(p.x - g_dragOffsetX, p.y - g_dragOffsetY);
|
||||
|
||||
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);
|
||||
}
|
||||
SetWindowPos(hwnd, nullptr, static_cast<int>(g_physics.x()), static_cast<int>(g_physics.y()),
|
||||
0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
break;
|
||||
}
|
||||
|
||||
// drag end or click
|
||||
case WM_LBUTTONUP: {
|
||||
if (!g_didDrag) {
|
||||
// play random sound
|
||||
if (g_sound)
|
||||
g_sound->PlayRandom();
|
||||
}
|
||||
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_physics.resetVelocity();
|
||||
|
||||
// sync gx/y with resized cords
|
||||
RECT r;
|
||||
GetWindowRect(hwnd, &r);
|
||||
g_physics.setPos(static_cast<double>(r.left), static_cast<double>(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 and scream face check
|
||||
case WM_TIMER: {
|
||||
const double now = Now();
|
||||
const double dt = now - g_lastTime;
|
||||
g_lastTime = now;
|
||||
|
||||
if (!g_dragging && !g_resizing) {
|
||||
int screenW = GetSystemMetrics(SM_CXSCREEN);
|
||||
int screenH = GetSystemMetrics(SM_CYSCREEN);
|
||||
g_physics.update(dt, screenW, screenH, g_winW, g_winH);
|
||||
SetWindowPos(hwnd, nullptr, static_cast<int>(g_physics.x()), static_cast<int>(g_physics.y()),
|
||||
0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
// use sound handler instead of doing this in main
|
||||
if (g_sound) {
|
||||
g_sound->Update(now);
|
||||
bool shouldScream = (g_imageScream && g_sound->IsAwAwA(now));
|
||||
if (shouldScream != g_screaming) {
|
||||
g_screaming = shouldScream;
|
||||
InvalidateRect(hwnd, nullptr, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// swap to scream face on peaks
|
||||
Image* frame = (g_screaming && g_imageScream) ? g_imageScream : g_image;
|
||||
if (frame)
|
||||
g.DrawImage(frame, 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);
|
||||
g_sound.reset(); // clean up sound handler
|
||||
delete g_image;
|
||||
delete g_imageScream;
|
||||
g_image = g_imageScream = 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<int>(g_physics.x()), static_cast<int>(g_physics.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<int>(msg.wParam);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Preamble:
|
||||
These exact physics calculations are documented in a TeX Document soon to be in the source tree of
|
||||
the project. (as of 06/05/26 not in the tree; as of 07/05/26 there is a TeX doc. file name: hyrax_exe-TeX_07_05_2026.pdf)
|
||||
|
||||
The physics calculations are done using a Semi-Implicit Euler integrator. (big words)
|
||||
|
||||
| Parameter | Value | Description | Mapped code identifier |
|
||||
|--------------------|--------|------------------------------------------------|------------------------------|
|
||||
| `GRAVITY` | 1200.0 | Downward acceleration (px s^-2) | `GRAVITY` (constant) |
|
||||
| `RESTITUTION` | 0.6 | Energy retention after bounce | `RESTITUTION` (constant) |
|
||||
| `AIR_DRAG` | 0.999 | Velocity multiplier per frame | `AIR_DRAG` (constant) |
|
||||
| `GROUND_FRICTION` | 0.8 | Horizontal speed reduction on ground | `GROUND_FRICTION` (constant) |
|
||||
| `REST_THRESHOLD` | 5.0 | Minimum `\|v_y\|` to consider at rest | `REST_THRESHOLD` (constant) |
|
||||
|
||||
|
||||
06/05/26 - rattatwinko ; when cleaning the source code
|
||||
*/
|
||||
|
||||
#include "physics.h"
|
||||
#include <cmath>
|
||||
|
||||
physics::physics() : physics(0.0, 0.0) {}
|
||||
|
||||
physics::physics(double x, double y, double vx, double vy)
|
||||
: m_x(x), m_y(y), m_vx(vx), m_vy(vy) {
|
||||
}
|
||||
|
||||
void physics::update(double dt, int screenWidth, int screenHeight, int objWidth, int objHeight) {
|
||||
m_vy += GRAVITY * dt;
|
||||
m_vx *= AIR_DRAG;
|
||||
m_vy *= AIR_DRAG;
|
||||
|
||||
m_x += m_vx * dt;
|
||||
m_y += m_vy * dt;
|
||||
|
||||
const double rightBound = static_cast<double>(screenWidth - objWidth);
|
||||
const double bottomBound = static_cast<double>(screenHeight - objHeight);
|
||||
|
||||
if (m_x < 0.0) {
|
||||
m_x = 0.0;
|
||||
m_vx = -m_vx * RESTITUTION;
|
||||
}
|
||||
else if (m_x > rightBound) {
|
||||
m_x = rightBound;
|
||||
m_vx = -m_vx * RESTITUTION;
|
||||
}
|
||||
|
||||
if (m_y < 0.0) {
|
||||
m_y = 0.0;
|
||||
m_vy = -m_vy * RESTITUTION;
|
||||
}
|
||||
else if (m_y > bottomBound) {
|
||||
m_y = bottomBound;
|
||||
m_vy = -m_vy * RESTITUTION;
|
||||
m_vx *= GROUND_FRICTION;
|
||||
if (std::fabs(m_vy) < REST_THRESHOLD)
|
||||
m_vy = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void physics::setPos(double x, double y) {
|
||||
m_x = x;
|
||||
m_y = y;
|
||||
}
|
||||
|
||||
void physics::setVelocity(double vx, double vy) {
|
||||
m_vx = vx;
|
||||
m_vy = vy;
|
||||
}
|
||||
|
||||
void physics::resetVelocity() {
|
||||
m_vx = m_vy = 0.0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#define scd static constexpr double
|
||||
|
||||
class physics
|
||||
{
|
||||
public:
|
||||
scd GRAVITY = 2500.0;
|
||||
scd RESTITUTION = 0.9;
|
||||
scd AIR_DRAG = 0.999;
|
||||
scd GROUND_FRICTION = 0.8;
|
||||
scd REST_THRESHOLD = 5.0;
|
||||
|
||||
physics();
|
||||
physics(double x, double y, double vx = 0.0, double vy = 0.0);
|
||||
void update(double dt, int screenW, int screenH, int objW, int objH);
|
||||
|
||||
// getters / setters
|
||||
double x() const { return m_x; }
|
||||
double y() const { return m_y; }
|
||||
double vx() const { return m_vx; }
|
||||
double vy() const { return m_vy; }
|
||||
void setPos(double x, double y);
|
||||
void setVelocity(double vx, double vy);
|
||||
void resetVelocity();
|
||||
|
||||
private:
|
||||
double m_x, m_y;
|
||||
double m_vx, m_vy;
|
||||
};
|
||||
|
||||
+11
-1
@@ -4,12 +4,22 @@
|
||||
//
|
||||
#define IDR_RCDATA1 111
|
||||
#define IDI_ICON1 114
|
||||
#define IDR_WAVE1 115
|
||||
#define IDR_WAVE2 116
|
||||
#define IDR_WAVE3 118
|
||||
#define IDR_WAVE4 119
|
||||
#define IDR_WAVE5 120
|
||||
#define IDR_WAVE6 121
|
||||
#define IDR_WAVE7 122
|
||||
#define IDR_WAVE8 123
|
||||
#define IDR_WAVE9 124
|
||||
#define IDB_BITMAP1 126
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 115
|
||||
#define _APS_NEXT_RESOURCE_VALUE 127
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
#include "sound_handler.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
sound_handler::sound_handler(HINSTANCE hInst, std::initializer_list<int> waveIds)
|
||||
: m_hInst(hInst), m_wavIds(waveIds)
|
||||
{
|
||||
for (int id : m_wavIds)
|
||||
m_peaks.push_back(AnalyzeWavResource(id));
|
||||
}
|
||||
|
||||
void sound_handler::PlayRandom()
|
||||
{
|
||||
if (m_wavIds.empty()) return;
|
||||
|
||||
int idx = rand() % static_cast<int>(m_wavIds.size());
|
||||
m_currentWave = idx;
|
||||
m_soundStart = Now();
|
||||
m_nextPeak = 0;
|
||||
|
||||
int id = m_wavIds[idx];
|
||||
PlaySoundW(MAKEINTRESOURCEW(id), m_hInst,
|
||||
SND_RESOURCE | SND_ASYNC | SND_NODEFAULT);
|
||||
}
|
||||
|
||||
void sound_handler::Update(double now)
|
||||
{
|
||||
if (m_currentWave < 0 || m_currentWave >= static_cast<int>(m_peaks.size()))
|
||||
return;
|
||||
|
||||
const auto& peaks = m_peaks[m_currentWave].times;
|
||||
double elapsed = now - m_soundStart;
|
||||
|
||||
while (m_nextPeak < static_cast<int>(peaks.size()) && elapsed >= peaks[m_nextPeak]) {
|
||||
m_screamUntil = now + p_hold;
|
||||
++m_nextPeak;
|
||||
}
|
||||
}
|
||||
|
||||
bool sound_handler::IsAwAwA(double now) const
|
||||
{
|
||||
return now < m_screamUntil;
|
||||
}
|
||||
|
||||
sound_handler::PeakData sound_handler::AnalyzeWavResource(int resId)
|
||||
{
|
||||
PeakData data;
|
||||
|
||||
HRSRC hRes = FindResource(m_hInst, MAKEINTRESOURCE(resId), L"WAVE");
|
||||
if (!hRes) return data;
|
||||
|
||||
HGLOBAL hData = LoadResource(m_hInst, hRes);
|
||||
if (!hData) return data;
|
||||
|
||||
DWORD size = SizeofResource(m_hInst, hRes);
|
||||
const BYTE* buf = static_cast<const BYTE*>(LockResource(hData));
|
||||
if (!buf) return data;
|
||||
|
||||
if (size < 44) return data;
|
||||
if (memcmp(buf, "RIFF", 4) != 0 || memcmp(buf + 8, "WAVE", 4) != 0)
|
||||
return data;
|
||||
|
||||
WORD channels = 0;
|
||||
DWORD sampleRate = 0;
|
||||
WORD bitsPerSample = 0;
|
||||
const BYTE* pcm = nullptr;
|
||||
DWORD pcmSize = 0;
|
||||
|
||||
DWORD pos = 12;
|
||||
while (pos + 8 <= size) {
|
||||
DWORD chunkSize = *reinterpret_cast<const DWORD*>(buf + pos + 4);
|
||||
|
||||
if (memcmp(buf + pos, "fmt ", 4) == 0 && chunkSize >= 16) {
|
||||
channels = *reinterpret_cast<const WORD*>(buf + pos + 10);
|
||||
sampleRate = *reinterpret_cast<const DWORD*>(buf + pos + 12);
|
||||
bitsPerSample = *reinterpret_cast<const WORD*>(buf + pos + 22);
|
||||
}
|
||||
else if (memcmp(buf + pos, "data", 4) == 0) {
|
||||
pcm = buf + pos + 8;
|
||||
pcmSize = chunkSize;
|
||||
break;
|
||||
}
|
||||
|
||||
pos += 8 + chunkSize;
|
||||
if (chunkSize & 1) pos++;
|
||||
}
|
||||
|
||||
if (!pcm || bitsPerSample != 16) return data;
|
||||
|
||||
DWORD totalSamples = pcmSize / (channels * sizeof(int16_t));
|
||||
|
||||
int maxAmp = 1;
|
||||
for (DWORD i = 0; i < pcmSize / sizeof(int16_t); i++) {
|
||||
int s = abs(static_cast<int>(
|
||||
*reinterpret_cast<const int16_t*>(pcm + i * sizeof(int16_t))));
|
||||
if (s > maxAmp) maxAmp = s;
|
||||
}
|
||||
|
||||
int threshold = static_cast<int>(maxAmp * p_thresh);
|
||||
DWORD windowSamples = sampleRate / 50; // 20 ms windows
|
||||
DWORD debounce = sampleRate / 8; // 125 ms minimum gap
|
||||
DWORD lastPeak = 0xFFFFFFFF;
|
||||
|
||||
for (DWORD s = 0; s + windowSamples <= totalSamples; s += windowSamples / 2) {
|
||||
int winMax = 0;
|
||||
for (DWORD j = 0; j < windowSamples * channels; j++) {
|
||||
DWORD byteOff = (s * channels + j) * sizeof(int16_t);
|
||||
if (byteOff + sizeof(int16_t) > pcmSize) break;
|
||||
int amp = abs(static_cast<int>(
|
||||
*reinterpret_cast<const int16_t*>(pcm + byteOff)));
|
||||
if (amp > winMax) winMax = amp;
|
||||
}
|
||||
|
||||
bool gapOk = (lastPeak == 0xFFFFFFFF) || (s - lastPeak >= debounce);
|
||||
if (winMax >= threshold && gapOk && data.times.size() < p_max) {
|
||||
data.times.push_back(static_cast<double>(s) / sampleRate);
|
||||
lastPeak = s;
|
||||
if (data.times.size() >= p_max) break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
double sound_handler::Now()
|
||||
{
|
||||
static LARGE_INTEGER freq = [] {
|
||||
LARGE_INTEGER f;
|
||||
QueryPerformanceFrequency(&f);
|
||||
return f;
|
||||
}();
|
||||
LARGE_INTEGER t;
|
||||
QueryPerformanceCounter(&t);
|
||||
return static_cast<double>(t.QuadPart) / static_cast<double>(freq.QuadPart);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class sound_handler
|
||||
{
|
||||
public:
|
||||
struct PeakData {
|
||||
vector<double> times;
|
||||
};
|
||||
|
||||
private:
|
||||
HINSTANCE m_hInst;
|
||||
vector<int> m_wavIds;
|
||||
vector<PeakData> m_peaks;
|
||||
|
||||
int m_currentWave = -1;
|
||||
double m_soundStart = 0.0; // time of playsound
|
||||
int m_nextPeak = 0;
|
||||
double m_screamUntil = 0.0;
|
||||
|
||||
static constexpr double p_hold = 0.10;
|
||||
static constexpr double p_thresh = 0.65;
|
||||
static constexpr int p_max = 64;
|
||||
|
||||
public:
|
||||
sound_handler(HINSTANCE hInst, initializer_list<int> waveIds);
|
||||
void PlayRandom();
|
||||
void Update(double now);
|
||||
bool IsAwAwA(double now) const;
|
||||
|
||||
private:
|
||||
PeakData AnalyzeWavResource(int resId);
|
||||
static double Now();
|
||||
};
|
||||
Reference in New Issue
Block a user