|
@@ -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; |
|
|
LRESULT result = 0; |
|
|
switch (message) { |
|
|
switch (message) { |
|
|
case WM_SIZE: { |
|
|
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) { |
|
|
internal void win32EndRecordingInput(Win32State *win32State) { |
|
|
CloseHandle(win32State->recordingHandle); |
|
|
|
|
|
win32State->inputRecordingIndex = 0; |
|
|
win32State->inputRecordingIndex = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -374,18 +375,19 @@ internal void win32RecordInput(Win32State *win32State, GameInput *newInput) { |
|
|
WriteFile(win32State->recordingHandle, newInput, sizeof(*newInput), &bytesWritten, NULL); |
|
|
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) { |
|
|
internal void win32EndInputPlayback(Win32State *win32State) { |
|
|
CloseHandle(win32State->playbackHandle); |
|
|
|
|
|
win32State->inputPlayingIndex = 0; |
|
|
win32State->inputPlayingIndex = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -443,11 +445,13 @@ internal void win32ProcessPendingMessages(Win32State *win32State, GameController |
|
|
} else if (VKCode == VK_SPACE) { |
|
|
} else if (VKCode == VK_SPACE) { |
|
|
} else if (VKCode == 'L') { |
|
|
} else if (VKCode == 'L') { |
|
|
if (isDown) { |
|
|
if (isDown) { |
|
|
if (win32State->inputRecordingIndex == 0) { |
|
|
|
|
|
|
|
|
if (win32State->inputRecordingIndex == 0 && win32State->inputPlayingIndex == 0) { |
|
|
win32BeginRecordingInput(win32State, 1); |
|
|
win32BeginRecordingInput(win32State, 1); |
|
|
} else { |
|
|
|
|
|
|
|
|
} else if (win32State->inputRecordingIndex != 0 && win32State->inputPlayingIndex == 0) { |
|
|
win32EndRecordingInput(win32State); |
|
|
win32EndRecordingInput(win32State); |
|
|
win32BeginInputPlayback(win32State, 1); |
|
|
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; |
|
|
*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_WIDTH 1280 |
|
|
#define WINDOW_HEIGHT 720 |
|
|
#define WINDOW_HEIGHT 720 |
|
|
|
|
|
|
|
|
int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLine, int commandShow) { |
|
|
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]; |
|
|
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 tempGameCodeDLLFilename[] = "handmade_temp.dll"; |
|
|
char tempGameCodeDLLFullPath[MAX_PATH]; |
|
|
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; |
|
|
LARGE_INTEGER performanceFrequencyResult; |
|
|
QueryPerformanceFrequency(&performanceFrequencyResult); |
|
|
QueryPerformanceFrequency(&performanceFrequencyResult); |
|
@@ -572,7 +580,6 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin |
|
|
RegisterHotKey(window, HH_CTRLW, MOD_CONTROL, 'W'); |
|
|
RegisterHotKey(window, HH_CTRLW, MOD_CONTROL, 'W'); |
|
|
|
|
|
|
|
|
globalRunning = true; |
|
|
globalRunning = true; |
|
|
Win32State win32State = {}; |
|
|
|
|
|
|
|
|
|
|
|
GameInput input[2] = {}; |
|
|
GameInput input[2] = {}; |
|
|
GameInput *oldInput = &input[0]; |
|
|
GameInput *oldInput = &input[0]; |
|
@@ -597,7 +604,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin |
|
|
#endif |
|
|
#endif |
|
|
GameMemory gameMemory = {}; |
|
|
GameMemory gameMemory = {}; |
|
|
gameMemory.permanentStorageSize = Megabytes(64); |
|
|
gameMemory.permanentStorageSize = Megabytes(64); |
|
|
gameMemory.transientStorageSize = Gigabytes((uint64)4); |
|
|
|
|
|
|
|
|
gameMemory.transientStorageSize = Gigabytes((uint64)1); |
|
|
gameMemory.debugFreeFileMemory = debugFreeFileMemory; |
|
|
gameMemory.debugFreeFileMemory = debugFreeFileMemory; |
|
|
gameMemory.debugWriteEntireFile = debugWriteEntireFile; |
|
|
gameMemory.debugWriteEntireFile = debugWriteEntireFile; |
|
|
gameMemory.debugReadEntireFile = debugReadEntireFile; |
|
|
gameMemory.debugReadEntireFile = debugReadEntireFile; |
|
@@ -608,6 +615,25 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin |
|
|
gameMemory.permanentStorage = win32State.gameMemoryBlock; |
|
|
gameMemory.permanentStorage = win32State.gameMemoryBlock; |
|
|
gameMemory.transientStorage = ((uint8 *)gameMemory.permanentStorage + gameMemory.permanentStorageSize); |
|
|
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); |
|
|
win32InitSound(window, soundOutput.samplesPerSecond, soundOutput.secondaryBufferSize); |
|
|
win32ClearBuffer(&soundOutput); |
|
|
win32ClearBuffer(&soundOutput); |
|
|
globalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING); |
|
|
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[3], GetKeyState(VK_XBUTTON1) & (1 << 15)); |
|
|
win32ProcessKeyboardKeypress(&newInput->mouseButtons[4], GetKeyState(VK_XBUTTON2) & (1 << 15)); |
|
|
win32ProcessKeyboardKeypress(&newInput->mouseButtons[4], GetKeyState(VK_XBUTTON2) & (1 << 15)); |
|
|
|
|
|
|
|
|
// TODO(dledda): day 25 34:00 |
|
|
|
|
|
|
|
|
|
|
|
XINPUT_STATE controllerState; |
|
|
XINPUT_STATE controllerState; |
|
|
int maxControllerCount = XUSER_MAX_COUNT; |
|
|
int maxControllerCount = XUSER_MAX_COUNT; |
|
|
if (maxControllerCount > ArrayCount(newInput->controllers) - 1) { |
|
|
if (maxControllerCount > ArrayCount(newInput->controllers) - 1) { |
|
|