add awawa face and scream sounds
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -140,6 +140,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">
|
||||
|
||||
@@ -39,5 +39,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.
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 |
+163
-18
@@ -18,10 +18,16 @@ rattatwinko - 04/05/26
|
||||
#include <windowsx.h>
|
||||
#include <gdiplus.h>
|
||||
#include <objidl.h>
|
||||
#include <mmsystem.h>
|
||||
#include <math.h>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <cstdint>
|
||||
#include "resource.h"
|
||||
|
||||
#pragma comment(lib, "gdiplus.lib")
|
||||
#pragma comment(lib, "winmm.lib")
|
||||
|
||||
using namespace Gdiplus;
|
||||
|
||||
@@ -33,13 +39,19 @@ 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
|
||||
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
|
||||
static constexpr int WAV_COUNT = 9;
|
||||
static constexpr int MAX_PEAKS = 64; // max screams per sound
|
||||
static constexpr double PEAK_HOLD = 0.10; // seconds which we hold the awawa face
|
||||
static constexpr double PEAK_THRESH = 0.65; // fraction of max amplitude to count as a peak
|
||||
|
||||
// globals
|
||||
static ULONG_PTR g_gdiplusToken = 0;
|
||||
static Image* g_image = nullptr;
|
||||
static int g_winW = 640;
|
||||
static int g_winH = 480;
|
||||
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 = {};
|
||||
|
||||
// physics states
|
||||
@@ -47,14 +59,24 @@ 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
|
||||
// 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;
|
||||
|
||||
// scream face stuff
|
||||
static bool g_screaming = false;
|
||||
static double g_screamUntil = 0.0; // timestamp to stop screaming
|
||||
static double g_soundStart = 0.0; // when playback began
|
||||
static double g_peakTimes[MAX_PEAKS] = {};
|
||||
static int g_peakCount = 0;
|
||||
static int g_peakIdx = 0; // next peak we havent fired yet
|
||||
|
||||
// helper definitions
|
||||
static double Now() {
|
||||
LARGE_INTEGER t;
|
||||
@@ -62,8 +84,9 @@ static double Now() {
|
||||
return static_cast<double>(t.QuadPart) / static_cast<double>(g_freq.QuadPart);
|
||||
}
|
||||
|
||||
static Image* LoadImageFromResource(HINSTANCE hInst, int resId) {
|
||||
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(resId), RT_RCDATA);
|
||||
// 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);
|
||||
@@ -101,6 +124,93 @@ static Image* LoadImageFromResource(HINSTANCE hInst, int resId) {
|
||||
return img;
|
||||
}
|
||||
|
||||
// walk RAW fucking PCM data and check for peaks
|
||||
static void FindWavPeaks(const BYTE* buf, DWORD size) {
|
||||
g_peakCount = 0;
|
||||
g_peakIdx = 0;
|
||||
|
||||
if (size < 44) return;
|
||||
if (memcmp(buf, "RIFF", 4) != 0 || memcmp(buf + 8, "WAVE", 4) != 0) return;
|
||||
|
||||
WORD channels = 0;
|
||||
DWORD sampleRate = 0;
|
||||
WORD bitsPerSample = 0;
|
||||
const BYTE* pcm = nullptr;
|
||||
DWORD pcmSize = 0;
|
||||
|
||||
// walk the chunks
|
||||
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++; // align word cause microsoft likes to fuck my ass
|
||||
}
|
||||
|
||||
// only 16bit PCM cause everything else is just stoopid
|
||||
if (!pcm || !sampleRate || bitsPerSample != 16) return;
|
||||
|
||||
DWORD totalSamples = pcmSize / (channels * sizeof(int16_t));
|
||||
|
||||
// global maximum
|
||||
int maxAmp = 1;
|
||||
for (DWORD i = 0; i < pcmSize / sizeof(int16_t); i++) {
|
||||
int s = abs((int)*reinterpret_cast<const int16_t*>(pcm + i * sizeof(int16_t)));
|
||||
if (s > maxAmp) maxAmp = s;
|
||||
}
|
||||
|
||||
int threshold = static_cast<int>(maxAmp * PEAK_THRESH);
|
||||
DWORD windowSamples = sampleRate / 50; // 20ms windows
|
||||
DWORD debounce = sampleRate / 8; // 125ms min gap so we dont spam
|
||||
DWORD lastPeak = 0xFFFFFFFF;
|
||||
|
||||
// stupid fucking logic. scan for loud moments
|
||||
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((int)*reinterpret_cast<const int16_t*>(pcm + byteOff));
|
||||
if (amp > winMax) winMax = amp;
|
||||
}
|
||||
|
||||
bool gapOk = (lastPeak == 0xFFFFFFFF) || (s - lastPeak >= debounce);
|
||||
if (winMax >= threshold && gapOk && g_peakCount < MAX_PEAKS) {
|
||||
g_peakTimes[g_peakCount++] = static_cast<double>(s) / sampleRate;
|
||||
lastPeak = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// play a random hyrax sound and prep the scream timeline
|
||||
static void PlayRandomSound(HINSTANCE hInst) {
|
||||
int id = IDR_WAVE1 + (rand() % WAV_COUNT);
|
||||
|
||||
// grab raw wave data and look for peaks ; possible cause of .rc WAVE type
|
||||
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(id), L"WAVE");
|
||||
HGLOBAL hData = hRes ? LoadResource(hInst, hRes) : nullptr;
|
||||
BYTE* pData = hData ? static_cast<BYTE*>(LockResource(hData)) : nullptr;
|
||||
DWORD sz = hRes ? SizeofResource(hInst, hRes) : 0;
|
||||
|
||||
if (pData && sz)
|
||||
FindWavPeaks(pData, sz);
|
||||
|
||||
g_soundStart = Now();
|
||||
|
||||
PlaySoundW(MAKEINTRESOURCEW(id), hInst, SND_RESOURCE | SND_ASYNC | SND_NODEFAULT);
|
||||
}
|
||||
|
||||
// physics "engine"
|
||||
static void StepPhysics(double dt) {
|
||||
const int screenW = GetSystemMetrics(SM_CXSCREEN);
|
||||
@@ -113,7 +223,7 @@ static void StepPhysics(double dt) {
|
||||
g_x += g_vx * dt;
|
||||
g_y += g_vy * dt;
|
||||
|
||||
// left/ right monitor borders
|
||||
// left / right monitor borders
|
||||
if (g_x < 0.0) {
|
||||
g_x = 0.0;
|
||||
g_vx = -g_vx * RESTITUTION;
|
||||
@@ -143,15 +253,18 @@ static void StepPhysics(double dt) {
|
||||
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (msg) {
|
||||
|
||||
// init the window
|
||||
// init the window
|
||||
case WM_CREATE: {
|
||||
QueryPerformanceFrequency(&g_freq);
|
||||
srand(static_cast<unsigned>(time(nullptr)));
|
||||
|
||||
GdiplusStartupInput si;
|
||||
GdiplusStartup(&g_gdiplusToken, &si, nullptr);
|
||||
|
||||
HINSTANCE hInst = reinterpret_cast<CREATESTRUCT*>(lParam)->hInstance;
|
||||
g_image = LoadImageFromResource(hInst, IMAGE_RESOURCE);
|
||||
|
||||
g_image = LoadImageFromResource(hInst, IDR_RCDATA1, RT_RCDATA);
|
||||
g_imageScream = LoadImageFromResource(hInst, IDB_BITMAP1, L"JPG");
|
||||
|
||||
if (g_image) {
|
||||
g_winW = static_cast<int>(g_image->GetWidth());
|
||||
@@ -170,11 +283,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
||||
// drag start
|
||||
case WM_LBUTTONDOWN: {
|
||||
g_dragging = true;
|
||||
g_didDrag = false;
|
||||
g_dragOffsetX = GET_X_LPARAM(lParam);
|
||||
g_dragOffsetY = GET_Y_LPARAM(lParam);
|
||||
g_vx = g_vy = 0.0;
|
||||
|
||||
GetCursorPos(&g_lastMouse);
|
||||
g_clickOrigin = g_lastMouse;
|
||||
g_lastMouseTime = Now();
|
||||
|
||||
SetCapture(hwnd);
|
||||
@@ -188,6 +303,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
||||
POINT p;
|
||||
GetCursorPos(&p);
|
||||
|
||||
if (abs(p.x - g_clickOrigin.x) > DRAG_THRESHOLD ||
|
||||
abs(p.y - g_clickOrigin.y) > DRAG_THRESHOLD)
|
||||
g_didDrag = true;
|
||||
|
||||
const double now = Now();
|
||||
const double dt = now - g_lastMouseTime;
|
||||
|
||||
@@ -207,12 +326,17 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
||||
break;
|
||||
}
|
||||
|
||||
// drag end
|
||||
case WM_LBUTTONUP:
|
||||
// drag end or click
|
||||
case WM_LBUTTONUP: {
|
||||
if (!g_didDrag) {
|
||||
HINSTANCE hInst = reinterpret_cast<HINSTANCE>(GetWindowLongPtrW(hwnd, GWLP_HINSTANCE));
|
||||
PlayRandomSound(hInst);
|
||||
}
|
||||
g_dragging = false;
|
||||
ReleaseCapture();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// while dragging nutz accross fohead disable OS from doing shit
|
||||
case WM_ENTERSIZEMOVE:
|
||||
g_resizing = true;
|
||||
@@ -269,7 +393,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
||||
}
|
||||
return DefWindowProcW(hwnd, msg, wParam, lParam);
|
||||
|
||||
// phyisks tick
|
||||
// phyisks tick and scream face check
|
||||
case WM_TIMER: {
|
||||
const double now = Now();
|
||||
const double dt = now - g_lastTime;
|
||||
@@ -280,6 +404,23 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
||||
SetWindowPos(hwnd, nullptr, static_cast<int>(g_x), static_cast<int>(g_y),
|
||||
0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
// extend scream hold
|
||||
if (g_peakCount > 0) {
|
||||
double elapsed = now - g_soundStart;
|
||||
while (g_peakIdx < g_peakCount && elapsed >= g_peakTimes[g_peakIdx]) {
|
||||
g_screamUntil = now + PEAK_HOLD;
|
||||
g_peakIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
// flip face state
|
||||
bool shouldScream = (g_imageScream && now < g_screamUntil);
|
||||
if (shouldScream != g_screaming) {
|
||||
g_screaming = shouldScream;
|
||||
InvalidateRect(hwnd, nullptr, FALSE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -296,8 +437,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
||||
Graphics g(memDC);
|
||||
g.SetInterpolationMode(InterpolationModeHighQualityBicubic);
|
||||
|
||||
if (g_image)
|
||||
g.DrawImage(g_image, 0, 0, g_winW, g_winH);
|
||||
// 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);
|
||||
|
||||
@@ -317,11 +460,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
||||
DestroyWindow(hwnd);
|
||||
break;
|
||||
|
||||
|
||||
// consuela
|
||||
case WM_DESTROY:
|
||||
KillTimer(hwnd, 1);
|
||||
delete g_image;
|
||||
g_image = nullptr;
|
||||
delete g_imageScream;
|
||||
g_image = g_imageScream = nullptr;
|
||||
GdiplusShutdown(g_gdiplusToken);
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
|
||||
+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
|
||||
|
||||
Reference in New Issue
Block a user