internal void Win32InitOpenGL(HDC WindowDC) { Win32LoadWGLExtensions(); HGLRC OpenGLRC = 0; bool32 ModernContext = true; if(wglCreateContextAttribsARB) { int Win32OpenGLAttribs[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 1, WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB #if LUDUS_INTERNAL | WGL_CONTEXT_DEBUG_BIT_ARB #endif , WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0 }; Win32SetPixelFormat(WindowDC); OpenGLRC = wglCreateContextAttribsARB(WindowDC, 0, Win32OpenGLAttribs); } if(!OpenGLRC) { ModernContext = false; OpenGLRC = wglCreateContext(WindowDC); } if(wglMakeCurrent(WindowDC, OpenGLRC)) { InitOpenGL(ModernContext); if(wglSwapInterval) { wglSwapInterval(1); } } else { Win32Log("Couldnt set OpenGL context"); LOG_FORMATTED_ERROR(4096); } }
int main (int argc, char **argv) { rvgGlutInit( argc, argv ); rvgGLInit(); wglSwapInterval( 0 ); shaderDefault = new Shader(); shaderDefault->addSource( ShaderType::Vertex, "shaders/default.vert.c" ); shaderDefault->addSource( ShaderType::Fragment, "shaders/default.frag.c" ); shaderDefault->load(); glutMainLoop(); }
void WIN32Window::setVerticalSync(bool enable) { #ifdef OPENGL_ES eglSwapInterval(m_eglDisplay, enable ? 1 : 0); #else if(!isExtensionSupported("WGL_EXT_swap_control")) return; typedef BOOL (WINAPI * wglSwapIntervalProc)(int); wglSwapIntervalProc wglSwapInterval = (wglSwapIntervalProc)getExtensionProcAddress("wglSwapIntervalEXT"); if(!wglSwapInterval) return; wglSwapInterval(enable ? 1 : 0); #endif }
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; }
void DisableVSync(void) { wglSwapIntervalFunc wglSwapInterval = (wglSwapIntervalFunc) wglGetProcAddress("wglSwapIntervalEXT"); if (wglSwapInterval) wglSwapInterval(0); }
MyWindow::MyWindow(const std::string &title,int width,int height) : initError(false),clientWidth(0),clientHeight(0),iconified(false),focused(true),sized(false), justCreated(true),mouseMoveCallback(0),inputCallback(0),lockCursor(false),foreground(true) { #ifdef WIN32 hglrc=0; hdc=0; // HINSTANCE hInstance=GetModuleHandle(0); WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_APPLICATION)); wcex.hCursor = LoadCursor(NULL,IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; #ifdef UNICODE wcex.lpszClassName = L"win32app"; #else wcex.lpszClassName = "win32app"; #endif wcex.hIconSm = LoadIcon(wcex.hInstance,MAKEINTRESOURCE(IDI_APPLICATION)); if(!RegisterClassEx(&wcex)) { std::cout << "MyWindow : Call to RegisterClassEx failed!\n"; } #ifdef UNICODE wchar_t title2[256]; MultiByteToWideChar(CP_ACP,0,title.c_str(),-1,title2,256); #else const char *title2=title.c_str(); #endif hWnd = CreateWindow(wcex.lpszClassName,title2,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,width,height,NULL,NULL,hInstance,NULL); SetWindowLongPtr(hWnd,GWL_USERDATA,(LONG_PTR)this); ShowWindow(hWnd,SW_SHOW); // hdc= GetDC(hWnd); PIXELFORMATDESCRIPTOR pfd; ZeroMemory(&pfd,sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cRedBits = pfd.cGreenBits = pfd.cBlueBits = 8; pfd.cDepthBits = 32; int iPixelFormat = ChoosePixelFormat(hdc,&pfd); if(iPixelFormat == 0) { std::cout << "MyWindow : ChoosePixelFormat failed.\n"; initError=true; return; } if(SetPixelFormat(hdc,iPixelFormat,&pfd) != TRUE) { std::cout << "MyWindow : SetPixelFormat failed.\n"; initError=true; return; } // HGLRC tempContext = wglCreateContext(hdc); wglMakeCurrent(hdc,tempContext); // PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB= (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); PFNWGLSWAPINTERVALEXTPROC wglSwapInterval= (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); // wglMakeCurrent(0,0); wglDeleteContext(tempContext); // int attribs[] ={ WGL_CONTEXT_MAJOR_VERSION_ARB,3, WGL_CONTEXT_MINOR_VERSION_ARB,3, WGL_CONTEXT_FLAGS_ARB,0, 0 }; hglrc=wglCreateContextAttribsARB(hdc,0,attribs); for(int i=2;i>=0;i--) { if(!hglrc) { attribs[3]=i; hglrc=wglCreateContextAttribsARB(hdc,0,attribs); } } if(!hglrc) { std::cout << "OpenGL 3+ not supported.\n"; initError=true; return; } wglMakeCurrent(hdc,hglrc); wglSwapInterval(1); // RAWINPUTDEVICE Rid[2]; Rid[0].usUsagePage = (USHORT)0x01;//HID_USAGE_PAGE_GENERIC; Rid[0].usUsage = (USHORT)0x02;//HID_USAGE_GENERIC_MOUSE; Rid[0].dwFlags = RIDEV_INPUTSINK; Rid[0].hwndTarget = hWnd; Rid[1].usUsagePage = (USHORT)0x01;//HID_USAGE_PAGE_GENERIC; Rid[1].usUsage = (USHORT)0x06;//HID_USAGE_GENERIC_KEYBOARD; Rid[1].dwFlags = RIDEV_INPUTSINK; Rid[1].hwndTarget = hWnd; RegisterRawInputDevices(Rid,2,sizeof(RAWINPUTDEVICE)); // //inputCodeMap[65]=keyA; //inputCodeMap[68]=keyD; //inputCodeMap[83]=keyS; //inputCodeMap[87]=keyW; #endif #ifdef LINUX // bool ctxErrorOccurred=false; display = XOpenDisplay(NULL); if(!display) { std::cout << "Window : Failed to open X display.\n"; initError=true; return; } static int visual_attribs[] ={ GLX_X_RENDERABLE,True, GLX_DRAWABLE_TYPE,GLX_WINDOW_BIT, GLX_RENDER_TYPE,GLX_RGBA_BIT, GLX_X_VISUAL_TYPE,GLX_TRUE_COLOR, GLX_RED_SIZE,8, GLX_GREEN_SIZE,8, GLX_BLUE_SIZE,8, GLX_ALPHA_SIZE,8, GLX_DEPTH_SIZE,24, GLX_STENCIL_SIZE,8, GLX_DOUBLEBUFFER,True, //GLX_SAMPLE_BUFFERS , 1, //GLX_SAMPLES , 4, None }; int glx_major,glx_minor; if(!glXQueryVersion(display,&glx_major,&glx_minor) || ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) { std::cout << "Window : Invalid GLX version.\n"; initError=true; return; } int fbcount; GLXFBConfig* fbc = glXChooseFBConfig(display,DefaultScreen(display),visual_attribs,&fbcount); if(!fbc) { std::cout << "Window :Failed to retrieve a framebuffer config.\n"; initError=true; return; } int best_fbc = -1,worst_fbc = -1,best_num_samp = -1,worst_num_samp = 999; for(int i=0; i<fbcount; ++i) { XVisualInfo *vi = glXGetVisualFromFBConfig(display,fbc[i]); if(vi) { int samp_buf,samples; glXGetFBConfigAttrib(display,fbc[i],GLX_SAMPLE_BUFFERS,&samp_buf); glXGetFBConfigAttrib(display,fbc[i],GLX_SAMPLES,&samples); std::cout << "Matching fbconfig " << i <<", visual ID 0x" << vi->visualid << ": SAMPLE_BUFFERS = " << samp_buf <<", SAMPLES = " << samples <<"\n"; if(best_fbc < 0 || samp_buf && samples > best_num_samp) { best_fbc = i; best_num_samp = samples; } if(worst_fbc < 0 || !samp_buf || samples < worst_num_samp) { worst_fbc = i; worst_num_samp = samples; } } XFree(vi); } GLXFBConfig bestFbc = fbc[best_fbc]; XFree(fbc); XVisualInfo *vi = glXGetVisualFromFBConfig(display,bestFbc); std::cout << "Chosen visual ID = 0x" << vi->visualid <<"\n"; XSetWindowAttributes swa; swa.colormap = cmap = XCreateColormap(display, RootWindow(display,vi->screen), vi->visual,AllocNone); swa.background_pixmap = None; swa.border_pixel = 0; swa.event_mask = ExposureMask | VisibilityChangeMask |KeyPressMask | PointerMotionMask |StructureNotifyMask; swa.bit_gravity = StaticGravity; win = XCreateWindow(display,RootWindow(display,vi->screen), 0,0,100,100,0,vi->depth,InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask,&swa); if(!win) { std::cout << "Window : Failed to create window.\n"; initError=true; return; } XFree(vi); XStoreName(display,win,title.c_str()); XMapWindow(display,win); const char *glxExts = glXQueryExtensionsString(display,DefaultScreen(display)); glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB((const GLubyte *) "glXCreateContextAttribsARB"); ctx = 0; ctxErrorOccurred = false; int(*oldHandler)(Display*,XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler); if(!isExtensionSupported(glxExts,"GLX_ARB_create_context") || !glXCreateContextAttribsARB) { std::cout << "Window : glXCreateContextAttribsARB() not found.\n"; initError=true; return; } else { int context_attribs[] ={ GLX_CONTEXT_MAJOR_VERSION_ARB,3, GLX_CONTEXT_MINOR_VERSION_ARB,0, GLX_CONTEXT_FLAGS_ARB,0, None }; ctx = glXCreateContextAttribsARB(display,bestFbc,0, True,context_attribs); XSync(display,False); if(!ctxErrorOccurred && ctx) { std::cout << "Created GL 3.0 context\n"; } else { std::cout << "Window : Failed to create GL 3.0 context.\n"; initError=true; return; } } // XSync(display,False); XSetErrorHandler(oldHandler); if(ctxErrorOccurred || !ctx) { std::cout << "Window : Failed to create an OpenGL context.\n"; initError=true; return; } // Verifying that context is a direct context if(!glXIsDirect(display,ctx)) { std::cout << "Indirect GLX rendering context obtained.\n"; } else { std::cout << "Direct GLX rendering context obtained.\n"; } // glXMakeCurrent(display,win,ctx); if(PFNGLXSWAPINTERVALMESAPROC glXSwapIntervalMESA= (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalMESA")) { glXSwapIntervalMESA(1); } else if(PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT= (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalEXT")) { glXSwapIntervalEXT(display,glXGetCurrentDrawable(),1); } else if(PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI= (PFNGLXSWAPINTERVALSGIPROC) glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalSGI")) { glXSwapIntervalSGI(1); } #endif }
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; }