Guest User

Untitled

a guest
Jun 9th, 2016
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 36.96 KB | None | 0 0
  1. #include "handmade.h"
  2. #include <stdio.h>
  3. #include <windows.h>
  4. #include <xinput.h>
  5. #include <dsound.h>
  6. #include "win32_handmade.h"
  7.  
  8.  
  9. static bool RUNNING;
  10. static bool globalPause;
  11. static win32_offscreen_buffer globalBackBuffer;
  12. static LPDIRECTSOUNDBUFFER globalSecondaryBuffer;
  13. static int64_t globalPerfFrequency;
  14.  
  15. //XInputGetState
  16. #define X_INPUT_GET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState)
  17. typedef X_INPUT_GET_STATE(x_input_get_state);
  18. X_INPUT_GET_STATE(XInputGetStateStub)
  19. {
  20.     return(ERROR_DEVICE_NOT_CONNECTED);
  21. }
  22. static x_input_get_state *XInputGetState_ = XInputGetStateStub;
  23. #define XInputGetState XInputGetState_
  24.  
  25. //XInputSetState
  26. #define X_INPUT_SET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration)
  27. typedef X_INPUT_SET_STATE(x_input_set_state);
  28. X_INPUT_SET_STATE(XInputSetStateStub)
  29. {
  30.     return(ERROR_DEVICE_NOT_CONNECTED);
  31. }
  32. static x_input_set_state *XInputSetState_ = XInputSetStateStub;
  33. #define XInputSetState XInputSetState_
  34.  
  35. #define DIRECT_SOUND_CREATE(name) HRESULT WINAPI name(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter)
  36. typedef DIRECT_SOUND_CREATE(direct_sound_create);
  37.  
  38. DEBUG_PLATFORM_FREE_FILE_MEMORY(DEBUGPlatformFreeFileMemory)
  39. {
  40.     if(memory)
  41.     {
  42.         VirtualFree(memory, 0, MEM_RELEASE);
  43.     }
  44. }
  45.  
  46. DEBUG_PLATFORM_READ_ENTIRE_FILE(DEBUGPlatformReadEntireFile)
  47. {
  48.     debug_read_file_result result = {};
  49.     HANDLE fileHandle = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
  50.     if(fileHandle != INVALID_HANDLE_VALUE)
  51.     {
  52.         LARGE_INTEGER fileSize;
  53.         if(GetFileSizeEx(fileHandle, &fileSize))
  54.         {
  55.             uint32_t fileSize32 = safeTruncateUint64(fileSize.QuadPart);
  56.             result.contents = VirtualAlloc(0, fileSize32, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
  57.             if(result.contents)
  58.             {
  59.                 DWORD bytesRead;
  60.                 if(ReadFile(fileHandle, result.contents, fileSize32, &bytesRead,0) && fileSize32 == bytesRead)
  61.                 {
  62.                     result.contentSize = bytesRead;
  63.                 }
  64.                 else
  65.                 {
  66.                     DEBUGPlatformFreeFileMemory(result.contents);
  67.                     result.contents = NULL;
  68.                 }
  69.             }
  70.         }
  71.         CloseHandle(fileHandle);
  72.     }
  73.     return result;
  74. }
  75.  
  76. DEBUG_PLATFORM_WRITE_ENTIRE_FILE(DEBUGPlatformWriteEntireFile)
  77. {
  78.     int result = false;
  79.     HANDLE fileHandle = CreateFileA(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
  80.     if (fileHandle != INVALID_HANDLE_VALUE)
  81.     {
  82.         DWORD bytesWritten;
  83.         if (WriteFile(fileHandle, memory, memorySize, &bytesWritten, 0))
  84.         {
  85.             result = (bytesWritten == memorySize);
  86.         }
  87.  
  88.         CloseHandle(fileHandle);
  89.     }
  90.     return result;
  91. }
  92.  
  93. struct win32_game_code
  94. {
  95.     HMODULE DLL;
  96.     FILETIME DLLLastWriteTime;
  97.     game_get_sound_samples *getSoundSamples;
  98.     game_update_and_render *updateAndRender;
  99.    
  100.     bool isValid;
  101. };
  102.  
  103. inline FILETIME Win32GetFileWriteTime(char * filename)
  104. {
  105.     FILETIME lastWriteTime = {};
  106.     WIN32_FIND_DATA findData;
  107.     HANDLE fileHandle = FindFirstFileA(filename, &findData);
  108.     if(fileHandle != INVALID_HANDLE_VALUE)
  109.     {
  110.         lastWriteTime = findData.ftLastWriteTime;
  111.         FindClose(fileHandle);
  112.     }
  113.    
  114.     return lastWriteTime;
  115. }
  116.  
  117. static win32_game_code Win32LoadGameCode(char *sourceDLLName, char * tempDLLName)
  118. {
  119.     win32_game_code gameCodeStruct = {};
  120.    
  121.     FILETIME latestDLLWriteTime = Win32GetFileWriteTime(sourceDLLName);
  122.     gameCodeStruct.DLLLastWriteTime = latestDLLWriteTime;
  123.     CopyFile(sourceDLLName, tempDLLName, FALSE);
  124.     gameCodeStruct.DLL = LoadLibrary(tempDLLName);
  125.     if(gameCodeStruct.DLL)
  126.     {
  127.         gameCodeStruct.updateAndRender = (game_update_and_render *)GetProcAddress(gameCodeStruct.DLL, "gameUpdateAndRender");
  128.         gameCodeStruct.getSoundSamples = (game_get_sound_samples *)GetProcAddress(gameCodeStruct.DLL, "gameGetSoundSamples");  
  129.    
  130.         gameCodeStruct.isValid = (gameCodeStruct.updateAndRender && gameCodeStruct.getSoundSamples);
  131.     }
  132.    
  133.     if(!gameCodeStruct.isValid)
  134.     {
  135.         gameCodeStruct.updateAndRender = gameUpdateAndRenderStub;
  136.         gameCodeStruct.getSoundSamples = gameGetSoundSamplesStub;
  137.     }
  138.    
  139.     return gameCodeStruct;
  140. }
  141.  
  142. static void Win32UnloadGameCode(win32_game_code *gameCode)
  143. {
  144.     if(gameCode->DLL)
  145.     {
  146.         FreeLibrary(gameCode->DLL);
  147.         gameCode->DLL = NULL;
  148.     }
  149.    
  150.     gameCode->isValid = false;
  151.     gameCode->updateAndRender = gameUpdateAndRenderStub;
  152.     gameCode->getSoundSamples = gameGetSoundSamplesStub;
  153.    
  154. }
  155.  
  156. static void Win32LoadXInput(void)
  157. {
  158.     HMODULE XInputLibrary = LoadLibrary("xinput1_4.dll");
  159.     if(!XInputLibrary)
  160.     {
  161.         XInputLibrary = LoadLibrary("xinput1_3.dll");
  162.     }
  163.    
  164.     if(!XInputLibrary)
  165.     {
  166.         XInputLibrary = LoadLibrary("xInput9_1_0.dll");
  167.     }
  168.  
  169.     if(XInputLibrary)
  170.     {
  171.         XInputGetState = (x_input_get_state *)GetProcAddress(XInputLibrary, "XInputGetState");
  172.         XInputSetState = (x_input_set_state *)GetProcAddress(XInputLibrary, "XInputSetState"); 
  173.     }  
  174. }
  175.  
  176. static void Win32InitDSound(HWND hWnd, uint32_t bufferSize, uint32_t samplesPerSecond)
  177. {
  178.     HMODULE dSoundLibrary = LoadLibrary("dsound.dll");
  179.     if(dSoundLibrary)
  180.     {
  181.         direct_sound_create * DirectSoundCreate = (direct_sound_create*)GetProcAddress(dSoundLibrary, "DirectSoundCreate");
  182.         LPDIRECTSOUND directSound;
  183.         if(DirectSoundCreate && SUCCEEDED(DirectSoundCreate(0, &directSound, 0)))
  184.         {
  185.             WAVEFORMATEX waveFormat = {};
  186.             waveFormat.wFormatTag = WAVE_FORMAT_PCM;
  187.             waveFormat.nChannels = 2;
  188.             waveFormat.wBitsPerSample = 16;
  189.             waveFormat.nSamplesPerSec = samplesPerSecond;
  190.             waveFormat.nBlockAlign = (waveFormat.nChannels*waveFormat.wBitsPerSample)/8;
  191.             waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
  192.             waveFormat.cbSize =0;
  193.                    
  194.             if(SUCCEEDED(directSound->SetCooperativeLevel(hWnd, DSSCL_PRIORITY)))
  195.             {
  196.                 DSBUFFERDESC bufferDescription = {};
  197.                 bufferDescription.dwSize = sizeof(bufferDescription);
  198.                 bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
  199.                
  200.                 LPDIRECTSOUNDBUFFER primaryBuffer;
  201.                 if(SUCCEEDED(directSound->CreateSoundBuffer(&bufferDescription, &primaryBuffer, 0)))
  202.                 {
  203.                     if(SUCCEEDED(primaryBuffer->SetFormat(&waveFormat)))
  204.                     {
  205.                        
  206.                     }
  207.                     else
  208.                     {
  209.                         //Diagnostic
  210.                     }
  211.                 }  
  212.             }
  213.             else
  214.             {
  215.                 //Diagnostic
  216.             }
  217.            
  218.             DSBUFFERDESC bufferDescription = {};
  219.             bufferDescription.dwSize = sizeof(bufferDescription);
  220.             bufferDescription.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
  221.             bufferDescription.lpwfxFormat = &waveFormat;
  222.             bufferDescription.dwBufferBytes = bufferSize;
  223.             if(SUCCEEDED(directSound->CreateSoundBuffer(&bufferDescription, &globalSecondaryBuffer, 0)))
  224.             {              
  225.             }
  226.         }
  227.         else
  228.         {
  229.             //Diagnostic
  230.         }
  231.     }
  232. }
  233.  
  234. static win32_window_dimension Win32GetWindowDimension(HWND window)
  235. {
  236.   win32_window_dimension result;
  237.  
  238.   RECT clientRect;
  239.   GetClientRect(window, &clientRect);
  240.   result.width = clientRect.right - clientRect.left;
  241.   result.height = clientRect.bottom - clientRect.top;
  242.  
  243.   return result;
  244. }
  245.  
  246. static void Win32ResizeDIBSection(win32_offscreen_buffer *buffer, int width, int height)
  247. {
  248.  
  249.   if(buffer->memory)
  250.   {
  251.     VirtualFree(buffer->memory, 0, MEM_RELEASE);
  252.   }
  253.  
  254.   int bytesPerPixel = 4;
  255.   buffer->bytesPerPixel = bytesPerPixel;
  256.  
  257.   buffer->width = width;
  258.   buffer->height = height;
  259.  
  260.   buffer->info.bmiHeader.biSize = sizeof(buffer->info.bmiHeader);
  261.   buffer->info.bmiHeader.biWidth = buffer->width;
  262.   buffer->info.bmiHeader.biHeight = -buffer->height;
  263.   buffer->info.bmiHeader.biPlanes = 1;
  264.   buffer->info.bmiHeader.biBitCount = 32;
  265.   buffer->info.bmiHeader.biCompression = BI_RGB;
  266.  
  267.   int bitmapMemorySize = bytesPerPixel * buffer->width * buffer->height;
  268.  
  269.   buffer->memory = VirtualAlloc(0, bitmapMemorySize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
  270.   buffer->pitch = buffer->width * bytesPerPixel;
  271. }
  272.  
  273. static void Win32DisplayBufferInWindow(HDC deviceContext, int windowWidth, int windowHeight, win32_offscreen_buffer buffer)
  274. {
  275.     StretchDIBits(deviceContext, 0, 0, windowWidth, windowHeight , 0, 0,  buffer.width, buffer.height, buffer.memory, &buffer.info, DIB_RGB_COLORS, SRCCOPY);
  276. }
  277.  
  278. static void Win32ClearBuffer(win32_sound_output * soundOutput)
  279. {
  280.     VOID *region1;
  281.     DWORD region1Size;
  282.     VOID *region2;
  283.     DWORD region2Size;
  284.     if(SUCCEEDED(globalSecondaryBuffer->Lock(0, soundOutput->secondaryBufferSize, &region1, &region1Size, &region2, &region2Size, 0)))
  285.     {
  286.         uint8_t *destSample = (uint8_t*)region1;
  287.         for(DWORD byteIndex = 0; byteIndex < region1Size; ++byteIndex)
  288.         {
  289.             *destSample++ = 0;
  290.         }
  291.        
  292.         destSample = (uint8_t*)region2;
  293.         for(DWORD byteIndex = 0; byteIndex < region2Size; ++byteIndex)
  294.         {
  295.             *destSample++ = 0;
  296.         }
  297.        
  298.         globalSecondaryBuffer->Unlock(region1, region1Size, region2, region2Size);
  299.     }
  300. }
  301.  
  302. static void Win32FillSoundBuffer(win32_sound_output * soundOutput, game_sound_output_buffer * sourceBuffer, DWORD byteToLock, DWORD bytesToWrite)
  303. {
  304.     VOID *region1;
  305.     DWORD region1Size;
  306.     VOID *region2;
  307.     DWORD region2Size;
  308.  
  309.     if(SUCCEEDED(globalSecondaryBuffer->Lock(byteToLock, bytesToWrite,&region1, &region1Size, &region2, &region2Size, 0)))
  310.     {
  311.         int16_t *destSample = (int16_t*)region1;
  312.         int16_t *sourceSample = sourceBuffer->samples;
  313.         DWORD region1SampleCount = region1Size/soundOutput->bytesPerSample;
  314.         for(DWORD sampleIndex = 0; sampleIndex < region1SampleCount; ++sampleIndex)
  315.         {
  316.             *destSample++ = *sourceSample++;
  317.             *destSample++ = *sourceSample++;
  318.             ++soundOutput->runningSampleIndex;
  319.         }
  320.    
  321.         destSample = (int16_t*)region2;
  322.         DWORD region2SampleCount = region2Size/soundOutput->bytesPerSample;
  323.         for(DWORD sampleIndex = 0; sampleIndex < region2SampleCount; ++sampleIndex)
  324.         {
  325.             *destSample++ = *sourceSample++;
  326.             *destSample++ = *sourceSample++;
  327.             ++soundOutput->runningSampleIndex;
  328.         }
  329.         globalSecondaryBuffer->Unlock(region1, region1Size, region2, region2Size);
  330.     }          
  331. }
  332.  
  333. static void Win32BeginRecordingInput(win32_state *win32State, int inputRecordingIndex)
  334. {
  335.     win32State->inputRecordingIndex = inputRecordingIndex;
  336.    
  337.     char * Filename = "foo.hmi";
  338.     win32State->recordingHandle = CreateFileA(Filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
  339.     DWORD bytesTowrite = (DWORD)win32State->totalSize;
  340.     Assert(win32State->totalSize == bytesTowrite);
  341.     DWORD bytesWritten;
  342.     WriteFile(win32State->recordingHandle, win32State->gameMemoryBlock, (DWORD)win32State->totalSize, &bytesWritten, 0);
  343.  
  344.     game_state *testState = (game_state*)win32State->gameMemoryBlock;
  345. }
  346.  
  347. static void Win32EndRecordingInput(win32_state *win32State)
  348. {
  349.     CloseHandle(win32State->recordingHandle);
  350.     win32State->inputRecordingIndex = 0;
  351. }
  352.  
  353. static void Win32BeginInputPlayback(win32_state *win32State, int inputPlayingIndex)
  354. {
  355.     win32State->inputPlayingIndex = inputPlayingIndex;
  356.    
  357.     char * Filename = "foo.hmi";
  358.     win32State->playbackHandle = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
  359.     DWORD bytesToRead = (DWORD)win32State->totalSize;
  360.     Assert(win32State->totalSize == bytesToRead);
  361.     DWORD bytesRead;
  362.     ReadFile(win32State->playbackHandle, win32State->gameMemoryBlock, bytesToRead, &bytesRead, 0);
  363.     game_state *testState = (game_state*)win32State->gameMemoryBlock;
  364. }
  365.  
  366. static void Win32EndInputPlayback(win32_state *win32State)
  367. {
  368.     CloseHandle(win32State->playbackHandle);
  369.     win32State->inputPlayingIndex = 0;
  370. }
  371.  
  372. static void Win32RecordInput(win32_state *win32State, game_input *newInput)
  373. {
  374.     DWORD bytesWritten = 0;
  375.     WriteFile(win32State->recordingHandle, newInput, sizeof(*newInput), &bytesWritten, 0);
  376. }
  377.  
  378. static void Win32PlayBackInput(win32_state *win32State, game_input *newInput)
  379. {
  380.     DWORD bytesRead = 0;
  381.     if(ReadFile(win32State->playbackHandle, newInput, sizeof(*newInput), &bytesRead, 0))
  382.     {
  383.         if(bytesRead == 0)
  384.         {
  385.             //No more input to read. Go back to beginning
  386.             int playingIndex = win32State->inputPlayingIndex;
  387.             Win32EndInputPlayback(win32State);
  388.             Win32BeginInputPlayback(win32State, playingIndex);
  389.             ReadFile(win32State->playbackHandle, newInput, sizeof(*newInput), &bytesRead, 0);
  390.         }
  391.     }
  392. }
  393.  
  394. static void Win32ProcessXInputDigitalButton(game_button_state *oldState, game_button_state *newState,
  395.                                                 DWORD xInputButtonState, DWORD buttonBit)
  396. {
  397.     newState->endedDown = ((xInputButtonState & buttonBit) == buttonBit);
  398.     newState->halfTransitionCount = (oldState->endedDown != newState->endedDown) ? 1 : 0;
  399. }
  400.  
  401. static void Win32ProcessKeyboardMessage(game_button_state *newState,
  402.                                                 int32_t isDown)
  403. {
  404.     Assert(newState->endedDown != isDown);
  405.     newState->endedDown = isDown;
  406.     ++newState->halfTransitionCount;
  407. }
  408.  
  409. static float Win32ProcessXInputStickPosition(SHORT thumbValue, SHORT deadZoneThreshold)
  410. {
  411.     float returnValue = 0.0f;
  412.     if(thumbValue < -deadZoneThreshold)
  413.     {
  414.         returnValue = (float)(thumbValue + deadZoneThreshold)/ (32768.0f - deadZoneThreshold);
  415.     }
  416.     else if(thumbValue > deadZoneThreshold)
  417.     {
  418.         returnValue = (float)(thumbValue - deadZoneThreshold) / (32767.0f - deadZoneThreshold);
  419.     }
  420.     return returnValue;
  421. }
  422.  
  423. static void Win32ProcessPendingMessages(win32_state *win32State, game_controller_input *keyboardController)
  424. {
  425.     MSG message;
  426.     while(PeekMessage(&message, 0, 0, 0, PM_REMOVE))
  427.     {
  428.         switch (message.message)
  429.         {
  430.             case WM_QUIT:
  431.             {
  432.                 RUNNING = false;
  433.             }break;
  434.             case WM_SYSKEYDOWN:
  435.             case WM_SYSKEYUP:
  436.             case WM_KEYDOWN:
  437.             case WM_KEYUP:
  438.             {
  439.                 uint32_t vkCode = (uint32_t)message.wParam;
  440.                 bool wasDown = ((message.lParam & (1 << 30)) != 0);
  441.                 bool isDown = ((message.lParam & (1 << 31)) == 0);
  442.  
  443.                 if (wasDown != isDown)
  444.                 {
  445.                     if (vkCode == 'Q')
  446.                     {
  447.                         Win32ProcessKeyboardMessage(&keyboardController->leftShoulder, isDown);
  448.                     }
  449.                     else if (vkCode == 'E')
  450.                     {
  451.                         Win32ProcessKeyboardMessage(&keyboardController->rightShoulder, isDown);
  452.                     }
  453.                     else if (vkCode == 'W')
  454.                     {
  455.                         Win32ProcessKeyboardMessage(&keyboardController->moveUp, isDown);  
  456.                     }
  457.                     else if (vkCode == 'S')
  458.                     {
  459.                         Win32ProcessKeyboardMessage(&keyboardController->moveDown, isDown);
  460.                     }
  461.                     else if (vkCode == 'A')
  462.                     {
  463.                         Win32ProcessKeyboardMessage(&keyboardController->moveLeft, isDown);
  464.                     }
  465.                     else if (vkCode == 'D')
  466.                     {
  467.                         Win32ProcessKeyboardMessage(&keyboardController->moveRight, isDown);
  468.                     }
  469.                     else if (vkCode == VK_UP)
  470.                     {
  471.                         Win32ProcessKeyboardMessage(&keyboardController->actionUp, isDown);
  472.                     }
  473.                     else if (vkCode == VK_DOWN)
  474.                     {
  475.                         Win32ProcessKeyboardMessage(&keyboardController->actionDown, isDown);
  476.                     }
  477.                     else if (vkCode == VK_LEFT)
  478.                     {
  479.                         Win32ProcessKeyboardMessage(&keyboardController->actionLeft, isDown);
  480.                     }
  481.                     else if (vkCode == VK_RIGHT)
  482.                     {
  483.                         Win32ProcessKeyboardMessage(&keyboardController->actionRight, isDown);
  484.                     }
  485.                     else if (vkCode == VK_ESCAPE)
  486.                     {
  487.                         Win32ProcessKeyboardMessage(&keyboardController->start, isDown);
  488.                     }
  489.                     else if (vkCode == VK_SPACE)
  490.                     {
  491.                         Win32ProcessKeyboardMessage(&keyboardController->back, isDown);
  492.                     }
  493. #if HANDMADE_INTERNAL
  494.                     else if (vkCode == 'P' && isDown)
  495.                     {
  496.                         globalPause = !globalPause;
  497.                     }
  498.                     else if(vkCode == 'L')
  499.                     {
  500.                         if(isDown)
  501.                         {
  502.                             if(win32State->inputRecordingIndex == 0)
  503.                             {
  504.                                 game_state *testState = (game_state*)win32State->gameMemoryBlock;
  505.                                 Win32BeginRecordingInput(win32State, 1);
  506.                             }
  507.                             else
  508.                             {
  509.                                 Win32EndRecordingInput(win32State);
  510.                                 Win32BeginInputPlayback(win32State, 1);
  511.                             }
  512.                         }
  513.                     }
  514. #endif
  515.                 }
  516.                 bool altKeyDown = ((message.lParam & (1 << 29)) != 0);
  517.                 if ((vkCode == VK_F4) && altKeyDown)
  518.                 {
  519.  
  520.                 }
  521.             }break;
  522.            
  523.             default:
  524.             {
  525.                 TranslateMessage(&message);
  526.                 DispatchMessage(&message);
  527.             }break;
  528.         }
  529.     }
  530. }
  531.  
  532. static LRESULT CALLBACK Win32WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  533. {
  534.   LRESULT result = 0;
  535.  
  536.   switch(uMsg)
  537.   {
  538.     case WM_DESTROY:
  539.     {
  540.       RUNNING = false;
  541.     } break;
  542.    
  543.     case WM_CLOSE:
  544.     {
  545.       RUNNING = false;
  546.     } break;
  547.    
  548.     case WM_ACTIVATEAPP:
  549.     {
  550.       OutputDebugStringA("WM_ACTIVATEAPP\n");
  551.     } break;
  552.  
  553.     case WM_SYSKEYDOWN:
  554.     case WM_SYSKEYUP:
  555.     case WM_KEYDOWN:
  556.     case WM_KEYUP:
  557.     {
  558.         Assert(!"Keyboard input came throught a non-dispatched message!");
  559.     }break;
  560.    
  561.     case WM_PAINT:
  562.     {
  563.       PAINTSTRUCT paint;
  564.       HDC deviceContext = BeginPaint(hWnd, &paint);
  565.       win32_window_dimension windowSize = Win32GetWindowDimension(hWnd);
  566.       Win32DisplayBufferInWindow(deviceContext, windowSize.width, windowSize.height, globalBackBuffer);
  567.       EndPaint(hWnd,&paint);
  568.     } break;
  569.    
  570.     default:
  571.     {
  572.       result = DefWindowProc(hWnd, uMsg, wParam, lParam);
  573.     } break;
  574.   }
  575.  
  576.   return result;
  577. }
  578.  
  579. inline LARGE_INTEGER Win32GetWallClock(void)
  580. {
  581.     LARGE_INTEGER returnInteger;
  582.     QueryPerformanceCounter(&returnInteger);
  583.     return returnInteger;
  584. }
  585.  
  586. inline float Win32GetSecondsElapsed(LARGE_INTEGER start, LARGE_INTEGER end)
  587. {
  588.     float secondsElapsedForWork = (float)(end.QuadPart - start.QuadPart)/(float)globalPerfFrequency;
  589.     return secondsElapsedForWork;
  590. }
  591.  
  592. static void Win32DebugDrawVertical(win32_offscreen_buffer *backBuffer, int x, int top, int bottom, uint32_t color)
  593. {
  594.     if(top <= 0)
  595.     {
  596.         top = 0;
  597.     }
  598.    
  599.     if(bottom > backBuffer->height)
  600.     {
  601.         bottom = backBuffer->height;
  602.     }
  603.    
  604.     if((x >= 0) && (x < backBuffer->width))
  605.     {
  606.         uint8_t * drawPixel =(uint8_t*)backBuffer->memory + x*backBuffer->bytesPerPixel + top *backBuffer->pitch;
  607.         for(int y = top; y < bottom; ++y)
  608.         {
  609.             *(uint32_t *)drawPixel = color;
  610.             drawPixel += backBuffer->pitch;
  611.         }
  612.     }
  613. }
  614.  
  615. static void Win32DrawSoundBufferMarker(win32_offscreen_buffer *backBuffer, win32_sound_output *soundOutput, float c, int padX, int top, int bottom, DWORD value, DWORD color)
  616. {
  617.     int x = padX + (int)(c * (float)value);
  618.     Win32DebugDrawVertical(backBuffer, x, top, bottom, color); 
  619. }
  620.  
  621. static void Win32DebugSyncDisplay(win32_offscreen_buffer *backBuffer, DWORD markerCount, win32_debug_time_marker * markers, DWORD currentMarkerIndex, win32_sound_output *soundOutput, float secondsPerFrame)
  622. {
  623.     int padX = 16;
  624.     int padY = 16;
  625.    
  626.     int lineHeight = 64;
  627.    
  628.     float c = (((float)backBuffer->width - (2*padX))/(float)soundOutput->secondaryBufferSize);
  629.     for(DWORD markerIndex = 0; markerIndex < markerCount ;  ++markerIndex)
  630.     {
  631.         win32_debug_time_marker *thisMarker = &markers[markerIndex];
  632.         Assert(thisMarker->outputPlayCursor < soundOutput->secondaryBufferSize);
  633.         Assert(thisMarker->outputWriteCursor < soundOutput->secondaryBufferSize);
  634.         Assert(thisMarker->outputLocation < soundOutput->secondaryBufferSize);
  635.         Assert(thisMarker->outputByteCount < soundOutput->secondaryBufferSize);
  636.         Assert(thisMarker->flipPlayCursor < soundOutput->secondaryBufferSize);
  637.         Assert(thisMarker->flipWriteCursor < soundOutput->secondaryBufferSize);    
  638.        
  639.         DWORD playColor = 0xFFFFFFFF;
  640.         DWORD writeColor = 0xFFFF0000;
  641.         DWORD expectedFlipColor = 0xFFFFFF00;
  642.         DWORD playWindowColor = 0xFFFF00FF;
  643.        
  644.         int top = padY;
  645.         int bottom = lineHeight + padY;
  646.         if(markerIndex == currentMarkerIndex)
  647.         {
  648.             top += lineHeight + padY;
  649.             bottom += lineHeight + padY;
  650.            
  651.             int firstTop = top;
  652.            
  653.             Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->outputPlayCursor, playColor);
  654.             Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->outputWriteCursor, writeColor);
  655.            
  656.             top += lineHeight + padY;
  657.             bottom += lineHeight + padY;
  658.  
  659.             Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->outputLocation, playColor);
  660.             Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->outputLocation + thisMarker->outputByteCount, writeColor);
  661.  
  662.             top += lineHeight + padY;
  663.             bottom += lineHeight + padY;
  664.            
  665.             Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, firstTop, bottom, thisMarker->expectedFlipPlayCursor, expectedFlipColor);
  666.         }
  667.         Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->flipPlayCursor, playColor);
  668.         Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, (thisMarker->flipPlayCursor + 480*soundOutput->bytesPerSample), playWindowColor);
  669.         Win32DrawSoundBufferMarker(backBuffer, soundOutput, c, padX, top, bottom, thisMarker->flipWriteCursor, writeColor);
  670.     }
  671. }
  672.  
  673. static void catStrings(size_t sourceACount, char *sourceA, size_t sourceBCount,char *sourceB, size_t destCount, char *dest)
  674. {
  675.     for(int index = 0; index < sourceACount; ++index)
  676.     {
  677.         *dest++ = *sourceA++;
  678.     }
  679.  
  680.     for(int index = 0; index < sourceBCount; ++index)
  681.     {
  682.         *dest++ = *sourceB++;
  683.     }
  684.    
  685.     *dest++ = 0;
  686. }
  687.  
  688. int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  689. {
  690.     win32_state win32State = {};
  691.     char exeFilename[MAX_PATH];
  692.     DWORD sizeOfFilename = GetModuleFileName(0, exeFilename, sizeof(exeFilename));
  693.     char * onePastLastSlash = exeFilename;
  694.     for(char * scan = exeFilename; *scan; ++scan)
  695.     {
  696.         if(*scan == '\\')
  697.         {
  698.             onePastLastSlash = scan + 1;
  699.         }
  700.     }
  701.    
  702.     char sourceGameCodeName[] = "handmade.dll";
  703.     char sourceGameCodefullPath[MAX_PATH];
  704.     catStrings(onePastLastSlash - exeFilename, exeFilename,
  705.                 sizeof(sourceGameCodeName) - 1, sourceGameCodeName,
  706.                 sizeof(sourceGameCodefullPath), sourceGameCodefullPath);
  707.    
  708.     char tempGameCodeName[] = "working_handmade.dll";
  709.     char tempGameCodeFullPath[MAX_PATH];
  710.         catStrings(onePastLastSlash - exeFilename, exeFilename,
  711.                 sizeof(tempGameCodeName) - 1, tempGameCodeName,
  712.                 sizeof(tempGameCodeFullPath), tempGameCodeFullPath);
  713.    
  714.     LARGE_INTEGER perfFrequencyResult;
  715.     QueryPerformanceFrequency(&perfFrequencyResult);
  716.     globalPerfFrequency = perfFrequencyResult.QuadPart;
  717.    
  718.     //Set the scheduler granularity to 1ms, so that sleep can be more granular
  719.     UINT desiredSchedulerMS = 1;
  720.     int sleepIsGranular = (timeBeginPeriod(desiredSchedulerMS) == TIMERR_NOERROR);
  721.    
  722.     Win32LoadXInput();
  723.    
  724.     WNDCLASS windowClass = {};
  725.  
  726.     Win32ResizeDIBSection(&globalBackBuffer, 1280, 720);
  727.  
  728.     windowClass.style = CS_OWNDC|CS_HREDRAW;
  729.     windowClass.lpfnWndProc = Win32WindowProc;
  730.     windowClass.hInstance = hInstance;
  731.     //windowClass.hIcon = ;
  732.     windowClass.lpszClassName = "HandmadeHeroWindowClass";
  733.    
  734.     #define monitorRefreshHz  60
  735.     #define gameUpdateHz  (monitorRefreshHz / 2)
  736.     float targetSecondsElapsedPerFrame = 1.0f/(float)gameUpdateHz;
  737.  
  738.     if(RegisterClass(&windowClass))
  739.     {
  740.         HWND window = CreateWindowEx(0,windowClass.lpszClassName, "Handmade Hero", WS_OVERLAPPEDWINDOW|WS_VISIBLE,CW_USEDEFAULT,
  741.                           CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance,0);
  742.         if(window)
  743.         {
  744.             HDC deviceContext = GetDC(window);
  745.            
  746.             win32_sound_output soundOutput = {};
  747.             soundOutput.samplesPerSecond = 48000;
  748.             soundOutput.bytesPerSample = sizeof(uint16_t) * 2;
  749.             soundOutput.secondaryBufferSize = soundOutput.samplesPerSecond * soundOutput.bytesPerSample;
  750.             soundOutput.latencySampleCount = 3 * (soundOutput.samplesPerSecond / gameUpdateHz);
  751.             soundOutput.safetyBytes = (soundOutput.samplesPerSecond * soundOutput.bytesPerSample / gameUpdateHz) / 3 ;
  752.            
  753.             Win32InitDSound(window, soundOutput.secondaryBufferSize, soundOutput.samplesPerSecond);
  754.             Win32ClearBuffer(&soundOutput);
  755.             globalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
  756.            
  757.             int16_t * samples = (int16_t *)VirtualAlloc(0, 48000*2*sizeof(uint16_t), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
  758.  
  759.    
  760. #if HANDMADE_INTERNAL
  761.     LPVOID baseAddress = (LPVOID)teraBytes(2);
  762. #else
  763.     LPVOID baseAddress = 0;
  764. #endif
  765.             game_memory gameMemory = {};
  766.             gameMemory.permanantStorageSize = megaBytes(64);
  767.             gameMemory.transientStorageSize = gigaBytes(1);
  768.             gameMemory.DEBUGPlatformReadEntireFile = DEBUGPlatformReadEntireFile;
  769.             gameMemory.DEBUGPlatformWriteEntireFile = DEBUGPlatformWriteEntireFile;
  770.             gameMemory.DEBUGPlatformFreeFileMemory = DEBUGPlatformFreeFileMemory;
  771.            
  772.             win32State.totalSize = gameMemory.permanantStorageSize + gameMemory.transientStorageSize;
  773.             win32State.gameMemoryBlock = VirtualAlloc(baseAddress,(size_t)win32State.totalSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
  774.             gameMemory.permanantStorage = win32State.gameMemoryBlock;
  775.             gameMemory.transientStorage = (uint8_t*)gameMemory.permanantStorage + gameMemory.permanantStorageSize;
  776.            
  777.             if(samples && gameMemory.permanantStorage && gameMemory.transientStorage)
  778.             {
  779.                 RUNNING = true;
  780.                
  781.                 game_input input[2] = {};
  782.                 game_input *newInput = &input[0];
  783.                 game_input *oldInput = &input[1];
  784.                
  785.                 LARGE_INTEGER lastCounter = Win32GetWallClock();
  786.                 LARGE_INTEGER flipWallClock = Win32GetWallClock();
  787.                
  788.                 int32_t soundIsValid = false;
  789.                 DWORD audioLatencyBytes = 0;
  790.                 float audioLatencySeconds = 0;
  791.                
  792. #if HANDMADE_INTERNAL
  793.                 int debugTimeMarkerIndex = 0;
  794.                 win32_debug_time_marker debugTimeMarkers[gameUpdateHz / 2] = {};
  795. #endif         
  796.                 win32_game_code game = Win32LoadGameCode(sourceGameCodefullPath, tempGameCodeFullPath);
  797.                 uint32_t loadCounter = 0;
  798.                
  799.                 int64_t lastCycleCount = __rdtsc();
  800.  
  801.                 while(RUNNING)
  802.                 {
  803.                     FILETIME newDLLWriteTime = Win32GetFileWriteTime(sourceGameCodefullPath);
  804.                     if(CompareFileTime(&newDLLWriteTime, &game.DLLLastWriteTime) != 0)
  805.                     {
  806.                         Win32UnloadGameCode(&game);
  807.                         game = Win32LoadGameCode(sourceGameCodefullPath, tempGameCodeFullPath);
  808.                     }
  809.                     game_controller_input *oldKeyboardController = getController(oldInput, 0);
  810.                     game_controller_input *newKeyboardController = getController(newInput, 0);
  811.                     *newKeyboardController = {};
  812.                     newKeyboardController->isConnected = true;
  813.                     for(int buttonIndex = 0; buttonIndex < arrayCount(oldKeyboardController->buttons); ++buttonIndex)
  814.                     {
  815.                         newKeyboardController->buttons[buttonIndex].endedDown = oldKeyboardController->buttons[buttonIndex].endedDown;
  816.                     }
  817.                    
  818.                     Win32ProcessPendingMessages(&win32State, newKeyboardController);
  819.  
  820.                     if(!globalPause)
  821.                     {
  822.                         DWORD maxControllerCount = XUSER_MAX_COUNT;
  823.                         if(maxControllerCount > (arrayCount(newInput->controllers) - 1))
  824.                         {
  825.                             maxControllerCount = (arrayCount(newInput->controllers) - 1);  
  826.                         }
  827.                        
  828.                         for(DWORD controllerIndex = 0; controllerIndex < maxControllerCount; ++controllerIndex)
  829.                         {
  830.                             int ourControllerIndex = controllerIndex + 1;
  831.                             game_controller_input *oldController = getController(oldInput, ourControllerIndex);
  832.                             game_controller_input *newController = getController(newInput, ourControllerIndex);
  833.                            
  834.                             XINPUT_STATE controllerState;
  835.                             if(XInputGetState(controllerIndex, &controllerState) == ERROR_SUCCESS)
  836.                             {
  837.                                 newController->isConnected = true;
  838.                                 XINPUT_GAMEPAD *pad = &controllerState.Gamepad;    
  839.                                
  840.                                 newController->stickAverageX = Win32ProcessXInputStickPosition(pad->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
  841.                                 newController->stickAverageY = Win32ProcessXInputStickPosition(pad->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
  842.                                
  843.                                 // if(newController->stickAverageX != 0.0f || newController->stickAverageY != 0.0f )
  844.                                 // {
  845.                                     newController->isAnalog = true;
  846.                                 // }
  847.                                
  848.                                 if(pad->wButtons & XINPUT_GAMEPAD_DPAD_UP)
  849.                                 {
  850.                                     newController->stickAverageY = 1.0f;
  851.                                     newController->isAnalog = false;
  852.                                 }
  853.                                 if(pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
  854.                                 {
  855.                                     newController->isAnalog = false;
  856.                                 }
  857.                                 if(pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
  858.                                 {
  859.                                     newController->isAnalog = false;
  860.                                 }
  861.                                 if(pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
  862.                                 {
  863.                                     newController->isAnalog = false;
  864.                                 }
  865.                            
  866.                                 float threshhold = 0.5f;
  867.                                 Win32ProcessXInputDigitalButton(&oldController->moveLeft, &newController->moveLeft, (newController->stickAverageX < -threshhold) ? 1: 0, 1);
  868.                                 Win32ProcessXInputDigitalButton(&oldController->moveRight, &newController->moveRight, (newController->stickAverageX < threshhold) ? 1: 0, 1);
  869.                                 Win32ProcessXInputDigitalButton(&oldController->moveDown, &newController->moveDown, (newController->stickAverageY < -threshhold) ? 1: 0, 1);
  870.                                 Win32ProcessXInputDigitalButton(&oldController->moveUp, &newController->moveUp, (newController->stickAverageY < threshhold) ? 1: 0, 1);
  871.                                
  872.                                 Win32ProcessXInputDigitalButton(&oldController->leftShoulder, &newController->leftShoulder, pad->wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER);
  873.                                 Win32ProcessXInputDigitalButton(&oldController->rightShoulder, &newController->rightShoulder, pad->wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER);
  874.                                 Win32ProcessXInputDigitalButton(&oldController->actionDown, &newController->actionDown, pad->wButtons, XINPUT_GAMEPAD_A);
  875.                                 Win32ProcessXInputDigitalButton(&oldController->actionRight, &newController->actionRight, pad->wButtons, XINPUT_GAMEPAD_B);
  876.                                 Win32ProcessXInputDigitalButton(&oldController->actionLeft, &newController->actionLeft, pad->wButtons, XINPUT_GAMEPAD_X);
  877.                                 Win32ProcessXInputDigitalButton(&oldController->actionUp, &newController->actionUp, pad->wButtons, XINPUT_GAMEPAD_Y);                      
  878.                                 Win32ProcessXInputDigitalButton(&oldController->back, &newController->back, pad->wButtons, XINPUT_GAMEPAD_BACK);
  879.                                 Win32ProcessXInputDigitalButton(&oldController->start, &newController->start, pad->wButtons, XINPUT_GAMEPAD_START);
  880.                             }
  881.                             else
  882.                             {
  883.                                 //Controller not available
  884.                                 newController->isConnected = false;
  885.                             }
  886.                    
  887.                         }
  888.                         game_offscreen_buffer buffer;
  889.                         buffer.memory = globalBackBuffer.memory;
  890.                         buffer.width = globalBackBuffer.width;
  891.                         buffer.height = globalBackBuffer.height;
  892.                         buffer.pitch = globalBackBuffer.pitch;
  893.                         buffer.bytesPerPixel = globalBackBuffer.bytesPerPixel;
  894.                        
  895.                         if(win32State.inputRecordingIndex)
  896.                         {
  897.                             Win32RecordInput(&win32State, newInput);
  898.                         }
  899.                        
  900.                         if(win32State.inputPlayingIndex)
  901.                         {
  902.                             Win32PlayBackInput(&win32State, newInput);
  903.                         }
  904.                        
  905.                         //Where the game actually updates
  906.                         game.updateAndRender(&gameMemory, &buffer, newInput);
  907.                        
  908.                         LARGE_INTEGER audioWallClock = Win32GetWallClock();
  909.                         float fromBeginToAudioInSeconds = Win32GetSecondsElapsed(flipWallClock, audioWallClock);
  910.                        
  911.                         DWORD playCursor;
  912.                         DWORD writeCursor;
  913.                         if(globalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor) == DS_OK)
  914.                         {
  915.                             /*
  916.                                 How sound output computation works.
  917.                                
  918.                                 We define a safety value that is the number of samples we thing our game update loop may vary
  919.                                 by (let's say by up to 2ms).
  920.                                
  921.                                 When we wake up to write audio, we will look and see what the play cursor position is and we
  922.                                 will forecast ahead where we think the play cursor will be on the next frame boundary.
  923.                                
  924.                                 We will then look to see if the write cursor is at least  before that safety value. If it is,
  925.                                 the target fill position is that frame boundary plus one frame. This gives us perfect audio sync
  926.                                 in the case of a card that has low enough latency.
  927.                                
  928.                                 If the write cursor is after that safety margin, then we assume we can never sync the
  929.                                 audio perfectly, so we will write one frame's worth of audio plus the safetys number of
  930.                                 guard samples.
  931.                             */
  932.                            
  933.                             if(!soundIsValid)
  934.                             {
  935.                                 soundOutput.runningSampleIndex = writeCursor / soundOutput.bytesPerSample;
  936.                                 soundIsValid = true;
  937.                             }
  938.                            
  939.                             DWORD byteToLock = (soundOutput.runningSampleIndex * soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize;
  940.                            
  941.                             DWORD expectedSoundBytesPerFrame =  (soundOutput.samplesPerSecond * soundOutput.bytesPerSample) / gameUpdateHz;
  942.                             float secondsLeftUntilFlip = (targetSecondsElapsedPerFrame - fromBeginToAudioInSeconds);
  943.                             DWORD expectedSoundBytesUntilFlip = (DWORD)((secondsLeftUntilFlip/(float)targetSecondsElapsedPerFrame) * (float)expectedSoundBytesPerFrame);
  944.                             DWORD expectedFrameBoundaryByte = playCursor + expectedSoundBytesPerFrame;
  945.                            
  946.                             DWORD safeWriteCursor = writeCursor;
  947.                             if(safeWriteCursor < playCursor)
  948.                             {
  949.                                 safeWriteCursor += soundOutput.secondaryBufferSize;
  950.                             }
  951.                             Assert(safeWriteCursor >= playCursor);
  952.                             safeWriteCursor += soundOutput.safetyBytes;
  953.                             int audioCardIsLowLatentcy = (safeWriteCursor < expectedFrameBoundaryByte);
  954.                            
  955.                             DWORD targetCursor = 0;
  956.                             if(audioCardIsLowLatentcy)
  957.                             {
  958.                                 targetCursor = expectedFrameBoundaryByte + expectedSoundBytesPerFrame;
  959.                             }
  960.                             else
  961.                             {
  962.                                 targetCursor = writeCursor + expectedSoundBytesPerFrame +
  963.                                                 soundOutput.safetyBytes;
  964.                             }
  965.                             targetCursor = targetCursor % soundOutput.secondaryBufferSize;
  966.  
  967.                             DWORD bytesToWrite = 0;
  968.                             if(byteToLock > targetCursor)
  969.                             {
  970.                                 bytesToWrite = soundOutput.secondaryBufferSize - byteToLock;
  971.                                 bytesToWrite += targetCursor;
  972.                             }
  973.                             else
  974.                             {
  975.                                 bytesToWrite = targetCursor - byteToLock;
  976.                             }
  977.                            
  978.                             game_sound_output_buffer soundBuffer = {};
  979.                             soundBuffer.samplesPerSecond = soundOutput.samplesPerSecond;
  980.                             soundBuffer.sampleCount = bytesToWrite/soundOutput.bytesPerSample;
  981.                             soundBuffer.samples = samples;
  982.                             game.getSoundSamples(&gameMemory, &soundBuffer);
  983.     #if HANDMADE_INTERNAL  
  984.                             win32_debug_time_marker *marker = &debugTimeMarkers[debugTimeMarkerIndex];
  985.                             marker->outputPlayCursor  = playCursor;
  986.                             marker->outputWriteCursor = writeCursor;
  987.                             marker->outputLocation = byteToLock;
  988.                             marker->outputByteCount = bytesToWrite;
  989.                             marker->expectedFlipPlayCursor = expectedFrameBoundaryByte;
  990.                            
  991.                             DWORD unwrappedWriteCursor = writeCursor;
  992.                             if(unwrappedWriteCursor < playCursor)
  993.                             {
  994.                                 unwrappedWriteCursor += soundOutput.secondaryBufferSize;
  995.                             }
  996.                             audioLatencyBytes = unwrappedWriteCursor - playCursor;
  997.                             audioLatencySeconds = (((float)audioLatencyBytes / (float)soundOutput.bytesPerSample)/
  998.                                                         (float)soundOutput.samplesPerSecond);
  999.                            
  1000.                             char textBuffer[256];
  1001.                             _snprintf_s(textBuffer, sizeof(textBuffer), "BTL:%u TC:%u BTW:%u - PC:%u WC:%u Delta:%u (%fs)\n",
  1002.                                         byteToLock, targetCursor, bytesToWrite, playCursor,
  1003.                                         writeCursor, audioLatencyBytes, audioLatencySeconds);
  1004.                             OutputDebugStringA(textBuffer);
  1005.     #endif
  1006.                             Win32FillSoundBuffer(&soundOutput, &soundBuffer, byteToLock, bytesToWrite);
  1007.                         }
  1008.                         else
  1009.                         {
  1010.                             soundIsValid = false;
  1011.                         }
  1012.                        
  1013.                         LARGE_INTEGER workCounter = Win32GetWallClock();
  1014.                         float workSecondsElapsed = Win32GetSecondsElapsed(lastCounter, workCounter);
  1015.                        
  1016.                         float secondsElapedForFrame = workSecondsElapsed;
  1017.                         if(secondsElapedForFrame < targetSecondsElapsedPerFrame)
  1018.                         {
  1019.                             if(sleepIsGranular)
  1020.                             {
  1021.                                 DWORD sleepMS = (DWORD)(1000.0f * (targetSecondsElapsedPerFrame - secondsElapedForFrame));
  1022.                                 if(sleepMS > 0)
  1023.                                 {
  1024.                                     Sleep(sleepMS);
  1025.                                 }
  1026.                             }
  1027.                            
  1028.                             if(secondsElapedForFrame < targetSecondsElapsedPerFrame)
  1029.                             {
  1030.                                 //Log missed frame
  1031.                             }
  1032.                            
  1033.                             while(secondsElapedForFrame < targetSecondsElapsedPerFrame)
  1034.                             {
  1035.                                 secondsElapedForFrame = Win32GetSecondsElapsed(lastCounter, Win32GetWallClock());
  1036.                             }
  1037.                         }
  1038.                         else
  1039.                         {
  1040.                             OutputDebugStringA("Missed a frame Rate!\n");
  1041.                         }
  1042.                        
  1043.                         LARGE_INTEGER endCounter = Win32GetWallClock();
  1044.                         float msPerFrame = 1000.0f*Win32GetSecondsElapsed(lastCounter, endCounter);
  1045.                         lastCounter = endCounter;
  1046.  
  1047.                         game_input *temp = newInput;
  1048.                         newInput = oldInput;
  1049.                         oldInput = temp;
  1050.                        
  1051.     #if HANDMADE_INTERNAL
  1052.         //This is wrong on the 0 index
  1053.         Win32DebugSyncDisplay(&globalBackBuffer, arrayCount(debugTimeMarkers), debugTimeMarkers, debugTimeMarkerIndex - 1 ,&soundOutput, targetSecondsElapsedPerFrame);
  1054.     #endif 
  1055.                         win32_window_dimension windowSize = Win32GetWindowDimension(window);
  1056.                         Win32DisplayBufferInWindow(deviceContext, windowSize.width, windowSize.height, globalBackBuffer);
  1057.  
  1058.                         flipWallClock = Win32GetWallClock();
  1059.     #if HANDMADE_INTERNAL
  1060.         {
  1061.             DWORD markerPlayCursor;
  1062.             DWORD markerWriteCursor;
  1063.             if(globalSecondaryBuffer->GetCurrentPosition(&markerPlayCursor, &markerWriteCursor) == DS_OK)
  1064.             {
  1065.                 Assert(debugTimeMarkerIndex < arrayCount(debugTimeMarkers))
  1066.                 win32_debug_time_marker *marker = &debugTimeMarkers[debugTimeMarkerIndex];
  1067.                 marker->flipPlayCursor = markerPlayCursor;
  1068.                 marker->flipWriteCursor = markerWriteCursor;
  1069.             }
  1070.         }
  1071.        
  1072.     #endif
  1073.                        
  1074.                         uint64_t endCycleCount = __rdtsc();
  1075.                         uint64_t cyclesElapsed = endCycleCount - lastCycleCount;
  1076.                         lastCycleCount = endCycleCount;
  1077.                        
  1078.                         float fps = 0.0f;//(uint32_t)(globalPerfFrequency/counterElapsed);
  1079.                         float MCPF = (float)(cyclesElapsed / (1000 * 1000));
  1080.                        
  1081.                         char statsBuffer[256];
  1082.                         _snprintf_s(statsBuffer, sizeof(statsBuffer), "%.02fms/f, %.02f/s, %.02fmc/f\n", msPerFrame, fps, MCPF);
  1083.                         OutputDebugStringA(statsBuffer);
  1084.     #if HANDMADE_INTERNAL
  1085.                         ++debugTimeMarkerIndex;
  1086.                         if(debugTimeMarkerIndex == arrayCount(debugTimeMarkers))
  1087.                         {
  1088.                             debugTimeMarkerIndex = 0;
  1089.                         }
  1090. #endif
  1091.                     }
  1092.                 }
  1093.             }
  1094.         }                        
  1095.     }
  1096.  
  1097.     return 0;
  1098. }
Add Comment
Please, Sign In to add comment