|
@@ -104,6 +104,7 @@ internal void resizeDIBSection(Win32OffscreenBuffer *buffer, int width, int heig |
|
|
buffer->width = width; |
|
|
buffer->width = width; |
|
|
buffer->height = height; |
|
|
buffer->height = height; |
|
|
buffer->bytesPerPixel = 4; |
|
|
buffer->bytesPerPixel = 4; |
|
|
|
|
|
buffer->pitch = buffer->width*buffer->bytesPerPixel; |
|
|
|
|
|
|
|
|
buffer->info.bmiHeader.biSize = sizeof(buffer->info.bmiHeader); |
|
|
buffer->info.bmiHeader.biSize = sizeof(buffer->info.bmiHeader); |
|
|
buffer->info.bmiHeader.biWidth = buffer->width; |
|
|
buffer->info.bmiHeader.biWidth = buffer->width; |
|
@@ -359,7 +360,56 @@ internal void win32FillSoundBuffer(Win32SoundOutput *soundOutput, DWORD byteToLo |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
internal void win32ProcessPendingMessages(GameControllerInput *keyboardController) { |
|
|
|
|
|
|
|
|
internal void win32BeginRecordingInput(Win32State *win32State, int inputRecordingIndex) { |
|
|
|
|
|
win32State->inputRecordingIndex = inputRecordingIndex; |
|
|
|
|
|
char *filename = "recording.hmi"; |
|
|
|
|
|
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 void win32EndRecordingInput(Win32State *win32State) { |
|
|
|
|
|
CloseHandle(win32State->recordingHandle); |
|
|
|
|
|
win32State->inputRecordingIndex = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
internal void win32RecordInput(Win32State *win32State, GameInput *newInput) { |
|
|
|
|
|
DWORD bytesWritten; |
|
|
|
|
|
WriteFile(win32State->recordingHandle, newInput, sizeof(*newInput), &bytesWritten, NULL); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
internal void win32BeginInputPlayback(Win32State *win32State, int inputPlayingIndex) { |
|
|
|
|
|
win32State->inputPlayingIndex = inputPlayingIndex; |
|
|
|
|
|
char *filename = "recording.hmi"; |
|
|
|
|
|
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 win32EndInputPlayback(Win32State *win32State) { |
|
|
|
|
|
CloseHandle(win32State->playbackHandle); |
|
|
|
|
|
win32State->inputPlayingIndex = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
internal void win32PlaybackInput(Win32State *win32State, GameInput *newInput) { |
|
|
|
|
|
DWORD bytesRead; |
|
|
|
|
|
if (ReadFile(win32State->playbackHandle, newInput, sizeof(*newInput), &bytesRead, NULL)) { |
|
|
|
|
|
if (bytesRead == 0) { |
|
|
|
|
|
// Restart |
|
|
|
|
|
int playingIndex = win32State->inputPlayingIndex; |
|
|
|
|
|
win32EndInputPlayback(win32State); |
|
|
|
|
|
win32BeginInputPlayback(win32State, playingIndex); |
|
|
|
|
|
} else { |
|
|
|
|
|
// there's still input, read next input |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
internal void win32ProcessPendingMessages(Win32State *win32State, GameControllerInput *keyboardController) { |
|
|
MSG message; |
|
|
MSG message; |
|
|
while (PeekMessageA(&message, NULL, NULL, NULL, PM_REMOVE)) { |
|
|
while (PeekMessageA(&message, NULL, NULL, NULL, PM_REMOVE)) { |
|
|
if (message.message == WM_QUIT) { |
|
|
if (message.message == WM_QUIT) { |
|
@@ -397,6 +447,15 @@ internal void win32ProcessPendingMessages(GameControllerInput *keyboardControlle |
|
|
} else if (VKCode == VK_RIGHT) { |
|
|
} else if (VKCode == VK_RIGHT) { |
|
|
win32ProcessKeyboardKeypress(&keyboardController->btnRight, isDown); |
|
|
win32ProcessKeyboardKeypress(&keyboardController->btnRight, isDown); |
|
|
} else if (VKCode == VK_SPACE) { |
|
|
} else if (VKCode == VK_SPACE) { |
|
|
|
|
|
} else if (VKCode == 'L') { |
|
|
|
|
|
if (isDown) { |
|
|
|
|
|
if (win32State->inputRecordingIndex == 0) { |
|
|
|
|
|
win32BeginRecordingInput(win32State, 1); |
|
|
|
|
|
} else { |
|
|
|
|
|
win32EndRecordingInput(win32State); |
|
|
|
|
|
win32BeginInputPlayback(win32State, 1); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -430,12 +489,11 @@ inline real32 win32GetSecondsElapsed(LARGE_INTEGER start, LARGE_INTEGER end) { |
|
|
#define monitorRefreshHz 60 |
|
|
#define monitorRefreshHz 60 |
|
|
#define gameUpdateHz (monitorRefreshHz / 2) |
|
|
#define gameUpdateHz (monitorRefreshHz / 2) |
|
|
|
|
|
|
|
|
internal void win32DebugDrawVertical(Win32OffscreenBuffer *screenBuffer, int x, int top, int bottom, int32 color) { |
|
|
|
|
|
int pitch = screenBuffer->width*screenBuffer->bytesPerPixel; |
|
|
|
|
|
uint8 *pixel = (uint8 *)screenBuffer->memory + top * pitch + x*screenBuffer->bytesPerPixel; |
|
|
|
|
|
|
|
|
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++) { |
|
|
for (int y = top; y < bottom; y++) { |
|
|
*(uint32 *)pixel = color; |
|
|
*(uint32 *)pixel = color; |
|
|
pixel += pitch; |
|
|
|
|
|
|
|
|
pixel += buffer->pitch; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -445,26 +503,27 @@ inline void win32DrawSoundBufferMarker(Win32OffscreenBuffer *buffer, Win32SoundO |
|
|
win32DebugDrawVertical(buffer, x, top, bottom, color); |
|
|
win32DebugDrawVertical(buffer, x, top, bottom, color); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
internal void win32DebugSyncDisplay(Win32OffscreenBuffer *screenBuffer, int markerCount, Win32DebugTimeMarker *markers, Win32SoundOutput *soundOutput, real32 targetSecondsPerFrame) { |
|
|
|
|
|
|
|
|
internal void win32DebugSyncDisplay(Win32OffscreenBuffer *buffer, int markerCount, Win32DebugTimeMarker *markers, Win32SoundOutput *soundOutput, real32 targetSecondsPerFrame) { |
|
|
int padX = 16; |
|
|
int padX = 16; |
|
|
int padY = 16; |
|
|
int padY = 16; |
|
|
|
|
|
|
|
|
int top = padY; |
|
|
int top = padY; |
|
|
int bottom = screenBuffer->height - padY; |
|
|
|
|
|
int renderWidth = screenBuffer->width - 2 *padX; |
|
|
|
|
|
|
|
|
int bottom = buffer->height - padY; |
|
|
|
|
|
int renderWidth = buffer->width - 2 *padX; |
|
|
|
|
|
|
|
|
real32 pxPerSoundBufferEntry = (real32)renderWidth / (real32)soundOutput->secondaryBufferSize; |
|
|
real32 pxPerSoundBufferEntry = (real32)renderWidth / (real32)soundOutput->secondaryBufferSize; |
|
|
int pitch = screenBuffer->width*screenBuffer->bytesPerPixel; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
for (int markerIndex = 0; markerIndex < markerCount; markerIndex++) { |
|
|
for (int markerIndex = 0; markerIndex < markerCount; markerIndex++) { |
|
|
Win32DebugTimeMarker *thisMarker = &markers[markerIndex]; |
|
|
Win32DebugTimeMarker *thisMarker = &markers[markerIndex]; |
|
|
real32 alpha = ((real32)(markerIndex + 1) / (real32)markerCount); |
|
|
real32 alpha = ((real32)(markerIndex + 1) / (real32)markerCount); |
|
|
int x = padX + (int)(pxPerSoundBufferEntry * (real32)thisMarker->writeCursor); |
|
|
int x = padX + (int)(pxPerSoundBufferEntry * (real32)thisMarker->writeCursor); |
|
|
uint8 *pixel = (uint8 *)screenBuffer->memory + top * pitch + x*screenBuffer->bytesPerPixel; |
|
|
|
|
|
|
|
|
uint8 *pixel = (uint8 *)buffer->memory + top * buffer->pitch + x*buffer->bytesPerPixel; |
|
|
uint32 newPixel = (uint32)((real32)alpha * 0xFFFFFFFF + (1.0f - alpha) * (*(uint32 *)pixel)); |
|
|
uint32 newPixel = (uint32)((real32)alpha * 0xFFFFFFFF + (1.0f - alpha) * (*(uint32 *)pixel)); |
|
|
win32DrawSoundBufferMarker(screenBuffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->playCursor, newPixel); |
|
|
|
|
|
win32DrawSoundBufferMarker(screenBuffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->writeCursor, 0x00FF0000); |
|
|
|
|
|
|
|
|
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) { |
|
|
void catStrings(size_t sourceACount, char *sourceA, size_t sourceBCount, char *sourceB, size_t destCount, char *dest) { |
|
@@ -536,6 +595,8 @@ 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]; |
|
|
GameInput *newInput = &input[1]; |
|
|
GameInput *newInput = &input[1]; |
|
@@ -568,8 +629,9 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin |
|
|
gameMemory.debugReadEntireFile = debugReadEntireFile; |
|
|
gameMemory.debugReadEntireFile = debugReadEntireFile; |
|
|
gameMemory.debug_printf = debug_printf; |
|
|
gameMemory.debug_printf = debug_printf; |
|
|
|
|
|
|
|
|
uint64 totalSize = gameMemory.permanentStorageSize + gameMemory.transientStorageSize; |
|
|
|
|
|
gameMemory.permanentStorage = VirtualAlloc(baseAddress, totalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); |
|
|
|
|
|
|
|
|
win32State.gameMemoryTotalSize = gameMemory.permanentStorageSize + gameMemory.transientStorageSize; |
|
|
|
|
|
win32State.gameMemoryBlock = VirtualAlloc(baseAddress, win32State.gameMemoryTotalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); |
|
|
|
|
|
gameMemory.permanentStorage = win32State.gameMemoryBlock; |
|
|
gameMemory.transientStorage = ((uint8 *)gameMemory.permanentStorage + gameMemory.permanentStorageSize); |
|
|
gameMemory.transientStorage = ((uint8 *)gameMemory.permanentStorage + gameMemory.permanentStorageSize); |
|
|
|
|
|
|
|
|
win32InitSound(window, soundOutput.samplesPerSecond, soundOutput.secondaryBufferSize); |
|
|
win32InitSound(window, soundOutput.samplesPerSecond, soundOutput.secondaryBufferSize); |
|
@@ -602,7 +664,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin |
|
|
newKeyboardController->buttons[buttonIndex].endedDown = oldKeyboardController->buttons[buttonIndex].endedDown; |
|
|
newKeyboardController->buttons[buttonIndex].endedDown = oldKeyboardController->buttons[buttonIndex].endedDown; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
win32ProcessPendingMessages(newKeyboardController); |
|
|
|
|
|
|
|
|
win32ProcessPendingMessages(&win32State, newKeyboardController); |
|
|
|
|
|
|
|
|
XINPUT_STATE controllerState; |
|
|
XINPUT_STATE controllerState; |
|
|
int maxControllerCount = XUSER_MAX_COUNT; |
|
|
int maxControllerCount = XUSER_MAX_COUNT; |
|
@@ -670,6 +732,16 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin |
|
|
videoBuffer.memory = globalBackBuffer.memory; |
|
|
videoBuffer.memory = globalBackBuffer.memory; |
|
|
videoBuffer.width = globalBackBuffer.width; |
|
|
videoBuffer.width = globalBackBuffer.width; |
|
|
videoBuffer.height = globalBackBuffer.height; |
|
|
videoBuffer.height = globalBackBuffer.height; |
|
|
|
|
|
videoBuffer.pitch = globalBackBuffer.pitch; |
|
|
|
|
|
videoBuffer.bytesPerPixel = globalBackBuffer.bytesPerPixel; |
|
|
|
|
|
|
|
|
|
|
|
if (win32State.inputRecordingIndex) { |
|
|
|
|
|
win32RecordInput(&win32State, newInput); |
|
|
|
|
|
} |
|
|
|
|
|
if (win32State.inputPlayingIndex) { |
|
|
|
|
|
win32PlaybackInput(&win32State, newInput); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
game.updateAndRender(&gameMemory, &videoBuffer, newInput); |
|
|
game.updateAndRender(&gameMemory, &videoBuffer, newInput); |
|
|
|
|
|
|
|
|
DWORD playCursor = 0; |
|
|
DWORD playCursor = 0; |
|
|