Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "handmade.h"
- #include <stdio.h>
- #include <windows.h>
- #include <xinput.h>
- #include <dsound.h>
- #include "win32_handmade.h"
- static bool RUNNING;
- static bool globalPause;
- static win32_offscreen_buffer globalBackBuffer;
- static LPDIRECTSOUNDBUFFER globalSecondaryBuffer;
- static int64_t globalPerfFrequency;
- //XInputGetState
- #define X_INPUT_GET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState)
- typedef X_INPUT_GET_STATE(x_input_get_state);
- X_INPUT_GET_STATE(XInputGetStateStub)
- {
- return(ERROR_DEVICE_NOT_CONNECTED);
- }
- static x_input_get_state *XInputGetState_ = XInputGetStateStub;
- #define XInputGetState XInputGetState_
- //XInputSetState
- #define X_INPUT_SET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration)
- typedef X_INPUT_SET_STATE(x_input_set_state);
- X_INPUT_SET_STATE(XInputSetStateStub)
- {
- return(ERROR_DEVICE_NOT_CONNECTED);
- }
- static x_input_set_state *XInputSetState_ = XInputSetStateStub;
- #define XInputSetState XInputSetState_
- #define DIRECT_SOUND_CREATE(name) HRESULT WINAPI name(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter)
- typedef DIRECT_SOUND_CREATE(direct_sound_create);
- DEBUG_PLATFORM_FREE_FILE_MEMORY(DEBUGPlatformFreeFileMemory)
- {
- if(memory)
- {
- VirtualFree(memory, 0, MEM_RELEASE);
- }
- }
- DEBUG_PLATFORM_READ_ENTIRE_FILE(DEBUGPlatformReadEntireFile)
- {
- debug_read_file_result result = {};
- HANDLE fileHandle = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
- if(fileHandle != INVALID_HANDLE_VALUE)
- {
- LARGE_INTEGER fileSize;
- if(GetFileSizeEx(fileHandle, &fileSize))
- {
- uint32_t fileSize32 = safeTruncateUint64(fileSize.QuadPart);
- result.contents = VirtualAlloc(0, fileSize32, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
- if(result.contents)
- {
- DWORD bytesRead;
- if(ReadFile(fileHandle, result.contents, fileSize32, &bytesRead,0) && fileSize32 == bytesRead)
- {
- result.contentSize = bytesRead;
- }
- else
- {
- DEBUGPlatformFreeFileMemory(result.contents);
- result.contents = NULL;
- }
- }
- }
- CloseHandle(fileHandle);
- }
- return result;
- }
- DEBUG_PLATFORM_WRITE_ENTIRE_FILE(DEBUGPlatformWriteEntireFile)
- {
- int result = false;
- HANDLE fileHandle = CreateFileA(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
- if (fileHandle != INVALID_HANDLE_VALUE)
- {
- DWORD bytesWritten;
- if (WriteFile(fileHandle, memory, memorySize, &bytesWritten, 0))
- {
- result = (bytesWritten == memorySize);
- }
- CloseHandle(fileHandle);
- }
- return result;
- }
- struct win32_game_code
- {
- HMODULE DLL;
- FILETIME DLLLastWriteTime;
- game_get_sound_samples *getSoundSamples;
- game_update_and_render *updateAndRender;
- bool isValid;
- };
- inline FILETIME Win32GetFileWriteTime(char * filename)
- {
- FILETIME lastWriteTime = {};
- WIN32_FIND_DATA findData;
- HANDLE fileHandle = FindFirstFileA(filename, &findData);
- if(fileHandle != INVALID_HANDLE_VALUE)
- {
- lastWriteTime = findData.ftLastWriteTime;
- FindClose(fileHandle);
- }
- return lastWriteTime;
- }
- static win32_game_code Win32LoadGameCode(char *sourceDLLName, char * tempDLLName)
- {
- win32_game_code gameCodeStruct = {};
- FILETIME latestDLLWriteTime = Win32GetFileWriteTime(sourceDLLName);
- gameCodeStruct.DLLLastWriteTime = latestDLLWriteTime;
- CopyFile(sourceDLLName, tempDLLName, FALSE);
- gameCodeStruct.DLL = LoadLibrary(tempDLLName);
- if(gameCodeStruct.DLL)
- {
- gameCodeStruct.updateAndRender = (game_update_and_render *)GetProcAddress(gameCodeStruct.DLL, "gameUpdateAndRender");
- gameCodeStruct.getSoundSamples = (game_get_sound_samples *)GetProcAddress(gameCodeStruct.DLL, "gameGetSoundSamples");
- gameCodeStruct.isValid = (gameCodeStruct.updateAndRender && gameCodeStruct.getSoundSamples);
- }
- if(!gameCodeStruct.isValid)
- {
- gameCodeStruct.updateAndRender = gameUpdateAndRenderStub;
- gameCodeStruct.getSoundSamples = gameGetSoundSamplesStub;
- }
- return gameCodeStruct;
- }
- static void Win32UnloadGameCode(win32_game_code *gameCode)
- {
- if(gameCode->DLL)
- {
- FreeLibrary(gameCode->DLL);
- gameCode->DLL = NULL;
- }
- gameCode->isValid = false;
- gameCode->updateAndRender = gameUpdateAndRenderStub;
- gameCode->getSoundSamples = gameGetSoundSamplesStub;
- }
- static void Win32LoadXInput(void)
- {
- HMODULE XInputLibrary = LoadLibrary("xinput1_4.dll");
- if(!XInputLibrary)
- {
- XInputLibrary = LoadLibrary("xinput1_3.dll");
- }
- if(!XInputLibrary)
- {
- XInputLibrary = LoadLibrary("xInput9_1_0.dll");
- }
- if(XInputLibrary)
- {
- XInputGetState = (x_input_get_state *)GetProcAddress(XInputLibrary, "XInputGetState");
- XInputSetState = (x_input_set_state *)GetProcAddress(XInputLibrary, "XInputSetState");
- }
- }
- static void Win32InitDSound(HWND hWnd, uint32_t bufferSize, uint32_t samplesPerSecond)
- {
- HMODULE dSoundLibrary = LoadLibrary("dsound.dll");
- if(dSoundLibrary)
- {
- direct_sound_create * DirectSoundCreate = (direct_sound_create*)GetProcAddress(dSoundLibrary, "DirectSoundCreate");
- LPDIRECTSOUND directSound;
- if(DirectSoundCreate && SUCCEEDED(DirectSoundCreate(0, &directSound, 0)))
- {
- WAVEFORMATEX waveFormat = {};
- waveFormat.wFormatTag = WAVE_FORMAT_PCM;
- waveFormat.nChannels = 2;
- waveFormat.wBitsPerSample = 16;
- waveFormat.nSamplesPerSec = samplesPerSecond;
- waveFormat.nBlockAlign = (waveFormat.nChannels*waveFormat.wBitsPerSample)/8;
- waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
- waveFormat.cbSize =0;
- if(SUCCEEDED(directSound->SetCooperativeLevel(hWnd, DSSCL_PRIORITY)))
- {
- DSBUFFERDESC bufferDescription = {};
- bufferDescription.dwSize = sizeof(bufferDescription);
- bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
- LPDIRECTSOUNDBUFFER primaryBuffer;
- if(SUCCEEDED(directSound->CreateSoundBuffer(&bufferDescription, &primaryBuffer, 0)))
- {
- if(SUCCEEDED(primaryBuffer->SetFormat(&waveFormat)))
- {
- }
- else
- {
- //Diagnostic
- }
- }
- }
- else
- {
- //Diagnostic
- }
- DSBUFFERDESC bufferDescription = {};
- bufferDescription.dwSize = sizeof(bufferDescription);
- bufferDescription.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
- bufferDescription.lpwfxFormat = &waveFormat;
- bufferDescription.dwBufferBytes = bufferSize;
- if(SUCCEEDED(directSound->CreateSoundBuffer(&bufferDescription, &globalSecondaryBuffer, 0)))
- {
- }
- }
- else
- {
- //Diagnostic
- }
- }
- }
- static win32_window_dimension Win32GetWindowDimension(HWND window)
- {
- win32_window_dimension result;
- RECT clientRect;
- GetClientRect(window, &clientRect);
- result.width = clientRect.right - clientRect.left;
- result.height = clientRect.bottom - clientRect.top;
- return result;
- }
- static void Win32ResizeDIBSection(win32_offscreen_buffer *buffer, int width, int height)
- {
- if(buffer->memory)
- {
- VirtualFree(buffer->memory, 0, MEM_RELEASE);
- }
- int bytesPerPixel = 4;
- buffer->bytesPerPixel = bytesPerPixel;
- buffer->width = width;
- buffer->height = height;
- buffer->info.bmiHeader.biSize = sizeof(buffer->info.bmiHeader);
- buffer->info.bmiHeader.biWidth = buffer->width;
- buffer->info.bmiHeader.biHeight = -buffer->height;
- buffer->info.bmiHeader.biPlanes = 1;
- buffer->info.bmiHeader.biBitCount = 32;
- buffer->info.bmiHeader.biCompression = BI_RGB;
- int bitmapMemorySize = bytesPerPixel * buffer->width * buffer->height;
- buffer->memory = VirtualAlloc(0, bitmapMemorySize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
- buffer->pitch = buffer->width * bytesPerPixel;
- }
- static void Win32DisplayBufferInWindow(HDC deviceContext, int windowWidth, int windowHeight, win32_offscreen_buffer buffer)
- {
- StretchDIBits(deviceContext, 0, 0, windowWidth, windowHeight , 0, 0, buffer.width, buffer.height, buffer.memory, &buffer.info, DIB_RGB_COLORS, SRCCOPY);
- }
- static void Win32ClearBuffer(win32_sound_output * soundOutput)
- {
- VOID *region1;
- DWORD region1Size;
- VOID *region2;
- DWORD region2Size;
- if(SUCCEEDED(globalSecondaryBuffer->Lock(0, soundOutput->secondaryBufferSize, ®ion1, ®ion1Size, ®ion2, ®ion2Size, 0)))
- {
- uint8_t *destSample = (uint8_t*)region1;
- for(DWORD byteIndex = 0; byteIndex < region1Size; ++byteIndex)
- {
- *destSample++ = 0;
- }
- destSample = (uint8_t*)region2;
- for(DWORD byteIndex = 0; byteIndex < region2Size; ++byteIndex)
- {
- *destSample++ = 0;
- }
- globalSecondaryBuffer->Unlock(region1, region1Size, region2, region2Size);
- }
- }
- static void Win32FillSoundBuffer(win32_sound_output * soundOutput, game_sound_output_buffer * sourceBuffer, DWORD byteToLock, DWORD bytesToWrite)
- {
- VOID *region1;
- DWORD region1Size;
- VOID *region2;
- DWORD region2Size;
- if(SUCCEEDED(globalSecondaryBuffer->Lock(byteToLock, bytesToWrite,®ion1, ®ion1Size, ®ion2, ®ion2Size, 0)))
- {
- int16_t *destSample = (int16_t*)region1;
- int16_t *sourceSample = sourceBuffer->samples;
- DWORD region1SampleCount = region1Size/soundOutput->bytesPerSample;
- for(DWORD sampleIndex = 0; sampleIndex < region1SampleCount; ++sampleIndex)
- {
- *destSample++ = *sourceSample++;
- *destSample++ = *sourceSample++;
- ++soundOutput->runningSampleIndex;
- }
- destSample = (int16_t*)region2;
- DWORD region2SampleCount = region2Size/soundOutput->bytesPerSample;
- for(DWORD sampleIndex = 0; sampleIndex < region2SampleCount; ++sampleIndex)
- {
- *destSample++ = *sourceSample++;
- *destSample++ = *sourceSample++;
- ++soundOutput->runningSampleIndex;
- }
- globalSecondaryBuffer->Unlock(region1, region1Size, region2, region2Size);
- }
- }
- static void Win32BeginRecordingInput(win32_state *win32State, int inputRecordingIndex)
- {
- win32State->inputRecordingIndex = inputRecordingIndex;
- char * Filename = "foo.hmi";
- win32State->recordingHandle = CreateFileA(Filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
- DWORD bytesTowrite = (DWORD)win32State->totalSize;
- Assert(win32State->totalSize == bytesTowrite);
- DWORD bytesWritten;
- WriteFile(win32State->recordingHandle, win32State->gameMemoryBlock, (DWORD)win32State->totalSize, &bytesWritten, 0);
- game_state *testState = (game_state*)win32State->gameMemoryBlock;
- }
- static void Win32EndRecordingInput(win32_state *win32State)
- {
- CloseHandle(win32State->recordingHandle);
- win32State->inputRecordingIndex = 0;
- }
- static void Win32BeginInputPlayback(win32_state *win32State, int inputPlayingIndex)
- {
- win32State->inputPlayingIndex = inputPlayingIndex;
- char * Filename = "foo.hmi";
- win32State->playbackHandle = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
- DWORD bytesToRead = (DWORD)win32State->totalSize;
- Assert(win32State->totalSize == bytesToRead);
- DWORD bytesRead;
- ReadFile(win32State->playbackHandle, win32State->gameMemoryBlock, bytesToRead, &bytesRead, 0);
- game_state *testState = (game_state*)win32State->gameMemoryBlock;
- }
- static void Win32EndInputPlayback(win32_state *win32State)
- {
- CloseHandle(win32State->playbackHandle);
- win32State->inputPlayingIndex = 0;
- }
- static void Win32RecordInput(win32_state *win32State, game_input *newInput)
- {
- DWORD bytesWritten = 0;
- WriteFile(win32State->recordingHandle, newInput, sizeof(*newInput), &bytesWritten, 0);
- }
- static void Win32PlayBackInput(win32_state *win32State, game_input *newInput)
- {
- DWORD bytesRead = 0;
- if(ReadFile(win32State->playbackHandle, newInput, sizeof(*newInput), &bytesRead, 0))
- {
- if(bytesRead == 0)
- {
- //No more input to read. Go back to beginning
- int playingIndex = win32State->inputPlayingIndex;
- Win32EndInputPlayback(win32State);
- Win32BeginInputPlayback(win32State, playingIndex);
- ReadFile(win32State->playbackHandle, newInput, sizeof(*newInput), &bytesRead, 0);
- }
- }
- }
- static void Win32ProcessXInputDigitalButton(game_button_state *oldState, game_button_state *newState,
- DWORD xInputButtonState, DWORD buttonBit)
- {
- newState->endedDown = ((xInputButtonState & buttonBit) == buttonBit);
- newState->halfTransitionCount = (oldState->endedDown != newState->endedDown) ? 1 : 0;
- }
- static void Win32ProcessKeyboardMessage(game_button_state *newState,
- int32_t isDown)
- {
- Assert(newState->endedDown != isDown);
- newState->endedDown = isDown;
- ++newState->halfTransitionCount;
- }
- static float Win32ProcessXInputStickPosition(SHORT thumbValue, SHORT deadZoneThreshold)
- {
- float returnValue = 0.0f;
- if(thumbValue < -deadZoneThreshold)
- {
- returnValue = (float)(thumbValue + deadZoneThreshold)/ (32768.0f - deadZoneThreshold);
- }
- else if(thumbValue > deadZoneThreshold)
- {
- returnValue = (float)(thumbValue - deadZoneThreshold) / (32767.0f - deadZoneThreshold);
- }
- return returnValue;
- }
- static void Win32ProcessPendingMessages(win32_state *win32State, game_controller_input *keyboardController)
- {
- MSG message;
- while(PeekMessage(&message, 0, 0, 0, PM_REMOVE))
- {
- switch (message.message)
- {
- case WM_QUIT:
- {
- RUNNING = false;
- }break;
- case WM_SYSKEYDOWN:
- case WM_SYSKEYUP:
- case WM_KEYDOWN:
- case WM_KEYUP:
- {
- uint32_t vkCode = (uint32_t)message.wParam;
- bool wasDown = ((message.lParam & (1 << 30)) != 0);
- bool isDown = ((message.lParam & (1 << 31)) == 0);
- if (wasDown != isDown)
- {
- if (vkCode == 'Q')
- {
- Win32ProcessKeyboardMessage(&keyboardController->leftShoulder, isDown);
- }
- else if (vkCode == 'E')
- {
- Win32ProcessKeyboardMessage(&keyboardController->rightShoulder, isDown);
- }
- else if (vkCode == 'W')
- {
- Win32ProcessKeyboardMessage(&keyboardController->moveUp, isDown);
- }
- else if (vkCode == 'S')
- {
- Win32ProcessKeyboardMessage(&keyboardController->moveDown, isDown);
- }
- else if (vkCode == 'A')
- {
- Win32ProcessKeyboardMessage(&keyboardController->moveLeft, isDown);
- }
- else if (vkCode == 'D')
- {
- Win32ProcessKeyboardMessage(&keyboardController->moveRight, isDown);
- }
- else if (vkCode == VK_UP)
- {
- Win32ProcessKeyboardMessage(&keyboardController->actionUp, isDown);
- }
- else if (vkCode == VK_DOWN)
- {
- Win32ProcessKeyboardMessage(&keyboardController->actionDown, isDown);
- }
- else if (vkCode == VK_LEFT)
- {
- Win32ProcessKeyboardMessage(&keyboardController->actionLeft, isDown);
- }
- else if (vkCode == VK_RIGHT)
- {
- Win32ProcessKeyboardMessage(&keyboardController->actionRight, isDown);
- }
- else if (vkCode == VK_ESCAPE)
- {
- Win32ProcessKeyboardMessage(&keyboardController->start, isDown);
- }
- else if (vkCode == VK_SPACE)
- {
- Win32ProcessKeyboardMessage(&keyboardController->back, isDown);
- }
- #if HANDMADE_INTERNAL
- else if (vkCode == 'P' && isDown)
- {
- globalPause = !globalPause;
- }
- else if(vkCode == 'L')
- {
- if(isDown)
- {
- if(win32State->inputRecordingIndex == 0)
- {
- game_state *testState = (game_state*)win32State->gameMemoryBlock;
- Win32BeginRecordingInput(win32State, 1);
- }
- else
- {
- Win32EndRecordingInput(win32State);
- Win32BeginInputPlayback(win32State, 1);
- }
- }
- }
- #endif
- }
- bool altKeyDown = ((message.lParam & (1 << 29)) != 0);
- if ((vkCode == VK_F4) && altKeyDown)
- {
- }
- }break;
- default:
- {
- TranslateMessage(&message);
- DispatchMessage(&message);
- }break;
- }
- }
- }
- static LRESULT CALLBACK Win32WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- LRESULT result = 0;
- switch(uMsg)
- {
- case WM_DESTROY:
- {
- RUNNING = false;
- } break;
- case WM_CLOSE:
- {
- RUNNING = false;
- } break;
- case WM_ACTIVATEAPP:
- {
- OutputDebugStringA("WM_ACTIVATEAPP\n");
- } break;
- case WM_SYSKEYDOWN:
- case WM_SYSKEYUP:
- case WM_KEYDOWN:
- case WM_KEYUP:
- {
- Assert(!"Keyboard input came throught a non-dispatched message!");
- }break;
- case WM_PAINT:
- {
- PAINTSTRUCT paint;
- HDC deviceContext = BeginPaint(hWnd, &paint);
- win32_window_dimension windowSize = Win32GetWindowDimension(hWnd);
- Win32DisplayBufferInWindow(deviceContext, windowSize.width, windowSize.height, globalBackBuffer);
- EndPaint(hWnd,&paint);
- } break;
- default:
- {
- result = DefWindowProc(hWnd, uMsg, wParam, lParam);
- } break;
- }
- return result;
- }
- inline LARGE_INTEGER Win32GetWallClock(void)
- {
- LARGE_INTEGER returnInteger;
- QueryPerformanceCounter(&returnInteger);
- return returnInteger;
- }
- inline float Win32GetSecondsElapsed(LARGE_INTEGER start, LARGE_INTEGER end)
- {
- float secondsElapsedForWork = (float)(end.QuadPart - start.QuadPart)/(float)globalPerfFrequency;
- return secondsElapsedForWork;
- }
- static void Win32DebugDrawVertical(win32_offscreen_buffer *backBuffer, int x, int top, int bottom, uint32_t color)
- {
- if(top <= 0)
- {
- top = 0;
- }
- if(bottom > backBuffer->height)
- {
- bottom = backBuffer->height;
- }
- if((x >= 0) && (x < backBuffer->width))
- {
- uint8_t * drawPixel =(uint8_t*)backBuffer->memory + x*backBuffer->bytesPerPixel + top *backBuffer->pitch;
- for(int y = top; y < bottom; ++y)
- {
- *(uint32_t *)drawPixel = color;
- drawPixel += backBuffer->pitch;
- }
- }
- }
- static void Win32DrawSoundBufferMarker(win32_offscreen_buffer *backBuffer, win32_sound_output *soundOutput, float c, int padX, int top, int bottom, DWORD value, DWORD color)
- {
- int x = padX + (int)(c * (float)value);
- Win32DebugDrawVertical(backBuffer, x, top, bottom, color);
- }
- static void Win32DebugSyncDisplay(win32_offscreen_buffer *backBuffer, DWORD markerCount, win32_debug_time_marker * markers, DWORD currentMarkerIndex, win32_sound_output *soundOutput, float secondsPerFrame)
- {
- int padX = 16;
- int padY = 16;
- int lineHeight = 64;
- float c = (((float)backBuffer->width - (2*padX))/(float)soundOutput->secondaryBufferSize);
- for(DWORD markerIndex = 0; markerIndex < markerCount ; ++markerIndex)
- {
- win32_debug_time_marker *thisMarker = &markers[markerIndex];
- Assert(thisMarker->outputPlayCursor < soundOutput->secondaryBufferSize);
- Assert(thisMarker->outputWriteCursor < soundOutput->secondaryBufferSize);
- Assert(thisMarker->outputLocation < soundOutput->secondaryBufferSize);
- Assert(thisMarker->outputByteCount < soundOutput->secondaryBufferSize);
- Assert(thisMarker->flipPlayCursor < soundOutput->secondaryBufferSize);
- Assert(thisMarker->flipWriteCursor < soundOutput->secondaryBufferSize);
- DWORD playColor = 0xFFFFFFFF;
- DWORD writeColor = 0xFFFF0000;
- DWORD expectedFlipColor = 0xFFFFFF00;
- DWORD playWindowColor = 0xFFFF00FF;
- int top = padY;
- int bottom = lineHeight + padY;
- if(markerIndex == currentMarkerIndex)
- {
- top += lineHeight + padY;
- bottom += lineHeight + padY;
- int firstTop = top;
- Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->outputPlayCursor, playColor);
- Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->outputWriteCursor, writeColor);
- top += lineHeight + padY;
- bottom += lineHeight + padY;
- Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->outputLocation, playColor);
- Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->outputLocation + thisMarker->outputByteCount, writeColor);
- top += lineHeight + padY;
- bottom += lineHeight + padY;
- Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, firstTop, bottom, thisMarker->expectedFlipPlayCursor, expectedFlipColor);
- }
- Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->flipPlayCursor, playColor);
- Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, (thisMarker->flipPlayCursor + 480*soundOutput->bytesPerSample), playWindowColor);
- Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->flipWriteCursor, writeColor);
- }
- }
- static void catStrings(size_t sourceACount, char *sourceA, size_t sourceBCount,char *sourceB, size_t destCount, char *dest)
- {
- for(int index = 0; index < sourceACount; ++index)
- {
- *dest++ = *sourceA++;
- }
- for(int index = 0; index < sourceBCount; ++index)
- {
- *dest++ = *sourceB++;
- }
- *dest++ = 0;
- }
- int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
- {
- win32_state win32State = {};
- char exeFilename[MAX_PATH];
- DWORD sizeOfFilename = GetModuleFileName(0, exeFilename, sizeof(exeFilename));
- char * onePastLastSlash = exeFilename;
- for(char * scan = exeFilename; *scan; ++scan)
- {
- if(*scan == '\\')
- {
- onePastLastSlash = scan + 1;
- }
- }
- char sourceGameCodeName[] = "handmade.dll";
- char sourceGameCodefullPath[MAX_PATH];
- catStrings(onePastLastSlash - exeFilename, exeFilename,
- sizeof(sourceGameCodeName) - 1, sourceGameCodeName,
- sizeof(sourceGameCodefullPath), sourceGameCodefullPath);
- char tempGameCodeName[] = "working_handmade.dll";
- char tempGameCodeFullPath[MAX_PATH];
- catStrings(onePastLastSlash - exeFilename, exeFilename,
- sizeof(tempGameCodeName) - 1, tempGameCodeName,
- sizeof(tempGameCodeFullPath), tempGameCodeFullPath);
- LARGE_INTEGER perfFrequencyResult;
- QueryPerformanceFrequency(&perfFrequencyResult);
- globalPerfFrequency = perfFrequencyResult.QuadPart;
- //Set the scheduler granularity to 1ms, so that sleep can be more granular
- UINT desiredSchedulerMS = 1;
- int sleepIsGranular = (timeBeginPeriod(desiredSchedulerMS) == TIMERR_NOERROR);
- Win32LoadXInput();
- WNDCLASS windowClass = {};
- Win32ResizeDIBSection(&globalBackBuffer, 1280, 720);
- windowClass.style = CS_OWNDC|CS_HREDRAW;
- windowClass.lpfnWndProc = Win32WindowProc;
- windowClass.hInstance = hInstance;
- //windowClass.hIcon = ;
- windowClass.lpszClassName = "HandmadeHeroWindowClass";
- #define monitorRefreshHz 60
- #define gameUpdateHz (monitorRefreshHz / 2)
- float targetSecondsElapsedPerFrame = 1.0f/(float)gameUpdateHz;
- if(RegisterClass(&windowClass))
- {
- HWND window = CreateWindowEx(0,windowClass.lpszClassName, "Handmade Hero", WS_OVERLAPPEDWINDOW|WS_VISIBLE,CW_USEDEFAULT,
- CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance,0);
- if(window)
- {
- HDC deviceContext = GetDC(window);
- win32_sound_output soundOutput = {};
- soundOutput.samplesPerSecond = 48000;
- soundOutput.bytesPerSample = sizeof(uint16_t) * 2;
- soundOutput.secondaryBufferSize = soundOutput.samplesPerSecond * soundOutput.bytesPerSample;
- soundOutput.latencySampleCount = 3 * (soundOutput.samplesPerSecond / gameUpdateHz);
- soundOutput.safetyBytes = (soundOutput.samplesPerSecond * soundOutput.bytesPerSample / gameUpdateHz) / 3 ;
- Win32InitDSound(window, soundOutput.secondaryBufferSize, soundOutput.samplesPerSecond);
- Win32ClearBuffer(&soundOutput);
- globalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
- int16_t * samples = (int16_t *)VirtualAlloc(0, 48000*2*sizeof(uint16_t), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
- #if HANDMADE_INTERNAL
- LPVOID baseAddress = (LPVOID)teraBytes(2);
- #else
- LPVOID baseAddress = 0;
- #endif
- game_memory gameMemory = {};
- gameMemory.permanantStorageSize = megaBytes(64);
- gameMemory.transientStorageSize = gigaBytes(1);
- gameMemory.DEBUGPlatformReadEntireFile = DEBUGPlatformReadEntireFile;
- gameMemory.DEBUGPlatformWriteEntireFile = DEBUGPlatformWriteEntireFile;
- gameMemory.DEBUGPlatformFreeFileMemory = DEBUGPlatformFreeFileMemory;
- win32State.totalSize = gameMemory.permanantStorageSize + gameMemory.transientStorageSize;
- win32State.gameMemoryBlock = VirtualAlloc(baseAddress,(size_t)win32State.totalSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
- gameMemory.permanantStorage = win32State.gameMemoryBlock;
- gameMemory.transientStorage = (uint8_t*)gameMemory.permanantStorage + gameMemory.permanantStorageSize;
- if(samples && gameMemory.permanantStorage && gameMemory.transientStorage)
- {
- RUNNING = true;
- game_input input[2] = {};
- game_input *newInput = &input[0];
- game_input *oldInput = &input[1];
- LARGE_INTEGER lastCounter = Win32GetWallClock();
- LARGE_INTEGER flipWallClock = Win32GetWallClock();
- int32_t soundIsValid = false;
- DWORD audioLatencyBytes = 0;
- float audioLatencySeconds = 0;
- #if HANDMADE_INTERNAL
- int debugTimeMarkerIndex = 0;
- win32_debug_time_marker debugTimeMarkers[gameUpdateHz / 2] = {};
- #endif
- win32_game_code game = Win32LoadGameCode(sourceGameCodefullPath, tempGameCodeFullPath);
- uint32_t loadCounter = 0;
- int64_t lastCycleCount = __rdtsc();
- while(RUNNING)
- {
- FILETIME newDLLWriteTime = Win32GetFileWriteTime(sourceGameCodefullPath);
- if(CompareFileTime(&newDLLWriteTime, &game.DLLLastWriteTime) != 0)
- {
- Win32UnloadGameCode(&game);
- game = Win32LoadGameCode(sourceGameCodefullPath, tempGameCodeFullPath);
- }
- game_controller_input *oldKeyboardController = getController(oldInput, 0);
- game_controller_input *newKeyboardController = getController(newInput, 0);
- *newKeyboardController = {};
- newKeyboardController->isConnected = true;
- for(int buttonIndex = 0; buttonIndex < arrayCount(oldKeyboardController->buttons); ++buttonIndex)
- {
- newKeyboardController->buttons[buttonIndex].endedDown = oldKeyboardController->buttons[buttonIndex].endedDown;
- }
- Win32ProcessPendingMessages(&win32State, newKeyboardController);
- if(!globalPause)
- {
- DWORD maxControllerCount = XUSER_MAX_COUNT;
- if(maxControllerCount > (arrayCount(newInput->controllers) - 1))
- {
- maxControllerCount = (arrayCount(newInput->controllers) - 1);
- }
- for(DWORD controllerIndex = 0; controllerIndex < maxControllerCount; ++controllerIndex)
- {
- int ourControllerIndex = controllerIndex + 1;
- game_controller_input *oldController = getController(oldInput, ourControllerIndex);
- game_controller_input *newController = getController(newInput, ourControllerIndex);
- XINPUT_STATE controllerState;
- if(XInputGetState(controllerIndex, &controllerState) == ERROR_SUCCESS)
- {
- newController->isConnected = true;
- XINPUT_GAMEPAD *pad = &controllerState.Gamepad;
- newController->stickAverageX = Win32ProcessXInputStickPosition(pad->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
- newController->stickAverageY = Win32ProcessXInputStickPosition(pad->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
- // if(newController->stickAverageX != 0.0f || newController->stickAverageY != 0.0f )
- // {
- newController->isAnalog = true;
- // }
- if(pad->wButtons & XINPUT_GAMEPAD_DPAD_UP)
- {
- newController->stickAverageY = 1.0f;
- newController->isAnalog = false;
- }
- if(pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
- {
- newController->isAnalog = false;
- }
- if(pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
- {
- newController->isAnalog = false;
- }
- if(pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
- {
- newController->isAnalog = false;
- }
- float threshhold = 0.5f;
- Win32ProcessXInputDigitalButton(&oldController->moveLeft, &newController->moveLeft, (newController->stickAverageX < -threshhold) ? 1: 0, 1);
- Win32ProcessXInputDigitalButton(&oldController->moveRight, &newController->moveRight, (newController->stickAverageX < threshhold) ? 1: 0, 1);
- Win32ProcessXInputDigitalButton(&oldController->moveDown, &newController->moveDown, (newController->stickAverageY < -threshhold) ? 1: 0, 1);
- Win32ProcessXInputDigitalButton(&oldController->moveUp, &newController->moveUp, (newController->stickAverageY < threshhold) ? 1: 0, 1);
- Win32ProcessXInputDigitalButton(&oldController->leftShoulder, &newController->leftShoulder, pad->wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER);
- Win32ProcessXInputDigitalButton(&oldController->rightShoulder, &newController->rightShoulder, pad->wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER);
- Win32ProcessXInputDigitalButton(&oldController->actionDown, &newController->actionDown, pad->wButtons, XINPUT_GAMEPAD_A);
- Win32ProcessXInputDigitalButton(&oldController->actionRight, &newController->actionRight, pad->wButtons, XINPUT_GAMEPAD_B);
- Win32ProcessXInputDigitalButton(&oldController->actionLeft, &newController->actionLeft, pad->wButtons, XINPUT_GAMEPAD_X);
- Win32ProcessXInputDigitalButton(&oldController->actionUp, &newController->actionUp, pad->wButtons, XINPUT_GAMEPAD_Y);
- Win32ProcessXInputDigitalButton(&oldController->back, &newController->back, pad->wButtons, XINPUT_GAMEPAD_BACK);
- Win32ProcessXInputDigitalButton(&oldController->start, &newController->start, pad->wButtons, XINPUT_GAMEPAD_START);
- }
- else
- {
- //Controller not available
- newController->isConnected = false;
- }
- }
- game_offscreen_buffer buffer;
- buffer.memory = globalBackBuffer.memory;
- buffer.width = globalBackBuffer.width;
- buffer.height = globalBackBuffer.height;
- buffer.pitch = globalBackBuffer.pitch;
- buffer.bytesPerPixel = globalBackBuffer.bytesPerPixel;
- if(win32State.inputRecordingIndex)
- {
- Win32RecordInput(&win32State, newInput);
- }
- if(win32State.inputPlayingIndex)
- {
- Win32PlayBackInput(&win32State, newInput);
- }
- //Where the game actually updates
- game.updateAndRender(&gameMemory, &buffer, newInput);
- LARGE_INTEGER audioWallClock = Win32GetWallClock();
- float fromBeginToAudioInSeconds = Win32GetSecondsElapsed(flipWallClock, audioWallClock);
- DWORD playCursor;
- DWORD writeCursor;
- if(globalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor) == DS_OK)
- {
- /*
- How sound output computation works.
- We define a safety value that is the number of samples we thing our game update loop may vary
- by (let's say by up to 2ms).
- When we wake up to write audio, we will look and see what the play cursor position is and we
- will forecast ahead where we think the play cursor will be on the next frame boundary.
- We will then look to see if the write cursor is at least before that safety value. If it is,
- the target fill position is that frame boundary plus one frame. This gives us perfect audio sync
- in the case of a card that has low enough latency.
- If the write cursor is after that safety margin, then we assume we can never sync the
- audio perfectly, so we will write one frame's worth of audio plus the safetys number of
- guard samples.
- */
- if(!soundIsValid)
- {
- soundOutput.runningSampleIndex = writeCursor / soundOutput.bytesPerSample;
- soundIsValid = true;
- }
- DWORD byteToLock = (soundOutput.runningSampleIndex * soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize;
- DWORD expectedSoundBytesPerFrame = (soundOutput.samplesPerSecond * soundOutput.bytesPerSample) / gameUpdateHz;
- float secondsLeftUntilFlip = (targetSecondsElapsedPerFrame - fromBeginToAudioInSeconds);
- DWORD expectedSoundBytesUntilFlip = (DWORD)((secondsLeftUntilFlip/(float)targetSecondsElapsedPerFrame) * (float)expectedSoundBytesPerFrame);
- DWORD expectedFrameBoundaryByte = playCursor + expectedSoundBytesPerFrame;
- DWORD safeWriteCursor = writeCursor;
- if(safeWriteCursor < playCursor)
- {
- safeWriteCursor += soundOutput.secondaryBufferSize;
- }
- Assert(safeWriteCursor >= playCursor);
- safeWriteCursor += soundOutput.safetyBytes;
- int audioCardIsLowLatentcy = (safeWriteCursor < expectedFrameBoundaryByte);
- DWORD targetCursor = 0;
- if(audioCardIsLowLatentcy)
- {
- targetCursor = expectedFrameBoundaryByte + expectedSoundBytesPerFrame;
- }
- else
- {
- targetCursor = writeCursor + expectedSoundBytesPerFrame +
- soundOutput.safetyBytes;
- }
- targetCursor = targetCursor % soundOutput.secondaryBufferSize;
- DWORD bytesToWrite = 0;
- if(byteToLock > targetCursor)
- {
- bytesToWrite = soundOutput.secondaryBufferSize - byteToLock;
- bytesToWrite += targetCursor;
- }
- else
- {
- bytesToWrite = targetCursor - byteToLock;
- }
- game_sound_output_buffer soundBuffer = {};
- soundBuffer.samplesPerSecond = soundOutput.samplesPerSecond;
- soundBuffer.sampleCount = bytesToWrite/soundOutput.bytesPerSample;
- soundBuffer.samples = samples;
- game.getSoundSamples(&gameMemory, &soundBuffer);
- #if HANDMADE_INTERNAL
- win32_debug_time_marker *marker = &debugTimeMarkers[debugTimeMarkerIndex];
- marker->outputPlayCursor = playCursor;
- marker->outputWriteCursor = writeCursor;
- marker->outputLocation = byteToLock;
- marker->outputByteCount = bytesToWrite;
- marker->expectedFlipPlayCursor = expectedFrameBoundaryByte;
- DWORD unwrappedWriteCursor = writeCursor;
- if(unwrappedWriteCursor < playCursor)
- {
- unwrappedWriteCursor += soundOutput.secondaryBufferSize;
- }
- audioLatencyBytes = unwrappedWriteCursor - playCursor;
- audioLatencySeconds = (((float)audioLatencyBytes / (float)soundOutput.bytesPerSample)/
- (float)soundOutput.samplesPerSecond);
- char textBuffer[256];
- _snprintf_s(textBuffer, sizeof(textBuffer), "BTL:%u TC:%u BTW:%u - PC:%u WC:%u Delta:%u (%fs)\n",
- byteToLock, targetCursor, bytesToWrite, playCursor,
- writeCursor, audioLatencyBytes, audioLatencySeconds);
- OutputDebugStringA(textBuffer);
- #endif
- Win32FillSoundBuffer(&soundOutput, &soundBuffer, byteToLock, bytesToWrite);
- }
- else
- {
- soundIsValid = false;
- }
- LARGE_INTEGER workCounter = Win32GetWallClock();
- float workSecondsElapsed = Win32GetSecondsElapsed(lastCounter, workCounter);
- float secondsElapedForFrame = workSecondsElapsed;
- if(secondsElapedForFrame < targetSecondsElapsedPerFrame)
- {
- if(sleepIsGranular)
- {
- DWORD sleepMS = (DWORD)(1000.0f * (targetSecondsElapsedPerFrame - secondsElapedForFrame));
- if(sleepMS > 0)
- {
- Sleep(sleepMS);
- }
- }
- if(secondsElapedForFrame < targetSecondsElapsedPerFrame)
- {
- //Log missed frame
- }
- while(secondsElapedForFrame < targetSecondsElapsedPerFrame)
- {
- secondsElapedForFrame = Win32GetSecondsElapsed(lastCounter, Win32GetWallClock());
- }
- }
- else
- {
- OutputDebugStringA("Missed a frame Rate!\n");
- }
- LARGE_INTEGER endCounter = Win32GetWallClock();
- float msPerFrame = 1000.0f*Win32GetSecondsElapsed(lastCounter, endCounter);
- lastCounter = endCounter;
- game_input *temp = newInput;
- newInput = oldInput;
- oldInput = temp;
- #if HANDMADE_INTERNAL
- //This is wrong on the 0 index
- Win32DebugSyncDisplay(&globalBackBuffer, arrayCount(debugTimeMarkers), debugTimeMarkers, debugTimeMarkerIndex - 1 ,&soundOutput, targetSecondsElapsedPerFrame);
- #endif
- win32_window_dimension windowSize = Win32GetWindowDimension(window);
- Win32DisplayBufferInWindow(deviceContext, windowSize.width, windowSize.height, globalBackBuffer);
- flipWallClock = Win32GetWallClock();
- #if HANDMADE_INTERNAL
- {
- DWORD markerPlayCursor;
- DWORD markerWriteCursor;
- if(globalSecondaryBuffer->GetCurrentPosition(&markerPlayCursor, &markerWriteCursor) == DS_OK)
- {
- Assert(debugTimeMarkerIndex < arrayCount(debugTimeMarkers))
- win32_debug_time_marker *marker = &debugTimeMarkers[debugTimeMarkerIndex];
- marker->flipPlayCursor = markerPlayCursor;
- marker->flipWriteCursor = markerWriteCursor;
- }
- }
- #endif
- uint64_t endCycleCount = __rdtsc();
- uint64_t cyclesElapsed = endCycleCount - lastCycleCount;
- lastCycleCount = endCycleCount;
- float fps = 0.0f;//(uint32_t)(globalPerfFrequency/counterElapsed);
- float MCPF = (float)(cyclesElapsed / (1000 * 1000));
- char statsBuffer[256];
- _snprintf_s(statsBuffer, sizeof(statsBuffer), "%.02fms/f, %.02f/s, %.02fmc/f\n", msPerFrame, fps, MCPF);
- OutputDebugStringA(statsBuffer);
- #if HANDMADE_INTERNAL
- ++debugTimeMarkerIndex;
- if(debugTimeMarkerIndex == arrayCount(debugTimeMarkers))
- {
- debugTimeMarkerIndex = 0;
- }
- #endif
- }
- }
- }
- }
- }
- return 0;
- }
Add Comment
Please, Sign In to add comment