Creating a double buffer with GDI, as well as transparency.
A custom Win32 window can be made transparent by using the dwExStyle's WS_EX_LAYERED and WS_EX_TRANSPARENT as well as the dwStyle WS_POPUPWINDOW so I'll have a certain frame.
hWnd = CreateWindowEx( WS_EX_LAYERED | WS_EX_TRANSPARENT, "MainClass", "Window Title", WS_POPUPWINDOW, CW_USEDEFAULT, /* int X position. */ CW_USEDEFAULT, /* int Y position. */ 240, /* int Width. */ 120, /* int Height. */ NULL, NULL, hInstance, NULL ); // // Sets up our window with the transparency it needs. // Styles via CreateWindowEx() takes care of the rest. // WS_POPUPWINDOW gives us a thin frame. // WS_EX_LAYERED is needed by the function below. // WS_EX_TRANSPARENT lets us interact with the game below. // SetLayeredWindowAttributes(hWnd, RGB(255, 255, 255), NULL, LWA_COLORKEY);
Never write to another GDI device (your potential overlay target) that a few bad tutorials will have you do. This will cause flicker and mess with game performance and makes absolutely no sense to do on purpose. What DOES make sense is creating a simple double buffered algorithm so it does its own thing and the layer will be perfect without flicker. GDI is perfectly suitable for representing X,Y data and I include this as it's suitable for entire 2D game developments, not just overlays. Double buffer sample code:
// Global variables, reuse instead of recreate. HBRUSH BgBrush; HFONT font; HDC hdc, BufferDC; HBITMAP BufferBitmap; COLORREF TrueWhite = RGB(255,255,255); // Our "white whatever" color since true white will be transparent. COLORREF White = RGB(224,224,224); // Example window size. int cx = 1980; int cy = 1080; // // Create a double buffer for the drawing. Draw on back-HDC and flip // it later to the front-HDC. Resulting in a single update per frame. // BufferDC = CreateCompatibleDC(hdc); BufferBitmap = CreateCompatibleBitmap(hdc, cx, cy); SelectObject(BufferDC, BufferBitmap); // // Overwrite current BG to avoid artifacts from last frame. // Achieve transparency by using same color as used with: // SetLayeredWindowAttributes (in WinMain). // BgBrush = CreateSolidBrush(TrueWhite); FillRect(BufferDC, &GameClientRect, BgBrush); DeleteObject(BgBrush); // // Do your drawing here... 3D/2D Radar/ESP, debug info, etc. // // // Write the back buffer to the front and clean up. // BitBlt(hdc, 0, 0, cx, cy, BufferDC, 0, 0, SRCCOPY); DeleteObject(BufferBitmap); DeleteDC(BufferDC);
Then you just move the window over whatever you want and keep it there with a HWND_TOPMOST in the main loop.