diff --git a/.gitignore b/.gitignore index ec8ccd8..bb6b7bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /build /.vs +HidCerberus.Lib.log diff --git a/HidCerberus.Lib.log b/HidCerberus.Lib.log deleted file mode 100644 index 5d75861..0000000 --- a/HidCerberus.Lib.log +++ /dev/null @@ -1,6 +0,0 @@ -2024-07-08 21:41:59.339 HidCerberus.Lib:HidGuardianOpen [Information]: Sending add request: http://localhost:26762/api/v1/hidguardian/whitelist/add/7440 -2024-07-09 18:33:47.443 HidCerberus.Lib:HidGuardianOpen [Information]: Sending add request: http://localhost:26762/api/v1/hidguardian/whitelist/add/7156 -2024-07-09 18:33:47.854 HidCerberus.Lib:HidGuardianClose [Information]: Sending remove request: http://localhost:26762/api/v1/hidguardian/whitelist/remove/7156 -2024-07-09 18:34:16.211 HidCerberus.Lib:HidGuardianOpen [Information]: Sending add request: http://localhost:26762/api/v1/hidguardian/whitelist/add/4240 -2024-07-09 18:34:16.316 HidCerberus.Lib:HidGuardianClose [Information]: Sending remove request: http://localhost:26762/api/v1/hidguardian/whitelist/remove/4240 -2024-07-09 18:34:23.477 HidCerberus.Lib:HidGuardianOpen [Information]: Sending add request: http://localhost:26762/api/v1/hidguardian/whitelist/add/7712 diff --git a/misc/build.bat b/misc/build.bat index ae070af..f9ad3ca 100644 --- a/misc/build.bat +++ b/misc/build.bat @@ -1,8 +1,21 @@ @echo off if NOT EXIST .\build mkdir .\build pushd .\build -pwd -cl -FC -Zi -Fe:handmade.exe ..\src\win32_handmade.cpp user32.lib Gdi32.lib +cl ^ + -MT %= Make sure the C runtime library is statically linked =%^ + -Fmwin32_handmade.map %= Create a map file =%^ + -Gm- %= Turns off incremently building =%^ + -nologo %= No one cares you made the compiler Microsoft =%^ + -Oi %= Always use intrinsics =%^ + -EHa- %= Disable exception handling =%^ + -GR- %= Never use runtime type info from C++ =%^ + -WX -W4 -wd4201 -wd4100 -wd4189 %= Compiler warnings, -WX warnings as errors, -W4 warning level 4, -wdXXXX disable warning XXXX =%^ + -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_WIN32=1 %= Custom #defines =%^ + -FC %= Full path of source code file in diagnostics =%^ + -Zi %= Generate debugger info =%^ + -Fe:handmade.exe ..\src\win32_handmade.cpp %= Output filename, input filename =%^ + user32.lib Gdi32.lib %= Linked libraries =%^ + /link -subsystem:windows,5.1 %= Linker stuff =% popd exit /b diff --git a/misc/shell.bat b/misc/shell.bat index 1e54aaa..a388445 100644 --- a/misc/shell.bat +++ b/misc/shell.bat @@ -2,4 +2,5 @@ start "ProconXInput" "C:\Program Files\ProconXInput\ProconXInput.exe" call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" set path=C:\source\repos\handmade\misc;%path% -cd C:\source\repos\handmade\ \ No newline at end of file +cd C:\source\repos\handmade\ +cmd /k \ No newline at end of file diff --git a/src/handmade.cpp b/src/handmade.cpp index f374ba8..09768e6 100644 --- a/src/handmade.cpp +++ b/src/handmade.cpp @@ -3,7 +3,7 @@ #define PI32 3.141592653589f void debug_printf(wchar_t* format, ...) { - int bufsize = wcslen(format)*10; + size_t bufsize = wcslen(format)*10; wchar_t *output = (wchar_t*)malloc(bufsize); va_list list; va_start(list, format); @@ -12,17 +12,16 @@ void debug_printf(wchar_t* format, ...) { free(output); } -internal void outputSound(GameSoundOutputBuffer *soundBuffer, int toneHz) { - local_persist real32 tSine; +internal void outputSineSound(GameSoundOutputBuffer *soundBuffer, GameState *state) { int16 toneVolume = 3000; - int wavePeriod = soundBuffer->samplesPerSecond/toneHz; + int wavePeriod = soundBuffer->samplesPerSecond/state->toneHz; int16 *sampleOut = soundBuffer->samples; for (int sampleIndex = 0; sampleIndex < soundBuffer->sampleCount; sampleIndex++) { - int16 sampleValue = (int16)(sin(tSine) * (real32)toneVolume); + int16 sampleValue = (int16)(sin(state->tSine) * (real32)toneVolume); *sampleOut++ = sampleValue; *sampleOut++ = sampleValue; - tSine += 2.0f * PI32 / (real32)wavePeriod; + state->tSine += 2.0f * PI32 / (real32)wavePeriod; } } @@ -33,18 +32,51 @@ internal void renderWeirdGradient(GameOffscreenBuffer *buffer, int xOffset, int for (int y = 0; y < buffer->height; y++) { uint32 *pixel = (uint32*)row; for (int x = 0; x < buffer->width; x++) { - uint8 blue = x + xOffset; - uint8 green = y + yOffset; + uint8 blue = (uint8)(x + xOffset); + uint8 green = (uint8)(y + yOffset); *pixel++ = (green << 8) | blue; } row += pitch; } } -internal void gameUpdateAndRender(GameOffscreenBuffer *videoBuf, GameInput *input, GameSoundOutputBuffer *soundBuf) { - local_persist int greenOffset = 0; - local_persist int blueOffset = 0; - local_persist int toneHz = 440; - outputSound(soundBuf, toneHz); - renderWeirdGradient(videoBuf, input->xOffset, input->yOffset); +internal void gameUpdateAndRender(GameMemory *memory, GameOffscreenBuffer *videoBuf, GameInput *input, GameSoundOutputBuffer *soundBuf) { + Assert(sizeof(GameState) <= memory->permanentStorageSize); + + GameState *state = (GameState*)memory->permanentStorage; + + if (!memory->isInitialised) { + //DebugReadFileResult bmpMem = DEBUG_platformReadEntireFile(__FILE__); + //if (bmpMem.contents) { + // DEBUG_platformWriteEntireFile("c:/source/repos/handmade/src/test.cpp", bmpMem.contentsSize, bmpMem.contents); + // DEBUG_platformFreeFileMemory(bmpMem.contents); + //} + + state->toneHz = 440; + state->tSine = 0; + memory->isInitialised = true; + } + + for (int controllerIndex = 0; controllerIndex < ArrayCount(input->controllers); controllerIndex++) { + GameControllerInput *controllerInput = &input->controllers[controllerIndex]; + if (controllerInput->isAnalog) { + state->toneHz = 440 + (int)(128.0f*controllerInput->stickAvgX); + state->greenOffset -= (int)(4.0f*controllerInput->stickAvgX); + state->blueOffset += (int)(4.0f*controllerInput->stickAvgY); + } else { + if (controllerInput->stickRight.endedDown) { + state->greenOffset -= 4; + } else if (controllerInput->stickLeft.endedDown) { + state->greenOffset += 4; + } + if (controllerInput->stickUp.endedDown) { + state->blueOffset += 4; + } else if (controllerInput->stickDown.endedDown) { + state->blueOffset -= 4; + } + } + } + + outputSineSound(soundBuf, state); + renderWeirdGradient(videoBuf, state->greenOffset, state->blueOffset); } diff --git a/src/handmade.h b/src/handmade.h index 399c693..f51261f 100644 --- a/src/handmade.h +++ b/src/handmade.h @@ -6,6 +6,38 @@ #pragma once +/* + * --------------- + * Global flags: + * --------------- + * + * HANDMADE_SLOW + * 0 - No slow code allowed + * 1 - Slow code welcome + * + * HANDMADE_INTERNAL + * 0 - Build for public release + * 1 - Build for developer only + * + * HANDMADE_WIN32 + * 0 - Not a windows build + * 1 - This is a windows build + * + */ + +#if HANDMADE_SLOW +#define Assert(Expression) if (!(Expression)) {*(int *)0 = 0;} +#else +#define Assert(Expression) +#endif + +#define Kilobytes(Value) (Value*1024) +#define Megabytes(Value) (Kilobytes(Value)*1024) +#define Gigabytes(Value) (Megabytes(Value)*1024) +#define Terabytes(Value) (Gigabytes(Value)*1024) + +#define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0])) + #define internal static // for functions #define local_persist static // for static variables in a scope #define global static // for global variables @@ -25,14 +57,14 @@ typedef double real64; typedef int32_t bool32; -void debug_printf(wchar_t* format, ...); +#define MAX_SAFE_UINT32 0xFFFFFFFF -// Game to platform layer services -struct GameInput { - int xOffset; - int yOffset; -}; +inline uint32 safeTruncateUInt64(uint64 val) { + Assert(val <= MAX_SAFE_UINT32); + return (uint32)val; +} +// Game to platform layer services struct GameSoundOutputBuffer { int samplesPerSecond; int sampleCount; @@ -45,6 +77,69 @@ struct GameOffscreenBuffer { int height; }; -void gameUpdateAndRender(GameOffscreenBuffer *videoBuf, GameInput *input, GameSoundOutputBuffer *soundBuf); +struct GameButtonState { + int halfTransitionCount; + bool32 endedDown; +}; + +struct GameControllerInput { + bool32 isAnalog; + + real32 stickAvgY; + real32 stickAvgX; + + union { + GameButtonState buttons[6]; + struct { + GameButtonState stickUp; + GameButtonState stickDown; + GameButtonState stickLeft; + GameButtonState stickRight; + GameButtonState btnUp; + GameButtonState btnDown; + GameButtonState btnLeft; + GameButtonState btnRight; + GameButtonState leftShoulder; + GameButtonState rightShoulder; + }; + }; +}; + +struct GameInput { + GameControllerInput controllers[5]; +}; + +struct GameMemory { + bool32 isInitialised; + uint64 permanentStorageSize; + void *permanentStorage; // required to be initialised to zero at startup + uint64 transientStorageSize; + void *transientStorage; // required to be initialised to zero at startup +}; + +struct GameState { + int toneHz; + int greenOffset; + int blueOffset; + real32 tSine; +}; + +// === Game to platform services === +void gameUpdateAndRender(GameMemory *memory, GameInput *input, GameOffscreenBuffer *videoBuf, GameSoundOutputBuffer *soundBuf); + +// === Platform to game services === +#if HANDMADE_INTERNAL + +struct DebugReadFileResult { + uint32 contentsSize; + void *contents; +}; + +DebugReadFileResult DEBUG_platformReadEntireFile(char *filename); +void DEBUG_platformFreeFileMemory(void *memory); +bool32 DEBUG_platformWriteEntireFile(char *filename, uint32 memorySize, void *memory); +void debug_printf(wchar_t* format, ...); + +#endif + -// Platform to game services diff --git a/src/test.cpp b/src/test.cpp new file mode 100644 index 0000000..c981900 --- /dev/null +++ b/src/test.cpp @@ -0,0 +1,86 @@ +#include "handmade.h" + +#define PI32 3.141592653589f + +void debug_printf(wchar_t* format, ...) { + size_t bufsize = wcslen(format)*10; + wchar_t *output = (wchar_t*)malloc(bufsize); + va_list list; + va_start(list, format); + vswprintf(output, bufsize, format, list); + OutputDebugStringW(output); + free(output); +} + +internal void outputSineSound(GameSoundOutputBuffer *soundBuffer, GameState *state) { + int16 toneVolume = 3000; + int wavePeriod = soundBuffer->samplesPerSecond/state->toneHz; + + int16 *sampleOut = soundBuffer->samples; + for (int sampleIndex = 0; sampleIndex < soundBuffer->sampleCount; sampleIndex++) { + int16 sampleValue = (int16)(sin(state->tSine) * (real32)toneVolume); + *sampleOut++ = sampleValue; + *sampleOut++ = sampleValue; + state->tSine += 2.0f * PI32 / (real32)wavePeriod; + } +} + +internal void renderWeirdGradient(GameOffscreenBuffer *buffer, int xOffset, int yOffset) { + int bytesPerPixel = 4; + int pitch = buffer->width*bytesPerPixel; + uint8 *row = (uint8 *)buffer->memory; + for (int y = 0; y < buffer->height; y++) { + uint32 *pixel = (uint32*)row; + for (int x = 0; x < buffer->width; x++) { + uint8 blue = (uint8)(x + xOffset); + uint8 green = (uint8)(y + yOffset); + *pixel++ = (green << 8) | blue; + } + row += pitch; + } +} + +internal void gameUpdateAndRender(GameMemory *memory, GameOffscreenBuffer *videoBuf, GameInput *input, GameSoundOutputBuffer *soundBuf) { + Assert(sizeof(GameState) <= memory->permanentStorageSize); + + GameState *state = (GameState*)memory->permanentStorage; + + if (!memory->isInitialised) { + DebugReadFileResult bmpMem = DEBUG_platformReadEntireFile(__FILE__); + if (bmpMem.contents) { + DEBUG_platformWriteEntireFile("c:/source/repos/handmade/src/test.cpp", bmpMem.contentsSize, bmpMem.contents); + DEBUG_platformFreeFileMemory(bmpMem.contents); + } + + state->toneHz = 440; + state->tSine = 0; + memory->isInitialised = true; + } + + for (int controllerIndex = 0; controllerIndex < ArrayCount(input->controllers); controllerIndex++) { + GameControllerInput *controllerInput = &input->controllers[controllerIndex]; + if (controllerInput->isAnalog) { + //state->toneHz = 440 + (int)(128.0f*controllerInput->stickAvgX); + //state->greenOffset -= (int)(4.0f*controllerInput->stickAvgX); + //state->blueOffset += (int)(4.0f*controllerInput->stickAvgY); + } else { + if (controllerInput->stickRight.endedDown) { + state->toneHz = 440 + 128; + state->greenOffset -= 4; + } else if (controllerInput->stickLeft.endedDown) { + state->toneHz = 440 - 128; + state->greenOffset += 4; + } else { + state->toneHz = 440; + } + if (controllerInput->stickUp.endedDown) { + state->blueOffset += 4; + } else if (controllerInput->stickDown.endedDown) { + state->blueOffset -= 4; + } + } + } + + outputSineSound(soundBuf, state); + renderWeirdGradient(videoBuf, state->greenOffset, state->blueOffset); +} diff --git a/src/win32_handmade.cpp b/src/win32_handmade.cpp index 29bd37a..79bdabd 100644 --- a/src/win32_handmade.cpp +++ b/src/win32_handmade.cpp @@ -7,7 +7,7 @@ #include "handmade.cpp" global ATOM HH_CTRLW; -global bool running; +global bool globalRunning; global Win32OffscreenBuffer globalBackBuffer; global LPDIRECTSOUNDBUFFER globalSecondaryBuffer; @@ -29,6 +29,61 @@ typedef HRESULT WINAPI DirectSoundCreateFn(LPCGUID pcGuidDevice, LPDIRECTSOUND * #define stackAlloc(size, type) (type*)_alloca(size*sizeof(type)) +void DEBUG_platformFreeFileMemory(void *fileMemory) { + if (fileMemory) { + VirtualFree(fileMemory, NULL, MEM_RELEASE); + } +} + +DebugReadFileResult DEBUG_platformReadEntireFile(char *filename) { + DebugReadFileResult result = {}; + HANDLE fileHandle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); + if (fileHandle != INVALID_HANDLE_VALUE) { + LARGE_INTEGER fileSize; + if (GetFileSizeEx(fileHandle, &fileSize)) { + uint32 fileSize32 = safeTruncateUInt64(fileSize.QuadPart); + result.contents = VirtualAlloc(NULL, fileSize.QuadPart, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (result.contents) { + DWORD bytesRead; + if (ReadFile(fileHandle, result.contents, (DWORD)fileSize.QuadPart, &bytesRead, NULL) && (fileSize32 == (uint32)bytesRead)) { + result.contentsSize = fileSize32; + } else { + DEBUG_platformFreeFileMemory(result.contents); + result.contents = NULL; + // logging + } + } else { + result.contents = NULL; + // logging + } + } else { + // logging + } + CloseHandle(fileHandle); + } else { + // logging + } + return result; +} + +bool32 DEBUG_platformWriteEntireFile(char *filename, uint32 memorySize, void *memory) { + bool32 result = false; + HANDLE fileHandle = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL); + if (fileHandle != INVALID_HANDLE_VALUE) { + DWORD bytesWritten; + if (WriteFile(fileHandle, memory, memorySize, &bytesWritten, NULL)) { + // file written successfully + result = bytesWritten == memorySize; + } else { + // logging + } + CloseHandle(fileHandle); + } else { + // logging + } + return result; +} + internal void resizeDIBSection(Win32OffscreenBuffer *buffer, int width, int height) { if (buffer->memory) { VirtualFree(buffer->memory, NULL, MEM_RELEASE); @@ -82,6 +137,16 @@ internal void win32LoadXInput() { } } +internal void win32ProcessKeyboardKeypress(GameButtonState *newState, bool32 isDown) { + newState->endedDown = isDown; + newState->halfTransitionCount++; +} + +internal void win32ProcessXInputDigitalButton(DWORD xInputButtonState, GameButtonState *oldState, GameButtonState *newState, DWORD buttonBit) { + newState->endedDown = (xInputButtonState & buttonBit) == buttonBit; + newState->halfTransitionCount = (oldState->endedDown != newState->endedDown) ? 1 : 0; +} + internal void win32InitSound(HWND window, int32 samplesPerSec, int bufferSize) { HMODULE dSoundLibrary = LoadLibraryA("dsound.dll"); if (dSoundLibrary) { @@ -145,7 +210,7 @@ LRESULT mainWindowCallback( } break; case WM_CLOSE: { - running = false; + globalRunning = false; } break; case WM_PAINT: { @@ -164,7 +229,7 @@ LRESULT mainWindowCallback( case WM_HOTKEY: { if (wParam == HH_CTRLW) { - running = false; + globalRunning = false; } } break; @@ -172,29 +237,7 @@ LRESULT mainWindowCallback( case WM_SYSKEYUP: case WM_KEYUP: case WM_KEYDOWN: { - uint32 VKCode = wParam; - bool wasDown = (lParam & (1 << 30)) != 0; - bool isDown = (lParam & (1 << 31)) == 0; - if (wasDown != isDown) { - if (VKCode == 'W') { - } else if (VKCode == 'A') { - } else if (VKCode == 'S') { - } else if (VKCode == 'D') { - } else if (VKCode == 'Q') { - } else if (VKCode == 'E') { - } else if (VKCode == VK_ESCAPE) { - } else if (VKCode == VK_UP) { - } else if (VKCode == VK_LEFT) { - } else if (VKCode == VK_DOWN) { - } else if (VKCode == VK_RIGHT) { - } else if (VKCode == VK_SPACE) { - } - } - - bool32 altKeyWasDown = lParam & (1 << 29); - if (altKeyWasDown && VKCode == VK_F4) { - running = false; - } + Assert(!"Keyboard input came in through a non-dispatch message."); } break; default: { @@ -253,6 +296,61 @@ internal void win32FillSoundBuffer(Win32SoundOutput *soundOutput, DWORD byteToLo } } +internal void win32ProcessPendingMessages(GameControllerInput *keyboardController) { + MSG message; + while (PeekMessageA(&message, NULL, NULL, NULL, PM_REMOVE)) { + if (message.message == WM_QUIT) { + globalRunning = false; + } + + switch (message.message) { + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_KEYUP: + case WM_KEYDOWN: { + uint32 VKCode = (uint32)message.wParam; + bool wasDown = (message.lParam & (1 << 30)) != 0; + bool isDown = (message.lParam & (1 << 31)) == 0; + if (wasDown != isDown) { + if (VKCode == 'W') { + win32ProcessKeyboardKeypress(&keyboardController->stickUp, isDown); + } else if (VKCode == 'A') { + win32ProcessKeyboardKeypress(&keyboardController->stickLeft, isDown); + } else if (VKCode == 'S') { + win32ProcessKeyboardKeypress(&keyboardController->stickDown, isDown); + } else if (VKCode == 'D') { + win32ProcessKeyboardKeypress(&keyboardController->stickRight, isDown); + } else if (VKCode == 'Q') { + win32ProcessKeyboardKeypress(&keyboardController->leftShoulder, isDown); + } else if (VKCode == 'E') { + win32ProcessKeyboardKeypress(&keyboardController->rightShoulder, isDown); + } else if (VKCode == VK_ESCAPE) { + } else if (VKCode == VK_UP) { + win32ProcessKeyboardKeypress(&keyboardController->btnUp, isDown); + } else if (VKCode == VK_LEFT) { + win32ProcessKeyboardKeypress(&keyboardController->btnLeft, isDown); + } else if (VKCode == VK_DOWN) { + win32ProcessKeyboardKeypress(&keyboardController->btnDown, isDown); + } else if (VKCode == VK_RIGHT) { + win32ProcessKeyboardKeypress(&keyboardController->btnRight, isDown); + } else if (VKCode == VK_SPACE) { + } + } + + bool32 altKeyWasDown = message.lParam & (1 << 29); + if (altKeyWasDown && VKCode == VK_F4) { + globalRunning = false; + } + } break; + + default: { + TranslateMessage(&message); + DispatchMessage(&message); + } break; + } + } +} + int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLine, int commandShow) { LARGE_INTEGER performanceFrequencyResult; QueryPerformanceFrequency(&performanceFrequencyResult); @@ -285,26 +383,36 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin HH_CTRLW = GlobalAddAtomA("HH_CTRLW"); RegisterHotKey(window, HH_CTRLW, MOD_CONTROL, 'W'); - MSG message; - running = true; + globalRunning = true; + GameInput input[2] = {}; + GameInput *oldInput = &input[0]; + GameInput *newInput = &input[1]; win32LoadXInput(); - // graphics test - int xOffset = 0; - int yOffset = 0; - // sound test Win32SoundOutput soundOutput = {}; soundOutput.samplesPerSecond = 48000; - soundOutput.wavePeriod = soundOutput.samplesPerSecond / soundOutput.toneHz; soundOutput.runningSampleIndex = 0; soundOutput.bytesPerSample = sizeof(int16)*2; soundOutput.secondaryBufferSize = soundOutput.samplesPerSecond*soundOutput.bytesPerSample; - soundOutput.latencySampleCount = soundOutput.samplesPerSecond / 15.0f; + soundOutput.latencySampleCount = (int)(soundOutput.samplesPerSecond / 15.0f); int16 *samples = (int16*)VirtualAlloc(NULL, soundOutput.secondaryBufferSize, MEM_COMMIT, PAGE_READWRITE); +#if HANDMADE_INTERNAL + LPVOID baseAddress = (LPVOID)Terabytes((uint64)2); +#else + LPVOID baseAddress = 0; +#endif + GameMemory gameMemory = {}; + gameMemory.permanentStorageSize = Megabytes(64); + gameMemory.transientStorageSize = Gigabytes((uint64)4); + + uint64 totalSize = gameMemory.permanentStorageSize + gameMemory.transientStorageSize; + gameMemory.permanentStorage = VirtualAlloc(baseAddress, totalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + gameMemory.transientStorage = ((uint8 *)gameMemory.permanentStorage + gameMemory.permanentStorageSize); + win32InitSound(window, soundOutput.samplesPerSecond, soundOutput.secondaryBufferSize); win32ClearBuffer(&soundOutput); globalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING); @@ -312,70 +420,90 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin LARGE_INTEGER lastCounter; QueryPerformanceCounter(&lastCounter); int64 lastCycleCount = __rdtsc(); - while (running) { - while (PeekMessageA(&message, NULL, NULL, NULL, PM_REMOVE)) { - if (message.message == WM_QUIT) { - running = false; - } - TranslateMessage(&message); - DispatchMessage(&message); + while (globalRunning) { + GameControllerInput *oldKeyboardController = &oldInput->controllers[0]; + GameControllerInput *newKeyboardController = &newInput->controllers[0]; + GameControllerInput zeroController = {}; + *newKeyboardController = zeroController; + for (int buttonIndex = 0; buttonIndex < ArrayCount(oldKeyboardController->buttons); buttonIndex++) { + newKeyboardController->buttons[buttonIndex].endedDown = oldKeyboardController->buttons[buttonIndex].endedDown; } + win32ProcessPendingMessages(newKeyboardController); + XINPUT_STATE controllerState; + int maxControllerCount = 1 + XUSER_MAX_COUNT; + if (maxControllerCount > ArrayCount(newInput->controllers)) { + maxControllerCount = ArrayCount(newInput->controllers); + } + for (DWORD controllerIndex = 0; controllerIndex < XUSER_MAX_COUNT; controllerIndex++) { if (XInputGetState(controllerIndex, &controllerState) == ERROR_SUCCESS) { - break; + DWORD ourControllerIndex = controllerIndex + 1; + GameControllerInput *oldController = &oldInput->controllers[ourControllerIndex]; + GameControllerInput *newController = &newInput->controllers[ourControllerIndex]; + + newController->isAnalog = true; + + XINPUT_GAMEPAD *pad = &controllerState.Gamepad; + + int16 stickX = pad->sThumbLX; + int16 stickY = pad->sThumbLY; + real32 stickYNorm = 0; + real32 stickXNorm = 0; + if (stickY != 0 && abs(stickY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + stickYNorm = stickY / 32767.0f; + } + if (stickX != 0 && abs(stickX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { + stickXNorm = stickX / 32767.0f; + } + + newController->stickAvgX = stickXNorm; + newController->stickAvgY = stickYNorm; + if (pad->wButtons & XINPUT_GAMEPAD_DPAD_UP) { + newController->stickAvgY = 1.0f; + } + if (pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN) { + newController->stickAvgY = -1.0f; + } + if (pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT) { + newController->stickAvgX = -1.0f; + } + if (pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) { + newController->stickAvgX = 1.0f; + } + + //bool start = (pad->wButtons & XINPUT_GAMEPAD_START); + //bool back = (pad->wButtons & XINPUT_GAMEPAD_BACK); + + win32ProcessXInputDigitalButton(pad->wButtons, &oldController->btnDown, &newController->btnDown, XINPUT_GAMEPAD_A); + win32ProcessXInputDigitalButton(pad->wButtons, &oldController->btnRight, &newController->btnRight, XINPUT_GAMEPAD_B); + win32ProcessXInputDigitalButton(pad->wButtons, &oldController->btnLeft, &newController->btnLeft, XINPUT_GAMEPAD_X); + win32ProcessXInputDigitalButton(pad->wButtons, &oldController->btnUp, &newController->btnUp, XINPUT_GAMEPAD_Y); + win32ProcessXInputDigitalButton(pad->wButtons, &oldController->leftShoulder, &newController->leftShoulder, XINPUT_GAMEPAD_LEFT_SHOULDER); + win32ProcessXInputDigitalButton(pad->wButtons, &oldController->rightShoulder, &newController->rightShoulder, XINPUT_GAMEPAD_RIGHT_SHOULDER); + + real32 threshold = 0.5f; + win32ProcessXInputDigitalButton((DWORD)(newController->stickAvgY < -threshold), &oldController->stickDown, &newController->stickDown, 1); + win32ProcessXInputDigitalButton((DWORD)(newController->stickAvgX > threshold), &oldController->stickRight, &newController->stickRight, 1); + win32ProcessXInputDigitalButton((DWORD)(newController->stickAvgX < -threshold), &oldController->stickLeft, &newController->stickLeft, 1); + win32ProcessXInputDigitalButton((DWORD)(newController->stickAvgY > threshold), &oldController->stickUp, &newController->stickUp, 1); } else { // controller not available } } - XINPUT_GAMEPAD *Pad = &controllerState.Gamepad; - bool up = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_UP); - bool down = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN); - bool left = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT); - bool right = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT); - bool start = (Pad->wButtons & XINPUT_GAMEPAD_START); - bool back = (Pad->wButtons & XINPUT_GAMEPAD_BACK); - bool leftShoulder = (Pad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER); - bool rightShoulder = (Pad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER); - bool aButton = (Pad->wButtons & XINPUT_GAMEPAD_A); - bool bButton = (Pad->wButtons & XINPUT_GAMEPAD_B); - bool xButton = (Pad->wButtons & XINPUT_GAMEPAD_X); - bool yButton = (Pad->wButtons & XINPUT_GAMEPAD_Y); - int16 stickX = Pad->sThumbLX; - int16 stickY = Pad->sThumbLY; - - float stickYNorm = 0; - float stickXNorm = 0; - if (stickY != 0 && abs(stickY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - stickYNorm = stickY / 32767.0; - } - if (stickX != 0 && abs(stickX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - stickXNorm = stickX / 32767.0; - } - - float factor = leftShoulder ? 2.5 : 1.0; - yOffset += stickY/5000.0 * factor; - xOffset -= stickX/5000.0 * factor; - - soundOutput.toneHz = 220 + (stickYNorm + 1.0)/2.0 * 220.0; - soundOutput.wavePeriod = soundOutput.samplesPerSecond / soundOutput.toneHz; GameOffscreenBuffer videoBuffer = {}; videoBuffer.memory = globalBackBuffer.memory; videoBuffer.width = globalBackBuffer.width; videoBuffer.height = globalBackBuffer.height; - GameInput input = {}; - input.xOffset = xOffset; - input.yOffset = yOffset; - // Sound test - DWORD playCursor; - DWORD writeCursor; - DWORD byteToLock; - DWORD targetCursor; - DWORD bytesToWrite; + DWORD playCursor = 0; + DWORD writeCursor = 0; + DWORD byteToLock = 0; + DWORD targetCursor = 0; + DWORD bytesToWrite = 0; bool soundIsValid = true; if (SUCCEEDED(globalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor))) { byteToLock = (soundOutput.runningSampleIndex*soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize; @@ -395,7 +523,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin soundBuffer.sampleCount = bytesToWrite / soundOutput.bytesPerSample; soundBuffer.samples = samples; - gameUpdateAndRender(&videoBuffer, &input, &soundBuffer); + gameUpdateAndRender(&gameMemory, &videoBuffer, newInput, &soundBuffer); if (soundIsValid) { win32FillSoundBuffer(&soundOutput, byteToLock, bytesToWrite, &soundBuffer); @@ -405,14 +533,18 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin LARGE_INTEGER endCounter; QueryPerformanceCounter(&endCounter); int64 endCycleCount = __rdtsc(); - int32 cyclesElapsed = endCycleCount - lastCycleCount; + int64 cyclesElapsed = endCycleCount - lastCycleCount; lastCycleCount = endCycleCount; int64 counterElapsed = endCounter.QuadPart - lastCounter.QuadPart; real32 msElapsed = (real32)(1000.0f*counterElapsed) / performanceFrequency; real32 fps = (real32)(1000.0f*performanceFrequency/(real32)counterElapsed)/1000.0f; - debug_printf(L"%f ms, %f fps, %f Mcl, %fGHz\n", msElapsed, fps, cyclesElapsed / 1000000.0f, (cyclesElapsed/(msElapsed*1000))/1000000.0f); + lastCounter = endCounter; + + GameInput *temp = newInput; + newInput = oldInput; + oldInput = temp; } } else { // failed diff --git a/src/win32_handmade.h b/src/win32_handmade.h new file mode 100644 index 0000000..fc26345 --- /dev/null +++ b/src/win32_handmade.h @@ -0,0 +1,24 @@ +#include "handmade.h" + +struct Win32OffscreenBuffer { + BITMAPINFO info; + void *memory; + int width; + int height; + int bytesPerPixel; +}; + +struct Win32WindowDimensions { + int width; + int height; +}; + +struct Win32SoundOutput { + int samplesPerSecond; + int16 toneVolume; + uint32 runningSampleIndex; + int bytesPerSample; + int secondaryBufferSize; + real32 tSine; + int latencySampleCount; +};