My main window has some child windows that contain movies managed by Media Foundation. The main window is drawn using Direct2D. I'm not doing any clipping when drawing the main window with Direct2D because I expect this to be done by BeginPaint in my WM_PAINT.
When my window is rather small, everything is drawn fine. However, when I maximize it to a 4096x2304px resolution, there is visible flicker and I can quickly see the stuff drawn by Direct2D beneath the Media Foundation child windows before Media Foundation draws its contents to them so it looks like Direct2D clipping doesn't really happen.
Is this true? Do I have to manually set up a Direct2D clipping region to prevent it from overdrawing the Media Foundation child windows or am I doing something wrong here? My main window has WS_CLIPCHILDREN set.
Related
I am developing a 2D video game and trying to implement a good fullscreen extension to the game maker, Clickteam Fusion.
I've tried using SetWindowPos and I can get the window to look the correct size, but then when using the Steam Overlay the overlay is showing offscreen because it is using the initial window size I set in the game maker.
it is clear that the SetWindowPos is just shrinking the window to fit the aspect ratio of my monitor, but the game still is acting like the game is still the initial window size so content gets loaded that is actually outside the display, including Steam Overlay notifications and such.
Is there a better Windows API command I can use to actually adjust a game window?
Is it possible to use the trick with overriding wm_nccalcsize to draw over entire window area with opengl?
I need to keep all aero features for windows (win 7 in this case), so i use (WS_POPUP | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME) styles
It works fine for maximized mode, I can leave the border outside the screen by adjusting the Lparam.
But a regular window still has 8px borders around it, even though they are supposedly part of client rect (which I checked with GetClientRect()
Image: dark-grey border is visible
And this is all done before I init opengl context. So I dont know what's happening. Or if this even possible. Am I supposed to just create borderless and re-implement all aero features? (no way I'm doing that)
upd 2:
If I draw a rect with GDI right before I init Opengl context this is what i get:
a nice (0,0,200,200) rect, starting in the nonclient area
So it is opengl context issue. I saw in msdn docs, that opengl draws only in client area. And it still does that, ignoring that I extended the client rect to whole window. siiiigh.
The usual way to combine Aero with OpenGL is to set the window client area using the DWM API to zero. This allows you to draw to the whole window (including titlebar) using OpenGL. I have this test program to tinker with it as part of my wglarb wrapper:
https://github.com/datenwolf/wglarb/blob/master/test/layered.c
You may also be interested in my dwm_load wrapper, which allows to you call DWM functions without rigidly linking your program against DWM (which makes it incompatible with older Windows versions; you wouldn't believe how often I still get "must run on WinXP" as a feature requirement) https://github.com/datenwolf/dwm_load
We need to overlay a target window with a custom shape and tracks the position of the target window such that the overlay drawing always appears above it. Also, the overlay drawing should appear in screenshots taken using BitBlt or PrintClient by screen-capturing tools like Camtasia, Debut, etc. Also, moving the target window around should not leave traces of the drawing at earlier location. The target window is not made using our code.
So far we've tried several ways but each method has its problems:
1) Layered Window:
Using a layered window as the child/owned window of the target window is the easiest thing and it works. But the problem is on Windows 7 and XP, layered windows do not appear in a BitBlt done without the CAPTUREBLT flag and the screen-capturing tools may call BitBlt without the flag, thereby skipping our window from the capture.
2) Region Window:
The crude approach to support all Windows versions then is to use a region window using SetWindowRgn and make the target window its owner. However, region windows are generally very slow in rendering complex shapes and also impact the performance of other windows, sometimes to the point of freezing the application. Region window also leaves traces on dragging the application window.
3) Subclassing and Drawing on HDC:
Another approach is to sub-class the target window and draw the shape on its HDC on the OnPaint() event inside the window procedure hook. The shape can be drawn on the desktop window instead too. The problem is that applications may draw without a paint event, like when some text is selected using the cursor, and such drawing may erase a part of the custom drawing. Tracking all possible paint events is not a good way to do this.
4) Drawing continuously in a timer:
The last resort is to draw the custom shape on the target window in a timer continuously so the drawing is always above the target, even on text selection. But this may show a bit of flicker when the text is selected. Not to mention, it is very performance heavy to draw constantly.
Question
What is the best way to achieve an overlay drawing which works on all Windows versions (since XP) at the same time appearing in screen-captures. We've exhausted all approaches. Is there some method I'm missing? Can the above mentioned ways be used with some improvement? Is DirectX an option? I'm looking for methods with fast rendering capacity to achieve this. Appreciate any help!
I think the best solution to draw an overlay window, is to use a double-buffered technique GDI, just like in this example:
Overlay Drawing in CScrollView
I have myself the same task, and the only solution was that one. Hope it help you.
I've written an application that overlays a transparent window over the screen. The transparent window is created by applying WS_EX_LAYERED style to it, and calling SetLayeredWindowAttributes(
hWnd,
RGB(0,0,255),
127,
LWA_ALPHA
);
I just run into a problem that when this transparent window is over Media Player that plays a video, the transparent region simply becomes gray and I can't see through it.
Why is that? And what can I possibly do to see the contents of Media Player through the transparent window?
I'm not sure about the following but it is what I believe it may be based on my knowledge.
Usually an overlay surface is created in the rectangle area that plays the video for hardware acceleration purposes and video card controls it (well... an application thru some api like directx controls it)
The overlay surface is draw over, let's call it, the gdi/window surface that usually is painted in black by the application.
And that's why you see the black/grey in the background.
I am drawing to a regular HwndRengerTarget but other windows, which have nothing to do with Direct2D, overlap it.
The problem is that these windows get painted over when I draw to the HwndRengerTarget.
I would like to tell Direct2D not to touch a specific region of the HwndRengerTarget (i.e. don't touch the pixels that are already on the screen), so that these windows remain correctly visible.
Is that possible?
If I draw normally then call RedrawWindow on the windows, it flickers a lot.
Thanks.
If you want to manually restrict your rendering to a certain region you can use layers (ID2D1Layer objects).
More info here Layers Overview
If the visible region is rectangular it may be simpler to use axis aligned clips via methods PushAxisAlignedClip and PopAxisAlignedClip.
ID2D1RenderTarget::PushAxisAlignedClip
Another method of restricting drawing to a certain shape is to render it to a bitmap and then use this bitmap via a bitmap brush in the FillGeomtry method.
ID2D1RenderTarget::FillGeometry
Why not arrange the windows (HWNDs) so that the Direct2D one is at the bottom of the z-index? It should be the first child of its parent. Then clipping will be automatic. You may need the WS_CLIPSIBLINGS window style.
I had the same problem.
Fixed by calling CreateWindowEx LAST for the D2D child HWND.
So AFTER all the other child windows are created.