Example #1
0
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;
}
Example #2
0
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);
}
Example #3
0
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;
}
Example #4
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;
}
Example #5
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(&currentFileTime, &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;
}