diff --git a/src/handmade.h b/src/handmade.h index aaf9a39..693db66 100644 --- a/src/handmade.h +++ b/src/handmade.h @@ -2,7 +2,6 @@ #include #include #include -#include #pragma once diff --git a/src/win32_handmade.cpp b/src/win32_handmade.cpp index a429b05..93189de 100644 --- a/src/win32_handmade.cpp +++ b/src/win32_handmade.cpp @@ -252,12 +252,7 @@ internal void win32InitSound(HWND window, int32 samplesPerSec, int bufferSize) { } } -LRESULT mainWindowCallback( - HWND window, - UINT message, - WPARAM wParam, - LPARAM lParam -) { +LRESULT mainWindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT result = 0; switch (message) { case WM_SIZE: { @@ -354,18 +349,24 @@ internal void win32FillSoundBuffer(Win32SoundOutput *soundOutput, DWORD byteToLo } } -internal void win32BeginRecordingInput(Win32State *win32State, int inputRecordingIndex) { - win32State->inputRecordingIndex = inputRecordingIndex; - char *filename = "replay.ipt"; - win32State->recordingHandle = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL); - DWORD bytesToWrite = (DWORD)win32State->gameMemoryTotalSize; - Assert(bytesToWrite < 0xFFFFFFFF); - DWORD bytesWritten; - WriteFile(win32State->recordingHandle, win32State->gameMemoryBlock, bytesToWrite, &bytesWritten, NULL); +internal Win32ReplayBuffer* win32GetReplayBuffer(Win32State *state, int unsigned index) { + Win32ReplayBuffer *result = &state->replayBuffers[index - 1]; + return result; +} + +internal void win32BeginRecordingInput(Win32State *state, int inputRecordingIndex) { + Win32ReplayBuffer *replayBuffer = win32GetReplayBuffer(state, inputRecordingIndex); + if (replayBuffer->memoryBlock) { + state->inputRecordingIndex = inputRecordingIndex; + state->recordingHandle = replayBuffer->fileHandle; + LARGE_INTEGER filePosition; + filePosition.QuadPart = state->gameMemoryTotalSize; + SetFilePointerEx(state->recordingHandle, filePosition, NULL, FILE_BEGIN); + CopyMemory(replayBuffer->memoryBlock, state->gameMemoryBlock, state->gameMemoryTotalSize); + } } internal void win32EndRecordingInput(Win32State *win32State) { - CloseHandle(win32State->recordingHandle); win32State->inputRecordingIndex = 0; } @@ -374,18 +375,19 @@ internal void win32RecordInput(Win32State *win32State, GameInput *newInput) { WriteFile(win32State->recordingHandle, newInput, sizeof(*newInput), &bytesWritten, NULL); } -internal void win32BeginInputPlayback(Win32State *win32State, int inputPlayingIndex) { - win32State->inputPlayingIndex = inputPlayingIndex; - char *filename = "replay.ipt"; - win32State->playbackHandle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); - DWORD bytesToRead = (DWORD)win32State->gameMemoryTotalSize; - Assert(bytesToRead < 0xFFFFFFFF); - DWORD bytesRead; - ReadFile(win32State->playbackHandle, win32State->gameMemoryBlock, bytesToRead, &bytesRead, NULL); +internal void win32BeginInputPlayback(Win32State *state, int inputPlayingIndex) { + Win32ReplayBuffer *replayBuffer = win32GetReplayBuffer(state, inputPlayingIndex); + if (replayBuffer->memoryBlock) { + state->inputPlayingIndex = inputPlayingIndex; + state->playbackHandle = replayBuffer->fileHandle; + LARGE_INTEGER filePosition; + filePosition.QuadPart = state->gameMemoryTotalSize; + SetFilePointerEx(state->playbackHandle, filePosition, NULL, FILE_BEGIN); + CopyMemory(state->gameMemoryBlock, replayBuffer->memoryBlock, state->gameMemoryTotalSize); + } } internal void win32EndInputPlayback(Win32State *win32State) { - CloseHandle(win32State->playbackHandle); win32State->inputPlayingIndex = 0; } @@ -443,11 +445,13 @@ internal void win32ProcessPendingMessages(Win32State *win32State, GameController } else if (VKCode == VK_SPACE) { } else if (VKCode == 'L') { if (isDown) { - if (win32State->inputRecordingIndex == 0) { + if (win32State->inputRecordingIndex == 0 && win32State->inputPlayingIndex == 0) { win32BeginRecordingInput(win32State, 1); - } else { + } else if (win32State->inputRecordingIndex != 0 && win32State->inputPlayingIndex == 0) { win32EndRecordingInput(win32State); win32BeginInputPlayback(win32State, 1); + } else if (win32State->inputRecordingIndex == 0 && win32State->inputPlayingIndex != 0) { + win32EndInputPlayback(win32State); } } } @@ -501,30 +505,34 @@ void catStrings(size_t sourceACount, char *sourceA, size_t sourceBCount, char *s *dest++ = 0; } +void win32GetExeFilename(Win32State *win32State) { + DWORD sizeOfFilename = GetModuleFileNameA(NULL, win32State->exeFilename, sizeof(win32State->exeFilename)); + win32State->onePastLastExeFilenameSlash = win32State->exeFilename; + for (char *scan = win32State->exeFilename; *scan; scan++) { + if (*scan == '\\') { + win32State->onePastLastExeFilenameSlash = scan + 1; + } + } +} + +void win32GetFullPathToLocalFile(Win32State *state, char *filename, int filenameSize, char *maxPathBuffer) { + catStrings(state->onePastLastExeFilenameSlash - state->exeFilename, state->exeFilename, filenameSize, filename, (size_t)MAX_PATH, maxPathBuffer); +} + #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)); - char *onePastLastSlash = exeFileName; - for (char *scan = exeFileName; *scan; scan++) { - if (*scan == '\\') { - onePastLastSlash = scan + 1; - } - } + Win32State win32State = {}; + win32GetExeFilename(&win32State); - char sourceGameCodeDLLFilename[] = "handmade.dll"; + char *sourceGameCodeDLLFilename = "handmade.dll"; char sourceGameCodeDLLFullPath[MAX_PATH]; - catStrings(onePastLastSlash - exeFileName, exeFileName, - sizeof(sourceGameCodeDLLFilename) - 1, sourceGameCodeDLLFilename, - sizeof(sourceGameCodeDLLFullPath) - 1, sourceGameCodeDLLFullPath); + win32GetFullPathToLocalFile(&win32State, sourceGameCodeDLLFilename, sizeof(sourceGameCodeDLLFullPath) - 1, sourceGameCodeDLLFullPath); char tempGameCodeDLLFilename[] = "handmade_temp.dll"; char tempGameCodeDLLFullPath[MAX_PATH]; - catStrings(onePastLastSlash - exeFileName, exeFileName, - sizeof(tempGameCodeDLLFilename) - 1, tempGameCodeDLLFilename, - sizeof(tempGameCodeDLLFullPath) - 1, tempGameCodeDLLFullPath); + win32GetFullPathToLocalFile(&win32State, tempGameCodeDLLFilename, sizeof(tempGameCodeDLLFullPath) - 1, tempGameCodeDLLFullPath); LARGE_INTEGER performanceFrequencyResult; QueryPerformanceFrequency(&performanceFrequencyResult); @@ -572,7 +580,6 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin RegisterHotKey(window, HH_CTRLW, MOD_CONTROL, 'W'); globalRunning = true; - Win32State win32State = {}; GameInput input[2] = {}; GameInput *oldInput = &input[0]; @@ -597,7 +604,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin #endif GameMemory gameMemory = {}; gameMemory.permanentStorageSize = Megabytes(64); - gameMemory.transientStorageSize = Gigabytes((uint64)4); + gameMemory.transientStorageSize = Gigabytes((uint64)1); gameMemory.debugFreeFileMemory = debugFreeFileMemory; gameMemory.debugWriteEntireFile = debugWriteEntireFile; gameMemory.debugReadEntireFile = debugReadEntireFile; @@ -608,6 +615,25 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin gameMemory.permanentStorage = win32State.gameMemoryBlock; gameMemory.transientStorage = ((uint8 *)gameMemory.permanentStorage + gameMemory.permanentStorageSize); + for (int i = 0; i < ArrayCount(win32State.replayBuffers); i++) { + // Filename + char prefix[] = "replay-"; + char suffix[] = ".hmr"; + const int totalLen = ArrayCount(prefix) + 1 + ArrayCount(suffix); + char replayFilename[totalLen] = {}; + char digit[] = {(char)(48 + i)}; + catStrings(ArrayCount(prefix) - 1, prefix, 1, digit, ArrayCount(replayFilename) - 1, replayFilename); + catStrings(ArrayCount(prefix), replayFilename, ArrayCount(suffix) - 1, suffix, ArrayCount(replayFilename) - 1, replayFilename); + win32GetFullPathToLocalFile(&win32State, replayFilename, sizeof(replayFilename) - 1, win32State.replayBuffers[i].replayFilename); + Win32ReplayBuffer *replayBuffer = &win32State.replayBuffers[i]; + + replayBuffer->fileHandle = CreateFileA(replayBuffer->replayFilename, GENERIC_WRITE | GENERIC_READ, NULL, NULL, CREATE_ALWAYS, NULL, NULL); + DWORD maxSizeLow = (win32State.gameMemoryTotalSize & 0xFFFFFFFF); + DWORD maxSizeHigh = (win32State.gameMemoryTotalSize >> 32); + replayBuffer->memoryMap = CreateFileMappingA(replayBuffer->fileHandle, NULL, PAGE_READWRITE, maxSizeHigh, maxSizeLow, NULL); + replayBuffer->memoryBlock = MapViewOfFile(replayBuffer->memoryMap, FILE_MAP_ALL_ACCESS, NULL, NULL, win32State.gameMemoryTotalSize); + } + win32InitSound(window, soundOutput.samplesPerSecond, soundOutput.secondaryBufferSize); win32ClearBuffer(&soundOutput); globalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING); @@ -651,8 +677,6 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin 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) { diff --git a/src/win32_handmade.h b/src/win32_handmade.h index 6176426..46d8174 100644 --- a/src/win32_handmade.h +++ b/src/win32_handmade.h @@ -1,4 +1,5 @@ #include "handmade.h" +#include struct Win32OffscreenBuffer { BITMAPINFO info; @@ -29,13 +30,27 @@ struct Win32RecordedInput { GameInput *inputStream; }; +#define WIN32_STATE_FILE_NAME_LENGTH MAX_PATH +struct Win32ReplayBuffer { + HANDLE memoryMap; + HANDLE fileHandle; + void *memoryBlock; + char replayFilename[WIN32_STATE_FILE_NAME_LENGTH]; +}; + struct Win32State { HANDLE recordingHandle; uint32 inputRecordingIndex; + HANDLE playbackHandle; uint32 inputPlayingIndex; + uint64 gameMemoryTotalSize; void *gameMemoryBlock; + Win32ReplayBuffer replayBuffers[4]; + + char exeFilename[WIN32_STATE_FILE_NAME_LENGTH]; + char *onePastLastExeFilenameSlash; }; struct Win32GameCode {