From 8f93c1380753c2f45f732e06e814a1c5bb5c8378 Mon Sep 17 00:00:00 2001 From: Ledda Date: Sun, 15 Sep 2024 23:09:47 +0100 Subject: [PATCH] update' --- src/handmade.cpp | 56 ++++++++--------- src/handmade.h | 21 ++++--- src/win32_handmade.cpp | 132 ++++++++++++++++------------------------- src/win32_handmade.h | 14 +++-- 4 files changed, 99 insertions(+), 124 deletions(-) diff --git a/src/handmade.cpp b/src/handmade.cpp index f8ab87d..efbf0cd 100644 --- a/src/handmade.cpp +++ b/src/handmade.cpp @@ -2,7 +2,7 @@ #define PI32 3.141592653589f -internal void renderPlayer(GameOffscreenBuffer *buffer, int playerX, int playerY) { +internal void renderSmallRect(GameOffscreenBuffer *buffer, int playerX, int playerY) { uint8 *endOfBuffer = (uint8 *)buffer->memory + buffer->pitch*buffer->height; uint32 color = 0xFFFFFFFF; int top = playerY; @@ -23,17 +23,15 @@ internal void outputSineSound(GameSoundOutputBuffer *soundBuffer, GameState *sta int16 toneVolume = 3000; int wavePeriod = soundBuffer->samplesPerSecond/state->toneHz; +#if 0 int16 *sampleOut = soundBuffer->samples; for (int sampleIndex = 0; sampleIndex < soundBuffer->sampleCount; sampleIndex++) { state->tSine += 2.0f * PI32 / (real32)wavePeriod; -#if 0 int16 sampleValue = (int16)(sin(state->tSine) * (real32)toneVolume); -#else - int16 sampleValue = 0; -#endif *sampleOut++ = sampleValue; *sampleOut++ = sampleValue; } +#endif } internal void renderWeirdGradient(GameOffscreenBuffer *buffer, int xOffset, int yOffset) { @@ -55,12 +53,12 @@ extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) { GameState *state = (GameState*)memory->permanentStorage; if (!memory->isInitialised) { - DebugReadFileResult bmpMem = memory->debugReadEntireFile(__FILE__); + DebugReadFileResult bmpMem = memory->debugReadEntireFile(ctx, __FILE__); if (bmpMem.contents) { if (false) { - memory->debugWriteEntireFile("c:/source/repos/handmade/src/test.cpp", bmpMem.contentsSize, bmpMem.contents); + memory->debugWriteEntireFile(ctx, "c:/source/repos/handmade/src/test.cpp", bmpMem.contentsSize, bmpMem.contents); } - memory->debugFreeFileMemory(bmpMem.contents); + memory->debugFreeFileMemory(ctx, bmpMem.contents); } state->toneHz = 440; @@ -74,37 +72,33 @@ extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) { 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)(20.0f*controllerInput->stickAvgX); - state->blueOffset += (int)(20.0f*controllerInput->stickAvgY); - } else { - if (controllerInput->stickRight.endedDown) { - state->toneHz = 440 + 128; - state->greenOffset -= 10; - } else if (controllerInput->stickLeft.endedDown) { - state->toneHz = 440 - 128; - state->greenOffset += 10; - } - if (controllerInput->stickUp.endedDown) { - state->blueOffset += 10; - } else if (controllerInput->stickDown.endedDown) { - state->blueOffset -= 10; - } - } - */ if (controllerInput->btnDown.endedDown) { state->playerY -= 30; } - state->playerX += (int)(4.0f*controllerInput->stickAvgX); - state->playerY -= (int)(4.0f*controllerInput->stickAvgY); + if (controllerInput->stickRight.endedDown) { + state->playerX += 10; + } + if (controllerInput->stickLeft.endedDown) { + state->playerX -= 10; + } + if (controllerInput->stickDown.endedDown) { + state->playerY += 10; + } + if (controllerInput->stickUp.endedDown) { + state->playerY -= 10; + } } renderWeirdGradient(videoBuf, state->greenOffset, state->blueOffset); - renderPlayer(videoBuf, state->playerX, state->playerY); + renderSmallRect(videoBuf, state->playerX, state->playerY); + renderSmallRect(videoBuf, input->mouseX, input->mouseY); + for (int i = 0; i < ArrayCount(input->mouseButtons); i++) { + if (input->mouseButtons[i].endedDown) { + renderSmallRect(videoBuf, 10 + i * 20, 10); + } + } } extern "C" GAME_GET_SOUND_SAMPLES(gameGetSoundSamples) { diff --git a/src/handmade.h b/src/handmade.h index 5004118..aaf9a39 100644 --- a/src/handmade.h +++ b/src/handmade.h @@ -64,6 +64,10 @@ inline uint32 safeTruncateUInt64(uint64 val) { return (uint32)val; } +struct ThreadContext { + int placeholder; +}; + // === Platform to game services === #if HANDMADE_INTERNAL @@ -72,13 +76,13 @@ struct DebugReadFileResult { void *contents; }; -#define DEBUG_PLATFORM_READ_ENTIRE_FILE(name) DebugReadFileResult name(char *filename) +#define DEBUG_PLATFORM_READ_ENTIRE_FILE(name) DebugReadFileResult name(ThreadContext *ctx, char *filename) typedef DEBUG_PLATFORM_READ_ENTIRE_FILE(DebugPlatformReadEntireFileFn); -#define DEBUG_PLATFORM_FREE_FILE_MEMORY(name) void name(void *fileMemory) +#define DEBUG_PLATFORM_FREE_FILE_MEMORY(name) void name(ThreadContext *ctx, void *fileMemory) typedef DEBUG_PLATFORM_FREE_FILE_MEMORY(DebugPlatformFreeFileMemoryFn); -#define DEBUG_PLATFORM_WRITE_ENTIRE_FILE(name) bool32 name(char *filename, uint32 memorySize, void *memory) +#define DEBUG_PLATFORM_WRITE_ENTIRE_FILE(name) bool32 name(ThreadContext *ctx, char *filename, uint32 memorySize, void *memory) typedef DEBUG_PLATFORM_WRITE_ENTIRE_FILE(DebugPlatformWriteEntireFileFn); #define DEBUG_PLATFORM_PRINTF(name) void name(wchar_t* format, ...) @@ -130,18 +134,19 @@ struct GameControllerInput { }; struct GameInput { + GameButtonState mouseButtons[5]; + int32 mouseX; + int32 mouseY; + int32 mouseZ; 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 - DebugPlatformReadEntireFileFn *debugReadEntireFile; DebugPlatformFreeFileMemoryFn *debugFreeFileMemory; DebugPlatformWriteEntireFileFn *debugWriteEntireFile; @@ -159,10 +164,10 @@ struct GameState { // === Game to platform services === -#define GAME_UPDATE_AND_RENDER(name) void name(GameMemory *memory, GameOffscreenBuffer *videoBuf, GameInput *input) +#define GAME_UPDATE_AND_RENDER(name) void name(ThreadContext *ctx, GameMemory *memory, GameOffscreenBuffer *videoBuf, GameInput *input) typedef GAME_UPDATE_AND_RENDER(GameUpdateAndRenderFn); GAME_UPDATE_AND_RENDER(gameUpdateAndRenderStub) {} -#define GAME_GET_SOUND_SAMPLES(name) void name(GameMemory *memory, GameSoundOutputBuffer *soundBuf) +#define GAME_GET_SOUND_SAMPLES(name) void name(ThreadContext *ctx, GameMemory *memory, GameSoundOutputBuffer *soundBuf) typedef GAME_GET_SOUND_SAMPLES(GameGetSoundSamplesFn); GAME_GET_SOUND_SAMPLES(gameGetSoundSamplesStub) {} diff --git a/src/win32_handmade.cpp b/src/win32_handmade.cpp index d463707..a429b05 100644 --- a/src/win32_handmade.cpp +++ b/src/win32_handmade.cpp @@ -60,7 +60,7 @@ DEBUG_PLATFORM_READ_ENTIRE_FILE(debugReadEntireFile) { if (ReadFile(fileHandle, result.contents, (DWORD)fileSize.QuadPart, &bytesRead, NULL) && (fileSize32 == (uint32)bytesRead)) { result.contentsSize = fileSize32; } else { - debugFreeFileMemory(result.contents); + debugFreeFileMemory(ctx, result.contents); result.contents = NULL; // logging } @@ -139,14 +139,6 @@ internal void win32DrawBufferInWindow(Win32OffscreenBuffer *buffer, HWND window) ); } -struct Win32GameCode { - HMODULE gameCodeLib; - GameUpdateAndRenderFn *updateAndRender; - GameGetSoundSamplesFn *getSoundSamples; - bool isValid; - FILETIME lastWriteTime; -}; - inline FILETIME win32GetLastWriteTime(char *filename) { FILETIME lastWriteTime = {}; WIN32_FIND_DATA findData; @@ -202,8 +194,10 @@ internal void win32LoadXInput() { } internal void win32ProcessKeyboardKeypress(GameButtonState *newState, bool32 isDown) { - newState->endedDown = isDown; - newState->halfTransitionCount++; + if (newState->endedDown != isDown) { + newState->endedDown = isDown; + newState->halfTransitionCount++; + } } internal void win32ProcessXInputDigitalButton(DWORD xInputButtonState, GameButtonState *oldState, GameButtonState *newState, DWORD buttonBit) { @@ -483,12 +477,6 @@ inline real32 win32GetSecondsElapsed(LARGE_INTEGER start, LARGE_INTEGER end) { return (real32)(end.QuadPart - start.QuadPart) / (real32)globalPerfCountFrequency; } -// int monitorRefreshHz = 60; -// int gameUpdateHz = monitorRefreshHz / 2; - -#define monitorRefreshHz 60 -#define gameUpdateHz (monitorRefreshHz / 2) - internal void win32DebugDrawVertical(Win32OffscreenBuffer *buffer, int x, int top, int bottom, int32 color) { uint8 *pixel = (uint8 *)buffer->memory + top * buffer->pitch + x*buffer->bytesPerPixel; for (int y = top; y < bottom; y++) { @@ -503,29 +491,6 @@ inline void win32DrawSoundBufferMarker(Win32OffscreenBuffer *buffer, Win32SoundO win32DebugDrawVertical(buffer, x, top, bottom, color); } -internal void win32DebugSyncDisplay(Win32OffscreenBuffer *buffer, int markerCount, Win32DebugTimeMarker *markers, Win32SoundOutput *soundOutput, real32 targetSecondsPerFrame) { - int padX = 16; - int padY = 16; - - int top = padY; - int bottom = buffer->height - padY; - int renderWidth = buffer->width - 2 *padX; - - real32 pxPerSoundBufferEntry = (real32)renderWidth / (real32)soundOutput->secondaryBufferSize; - -#if 0 - for (int markerIndex = 0; markerIndex < markerCount; markerIndex++) { - Win32DebugTimeMarker *thisMarker = &markers[markerIndex]; - real32 alpha = ((real32)(markerIndex + 1) / (real32)markerCount); - int x = padX + (int)(pxPerSoundBufferEntry * (real32)thisMarker->writeCursor); - uint8 *pixel = (uint8 *)buffer->memory + top * buffer->pitch + x*buffer->bytesPerPixel; - uint32 newPixel = (uint32)((real32)alpha * 0xFFFFFFFF + (1.0f - alpha) * (*(uint32 *)pixel)); - win32DrawSoundBufferMarker(buffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->playCursor, newPixel); - win32DrawSoundBufferMarker(buffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->writeCursor, 0x00FF0000); - } -#endif -} - void catStrings(size_t sourceACount, char *sourceA, size_t sourceBCount, char *sourceB, size_t destCount, char *dest) { for (int i = 0; i < sourceACount; i++) { *dest++ = *sourceA++; @@ -536,6 +501,9 @@ void catStrings(size_t sourceACount, char *sourceA, size_t sourceBCount, char *s *dest++ = 0; } +#define WINDOW_WIDTH 1280 +#define WINDOW_HEIGHT 720 + int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLine, int commandShow) { char exeFileName[MAX_PATH]; DWORD sizeOfFilename = GetModuleFileNameA(NULL, exeFileName, sizeof(exeFileName)); @@ -570,27 +538,36 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin windowClass.lpfnWndProc = &mainWindowCallback; windowClass.hInstance = instance; windowClass.lpszClassName = "HandmadeHeroWindowClass"; - - resizeDIBSection(&globalBackBuffer, 1280, 720); - - real32 targetSecondsPerFrame = 1.0f / (real32)gameUpdateHz; + resizeDIBSection(&globalBackBuffer, WINDOW_WIDTH, WINDOW_HEIGHT); if (RegisterClass(&windowClass)) { + DWORD windowFlags = WS_OVERLAPPEDWINDOW | WS_VISIBLE; + RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT }; + AdjustWindowRectEx(&rect, windowFlags, false, NULL); HWND window = CreateWindowExA( NULL, windowClass.lpszClassName, "Handmade Hero", - WS_OVERLAPPEDWINDOW | WS_VISIBLE, - CW_USEDEFAULT, - CW_USEDEFAULT, + windowFlags, CW_USEDEFAULT, CW_USEDEFAULT, + rect.right - rect.left, + rect.bottom - rect.top, NULL, NULL, instance, NULL ); + if (window) { + int monitorRefreshHz = 60; + int win32RefreshRate = GetDeviceCaps(GetDC(window), VREFRESH); + if (win32RefreshRate > 1) { + monitorRefreshHz = win32RefreshRate; + } + real32 gameUpdateHz = monitorRefreshHz / 2.0f; + real32 targetSecondsPerFrame = 1.0f / (real32)gameUpdateHz; + HH_CTRLW = GlobalAddAtomA("HH_CTRLW"); RegisterHotKey(window, HH_CTRLW, MOD_CONTROL, 'W'); @@ -601,9 +578,6 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin GameInput *oldInput = &input[0]; GameInput *newInput = &input[1]; - int debugTimeMarkerIndex = 0; - Win32DebugTimeMarker debugMarkers[gameUpdateHz / 2] = {}; - win32LoadXInput(); // sound test @@ -612,7 +586,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin soundOutput.runningSampleIndex = 0; soundOutput.bytesPerSample = sizeof(int16)*2; soundOutput.secondaryBufferSize = soundOutput.samplesPerSecond*soundOutput.bytesPerSample; - soundOutput.safetyBytes = (soundOutput.samplesPerSecond * soundOutput.bytesPerSample / gameUpdateHz) / 2; + soundOutput.safetyBytes = (int)((soundOutput.samplesPerSecond * soundOutput.bytesPerSample / gameUpdateHz) / 2.0f); int16 *samples = (int16*)VirtualAlloc(NULL, soundOutput.secondaryBufferSize, MEM_COMMIT, PAGE_READWRITE); @@ -641,7 +615,6 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin LARGE_INTEGER lastWorkCounter = win32GetWallClock(); LARGE_INTEGER flipWallClock = win32GetWallClock(); - DWORD audioLatencyBytes = 0; real32 audioLatencySeconds = 0; bool soundIsValid = false; @@ -666,6 +639,20 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin win32ProcessPendingMessages(&win32State, newKeyboardController); + POINT mousePos; + GetCursorPos(&mousePos); + ScreenToClient(window, &mousePos); + newInput->mouseX = mousePos.x; + newInput->mouseY = mousePos.y; + newInput->mouseZ = 0; // mouse wheel + win32ProcessKeyboardKeypress(&newInput->mouseButtons[0], GetKeyState(VK_LBUTTON) & (1 << 15)); + win32ProcessKeyboardKeypress(&newInput->mouseButtons[1], GetKeyState(VK_MBUTTON) & (1 << 15)); + win32ProcessKeyboardKeypress(&newInput->mouseButtons[2], GetKeyState(VK_RBUTTON) & (1 << 15)); + win32ProcessKeyboardKeypress(&newInput->mouseButtons[3], GetKeyState(VK_XBUTTON1) & (1 << 15)); + win32ProcessKeyboardKeypress(&newInput->mouseButtons[4], GetKeyState(VK_XBUTTON2) & (1 << 15)); + + // TODO(dledda): day 25 34:00 + XINPUT_STATE controllerState; int maxControllerCount = XUSER_MAX_COUNT; if (maxControllerCount > ArrayCount(newInput->controllers) - 1) { @@ -728,6 +715,8 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin } } + ThreadContext threadCtx = {}; + GameOffscreenBuffer videoBuffer = {}; videoBuffer.memory = globalBackBuffer.memory; videoBuffer.width = globalBackBuffer.width; @@ -742,20 +731,25 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin win32PlaybackInput(&win32State, newInput); } - game.updateAndRender(&gameMemory, &videoBuffer, newInput); + if (game.updateAndRender) { + game.updateAndRender(&threadCtx, &gameMemory, &videoBuffer, newInput); + } + + LARGE_INTEGER audioWallClock = win32GetWallClock(); + real32 fromBeginToAudioSeconds = win32GetSecondsElapsed(flipWallClock, audioWallClock); DWORD playCursor = 0; DWORD writeCursor = 0; - if (SUCCEEDED(globalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor))) { if (!soundIsValid) { soundOutput.runningSampleIndex = writeCursor / soundOutput.bytesPerSample; soundIsValid = true; } DWORD byteToLock = (soundOutput.runningSampleIndex*soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize; - - DWORD expectedSoundBytesPerFrame = (soundOutput.samplesPerSecond * soundOutput.bytesPerSample) / gameUpdateHz; - DWORD expectedFrameBoundaryByte = playCursor + expectedSoundBytesPerFrame; + DWORD expectedSoundBytesPerFrame = (DWORD)((soundOutput.samplesPerSecond * soundOutput.bytesPerSample) / gameUpdateHz); + real32 secondsLeftUntilFlip = targetSecondsPerFrame - fromBeginToAudioSeconds; + DWORD expectedBytesUntilFlip = (DWORD)((secondsLeftUntilFlip/targetSecondsPerFrame) * (real32)expectedSoundBytesPerFrame); + DWORD expectedFrameBoundaryByte = playCursor + expectedBytesUntilFlip; DWORD safeWriteCursor = writeCursor; if (safeWriteCursor < playCursor) { @@ -785,25 +779,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin soundBuffer.samplesPerSecond = soundOutput.samplesPerSecond; soundBuffer.sampleCount = bytesToWrite / soundOutput.bytesPerSample; soundBuffer.samples = samples; - game.getSoundSamples(&gameMemory, &soundBuffer); -#if HANDMADE_INTERNAL - Assert(debugTimeMarkerIndex < ArrayCount(debugMarkers)); - - Win32DebugTimeMarker *marker = &debugMarkers[debugTimeMarkerIndex++]; - - DWORD unwrappedWriteCursor = writeCursor; - if (unwrappedWriteCursor < targetCursor) { - unwrappedWriteCursor += soundOutput.secondaryBufferSize; - } - audioLatencyBytes = unwrappedWriteCursor - playCursor; - audioLatencySeconds = (((real32)audioLatencyBytes / (real32)soundOutput.bytesPerSample) / (real32)soundOutput.samplesPerSecond); - - if (debugTimeMarkerIndex >= ArrayCount(debugMarkers)) { - debugTimeMarkerIndex = 0; - } - - globalSecondaryBuffer->GetCurrentPosition(&marker->playCursor, &marker->writeCursor); -#endif + game.getSoundSamples(&threadCtx, &gameMemory, &soundBuffer); win32FillSoundBuffer(&soundOutput, byteToLock, bytesToWrite, &soundBuffer); } else { soundIsValid = false; @@ -827,10 +803,6 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin lastWorkCounter = win32GetWallClock(); -#if HANDMADE_INTERNAL - win32DebugSyncDisplay(&globalBackBuffer, ArrayCount(debugMarkers), debugMarkers, &soundOutput, targetSecondsPerFrame); -#endif - win32DrawBufferInWindow(&globalBackBuffer, window); flipWallClock = win32GetWallClock(); diff --git a/src/win32_handmade.h b/src/win32_handmade.h index 5a9e16f..6176426 100644 --- a/src/win32_handmade.h +++ b/src/win32_handmade.h @@ -24,11 +24,6 @@ struct Win32SoundOutput { int safetyBytes; }; -struct Win32DebugTimeMarker { - DWORD playCursor; - DWORD writeCursor; -}; - struct Win32RecordedInput { int inputCount; GameInput *inputStream; @@ -42,3 +37,12 @@ struct Win32State { uint64 gameMemoryTotalSize; void *gameMemoryBlock; }; + +struct Win32GameCode { + HMODULE gameCodeLib; + GameUpdateAndRenderFn *updateAndRender; + GameGetSoundSamplesFn *getSoundSamples; + bool isValid; + FILETIME lastWriteTime; +}; +