HWND player_impl::create_window(const char *player_name) { WNDCLASSEXA wcex; // 得到进程实例句柄. m_hinstance = (HINSTANCE)GetModuleHandle(NULL); // 创建非纯黑色的画刷, 用于ddraw播放时刷背景色. m_brbackground = CreateSolidBrush(RGB(0, 0, 1)); wcex.cbSize = sizeof(WNDCLASSEXA); wcex.style = CS_CLASSDC/*CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS*/; wcex.lpfnWndProc = player_impl::static_win_wnd_proc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = m_hinstance; wcex.hIcon = LoadIcon(m_hinstance, MAKEINTRESOURCE(IDC_ICON)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = m_brbackground; // (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; // MAKEINTRESOURCE(IDC_AVPLAYER); wcex.lpszClassName = player_name; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDC_ICON)); if (!RegisterClassExA(&wcex)) { ::logger("register window class failed!\n"); return NULL; } // 创建hook, 以便在窗口创建之前得到HWND句柄, 使HWND与this绑定. HHOOK hook = SetWindowsHookEx(WH_CBT, win_cbt_filter_hook, NULL, GetCurrentThreadId()); win_cbt_context win_cbt_ctx; win_tls.set(&win_cbt_ctx); win_tls->hook = hook; win_tls->win = this; // 创建窗口. m_hwnd = CreateWindowExA(/*WS_EX_APPWINDOW*/0, player_name, player_name, WS_OVERLAPPEDWINDOW/* | WS_CLIPSIBLINGS | WS_CLIPCHILDREN*/, 0, 0, 800, 600, NULL, NULL, m_hinstance, NULL); // 撤销hook. UnhookWindowsHookEx(hook); win_tls->hook = NULL; win_tls->win = NULL; ShowWindow(m_hwnd, SW_SHOW); return m_hwnd; }
static void register_testwindow_class(void) { WNDCLASSEXA cls; ZeroMemory(&cls, sizeof(cls)); cls.cbSize = sizeof(cls); cls.style = 0; cls.lpfnWndProc = testwindow_wndproc; cls.hInstance = NULL; cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); cls.hbrBackground = (HBRUSH) COLOR_WINDOW; cls.lpszClassName = testwindow_class; RegisterClassExA(&cls); }
static BOOL init(void) { WNDCLASSEX wc; HIMC imc; HMODULE hmod,huser; hmod = GetModuleHandleA("imm32.dll"); huser = GetModuleHandleA("user32"); pImmAssociateContextEx = (void*)GetProcAddress(hmod, "ImmAssociateContextEx"); pImmIsUIMessageA = (void*)GetProcAddress(hmod, "ImmIsUIMessageA"); pSendInput = (void*)GetProcAddress(huser, "SendInput"); wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = wndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandle(0); wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = wndcls; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassExA(&wc)) return FALSE; hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, GetModuleHandle(0), NULL); if (!hwnd) return FALSE; imc = ImmGetContext(hwnd); if (!imc) { win_skip("IME support not implemented\n"); return FALSE; } ImmReleaseContext(hwnd, imc); ShowWindow(hwnd, SW_SHOWNORMAL); UpdateWindow(hwnd); msg_spy_init(hwnd); return TRUE; }
////////// // // Creates the message window used for communicating actions // ////// void iVjr_init_createMessageWindow(void) { ATOM atom; WNDCLASSEXA classa; ////////// // Register the classes if need be ////// while (1) { if (!GetClassInfoExA(ghInstance, (cs8*)cgcMessageWindowClass, &classa)) { // Initialize memset(&classa, 0, sizeof(classa)); // Populate classa.cbSize = sizeof(WNDCLASSEXA); classa.hInstance = ghInstance; classa.lpszClassName = (cs8*)cgcMessageWindowClass; classa.lpfnWndProc = &iWindow_wndProcMessage; // Register atom = RegisterClassExA(&classa); if (!atom) break; } ////////// // Create the message window ////// ghwndMsg = CreateWindowA((cs8*)cgcMessageWindowClass, (cs8*)cgcMessageWindowClass, 0, 0, 0, 0, 0, HWND_MESSAGE, null0, ghInstance, 0); if (ghwndMsg) { // Create a timer for the message window firing 20x per second SetTimer(ghwndMsg, 0, 50, null0); // Read events CreateThread(NULL, 0, &iReadEvents_messageWindow, 0, 0, 0); return; } break; } // We should never get here MessageBoxA(null0, "Error creating Visual FreePro Jr's message window.", "VJr - Fatal Error", MB_OK); }
void createDialog(void) { STARTUPINFOA startinfo; WNDCLASSEXA WndClass; g_hInstance = GetModuleHandle(NULL); GetStartupInfoA(&startinfo); WndClass.cbSize = sizeof WndClass; WndClass.style = 0; WndClass.lpfnWndProc = WndProc; WndClass.cbClsExtra = 0; WndClass.cbWndExtra = 0; WndClass.hInstance = g_hInstance; WndClass.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MAINICON)); WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); WndClass.lpszMenuName = MAKEINTRESOURCEA(IDM_MAINMENU); WndClass.lpszClassName = "DrMingw"; WndClass.hIconSm = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MAINICON)); if (!RegisterClassExA(&WndClass)) { ErrorMessageBox("RegisterClassEx: %s", LastErrorMessage()); exit(EXIT_FAILURE); } g_hWnd = CreateWindowExA( WS_EX_CLIENTEDGE, WndClass.lpszClassName, "Dr. Mingw", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInstance, NULL ); if (g_hWnd == NULL) { ErrorMessageBox("CreateWindowEx: %s", LastErrorMessage()); exit(EXIT_FAILURE); } ShowWindow(g_hWnd, (startinfo.dwFlags & STARTF_USESHOWWINDOW) ? startinfo.wShowWindow : SW_SHOWDEFAULT); UpdateWindow(g_hWnd); }
bool PlatformInit() { g_window.need_quit = false; // Skip any upcoming error GetLastError(); // Some dual core systems have a problem where the different CPUs return different // QueryPerformanceCounter values. So when this thread is schedule on the other CPU // in a later frame, we could even get a negative frameTime. To solve this we force // the main thread to always run on CPU 0. SetThreadAffinityMask(GetCurrentThread(), 1); // This is the way to change window icon manually: g_window.icon = LoadIcon(NULL, IDI_APPLICATION); if (g_window.icon == NULL) { MessageBox(HWND_DESKTOP, TEXT("Icon loading failed!"), TEXT("Error"), MB_OK | MB_ICONEXCLAMATION); return false; } g_window.instance = GetModuleHandle(NULL); // Register A Window Class WNDCLASSEXA window_class; ZeroMemory(&window_class, sizeof(WNDCLASSEX)); window_class.cbSize = sizeof(WNDCLASSEX); window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; window_class.lpfnWndProc = (WNDPROC)(WindowProc); window_class.hInstance = g_window.instance; window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); window_class.hCursor = LoadCursor(NULL, IDC_ARROW); window_class.hIcon = g_window.icon; window_class.hIconSm = g_window.icon; window_class.lpszClassName = kApplicationClassName; if (RegisterClassExA(&window_class) == 0) { DestroyIcon(g_window.icon); MessageBox(HWND_DESKTOP, TEXT("RegisterClassEx Failed!"), TEXT("Error"), MB_OK | MB_ICONEXCLAMATION); return false; } AdjustVideoSettings(); return true; }
static cairo_status_t _wgl_dummy_ctx (cairo_wgl_context_t *ctx) { WNDCLASSEXA wincl; PIXELFORMATDESCRIPTOR pfd; int format; HDC dc; ZeroMemory (&wincl, sizeof (WNDCLASSEXA)); wincl.cbSize = sizeof (WNDCLASSEXA); wincl.hInstance = GetModuleHandle (0); wincl.lpszClassName = "cairo_wgl_context_dummy"; wincl.lpfnWndProc = DefWindowProcA; wincl.style = CS_OWNDC; RegisterClassExA (&wincl); ctx->dummy_wnd = CreateWindowA ("cairo_wgl_context_dummy", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); ctx->dummy_dc = GetDC (ctx->dummy_wnd); ZeroMemory (&pfd, sizeof (PIXELFORMATDESCRIPTOR)); pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; #ifndef WKC_CAIRO_CUSTOMIZE pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cDepthBits = 16; #else pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;/* | PFD_DOUBLEBUFFER;*/ pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 32; pfd.cDepthBits = 32; pfd.cStencilBits = 32; #endif pfd.iLayerType = PFD_MAIN_PLANE; format = ChoosePixelFormat (ctx->dummy_dc, &pfd); SetPixelFormat (ctx->dummy_dc, format, &pfd); wglMakeCurrent(ctx->dummy_dc, ctx->rc); return CAIRO_STATUS_SUCCESS; }
ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = NULL; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(NULL, IDI_SHIELD); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = NULL; wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); wcex.lpszClassName = szWindowClass; wcex.hIconSm = NULL; return RegisterClassExA(&wcex); }
void DX_Init(DWORD* table) { WNDCLASSEXA wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandleA(NULL), NULL, NULL, NULL, NULL, "DX", NULL }; RegisterClassExA(&wc); HWND hWnd = CreateWindowA("DX", NULL, WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, GetDesktopWindow(), NULL, wc.hInstance, NULL); LPDIRECT3D9 pD3D = Direct3DCreate9(D3D_SDK_VERSION); D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; LPDIRECT3DDEVICE9 pd3dDevice; pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice); DWORD* pVTable = (DWORD*)pd3dDevice; pVTable = (DWORD*)pVTable[0]; table[0] = pVTable[42]; table[1] = pVTable[82]; DestroyWindow(hWnd); }
//Registers, creates, and shows the Window!! bool WinCreate() { WindowINST = GetModuleHandle(0); // Get current process handle std::string title = string_format("Cataclysm: Dark Days Ahead - %s", getVersionString()); // Register window class WNDCLASSEXA WindowClassType = WNDCLASSEXA(); WindowClassType.cbSize = sizeof(WNDCLASSEXA); WindowClassType.lpfnWndProc = ProcessMessages;//the procedure that gets msgs WindowClassType.hInstance = WindowINST;// hInstance WindowClassType.hIcon = LoadIcon(WindowINST, MAKEINTRESOURCE(0)); // Get first resource WindowClassType.hIconSm = LoadIcon(WindowINST, MAKEINTRESOURCE(0)); WindowClassType.hCursor = LoadCursor(NULL, IDC_ARROW); WindowClassType.lpszClassName = szWindowClass; if (!RegisterClassExA(&WindowClassType)) return false; // Adjust window size uint32_t WndStyle = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE; // Basic window, show on creation RECT WndRect; WndRect.left = WndRect.top = 0; WndRect.right = WindowWidth; WndRect.bottom = WindowHeight; AdjustWindowRect(&WndRect, WndStyle, false); // Center window RECT WorkArea; SystemParametersInfo(SPI_GETWORKAREA, 0, &WorkArea, 0); int WindowX = WorkArea.right/2 - (WndRect.right - WndRect.left)/2; int WindowY = WorkArea.bottom/2 - (WndRect.bottom - WndRect.top)/2; // Magic WindowHandle = CreateWindowExA(0, szWindowClass , title.c_str(), WndStyle, WindowX, WindowY, WndRect.right - WndRect.left, WndRect.bottom - WndRect.top, 0, 0, WindowINST, NULL); if (WindowHandle == 0) return false; return true; };
void RegisterWindowClassA() { WNDCLASSEXA wcex; wcex.cbSize = sizeof(WNDCLASSEXA); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProcA; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = 0; wcex.hCursor = 0; wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = 0; wcex.lpszClassName = "Azureus Window Hook"; wcex.hIconSm = 0; RegisterClassExA(&wcex); }
static BOOL xxRegisterWndClasses(LPCSTR menuName) { POCDEBUG_BREAK(); CHAR buf[0x10] = { 0 }; for (LONG i = 0; i < tmpTimes; i++) { WNDCLASSEXA Class = { 0 }; sprintf(buf, "CLS_%d", i); Class.lpfnWndProc = DefWindowProcA; Class.lpszClassName = buf; Class.lpszMenuName = menuName; Class.cbSize = sizeof(WNDCLASSEXA); if (!RegisterClassExA(&Class)) { return FALSE; } } return TRUE; }
ATOM WINAPI MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = 0; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wcex.lpszMenuName = NULL; wcex.lpszClassName = szClassName; wcex.hIconSm = NULL; return RegisterClassExA(&wcex); }
static int init(void) { WNDCLASSEX wc; HIMC imc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = DefWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandle(0); wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = wndcls; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassExA(&wc)) return 0; hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, GetModuleHandle(0), NULL); if (!hwnd) return 0; imc = ImmGetContext(hwnd); if (!imc) { win_skip("IME support not implemented\n"); return 0; } ImmReleaseContext(hwnd, imc); ShowWindow(hwnd, SW_SHOWNORMAL); UpdateWindow(hwnd); msg_spy_init(hwnd); return 1; }
ATOM RegisterWinClass(const char* pszName, WNDPROC proc, HINSTANCE hInst, UINT menuID, UINT iconID, UINT smallIconID) { WNDCLASSEXA wc = {}; wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = proc; wc.lpszClassName = pszName; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hInstance = hInst; wc.lpszMenuName = MAKEINTRESOURCEA(menuID); wc.hIcon = LoadIconA(hInst, MAKEINTRESOURCEA(iconID)); wc.hIconSm = LoadIconA(hInst, MAKEINTRESOURCEA(smallIconID)); return RegisterClassExA(&wc); }
/*********************************************************************** * AtlModuleRegisterWndClassInfoA [ATL.@] * * See AtlModuleRegisterWndClassInfoW. */ ATOM WINAPI AtlModuleRegisterWndClassInfoA(_ATL_MODULEA *pm, _ATL_WNDCLASSINFOA *wci, WNDPROC *pProc) { ATOM atom; FIXME("%p %p %p semi-stub\n", pm, wci, pProc); atom = wci->m_atom; if (!atom) { WNDCLASSEXA wc; TRACE("wci->m_wc.lpszClassName = %s\n", wci->m_wc.lpszClassName); if (wci->m_lpszOrigName) FIXME( "subclassing %s not implemented\n", debugstr_a(wci->m_lpszOrigName)); if (!wci->m_wc.lpszClassName) { snprintf(wci->m_szAutoName, sizeof(wci->m_szAutoName), "ATL%08lx", (UINT_PTR)wci); TRACE("auto-generated class name %s\n", wci->m_szAutoName); wci->m_wc.lpszClassName = wci->m_szAutoName; } atom = GetClassInfoExA(pm->m_hInst, wci->m_wc.lpszClassName, &wc); if (!atom) { wci->m_wc.hInstance = pm->m_hInst; wci->m_wc.hCursor = LoadCursorA( wci->m_bSystemCursor ? NULL : pm->m_hInst, wci->m_lpszCursorID ); atom = RegisterClassExA(&wci->m_wc); } wci->pWndProc = wci->m_wc.lpfnWndProc; wci->m_atom = atom; } if (wci->m_lpszOrigName) *pProc = wci->pWndProc; TRACE("returning 0x%04x\n", atom); return atom; }
BOOL InitInstance(HANDLE hInstance) { WNDCLASSEX wcex; RECT rect; int height, width; memset(&wcex, 0x00, sizeof(wcex)); wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.hInstance = hInstance; wcex.lpszClassName = ClassName; RegisterClassExA(&wcex); //calculate required window width and height, taking in account the required client area and borders height = BoardHeight*BlockSize; width = BoardWidth*BlockSize; rect.left = 0; rect.top = 0; rect.bottom = height; rect.right = width; AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_TOPMOST); height += ((rect.bottom - rect.top) - height); width += ((rect.right - rect.left) - width); ///////////////////////////////////////////////// if ((hWndMain = CreateWindowExA(WS_EX_TOPMOST, ClassName, MainTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, hInstance, NULL)) == NULL) { return FALSE; } ShowWindow(hWndMain, SW_SHOW); UpdateWindow(hWndMain); return TRUE; }
//-------------------------------------------------------------------------- void VeWindows::_CreateWindow(Window* pkWindow) { WNDCLASSEXA kClass; kClass.cbSize = sizeof(WNDCLASSEXA); kClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; kClass.lpfnWndProc = WndProc; kClass.cbClsExtra = 0; kClass.cbWndExtra = 0; kClass.hInstance = m_kParams.m_hInstance; kClass.hIcon = 0; kClass.hCursor = LoadCursor(NULL, IDC_ARROW); kClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); kClass.lpszMenuName = NULL; kClass.lpszClassName = m_kParams.m_pcAppName; kClass.hIconSm = 0; VE_ASSERT_NOT_EQ(RegisterClassExA(&kClass), VE_FALSE); HWND hWnd; RECT kRect; DWORD dwStyle = STYLE_BASIC; VeInt32 x, y; VeInt32 w, h; dwStyle |= GetWindowStyle(pkWindow); kRect.left = pkWindow->x; kRect.top = pkWindow->y; kRect.right = pkWindow->x + pkWindow->w; kRect.bottom = pkWindow->y + pkWindow->h; AdjustWindowRectEx(&kRect, dwStyle, FALSE, 0); x = kRect.left; y = kRect.top; w = (kRect.right - kRect.left); h = (kRect.bottom - kRect.top); hWnd = CreateWindowA(m_kParams.m_pcAppName, "", dwStyle, x, y, w, h, NULL, NULL, m_kParams.m_hInstance, NULL); VE_ASSERT(hWnd); _PumpEvents(); SetupWindowData(pkWindow, hWnd, VE_TRUE); _DisableIME(pkWindow); }
bool pinDialogPriv::doNonmodalNotifyDlg(bool messageLoop) { MSG msg ; HWND hwnd = GetForegroundWindow(); WNDCLASSEXA wc = {0}; wc.cbSize = sizeof(WNDCLASSEX); wc.lpfnWndProc = (WNDPROC) nonmodalDialogProc; wc.hInstance = params.m_hInst; wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); wc.lpszClassName = "DialogClass"; RegisterClassExA(&wc); m_hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME | WS_EX_TOPMOST, "DialogClass", "PIN message", WS_VISIBLE | WS_SYSMENU | WS_CAPTION , 100, 100, 380, 80, NULL, NULL, params.m_hInst, this); int counter = 20; //always pump some messages, like dialog init while( GetMessage(&msg, NULL, 0, 0) && counter--) { DispatchMessage(&msg); if (messageLoop) counter = 20; } return true; }
void createWindow() { HINSTANCE hInst = GetModuleHandle(NULL); WNDCLASSEX wnd; wnd = {}; wnd.cbSize = sizeof(wnd); wnd.style = CS_HREDRAW | CS_VREDRAW; wnd.lpfnWndProc = msgProc; wnd.hInstance = hInst; wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); wnd.hCursor = LoadCursor(NULL, IDC_ARROW); wnd.lpszClassName = "App"; wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassExA(&wnd); m_hwnd = CreateWindowA("App", "App", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 800, 600, NULL, NULL, hInst, 0); RAWINPUTDEVICE Rid; Rid.usUsagePage = 0x01; Rid.usUsage = 0x02; Rid.dwFlags = 0; Rid.hwndTarget = 0; RegisterRawInputDevices(&Rid, 1, sizeof(Rid)); }
static int Win32_RegisterClass(Jim_Interp *interp, int objc, Jim_Obj *const objv[]) { WNDCLASSEXA wc; if (objc < 2 || objc > 3) { Jim_WrongNumArgs(interp, 1, objv, "classname ?windowproc?"); return JIM_ERR; } // FIX ME: deal with the windowproc wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = DefWindowProc; wc.cbClsExtra = 16; wc.cbWndExtra = 0; wc.hInstance = g_hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); wc.lpszMenuName = wc.lpszClassName = Jim_GetString(objv[1], NULL); if (objc == 3) { wc.lpfnWndProc = JimWin32WindowProc; } if (!RegisterClassExA(&wc)) { Jim_SetResult(interp, Win32ErrorObj(interp, "RegisterClassEx", GetLastError())); return JIM_ERR; } return JIM_OK; }
int DigitalWatchWindow::Create(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { char szWindowClass[100]; char szTitle[100]; sprintf((char *)&szWindowClass, "DIGITALWATCH_BDA"); sprintf((char *)&szTitle, "DigitalWatch"); g_pData->hWnd = FindWindowW(CA2W(szWindowClass), NULL); //LATER: Option for multiple instances if (g_pData->hWnd != NULL && !g_pData->settings.application.multiple) { (log << "An instance of Digital Watch is already running.\n Bringing the existing instance to the foreground.\n").Write(); SetForegroundWindow(g_pData->hWnd); return FALSE; } // if (g_pData->hWnd != NULL && g_pData->settings.application.multiple) // g_pData->values.application.multiple = g_pData->settings.application.multiple; HBRUSH br = CreateSolidBrush(0x00000000); WNDCLASSEXA wcex; wcex.cbSize = sizeof(WNDCLASSEXA); wcex.style = CS_DBLCLKS;// | CS_HREDRAW | CS_VREDRAW;// | CS_NOCLOSE | CS_DBLCLKS; wcex.lpfnWndProc = (WNDPROC)MainWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = 0; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_DIGITALWATCH); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = br; wcex.lpszMenuName = 0; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); ATOM ar = RegisterClassExA(&wcex); USES_CONVERSION; g_pData->hWnd = CreateWindowA(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW/*WS_THICKFRAME*/, CW_USEDEFAULT, 0, 726, 435, NULL, NULL, NULL, NULL); if (!g_pData->hWnd) { __int64 err = GetLastError(); //return_FALSE_SHOWMSG("Error creating window: " << err) return (log << "Error creating window: " << err << "\n").Show(); } SetWindowLong(g_pData->hWnd, GWL_STYLE, GetWindowLong(g_pData->hWnd, GWL_STYLE) & (~(WS_CAPTION/* | WS_BORDER*/))); if (g_pData->settings.window.startAtLastWindowPosition && g_pData->settings.loadedFromFile) { (log << "Restoring last window position. x=" << g_pData->values.window.position.x << " y=" << g_pData->values.window.position.y << " width=" <<g_pData->values.window.size.width << " height=" << g_pData->values.window.size.height << "\n").Write(); } BOOL bFullscreen = g_pData->values.window.bFullScreen; g_pData->values.window.bFullScreen = FALSE; g_pTv->SetWindowPos(g_pData->values.window.position.x, g_pData->values.window.position.y, g_pData->values.window.size.width, g_pData->values.window.size.height, g_pData->settings.window.startAtLastWindowPosition && g_pData->settings.loadedFromFile, TRUE); g_pData->values.window.bFullScreen = bFullscreen; ShowWindow(g_pData->hWnd, nCmdShow); UpdateWindow(g_pData->hWnd); if (g_pData->settings.window.startFullscreen != 0) { (log << "Restoring fullscreen state\n").Write(); g_pTv->Fullscreen(); } if (g_pData->settings.window.startAlwaysOnTop != 0) { (log << "Restoring always on top\n").Write(); g_pTv->AlwaysOnTop(); } return TRUE; }
int RetRotMainLoop() { isStarted = true; HWND hWnd; WNDCLASSEXA winc; MSG msg; HINSTANCE hInstance = GetModuleHandle(NULL); g_pixSz = Settings.initialPixelSize; g_fullScr = Settings.initialFullScrMode; ImmDisableIME((DWORD)-1); winc.cbSize = sizeof(WNDCLASSEX); winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = WndProc; winc.cbClsExtra = 0; winc.cbWndExtra = 0; winc.hInstance = hInstance; winc.hIcon = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(Settings.icon), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); winc.hIconSm = NULL; winc.hCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); winc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_MENU)); winc.lpszMenuName = NULL; winc.lpszClassName = "MAIN"; if (!RegisterClassExA(&winc)) { return 0; } SIZE sz = GetWindowSize(); if (Settings.WndMenu != NULL) { hWndMenu = Settings.WndMenu; } else { hWndMenu = LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(Settings.WndMenuID)); } hWnd = CreateWindowA( "MAIN", Settings.title, g_fullScr ? WS_FULLSCRMODE : (Settings.ScreenOnly ? WS_WINDOWMODE_NOFRAME : WS_WINDOWMODE), g_fullScr ? 0 : CW_USEDEFAULT, g_fullScr ? 0 : CW_USEDEFAULT, sz.cx, sz.cy, NULL, hWndMenu != NULL ? hWndMenu : NULL, hInstance, NULL ); if (hWnd == NULL) { return 0; } FpsControl fc; do { if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { BOOL ret = GetMessage(&msg, NULL, 0, 0); if (ret == 0 || ret == -1) { break; } DispatchMessage(&msg); } else { Sleep(1); } } while (msg.message != WM_QUIT); isStarted = false; return (int)msg.wParam; }
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE ignoreMe0, LPSTR ignoreMe1, INT ignoreMe2) { LPCSTR szName = "Pez App"; WNDCLASSEXA wc = { sizeof(WNDCLASSEX), CS_CLASSDC | CS_DBLCLKS, MsgProc, 0L, 0L, GetModuleHandle(0), 0, 0, 0, 0, szName, 0 }; DWORD dwStyle = WS_SYSMENU | WS_VISIBLE | WS_POPUP; DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; RECT rect; int windowWidth, windowHeight, windowLeft, windowTop; HWND hWnd; PIXELFORMATDESCRIPTOR pfd; HDC hDC; HGLRC hRC; int pixelFormat; GLenum err; MSG msg = {0}; LARGE_INTEGER previousTime; LARGE_INTEGER freqTime; wc.hCursor = LoadCursor(0, IDC_ARROW); RegisterClassExA(&wc); SetRect(&rect, 0, 0, PEZ_VIEWPORT_WIDTH, PEZ_VIEWPORT_HEIGHT); AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle); windowWidth = rect.right - rect.left; windowHeight = rect.bottom - rect.top; windowLeft = GetSystemMetrics(SM_XVIRTUALSCREEN) + GetSystemMetrics(SM_CXSCREEN) / 2 - windowWidth / 2; windowTop = GetSystemMetrics(SM_CYSCREEN) / 2 - windowHeight / 2; hWnd = CreateWindowExA(0, szName, szName, dwStyle, windowLeft, windowTop, windowWidth, windowHeight, 0, 0, 0, 0); // Create the GL context. ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cDepthBits = 0; pfd.cStencilBits = 0; pfd.iLayerType = PFD_MAIN_PLANE; hDC = GetDC(hWnd); pixelFormat = ChoosePixelFormat(hDC, &pfd); SetPixelFormat(hDC, pixelFormat, &pfd); hRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hRC); if (PEZ_ENABLE_MULTISAMPLING) { int pixelAttribs[] = { WGL_SAMPLES_ARB, 16, WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, WGL_SUPPORT_OPENGL_ARB, GL_TRUE, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, WGL_RED_BITS_ARB, 8, WGL_GREEN_BITS_ARB, 8, WGL_BLUE_BITS_ARB, 8, WGL_ALPHA_BITS_ARB, 8, WGL_DEPTH_BITS_ARB, 24, WGL_STENCIL_BITS_ARB, 8, WGL_DOUBLE_BUFFER_ARB, GL_TRUE, 0 }; int* sampleCount = pixelAttribs + 1; int* useSampleBuffer = pixelAttribs + 3; int pixelFormat = -1; PROC proc = wglGetProcAddress("wglChoosePixelFormatARB"); unsigned int numFormats; PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) proc; if (!wglChoosePixelFormatARB) { PezFatalError("Could not load function pointer for 'wglChoosePixelFormatARB'. Is your driver properly installed?"); } // Try fewer and fewer samples per pixel till we find one that is supported: while (pixelFormat <= 0 && *sampleCount >= 0) { wglChoosePixelFormatARB(hDC, pixelAttribs, 0, 1, &pixelFormat, &numFormats); (*sampleCount)--; if (*sampleCount <= 1) { *useSampleBuffer = GL_FALSE; } } // Win32 allows the pixel format to be set only once per app, so destroy and re-create the app: DestroyWindow(hWnd); hWnd = CreateWindowExA(0, szName, szName, dwStyle, windowLeft, windowTop, windowWidth, windowHeight, 0, 0, 0, 0); SetWindowPos(hWnd, HWND_TOP, windowLeft, windowTop, windowWidth, windowHeight, 0); hDC = GetDC(hWnd); SetPixelFormat(hDC, pixelFormat, &pfd); hRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hRC); } #define PEZ_TRANSPARENT_WINDOW 0 // For transparency, this doesn't seem to work. I think I'd need to read back from an OpenGL FBO and blit it with GDI. if (PEZ_TRANSPARENT_WINDOW) { long flag = GetWindowLong(hWnd, GWL_EXSTYLE); int opacity = 128; flag |= WS_EX_LAYERED; SetWindowLong(hWnd, GWL_EXSTYLE, flag); SetLayeredWindowAttributes(hWnd, 0, opacity, LWA_ALPHA); } err = glewInit(); if (GLEW_OK != err) { PezFatalError("GLEW Error: %s\n", glewGetErrorString(err)); } PezDebugString("OpenGL Version: %s\n", glGetString(GL_VERSION)); if (!PEZ_VERTICAL_SYNC) { wglSwapIntervalEXT(0); } if (PEZ_FORWARD_COMPATIBLE_GL) { const int contextAttribs[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 2, WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, 0 }; HGLRC newRC = wglCreateContextAttribsARB(hDC, 0, contextAttribs); wglMakeCurrent(0, 0); wglDeleteContext(hRC); hRC = newRC; wglMakeCurrent(hDC, hRC); } { const char* szWindowTitle = PezInitialize(PEZ_VIEWPORT_WIDTH, PEZ_VIEWPORT_HEIGHT); SetWindowTextA(hWnd, szWindowTitle); } QueryPerformanceFrequency(&freqTime); QueryPerformanceCounter(&previousTime); // ------------------- // Start the Game Loop // ------------------- while (msg.message != WM_QUIT) { if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { LARGE_INTEGER currentTime; __int64 elapsed; double deltaTime; QueryPerformanceCounter(¤tTime); elapsed = currentTime.QuadPart - previousTime.QuadPart; deltaTime = elapsed * 1000000.0 / freqTime.QuadPart; previousTime = currentTime; PezUpdate((unsigned int) deltaTime); PezRender(0); SwapBuffers(hDC); PezCheckCondition(glGetError() == GL_NO_ERROR, "OpenGL error.\n"); } } UnregisterClassA(szName, wc.hInstance); return 0; }
bool Win32Window::Initialize(const char* name, size_t width, size_t height) { Destroy(); IsMouseInWindow(false); parentClassName = name; childClassName = parentClassName + "_Child"; // Work around compile error from not defining "UNICODE" while Chromium does const LPSTR idcArrow = MAKEINTRESOURCEA(32512); WNDCLASSEXA parentWindowClass = { 0 }; parentWindowClass.cbSize = sizeof(WNDCLASSEXA); parentWindowClass.style = 0; parentWindowClass.lpfnWndProc = WndProc; parentWindowClass.cbClsExtra = 0; parentWindowClass.cbWndExtra = 0; parentWindowClass.hInstance = GetModuleHandle(NULL); parentWindowClass.hIcon = NULL; parentWindowClass.hCursor = LoadCursorA(NULL, idcArrow); parentWindowClass.hbrBackground = 0; parentWindowClass.lpszMenuName = NULL; parentWindowClass.lpszClassName = parentClassName.c_str(); if (!RegisterClassExA(&parentWindowClass)) { return false; } WNDCLASSEXA childWindowClass = { 0 }; childWindowClass.cbSize = sizeof(WNDCLASSEXA); childWindowClass.style = CS_OWNDC; childWindowClass.lpfnWndProc = WndProc; childWindowClass.cbClsExtra = 0; childWindowClass.cbWndExtra = 0; childWindowClass.hInstance = GetModuleHandle(NULL); childWindowClass.hIcon = NULL; childWindowClass.hCursor = LoadCursorA(NULL, idcArrow); childWindowClass.hbrBackground = 0; childWindowClass.lpszMenuName = NULL; childWindowClass.lpszClassName = childClassName.c_str(); if (!RegisterClassExA(&childWindowClass)) { return false; } DWORD parentStyle = WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU; DWORD parentExtendedStyle = WS_EX_APPWINDOW; RECT sizeRect = { 0, 0, static_cast<LONG>(width), static_cast<LONG>(height) }; AdjustWindowRectEx(&sizeRect, parentStyle, FALSE, parentExtendedStyle); parentWindow = CreateWindowExA( parentExtendedStyle, parentClassName.c_str(), name, parentStyle, CW_USEDEFAULT, CW_USEDEFAULT, sizeRect.right - sizeRect.left, sizeRect.bottom - sizeRect.top, NULL, NULL, GetModuleHandle(NULL), this ); nativeWindow = CreateWindowExA( 0, childClassName.c_str(), name, WS_CHILD, 0, 0, static_cast<int>(width), static_cast<int>(height), parentWindow, NULL, GetModuleHandle(NULL), this ); nativeDisplay = GetDC(nativeWindow); if (!nativeDisplay) { Destroy(); return false; } { Event event; event.Type = Event::EVENT_INIT_WINDOW; event.Time = GetTickCount64(); PushEvent(event); } return true; }
static DWORD WINAPI detectCDThread(LPVOID lpParameter) { const char *classname = "PhysicsFSDetectCDCatcher"; const char *winname = "PhysicsFSDetectCDMsgWindow"; HINSTANCE hInstance = GetModuleHandleW(NULL); ATOM class_atom = 0; WNDCLASSEXA wce; MSG msg; memset(&wce, '\0', sizeof (wce)); wce.cbSize = sizeof (wce); wce.lpfnWndProc = detectCDWndProc; wce.lpszClassName = classname; wce.hInstance = hInstance; class_atom = RegisterClassExA(&wce); if (class_atom == 0) { initialDiscDetectionComplete = 1; /* let main thread go on. */ return 0; } /* if */ detectCDHwnd = CreateWindowExA(0, classname, winname, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL); if (detectCDHwnd == NULL) { initialDiscDetectionComplete = 1; /* let main thread go on. */ UnregisterClassA(classname, hInstance); return 0; } /* if */ /* We'll get events when discs come and go from now on. */ /* Do initial detection, possibly blocking awhile... */ drivesWithMediaBitmap = pollDiscDrives(); initialDiscDetectionComplete = 1; /* let main thread go on. */ do { const BOOL rc = GetMessageW(&msg, detectCDHwnd, 0, 0); if ((rc == 0) || (rc == -1)) break; /* don't care if WM_QUIT or error break this loop. */ TranslateMessage(&msg); DispatchMessageW(&msg); } while (1); /* we've been asked to quit. */ DestroyWindow(detectCDHwnd); do { const BOOL rc = GetMessage(&msg, detectCDHwnd, 0, 0); if ((rc == 0) || (rc == -1)) break; TranslateMessage(&msg); DispatchMessageW(&msg); } while (1); UnregisterClassA(classname, hInstance); return 0; } /* detectCDThread */
/* * ::createGlInitContext */ BOOL createGlInitContext(GlInitContext *outCtx) { HINSTANCE hInst = GetModuleHandle(NULL); GLuint pixelFormat = 0; PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0 }; WNDCLASSEXA wndClass; if (outCtx == NULL) { return FALSE; } outCtx->hWnd = NULL; outCtx->hDC = NULL; outCtx->hRC = NULL; /* Register window class, if not yet available. */ if (!GetClassInfoExA(hInst, INITCTX_WNDCLASS_NAME, &wndClass)) { ZeroMemory(&wndClass, sizeof(WNDCLASSEX)); wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_CLASSDC; wndClass.lpfnWndProc = DefWindowProc; wndClass.hInstance = hInst; wndClass.lpszClassName = INITCTX_WNDCLASS_NAME; if (!RegisterClassExA(&wndClass)) { dbgPrint(DBGLVL_ERROR, "Registering window class for GL detours initialisation " "failed: %u\n", GetLastError()); return FALSE; } } /* Create window. */ if ((outCtx->hWnd = CreateWindowExA(WS_EX_APPWINDOW, INITCTX_WNDCLASS_NAME, "", WS_POPUP, 0, 0, 1, 1, NULL, NULL, hInst, NULL)) == NULL) { dbgPrint(DBGLVL_ERROR, "Creating window for GL detours initialisation failed:\n", GetLastError()); releaseGlInitContext(outCtx); return FALSE; } /* Create OpenGL context. */ outCtx->hDC = GetDC(outCtx->hWnd); if ((pixelFormat = ChoosePixelFormat(outCtx->hDC, &pfd)) == 0) { dbgPrint(DBGLVL_ERROR, "ChoosePixelFormat failed: %u\n", GetLastError()); releaseGlInitContext(outCtx); return FALSE; } if (!SetPixelFormat(outCtx->hDC, pixelFormat, &pfd)) { dbgPrint(DBGLVL_ERROR, "SetPixelFormat failed: %u\n", GetLastError()); releaseGlInitContext(outCtx); return FALSE; } if ((outCtx->hRC = wglCreateContext(outCtx->hDC)) == NULL) { dbgPrint(DBGLVL_ERROR, "wglCreateContext failed: %u\n", GetLastError()); releaseGlInitContext(outCtx); return FALSE; } if (!wglMakeCurrent(outCtx->hDC, outCtx->hRC)) { dbgPrint(DBGLVL_ERROR, "wglMakeCurrent failed: %u\n", GetLastError()); releaseGlInitContext(outCtx); return FALSE; } return TRUE; }
/****************************************************************** * WDML_CreateServerConv * * */ static WDML_CONV* WDML_CreateServerConv(WDML_INSTANCE* pInstance, HWND hwndClient, HWND hwndServerName, HSZ hszApp, HSZ hszTopic) { HWND hwndServerConv; WDML_CONV* pConv; if (pInstance->unicode) { WNDCLASSEXW wndclass; wndclass.cbSize = sizeof(wndclass); wndclass.style = 0; wndclass.lpfnWndProc = WDML_ServerConvProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 2 * sizeof(DWORD); wndclass.hInstance = 0; wndclass.hIcon = 0; wndclass.hCursor = 0; wndclass.hbrBackground = 0; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = WDML_szServerConvClassW; wndclass.hIconSm = 0; RegisterClassExW(&wndclass); hwndServerConv = CreateWindowW(WDML_szServerConvClassW, 0, WS_CHILD, 0, 0, 0, 0, hwndServerName, 0, 0, 0); } else { WNDCLASSEXA wndclass; wndclass.cbSize = sizeof(wndclass); wndclass.style = 0; wndclass.lpfnWndProc = WDML_ServerConvProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 2 * sizeof(DWORD); wndclass.hInstance = 0; wndclass.hIcon = 0; wndclass.hCursor = 0; wndclass.hbrBackground = 0; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = WDML_szServerConvClassA; wndclass.hIconSm = 0; RegisterClassExA(&wndclass); hwndServerConv = CreateWindowA(WDML_szServerConvClassA, 0, WS_CHILD, 0, 0, 0, 0, hwndServerName, 0, 0, 0); } TRACE("Created convServer=%04x (nameServer=%04x) for instance=%08lx\n", hwndServerConv, hwndServerName, pInstance->instanceID); pConv = WDML_AddConv(pInstance, WDML_SERVER_SIDE, hszApp, hszTopic, hwndClient, hwndServerConv); if (pConv) { SetWindowLongA(hwndServerConv, GWL_WDML_INSTANCE, (DWORD)pInstance); SetWindowLongA(hwndServerConv, GWL_WDML_CONVERSATION, (DWORD)pConv); /* this should be the only place using SendMessage for WM_DDE_ACK */ /* note: sent messages shall not use packing */ SendMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServerConv, MAKELPARAM(WDML_MakeAtomFromHsz(hszApp), WDML_MakeAtomFromHsz(hszTopic))); /* we assume we're connected since we've sent an answer... * I'm not sure what we can do... it doesn't look like the return value * of SendMessage is used... sigh... */ pConv->wStatus |= ST_CONNECTED; } else { DestroyWindow(hwndServerConv); } return pConv; }
bool NativeApp::PreInit() { COut(C_Info) << "Detecting video system..." << std::endl; //#define HACK_DISABLE_GL #if defined(RAD_OPT_GL) && !defined(HACK_DISABLE_GL) { WNDCLASSEXA clex; memset(&clex, 0, sizeof(WNDCLASSEXA)); clex.cbSize = sizeof(WNDCLASSEXA); clex.style = CS_OWNDC; clex.lpfnWndProc = DefWindowProc; clex.hInstance = s_hInstance; clex.lpszClassName = "rad_openGL_ini"; RegisterClassExA(&clex); } HWND wglWnd = CreateWindowA( "rad_openGL_ini", "", WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 0, 0, 100, 100, 0, 0, s_hInstance, 0 ); if (!wglWnd) { COut(C_Error) << "ERROR: Unable to create device window!" << std::endl; return false; } HDC wglDC = GetDC(wglWnd); { PIXELFORMATDESCRIPTOR pfd; memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cAlphaBits = 8; pfd.cDepthBits = 24; pfd.cStencilBits = 8; pfd.iLayerType = PFD_MAIN_PLANE; int pf = ChoosePixelFormat(wglDC, &pfd); if (pf < 1) { ReleaseDC(wglWnd, wglDC); DestroyWindow(wglWnd); COut(C_Error) << "ERROR: Unable to bind device window pixel format!" << std::endl; return false; } DescribePixelFormat(wglDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd); if (!SetPixelFormat(wglDC, pf, &pfd)) { COut(C_Error) << "ERROR: Unable to bind device window pixel format!" << std::endl; return false; } } HGLRC wglRC = myWglCreateContex(wglDC); if (!wglRC) { COut(C_Error) << "ERROR: Unable to create device window context!" << std::endl; return false; } wglMakeCurrent(wglDC, wglRC); PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); if (!wglGetExtensionsStringARB) { wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringEXT"); if (!wglGetExtensionsStringARB) { wglMakeCurrent(0, 0); wglDeleteContext(wglRC); ReleaseDC(wglWnd, wglDC); DestroyWindow(wglWnd); COut(C_Error) << "Unable to find wglGetExtensionsStringARB" << std::endl; return false; } } const char *wglStrings = wglGetExtensionsStringARB(wglDC); if (wglStrings) COut(C_Info) << "wglGetExtensionsStringARB: " << wglStrings << std::endl; if (!wglStrings || !string::strstr(wglStrings, "WGL_ARB_pixel_format")) { wglMakeCurrent(0, 0); wglDeleteContext(wglRC); ReleaseDC(wglWnd, wglDC); DestroyWindow(wglWnd); COut(C_Error) << "WGL_ARB_pixel_format is required but not found." << std::endl; return false; } bool multiSample = false; if (string::strstr(wglStrings, "WGL_ARB_multisample")) multiSample = true; PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB"); #endif DISPLAY_DEVICEA wdd; for (int i = 0; ; ++i) { wdd.cb = sizeof(DISPLAY_DEVICEA); if (!EnumDisplayDevicesA(0, (DWORD)i, &wdd, 0)) break; if (!(wdd.StateFlags&DISPLAY_DEVICE_ACTIVE)) continue; ::DisplayDevice::Ref _dd(new (ZEngine) ::DisplayDevice()); DisplayDevice *dd = &_dd->m_imp; dd->m_vars.reset(new (ZEngine) DDVars()); DDVars *ddv = DDVars::Get(dd->m_vars); memcpy(&ddv->dd, &wdd, sizeof(DISPLAY_DEVICEA)); if (wdd.StateFlags&DISPLAY_DEVICE_PRIMARY_DEVICE) { dd->m_primary = true; } else { dd->m_primary = false; } DEVMODEA dm; dm.dmSize = sizeof(DEVMODEA); BOOL r = EnumDisplaySettingsA(ddv->dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm); if (!r || ((dm.dmFields&kRequiredDMFields) != kRequiredDMFields)) { if (dd->m_primary) { // this is kinda bad COut(C_Error) << "ERROR: failed to enumerate primary display, initialization failed." << std::endl; return false; } continue; } if (!(dm.dmFields & DM_POSITION)) { // dmPosition is not valid, meaning we cannot identify this as secondary monitor... if (dd->m_primary) { dm.dmPosition.x = 0; dm.dmPosition.y = 0; dm.dmFields |= DM_POSITION; } else { continue; // this monitor cannot be identified. } } string::ncpy((char*)dm.dmDeviceName, wdd.DeviceName, 32); memcpy(&ddv->dm, &dm, sizeof(DEVMODEA)); dd->m_defMode = VidModeFromDevMode(dm); dd->m_curMode = dd->m_defMode; dd->m_maxMSAA = 0; dd->m_maxAnisotropy = 0; // enumerate valid display modes. COut(C_Info) << "Display " << i << ": '" << ddv->dd.DeviceName << " - " << ddv->dd.DeviceString << "':" << std::endl; for (int k = 0; ; ++k) { dm.dmSize = sizeof(DEVMODEA); if (!EnumDisplaySettingsA(ddv->dd.DeviceName, k, &dm)) break; if ((dm.dmFields&kRequiredDMFields) != kRequiredDMFields) continue; if (dm.dmBitsPerPel < 32) continue; r::VidMode m = VidModeFromDevMode(dm); r::VidModeVec::iterator it; for (it = dd->m_vidModes.begin(); it != dd->m_vidModes.end(); ++it) { r::VidMode &x = *it; if (x.w == m.w && x.h == m.h) { // matches. // prefer we use the same hz as our desktop... if (m.hz == dd->m_defMode.hz) x.hz = m.hz; break; } } if (it == dd->m_vidModes.end()) dd->m_vidModes.push_back(m); } for (r::VidModeVec::const_iterator it = dd->m_vidModes.begin(); it != dd->m_vidModes.end(); ++it) { const r::VidMode &m = *it; COut(C_Info) << "\t" << (it-dd->m_vidModes.begin()) << ": " << m.w << "x" << m.h << "x" << m.bpp << " @ " << m.hz << "hz" << std::endl; } if (dd->m_vidModes.empty()) { if (dd->m_primary) { COut(C_Error) << "ERROR: primary display '" << ddv->dd.DeviceName << "' is invalid, initialization failed." << std::endl; return false; } continue; } #if defined(RAD_OPT_GL) && !defined(HACK_DISABLE_GL) if (multiSample) { int maxSamples = 0; int reqAttribs[9] = { WGL_SUPPORT_OPENGL_ARB, WGL_DRAW_TO_WINDOW_ARB, WGL_ACCELERATION_ARB, WGL_PIXEL_TYPE_ARB, WGL_COLOR_BITS_ARB, WGL_ALPHA_BITS_ARB, WGL_DEPTH_BITS_ARB, WGL_STENCIL_BITS_ARB, WGL_SAMPLES_ARB }; int attribs[9]; // Enumerate all pixel formats, find highest multi-sample count for (int k = 1; ; ++k) { // PF's are 1 based if (!wglGetPixelFormatAttribivARB(wglDC, k, PFD_MAIN_PLANE, 9, reqAttribs, attribs)) break; if (attribs[0] != TRUE) continue; if (attribs[1] != TRUE) continue; if (attribs[2] != WGL_FULL_ACCELERATION_ARB) continue; if (attribs[3] != WGL_TYPE_RGBA_ARB) continue; if (attribs[4] < 24) continue; if (attribs[5] < 8) continue; if (attribs[6] < 24) continue; if (attribs[7] < 8) continue; if (maxSamples < attribs[8]) maxSamples = attribs[8]; if (maxSamples >= kMaxMultiSample) break; } dd->m_maxMSAA = maxSamples; } const char *glExt = (const char *)glGetString(GL_EXTENSIONS); if (glExt && string::strstr(glExt, "GL_EXT_texture_filter_anisotropic")) { GLint maxAnisotropy; glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy); dd->m_maxAnisotropy = maxAnisotropy; } #endif m_displayDevices.push_back(_dd); if (dd->m_primary) m_primaryDisplay = _dd; } if (!m_primaryDisplay) { COut(C_Error) << "ERROR: no primary display detected, initialization failed!" << std::endl; return false; } return true; }
int CALLBACK WinMain(HINSTANCE Instance, HINSTANCE PrevInstance, LPSTR CommandLine, int ShowCode) { win32_state Win32State = {}; LARGE_INTEGER PerfCounterFrequencyResult; QueryPerformanceFrequency(&PerfCounterFrequencyResult); GlobalPerfCounterFrequency = PerfCounterFrequencyResult.QuadPart; Win32GetEXEFileName(&Win32State); char SourceGameCodeDLLFullPath[WIN32_STATE_FILE_NAME_COUNT]; Win32BuildEXEPathFileName(&Win32State, "handmade.dll", sizeof(SourceGameCodeDLLFullPath), SourceGameCodeDLLFullPath); char TempGameCodeDLLFullPath[WIN32_STATE_FILE_NAME_COUNT]; Win32BuildEXEPathFileName(&Win32State, "handmade_temp.dll", sizeof(TempGameCodeDLLFullPath), TempGameCodeDLLFullPath); char GameCodeLockFullPath[WIN32_STATE_FILE_NAME_COUNT]; Win32BuildEXEPathFileName(&Win32State, "lock.tmp", sizeof(GameCodeLockFullPath), GameCodeLockFullPath); // NOTE: setting windows scheduler granularity for our sleep() call UINT DesiredSchedulerMS = 1; bool32 SleepIsGranular = (timeBeginPeriod(DesiredSchedulerMS) == TIMERR_NOERROR); Win32LoadXInput(); Win32ResizeDIBSection(&GlobalBackbuffer, 960, 540); #if HANDMADE_INTERNAL DEBUGGlobalShowCursor = true; #endif WNDCLASSEXA WindowClass = {}; WindowClass.style = CS_VREDRAW | CS_HREDRAW; WindowClass.cbSize = sizeof(WNDCLASSEXA); WindowClass.lpfnWndProc = Win32MainWindowCallback; WindowClass.hInstance = Instance; WindowClass.hCursor = LoadCursor(0, IDC_ARROW); // WindowClass.hIcon; WindowClass.lpszClassName = "HandmadeHeroWindowClass"; if (RegisterClassExA(&WindowClass)) { // WS_EX_TOPMOST|WS_EX_LAYERED HWND Window = CreateWindowExA(0, WindowClass.lpszClassName, "Handmade Hero", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 996, 600, 0, 0, Instance, 0); if (Window) { // TODO: reliably query this from windows int MonitorRefreshHz = 60; HDC RefreshDC = GetDC(Window); int Win32RefreshRate = GetDeviceCaps(RefreshDC, VREFRESH); ReleaseDC(Window, RefreshDC); if (Win32RefreshRate > 1) { MonitorRefreshHz = Win32RefreshRate; if (MonitorRefreshHz == 59) { MonitorRefreshHz = 60; } } real32 GameUpdateHz = MonitorRefreshHz / 2.0f; real32 TargetSecondsPerFrame = 1.0f / GameUpdateHz; // NOTE: sound test win32_sound_output SoundOutput = {}; SoundOutput.SamplesPerSecond = 48000; SoundOutput.BytesPerSample = sizeof(int16) * 2; SoundOutput.SecondaryBufferSize = SoundOutput.SamplesPerSecond * SoundOutput.BytesPerSample; // TODO: compute this variance and see what the lowest reasonable value is SoundOutput.SafetyBytes = (int)((real32)SoundOutput.SamplesPerSecond * (real32)SoundOutput.BytesPerSample / GameUpdateHz / 3.0f); Win32InitDSound(Window, SoundOutput.SamplesPerSecond, SoundOutput.SecondaryBufferSize); Win32ClearSoundBuffer(&SoundOutput); GlobalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING); GlobalRunning = true; // TODO: pool with bitmap virtualalloc int16 *Samples = (int16 *)VirtualAlloc(0, SoundOutput.SecondaryBufferSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); #if HANDMADE_INTERNAL LPVOID BaseAddress = (LPVOID)Terabytes(2); #else LPVOID BaseAddress = 0; #endif game_memory GameMemory = {}; GameMemory.PermanentStorageSize = Megabytes(64); GameMemory.TransientStorageSize = Gigabytes(1); GameMemory.DEBUGPlatformFreeFileMemory = DEBUGPlatformFreeFileMemory; GameMemory.DEBUGPlatformReadEntireFile = DEBUGPlatformReadEntireFile; GameMemory.DEBUGPlatformWriteEntireFile = DEBUGPlatformWriteEntireFile; // TODO: handle various memory footprints using system metrics // TODO: use MEM_LARGE_PAGES Win32State.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize; Win32State.GameMemoryBlock = VirtualAlloc(BaseAddress, (size_t)Win32State.TotalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); GameMemory.PermanentStorage = Win32State.GameMemoryBlock; GameMemory.TransientStorage = (uint8 *)GameMemory.PermanentStorage + GameMemory.PermanentStorageSize; for (int ReplayIndex = 1; ReplayIndex < ArrayCount(Win32State.ReplayBuffers); ++ReplayIndex) { // TODO: recording system still takes too long on record start win32_replay_buffer *ReplayBuffer = &Win32State.ReplayBuffers[ReplayIndex]; Win32GetInputFileLocation(&Win32State, false, ReplayIndex, sizeof(ReplayBuffer->FileName), ReplayBuffer->FileName); ReplayBuffer->FileHandle = CreateFileA(ReplayBuffer->FileName, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); LARGE_INTEGER MaxSize; MaxSize.QuadPart = Win32State.TotalSize; ReplayBuffer->MemoryMap = CreateFileMapping(ReplayBuffer->FileHandle, 0, PAGE_READWRITE, MaxSize.HighPart, MaxSize.LowPart, 0); ReplayBuffer->MemoryBlock = MapViewOfFile(ReplayBuffer->MemoryMap, FILE_MAP_ALL_ACCESS, 0, 0, (size_t)Win32State.TotalSize); if (!ReplayBuffer->MemoryBlock) { // TODO: diagnostic } } if (Samples && GameMemory.PermanentStorage && GameMemory.TransientStorage) { game_input Input[2] = {}; game_input *NewInput = &Input[0]; game_input *OldInput = &Input[1]; LARGE_INTEGER LastCounter = Win32GetWallClock(); LARGE_INTEGER FlipWallClock = Win32GetWallClock(); int DebugTimeMarkerIndex = 0; win32_debug_time_marker DebugTimeMarkers[30] = { 0 }; // TODO: handle startup specially bool32 SoundIsValid = false; DWORD AudioLatencyBytes = 0; real32 AudioLatencySeconds = 0; win32_game_code Game = Win32LoadGameCode(SourceGameCodeDLLFullPath, TempGameCodeDLLFullPath, GameCodeLockFullPath); uint64 LastCycleCount = __rdtsc(); while (GlobalRunning) { NewInput->FrameTimeDelta = TargetSecondsPerFrame; FILETIME NewDLLWriteTime = Win32GetLastWriteTime(SourceGameCodeDLLFullPath); if (CompareFileTime(&NewDLLWriteTime, &Game.DLLLastWriteTime) != 0) { Win32UnloadGameCode(&Game); Game = Win32LoadGameCode(SourceGameCodeDLLFullPath, TempGameCodeDLLFullPath, GameCodeLockFullPath); } // TODO: zeroing macro // TODO: we cant zero everything as the up/down state will be wrong game_controller_input *OldKeyboardController = GetController(OldInput, 0); game_controller_input *NewKeyboardController = GetController(NewInput, 0); *NewKeyboardController = {}; NewKeyboardController->IsConnected = true; for (int ButtonIndex = 0; ButtonIndex < ArrayCount(NewKeyboardController->Buttons); ++ButtonIndex) { NewKeyboardController->Buttons[ButtonIndex].EndedDown = OldKeyboardController->Buttons[ButtonIndex].EndedDown; } Win32ProcessPendingMessages(&Win32State, NewKeyboardController); if (!GlobalPause) { POINT MousePoint; GetCursorPos(&MousePoint); ScreenToClient(Window, &MousePoint); NewInput->MouseX = MousePoint.x; NewInput->MouseY = MousePoint.y; NewInput->MouseZ = 0; // TODO: support mousewheel? Win32ProcessKeyboardMessage(&NewInput->MouseButtons[0], GetKeyState(VK_LBUTTON) & (1 << 15)); Win32ProcessKeyboardMessage(&NewInput->MouseButtons[1], GetKeyState(VK_MBUTTON) & (1 << 15)); Win32ProcessKeyboardMessage(&NewInput->MouseButtons[2], GetKeyState(VK_RBUTTON) & (1 << 15)); Win32ProcessKeyboardMessage(&NewInput->MouseButtons[3], GetKeyState(VK_XBUTTON1) & (1 << 15)); Win32ProcessKeyboardMessage(&NewInput->MouseButtons[4], GetKeyState(VK_XBUTTON2) & (1 << 15)); // TODO: should we poll this more frequently // TODO: dont poll disconnected controllers to prevent xinput frame rate impact DWORD MaxControllerCount = XUSER_MAX_COUNT; if (MaxControllerCount > (ArrayCount(NewInput->Controllers) - 1)) { MaxControllerCount = (ArrayCount(NewInput->Controllers) - 1); } for (DWORD ControllerIndex = 0; ControllerIndex < MaxControllerCount; ++ControllerIndex) { DWORD OurControllerIndex = ControllerIndex + 1; game_controller_input *OldController = GetController(OldInput, OurControllerIndex); game_controller_input *NewController = GetController(NewInput, OurControllerIndex); XINPUT_STATE ControllerState; if (XInputGetState(ControllerIndex, &ControllerState) == ERROR_SUCCESS) { NewController->IsConnected = true; NewController->IsAnalog = OldController->IsAnalog; // TODO: See if ControllerState.dwPacketNumber increments too rapidly XINPUT_GAMEPAD *Pad = &ControllerState.Gamepad; // TODO: currently handling a square deadzone, check if it is circular NewController->StickAverageX = Win32ProcessXInputStickValue(Pad->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); NewController->StickAverageY = Win32ProcessXInputStickValue(Pad->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); if ((NewController->StickAverageX != 0.0f) || (NewController->StickAverageY != 0.0f)) { NewController->IsAnalog = true; } if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_UP) { NewController->StickAverageY = 1.0f; NewController->IsAnalog = false; } if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN) { NewController->StickAverageY = -1.0f; NewController->IsAnalog = false; } if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT) { NewController->StickAverageX = -1.0f; NewController->IsAnalog = false; } if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) { NewController->StickAverageX = 1.0f; NewController->IsAnalog = false; } real32 Threshold = 0.5f; Win32ProcessXInputDigitalButton((NewController->StickAverageX < -Threshold) ? 1 : 0, &OldController->MoveLeft, 1, &NewController->MoveLeft); Win32ProcessXInputDigitalButton((NewController->StickAverageX > Threshold) ? 1 : 0, &OldController->MoveRight, 1, &NewController->MoveRight); Win32ProcessXInputDigitalButton((NewController->StickAverageY < -Threshold) ? 1 : 0, &OldController->MoveDown, 1, &NewController->MoveDown); Win32ProcessXInputDigitalButton((NewController->StickAverageY > Threshold) ? 1 : 0, &OldController->MoveUp, 1, &NewController->MoveUp); Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionDown, XINPUT_GAMEPAD_A, &NewController->ActionDown); Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionRight, XINPUT_GAMEPAD_B, &NewController->ActionRight); Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionLeft, XINPUT_GAMEPAD_X, &NewController->ActionLeft); Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionUp, XINPUT_GAMEPAD_Y, &NewController->ActionUp); Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->LeftShoulder, XINPUT_GAMEPAD_LEFT_SHOULDER, &NewController->LeftShoulder); Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->RightShoulder, XINPUT_GAMEPAD_RIGHT_SHOULDER, &NewController->RightShoulder); Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->Start, XINPUT_GAMEPAD_START, &NewController->Start); Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->Back, XINPUT_GAMEPAD_BACK, &NewController->Back); } else { // NOTE: the controller is not available NewController->IsConnected = false; } } thread_context Thread = {}; game_offscreen_buffer Buffer = {}; Buffer.Memory = GlobalBackbuffer.Memory; Buffer.Width = GlobalBackbuffer.Width; Buffer.Height = GlobalBackbuffer.Height; Buffer.Pitch = GlobalBackbuffer.Pitch; Buffer.BytesPerPixel = GlobalBackbuffer.BytesPerPixel; if (Win32State.InputRecordingIndex) { Win32RecordInput(&Win32State, NewInput); } if (Win32State.InputPlaybackIndex) { Win32PlaybackInput(&Win32State, NewInput); } if (Game.UpdateAndRender) { Game.UpdateAndRender(&Thread, &GameMemory, NewInput, &Buffer); } LARGE_INTEGER AudioWallClock = Win32GetWallClock(); real32 FromBeginToAudioSeconds = Win32GetSecondsElapsed(FlipWallClock, AudioWallClock); DWORD PlayCursor; DWORD WriteCursor; if (GlobalSecondaryBuffer->GetCurrentPosition(&PlayCursor, &WriteCursor) == DS_OK) { /* NOTE: Sound output explanation We define a safety value that is the number of samples we think our game update loop can vary by. When we wake up to write audio we look at the play cursor position and forecast where we think it will be on the next frame boundary. If the write cursor is before that by at least our safety value, the target fill position is the frame boundary plus one frame. This gives us perfect audio sync if the audio latency is low enough. If the write cursor is after that safety value then we assume we can't sync the audio so we write one frames worth of audio plus the safety values worth of samples. */ if (!SoundIsValid) { SoundOutput.RunningSampleIndex = WriteCursor / SoundOutput.BytesPerSample; SoundIsValid = true; } DWORD ByteToLock = (SoundOutput.RunningSampleIndex * SoundOutput.BytesPerSample) % SoundOutput.SecondaryBufferSize; DWORD ExpectedSoundBytesPerFrame = (int)((real32)(SoundOutput.SamplesPerSecond * SoundOutput.BytesPerSample) / GameUpdateHz); real32 SecondsLeftUntilFlip = TargetSecondsPerFrame - FromBeginToAudioSeconds; DWORD ExpectedBytesUntilFlip = (DWORD)((SecondsLeftUntilFlip / TargetSecondsPerFrame) * (real32)ExpectedSoundBytesPerFrame); DWORD ExpectedFrameBoundaryByte = PlayCursor + ExpectedBytesUntilFlip; DWORD SafeWriteCursor = WriteCursor; if (SafeWriteCursor < PlayCursor) { SafeWriteCursor += SoundOutput.SecondaryBufferSize; } Assert(SafeWriteCursor >= PlayCursor); SafeWriteCursor += SoundOutput.SafetyBytes; bool32 AudioCardIsLowLatency = (SafeWriteCursor < ExpectedFrameBoundaryByte); DWORD TargetCursor = 0; if (AudioCardIsLowLatency) { TargetCursor = ExpectedFrameBoundaryByte + ExpectedSoundBytesPerFrame; } else { TargetCursor = WriteCursor + ExpectedSoundBytesPerFrame + SoundOutput.SafetyBytes; } TargetCursor = TargetCursor % SoundOutput.SecondaryBufferSize; DWORD BytesToWrite = 0; if (ByteToLock > TargetCursor) { BytesToWrite = SoundOutput.SecondaryBufferSize - ByteToLock; BytesToWrite += TargetCursor; } else { BytesToWrite = TargetCursor - ByteToLock; } game_sound_output_buffer SoundBuffer = {}; SoundBuffer.SamplesPerSecond = SoundOutput.SamplesPerSecond; SoundBuffer.SampleCount = BytesToWrite / SoundOutput.BytesPerSample; SoundBuffer.Samples = Samples; if (Game.GetSoundSamples) { Game.GetSoundSamples(&Thread, &GameMemory, &SoundBuffer); } #if HANDMADE_INTERNAL win32_debug_time_marker *Marker = &DebugTimeMarkers[DebugTimeMarkerIndex]; Marker->OutputPlayCursor = PlayCursor; Marker->OutputWriteCursor = WriteCursor; Marker->OutputLocation = ByteToLock; Marker->OutputByteCount = BytesToWrite; Marker->ExpectedFlipPlayCursor = ExpectedFrameBoundaryByte; DWORD UnwrappedWriteCursor = WriteCursor; if (UnwrappedWriteCursor < PlayCursor) { UnwrappedWriteCursor += SoundOutput.SecondaryBufferSize; } AudioLatencyBytes = UnwrappedWriteCursor - PlayCursor; AudioLatencySeconds = ((real32)AudioLatencyBytes / (real32)SoundOutput.BytesPerSample) / (real32)SoundOutput.SamplesPerSecond; #if 0 char DebugSoundBuffer[256]; sprintf_s(DebugSoundBuffer, "BTL:%u TC:%u BTW:%u - PC:%u WC:%u DELTA:%u (%fs)\n", ByteToLock, TargetCursor, BytesToWrite, PlayCursor, WriteCursor, AudioLatencyBytes, AudioLatencySeconds); OutputDebugStringA(DebugSoundBuffer); #endif #endif Win32FillSoundBuffer(&SoundOutput, ByteToLock, BytesToWrite, &SoundBuffer); } else { SoundIsValid = false; } LARGE_INTEGER WorkCounter = Win32GetWallClock(); real32 WorkSecondsElapsed = Win32GetSecondsElapsed(LastCounter, WorkCounter); // TODO: not tested yet! real32 SecondsElapsedForFrame = WorkSecondsElapsed; if (SecondsElapsedForFrame < TargetSecondsPerFrame) { if (SleepIsGranular) { DWORD SleepMS = (DWORD)(1000.0f * (TargetSecondsPerFrame - SecondsElapsedForFrame)); if (SleepMS > 0) { Sleep(SleepMS); } } real32 TestSecondsElapsedForFrame = Win32GetSecondsElapsed(LastCounter, Win32GetWallClock()); if (TestSecondsElapsedForFrame < TargetSecondsPerFrame) { // TODO: log missed sleep here } while (SecondsElapsedForFrame < TargetSecondsPerFrame) { SecondsElapsedForFrame = Win32GetSecondsElapsed(LastCounter, Win32GetWallClock()); } } else { // TODO: missed frame rate // TODO: logging } LARGE_INTEGER EndCounter = Win32GetWallClock(); real32 MSPerFrame = 1000.0f * Win32GetSecondsElapsed(LastCounter, EndCounter); LastCounter = EndCounter; win32_window_dimension Dimension = Win32GetWindowDimension(Window); HDC BufferDC = GetDC(Window); Win32DisplayBufferInWindow(&GlobalBackbuffer, BufferDC, Dimension.Width, Dimension.Height); ReleaseDC(Window, BufferDC); FlipWallClock = Win32GetWallClock(); #if HANDMADE_INTERNAL DWORD DebugPlayCursor; DWORD DebugWriteCursor; if (GlobalSecondaryBuffer->GetCurrentPosition(&DebugPlayCursor, &DebugWriteCursor) == DS_OK) { Assert(DebugTimeMarkerIndex < ArrayCount(DebugTimeMarkers)); win32_debug_time_marker *Marker = &DebugTimeMarkers[DebugTimeMarkerIndex]; Marker->FlipPlayCursor = DebugPlayCursor; Marker->FlipWriteCursor = DebugWriteCursor; } #endif game_input *Temp = NewInput; NewInput = OldInput; OldInput = Temp; // TODO: should these be cleared? #if 0 uint64 EndCycleCount = __rdtsc(); uint64 CyclesElapsed = EndCycleCount - LastCycleCount; LastCycleCount = EndCycleCount; // real32 FPS = (real32)GlobalPerfCounterFrequency / (real32)CounterElapsed; real32 FPS = 0.0f; real32 MCPF = (real32)CyclesElapsed / (1000.0f * 1000.0f); char DebugPerformanceBuffer[256]; sprintf_s(DebugPerformanceBuffer, "%0.02fmspf, %0.02ffps, %0.02fmcpf\n", MSPerFrame, FPS, MCPF); OutputDebugStringA(DebugPerformanceBuffer); #endif #if HANDMADE_INTERNAL ++DebugTimeMarkerIndex; if (DebugTimeMarkerIndex == ArrayCount(DebugTimeMarkers)) { DebugTimeMarkerIndex = 0; } #endif } } } else { // TODO: logging } } else { // TODO: logging } } else { // TODO: logging } return(0); }