LRESULT CALLBACK Win32WindowProc(HWND Window, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT Result = 0; switch (uMsg) { case WM_CLOSE: { g_running = false; } break; case WM_PAINT: { PAINTSTRUCT Paint = {}; HDC hdc = BeginPaint(Window, &Paint); Win32UpdateWindow(hdc); EndPaint(Window, &Paint); } break; case WM_SYSKEYDOWN: case WM_SYSKEYUP: case WM_KEYDOWN: case WM_KEYUP: { assert(!"Keyboard input came in through a non-dispatch message!"); } break; default: { Result = DefWindowProc(Window, uMsg, wParam, lParam); } break; } return Result; }
LRESULT CALLBACK Win32MainWindowCallback( HWND Window, UINT Message, WPARAM WParam, LPARAM LParam) { LRESULT Result = 0; switch(Message) { case WM_SIZE: { RECT ClientRect; GetClientRect(Window, &ClientRect); int Width = ClientRect.right - ClientRect.left; int Height = ClientRect.bottom - ClientRect.top; Win32ResizeDIBSection(Width, Height); } break; case WM_DESTROY: { Running = false; }break; case WM_CLOSE: { PostQuitMessage(0); Running = false; }break; case WM_ACTIVATEAPP: { OutputDebugStringA(""); }break; case WM_PAINT: { PAINTSTRUCT Paint; HDC DeviceContext = BeginPaint(Window, &Paint); int X = Paint.rcPaint.left; int Y = Paint.rcPaint.top; int Width = Paint.rcPaint.right - Paint.rcPaint.left; int Height = Paint.rcPaint.bottom - Paint.rcPaint.top; RECT ClientRect; GetClientRect(Window, &ClientRect); Win32UpdateWindow(DeviceContext, &ClientRect, X, Y, Width, Height); EndPaint(Window, &Paint); }break; default: { OutputDebugStringA(""); Result = DefWindowProcA(Window, Message, WParam, LParam); }break; } return (Result); }
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Init pixel buffer // g_pixel_buffer.allocate(&g_program_memory); // Create window class WNDCLASS WindowClass = {}; WindowClass.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; WindowClass.lpfnWndProc = Win32WindowProc; WindowClass.hInstance = hInstance; WindowClass.lpszClassName = "VMWindowClass"; if (!RegisterClass(&WindowClass)) { // TODO: logging printf("Couldn't register window class\n"); exit(1); } // Create window so that its client area is exactly kWindowWidth/Height DWORD WindowStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE; RECT WindowRect = {}; const int kWindowWidth = 1024; const int kWindowHeight = 768; g_pixel_buffer.width = kWindowWidth; g_pixel_buffer.height = kWindowHeight; g_pixel_buffer.max_width = 3000; g_pixel_buffer.max_height = 3000; g_pixel_buffer.memory = malloc(sizeof(u32) * g_pixel_buffer.width * g_pixel_buffer.height + 100); WindowRect.right = kWindowWidth; WindowRect.bottom = kWindowHeight; AdjustWindowRect(&WindowRect, WindowStyle, 0); int WindowWidth = WindowRect.right - WindowRect.left; int WindowHeight = WindowRect.bottom - WindowRect.top; HWND Window = CreateWindow(WindowClass.lpszClassName, 0, WindowStyle, CW_USEDEFAULT, CW_USEDEFAULT, WindowWidth, WindowHeight, 0, 0, hInstance, 0); if (!Window) { printf("Couldn't create window\n"); exit(1); } // We're not going to release it as we use CS_OWNDC HDC hdc = GetDC(Window); g_running = true; // Set proper buffer values based on actual client size Win32ResizeClientWindow(Window); printf("%d:%d\n", g_pixel_buffer.width, g_pixel_buffer.height); // Init OpenGL { PIXELFORMATDESCRIPTOR DesiredPixelFormat = {}; DesiredPixelFormat.nSize = sizeof(DesiredPixelFormat); DesiredPixelFormat.nVersion = 1; DesiredPixelFormat.iPixelType = PFD_TYPE_RGBA; DesiredPixelFormat.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; DesiredPixelFormat.cColorBits = 32; DesiredPixelFormat.cAlphaBits = 8; DesiredPixelFormat.iLayerType = PFD_MAIN_PLANE; int SuggestedPixelFormatIndex = ChoosePixelFormat(hdc, &DesiredPixelFormat); PIXELFORMATDESCRIPTOR SuggestedPixelFormat; DescribePixelFormat(hdc, SuggestedPixelFormatIndex, sizeof(SuggestedPixelFormat), &SuggestedPixelFormat); SetPixelFormat(hdc, SuggestedPixelFormatIndex, &SuggestedPixelFormat); HGLRC OpenGLRC = wglCreateContext(hdc); if (wglMakeCurrent(hdc, OpenGLRC)) { // Success glGenTextures(1, &gTextureHandle); typedef BOOL WINAPI wgl_swap_interval_ext(int interval); wgl_swap_interval_ext *wglSwapInterval = (wgl_swap_interval_ext *)wglGetProcAddress("wglSwapIntervalEXT"); if (wglSwapInterval) { wglSwapInterval(1); } else { // VSync not enabled or not supported assert(false); } } else { // Something's wrong assert(false); } } // Event loop while (g_running) { // Process messages MSG message; while (PeekMessage(&message, 0, 0, 0, PM_REMOVE)) { // Get keyboard messages switch (message.message) { case WM_QUIT: { g_running = false; } break; case WM_SYSKEYDOWN: case WM_SYSKEYUP: case WM_KEYDOWN: case WM_KEYUP: { u32 vk_code = (u32)message.wParam; b32 was_down = ((message.lParam & (1 << 30)) != 0); b32 is_down = ((message.lParam & (1 << 31)) == 0); b32 alt_key_was_down = (message.lParam & (1 << 29)); if ((vk_code == VK_F4) && alt_key_was_down) { g_running = false; } if (was_down == is_down) { break; // nothing has changed } if (vk_code == VK_ESCAPE) { g_running = false; } } break; default: { TranslateMessage(&message); DispatchMessageA(&message); } break; } } update_and_render(&g_pixel_buffer); Win32UpdateWindow(hdc); } return 0; }
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Allocate program memory g_program_memory.start = malloc(MAX_INTERNAL_MEMORY_SIZE); g_program_memory.free_memory = g_program_memory.start; // TODO: add checks for overflow when allocating // Main program state Program_State *state = (Program_State *)g_program_memory.allocate(sizeof(Program_State)); state->init(&g_program_memory, &g_pixel_buffer, (Raytrace_Work_Queue *)&g_raytrace_queue); // Create window class WNDCLASS WindowClass = {}; WindowClass.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; WindowClass.lpfnWndProc = Win32WindowProc; WindowClass.hInstance = hInstance; WindowClass.lpszClassName = "VMWindowClass"; // Set target sleep resolution { TIMECAPS tc; UINT wTimerRes; if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) { OutputDebugStringA("Cannot set the sleep resolution\n"); exit(1); } wTimerRes = min(max(tc.wPeriodMin, 1), tc.wPeriodMax); // 1 ms timeBeginPeriod(wTimerRes); } QueryPerformanceFrequency(&gPerformanceFrequency); if (!RegisterClass(&WindowClass)) { // TODO: logging printf("Couldn't register window class\n"); exit(1); } // Create window so that its client area is exactly kWindowWidth/Height DWORD WindowStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE; RECT WindowRect = {}; WindowRect.right = state->kWindowWidth; WindowRect.bottom = state->kWindowHeight; AdjustWindowRect(&WindowRect, WindowStyle, 0); int WindowWidth = WindowRect.right - WindowRect.left; int WindowHeight = WindowRect.bottom - WindowRect.top; HWND Window = CreateWindow(WindowClass.lpszClassName, 0, WindowStyle, CW_USEDEFAULT, CW_USEDEFAULT, WindowWidth, WindowHeight, 0, 0, hInstance, 0); if (!Window) { printf("Couldn't create window\n"); exit(1); } // We're not going to release it as we use CS_OWNDC HDC hdc = GetDC(Window); g_running = true; // Set proper buffer values based on actual client size Win32ResizeClientWindow(Window); // Init OpenGL { PIXELFORMATDESCRIPTOR DesiredPixelFormat = {}; DesiredPixelFormat.nSize = sizeof(DesiredPixelFormat); DesiredPixelFormat.nVersion = 1; DesiredPixelFormat.iPixelType = PFD_TYPE_RGBA; DesiredPixelFormat.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; DesiredPixelFormat.cColorBits = 32; DesiredPixelFormat.cAlphaBits = 8; DesiredPixelFormat.iLayerType = PFD_MAIN_PLANE; int SuggestedPixelFormatIndex = ChoosePixelFormat(hdc, &DesiredPixelFormat); PIXELFORMATDESCRIPTOR SuggestedPixelFormat; DescribePixelFormat(hdc, SuggestedPixelFormatIndex, sizeof(SuggestedPixelFormat), &SuggestedPixelFormat); SetPixelFormat(hdc, SuggestedPixelFormatIndex, &SuggestedPixelFormat); HGLRC OpenGLRC = wglCreateContext(hdc); if (wglMakeCurrent(hdc, OpenGLRC)) { // Success glGenTextures(1, &gTextureHandle); typedef BOOL WINAPI wgl_swap_interval_ext(int interval); wgl_swap_interval_ext *wglSwapInterval = (wgl_swap_interval_ext *)wglGetProcAddress("wglSwapIntervalEXT"); if (wglSwapInterval) { wglSwapInterval(1); } else { // VSync not enabled or not supported assert(false); } } else { // Something's wrong assert(false); } } Cursor_Type current_cursor = Cursor_Type_Arrow; HCURSOR win_cursors[Cursor_Type__COUNT]; win_cursors[Cursor_Type_Arrow] = LoadCursor(NULL, IDC_ARROW); win_cursors[Cursor_Type_Cross] = LoadCursor(NULL, IDC_CROSS); win_cursors[Cursor_Type_Hand] = LoadCursor(NULL, IDC_HAND); win_cursors[Cursor_Type_Resize_Vert] = LoadCursor(NULL, IDC_SIZENS); win_cursors[Cursor_Type_Resize_Horiz] = LoadCursor(NULL, IDC_SIZEWE); User_Input inputs[2]; User_Input *old_input = &inputs[0]; User_Input *new_input = &inputs[1]; *new_input = {}; LARGE_INTEGER last_timestamp = Win32GetWallClock(); // Create worker threads { const int kNumThreads = 4; // Init work queue g_raytrace_queue.next_entry_to_add = 0; g_raytrace_queue.next_entry_to_do = 0; u32 initial_num_threads = 0; g_raytrace_queue.semaphore = CreateSemaphoreEx( 0, initial_num_threads, kNumThreads, 0, 0, SEMAPHORE_ALL_ACCESS); Thread_Info threads[kNumThreads]; for (int i = 0; i < kNumThreads; i++) { threads[i].thread_num = i + 1; HANDLE thread_handle = CreateThread( 0, // LPSECURITY_ATTRIBUTES lpThreadAttributes, 0, // SIZE_T dwStackSize, RaytraceWorkerThread, // LPTHREAD_START_ROUTINE lpStartAddress, &threads[i], // LPVOID lpParameter, 0, // DWORD dwCreationFlags, NULL // LPDWORD lpThreadId ); threads[i].thread_handle = thread_handle; if (thread_handle == NULL) { printf("CreateThread error: %d\n", GetLastError()); exit(1); } } } // Event loop while (g_running) { // Process messages MSG message; while (PeekMessage(&message, 0, 0, 0, PM_REMOVE)) { // Get keyboard messages switch (message.message) { case WM_QUIT: { g_running = false; } break; case WM_SYSKEYDOWN: case WM_SYSKEYUP: case WM_KEYDOWN: case WM_KEYUP: { u32 vk_code = (u32)message.wParam; bool was_down = ((message.lParam & (1 << 30)) != 0); bool is_down = ((message.lParam & (1 << 31)) == 0); bool alt_key_was_down = (message.lParam & (1 << 29)) != 0; if ((vk_code == VK_F4) && alt_key_was_down) { g_running = false; } if (was_down == is_down) { break; // nothing has changed } if (vk_code == VK_ESCAPE) { new_input->buttons[IB_escape] = is_down; } if (vk_code == VK_UP) { new_input->buttons[IB_up] = is_down; } if (vk_code == VK_DOWN) { new_input->buttons[IB_down] = is_down; } if (vk_code == VK_LEFT) { new_input->buttons[IB_left] = is_down; } if (vk_code == VK_RIGHT) { new_input->buttons[IB_right] = is_down; } if (vk_code == VK_SHIFT) { new_input->buttons[IB_shift] = is_down; } // Handle symbols int symbol = (int)vk_code; if (vk_code == VK_NUMPAD0) symbol = '0'; else if (vk_code == VK_NUMPAD1) symbol = '1'; else if (vk_code == VK_NUMPAD2) symbol = '2'; else if (vk_code == VK_NUMPAD3) symbol = '3'; else if (vk_code == VK_NUMPAD4) symbol = '4'; else if (vk_code == VK_NUMPAD5) symbol = '5'; else if (vk_code == VK_NUMPAD6) symbol = '6'; else if (vk_code == VK_NUMPAD7) symbol = '7'; else if (vk_code == VK_NUMPAD8) symbol = '8'; else if (vk_code == VK_NUMPAD9) symbol = '9'; if (('A' <= symbol && symbol <= 'Z') || ('0' <= symbol && symbol <= '9')) { new_input->buttons[IB_key] = is_down; new_input->symbol = symbol; } } break; case WM_MOUSEWHEEL: { int delta = (int)message.wParam / (65536 * WHEEL_DELTA); new_input->scroll += delta; } break; default: { TranslateMessage(&message); DispatchMessageA(&message); } break; } } // Get mouse input { POINT mouse_pointer; GetCursorPos(&mouse_pointer); ScreenToClient(Window, &mouse_pointer); new_input->mouse = {mouse_pointer.x, mouse_pointer.y}; new_input->buttons[IB_mouse_left] = (GetKeyState(VK_LBUTTON) & (1 << 15)) != 0; new_input->buttons[IB_mouse_right] = (GetKeyState(VK_RBUTTON) & (1 << 15)) != 0; new_input->buttons[IB_mouse_middle] = (GetKeyState(VK_MBUTTON) & (1 << 15)) != 0; } Update_Result result = update_and_render(&g_program_memory, state, new_input); #include "debug/ED_debug_draw.cpp" assert(0 <= result.cursor && result.cursor < Cursor_Type__COUNT); SetCursor(win_cursors[result.cursor]); Win32UpdateWindow(hdc); // Swap inputs User_Input *tmp = old_input; old_input = new_input; new_input = tmp; // Zero input *new_input = {}; new_input->old = old_input; // Save so we can refer to it later // Retain the button state for (size_t i = 0; i < COUNT_OF(new_input->buttons); i++) { new_input->buttons[i] = old_input->buttons[i]; } for (size_t i = 0; i < COUNT_OF(new_input->mouse_positions); i++) { new_input->mouse_positions[i] = old_input->mouse_positions[i]; } new_input->symbol = old_input->symbol; r32 ms_elapsed = Win32GetMillisecondsElapsed(last_timestamp, Win32GetWallClock()); g_FPS.value = (int)(1000.0f / ms_elapsed); last_timestamp = Win32GetWallClock(); } return 0; }
int CALLBACK WinMain( HINSTANCE Instance, HINSTANCE PrevInstance, LPSTR CommandLine, int ShowCode) { WNDCLASS WindowClass = {}; WindowClass.style = CS_OWNDC|CS_HREDRAW|CS_VREDRAW; WindowClass.lpfnWndProc = Win32MainWindowCallback; WindowClass.hInstance = Instance; //WindowClass.icon WindowClass.lpszClassName = "HandmadeHeroWindowClass"; 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, Instance, 0); if(Window) { int XOffset = 0; int YOffset = 0; Running = true; while(Running) { MSG Message; while(PeekMessage(&Message, 0, 0, 0, PM_REMOVE)) { if(Message.message == WM_QUIT) { Running = false; } TranslateMessage(&Message); DispatchMessage(&Message); } RenderWeirdGradient(XOffset, YOffset); HDC DeviceContext = GetDC(Window); RECT ClientRect; GetClientRect(Window, &ClientRect); int WindowWidth = ClientRect.right - ClientRect.left; int WindowHeight = ClientRect.bottom - ClientRect.top; Win32UpdateWindow(DeviceContext, &ClientRect, 0,0, WindowWidth,WindowHeight); ReleaseDC(Window, DeviceContext); ++XOffset; } } else {//logging } } else { } return (0); }
// WINDOWS MAIN FUNCTION // hInst = current instance of the program // hPrevInst = previous instance which is not used anymore. // cmdLine = holds command line arguments to be passed in to the program // cmdShow = holds an integer to specify if we want to show this window. int CALLBACK WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdLine, int cmdShow) { WNDCLASS wc = {0}; wc.style = CS_HREDRAW | CS_VREDRAW; wc.hInstance = hInst; wc.hbrBackground = (HBRUSH)COLOR_WINDOW; wc.lpszClassName = wndClassName; wc.hCursor = 0; //TODO: Add cursors and icons to this program. wc.hIcon = 0; wc.lpfnWndProc = (WNDPROC)wndProc; RegisterClass(&wc); HWND window = CreateWindow(wndClassName, wndTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, wndWidth, wndHeight, 0, 0, hInst, 0); if(window) { ShowWindow(window, SW_SHOW); UpdateWindow(window); // NOTE: Initializing SDL if(SDL_Init(SDL_INIT_VIDEO) != 0 ) { DestroyWindow(window); return -2; } IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG); sdlWindow = SDL_CreateWindowFrom((void*)window); char error[MAX_PATH]; stringCopy(error, SDL_GetError()); OutputDebugStringA(error); if(!sdlWindow) { SDL_Quit(); DestroyWindow(window); return -3; } renderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if(!renderer) { SDL_DestroyWindow(sdlWindow); SDL_Quit(); DestroyWindow(window); return -4; } i32 RefreshRate = 0; HDC dc = GetDC(window); i32 winRefreshRate = GetDeviceCaps(dc, VREFRESH); if( winRefreshRate > 1 ) { RefreshRate = winRefreshRate / 2; } else { RefreshRate = 30; } r32 targetSecsPerFrame = 1.0f / RefreshRate; GameMemory memory = {}; memory.permanentSize = Megabytes(64); memory.transientSize = Megabytes(64); memory.totalSize = memory.permanentSize + memory.transientSize; gameMemoryBlock = VirtualAlloc( 0, memory.totalSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if(!gameMemoryBlock) { SDL_DestroyRenderer(renderer); SDL_DestroyWindow(sdlWindow); SDL_Quit(); DestroyWindow(window); return -5; } memory.permanentBlock = gameMemoryBlock; memory.transientBlock = (i8*)gameMemoryBlock + memory.permanentSize; memory.readEntireFile = ReadEntireFile; memory.freeFile = FreeFile; memory.writeEntireFile = WriteEntireFile; Win32Dims windowDims = GetWindowDimensions(window); Render render = {}; render.renderer = renderer; render.screenW = windowDims.width; render.screenH = windowDims.height; GameController input = {0}; input.dt = targetSecsPerFrame; Win32State state = {0}; state.memoryBlock = gameMemoryBlock; state.memorySize = memory.totalSize; GameCodeDLL gameCode = Win32LoadGameCode("Game.dll", "Game_temp.dll", "lock.tmp"); isRunning = true; r32 sleepIsGranular = (timeBeginPeriod(1) == TIMERR_NOERROR); LARGE_INTEGER lastCounter = Win32GetClock(); i64 lastCycles = __rdtsc(); LARGE_INTEGER performanceFreqPerSecRes; QueryPerformanceFrequency(&performanceFreqPerSecRes); globalPerformanceCountFreq = performanceFreqPerSecRes.QuadPart; // NOTE: PROGRAM LOOP!! while(isRunning) { // NOTE: compare File times for us to be able to reload the new game code FILETIME currentFileTime = Win32GetLastWriteTime("Game.dll"); if(CompareFileTime(¤tFileTime, &gameCode.lastWriteTime) != 0) { Win32UnloadGameCode(&gameCode); gameCode = Win32LoadGameCode("Game.dll", "Game_temp.dll", "lock.tmp"); } MSG msg = {0}; while(PeekMessage(&msg, window, 0, 0, PM_REMOVE)) { switch(msg.message) { case WM_CLOSE: { isRunning = false; }break; case WM_KEYUP: case WM_KEYDOWN: case WM_SYSKEYUP: case WM_SYSKEYDOWN: { u32 vkCode = (u32)msg.wParam; // This contains the keycode for the key that the user pressed. bool isDown = ((msg.lParam & (1 << 31)) == 0); // Check to see if the key is down now. bool wasDown = ((msg.lParam & (1 << 30)) != 0); // Check to see if the key was down previously. if(isDown != wasDown) { if(vkCode == 'W') { input.moveUp.isDown = isDown; } else if(vkCode == 'S') { input.moveDown.isDown = isDown; } else if(vkCode == 'A') { input.moveLeft.isDown = isDown; } else if(vkCode == 'D') { input.moveRight.isDown = isDown; } if(vkCode == VK_UP) { input.actionUp.isDown = isDown; } else if(vkCode == VK_DOWN) { input.actionDown.isDown = isDown; } else if(vkCode == VK_LEFT) { input.actionLeft.isDown = isDown; } else if(vkCode == VK_RIGHT) { input.actionRight.isDown = isDown; } else if(vkCode == VK_ESCAPE) { input.back.isDown = isDown; } else if(vkCode == 'O') { if(isDown) { if(state.recordingIndex == 0) { BeginRecording(&state, 1); } else { EndRecording(&state); BeginPlayback(&state, 1); } } } else if(vkCode == 'P') { if(isDown) { if(state.playbackIndex > 0) { EndPlayback(&state); ZeroMemory(&input, sizeof(input)); } } } } if(isDown) { bool AltKeyWasDown = ((msg.lParam & (1 << 29)) != 0); if(vkCode == VK_RETURN && AltKeyWasDown) { if(msg.hwnd) { isFullscreen = !isFullscreen; Win32FullscreenToggle(msg.hwnd); } } } }break; default: { TranslateMessage(&msg); DispatchMessage(&msg); } } } if(input.back.isDown) { isRunning = false; PostQuitMessage(0); } if(state.recordingIndex > 0) { RecordingInput(&state, &input); } else if(state.playbackIndex > 0) { PlaybackInput(&state, &input); } Win32Dims windowDims = GetWindowDimensions(window); Win32UpdateWindow(windowDims, (i32*)&render.screenW, (i32*)&render.screenH); if(gameCode.UpdateRender) { gameCode.UpdateRender(&memory, &input, &render); } LARGE_INTEGER workCounter = Win32GetClock(); r32 workSecsElapsed = Win32GetSecondsElapsed(lastCounter, workCounter); r32 secondsElapsed = workSecsElapsed; if(secondsElapsed < targetSecsPerFrame) { if(sleepIsGranular) { DWORD sleepMS = (DWORD)(1000.0f * (targetSecsPerFrame - secondsElapsed)); if(sleepMS > 0) { Sleep(sleepMS); } } r32 testSecsElapsed = Win32GetSecondsElapsed(lastCounter, Win32GetClock()); if(testSecsElapsed < targetSecsPerFrame) { //TODO: LOG MISSED SLEEP HERE!! } while(secondsElapsed < targetSecsPerFrame) { secondsElapsed = Win32GetSecondsElapsed(lastCounter, Win32GetClock()); } } else { //TODO: MISSED FRAME RATE!! } LARGE_INTEGER endCounter = Win32GetClock(); i64 endCycles = __rdtsc(); r64 elapsedCounts = (r64)(endCounter.QuadPart - lastCounter.QuadPart); r64 elapsedCycles = (r64)(endCycles - lastCycles); r32 MSperFrame = ((1000.0f * Win32GetSecondsElapsed(lastCounter, endCounter))); r32 FPS = (r32)(globalPerformanceCountFreq / elapsedCounts); r32 MegaCyclesPerFrame = (r32)(elapsedCycles / (1000.0f * 1000.0f)); char buffer[256]; sprintf_s(buffer, "%.02fms, %.02ffps, %.02fmcpf\n", MSperFrame, FPS, MegaCyclesPerFrame); OutputDebugStringA(buffer); lastCounter = endCounter; lastCycles = endCycles; } // NOTE: END OF WHILE LOOP //IMPORTANT: Unload this when we exit the program. Win32UnloadGameCode(&gameCode); } else { // TODO: Handle Error Loggin here!! return -1; } if(gameMemoryBlock) { VirtualFree(gameMemoryBlock, 0, MEM_RELEASE); } //Close SDL_DestroyRenderer(renderer); SDL_DestroyWindow(sdlWindow); IMG_Quit(); SDL_Quit(); DestroyWindow(window); return 0; }