How to render in the title bar with D3D11 in Windows 7? - c++

I have a program that renders to a D3D11 swapchain created with IDXGIFactory2::CreateSwapChainForHwnd. It clears the swap chain to a particular color, specifically green, and draws a textured rectangle. Following the guide at https://learn.microsoft.com/en-us/windows/desktop/dwm/customframe, I extended the window caption downward using DwmExtendFrameIntoClientArea and I extended the client area to the entire window by handling the WM_NCCALCSIZE message. When the swap chain is presented, the contents of the swap chain buffer is drawn on top of the window, completely covering the DWM-drawn glass frame and caption buttons. How can I leave regions of the glass frame and caption buttons to be drawn by DWM while still drawing in the window frame using D3D11?
I have already tried to clear the RenderTargetView to a color of {0.0f, 0.0f, 0.0f, 0.0f} with ID3D11DeviceContext::ClearRenderTargetView but the alpha component appears to be ignored. I've tried to specify DXGI_ALPHA_MODE_STRAIGHT and DXGI_ALPHA_MODE_PREMULTIPLIED in the AlphaMode member of the DXGI_SWAP_CHAIN_DESC1 used to create the swap chain, but it crashes because alpha-blended swapchains must be created by CreateSwapChainForComposition or CreateSwapChainForCoreWindow. Those functions are not viable since I would like to support Windows 7.
Another thing I've tried is creating a blend state and making parts of the texture transparent. All this does is blend the transparent parts of texture with the clear color. Nothing is getting rendered by DWM though.

Related

How to change the background color of a dxgi swap chain?

I recently ported my app from using an ID2D1HwndRenderTarget to using an ID2D1DeviceContext with a dxgi swap chain. With an hwnd render target I can have a transparent background by calling pRT->Clear({});(not a transparent window, only the render target itself is transparent, so I can see whatever content underneath it). That's not the case with a dxgi swap chain, the background is always black, even if no drawing is done on that area. How can I change this behavior and have a see through render target?

Draw semi transparent shadow around Window

I'm trying to do something like what Auslogics Disk Defrag does with its custom window:
As can be seen, the blurred semi transparent shadow surrounding the window is much darker than the standard one, so the program must be drawing it by itself. The problem is, I can't find a way to paint anything transparent around a window.
In an answer to a similiar question, someone suggested creating a slightly bigger transparent window (using WS_EX_LAYERED + SetLayeredWindowAttributes()) behind the actual application window, and then do the translucent drawing on the transparent one. Not only does it sound like an ugly hack, it doesn't actually work. If, for example, one tries to draw a semi transparent black rectangle on a transparent window via GDI+, alpha blending is applied to the shape's color over the window background color (which would also be the transparency color) and then the shape is drawn with the calculated color, which obviously is not the window transparency, resulting in an opaque rectangle.
The semi transparent shadow is actually done by Gaussian Blur of the black square.
You can use this effect to create glows and drop shadows and use the
composite effect to apply the result to the original image. It is
useful in photo processing for filters like highlights and shadows.
You can use the output of this effect for input into lighting effects,
like the Specular Lighting or Diffuse Lighting effects, because the
alpha channel is blurred, too and lighting effects use the alpha
channel to determine surface geometry as a height map.
This effect is used by the built-in Shadow effect.
Refer: Gaussian blur effect
Then remove the standard frame, the entire window is your client area, so you can draw shadow in the extended frame.
Refer: Drawing in the Extended Frame Window
I think I've found a solution that works for me. I was hoping I wouldn't have to create an extra window just for the shadow, but every method I could find or think of would require me to draw all the controls by myself and/or somehow correct their alpha values.
So, I'm using a layered window with per pixel alpha. I paint over it with Direct2D, or, alternatively, I use some PNGs with transparency for the edges and corners of the shadow and copy them on a memory DC. Either way I simply recreate the shadow with the right dimensions when the window is resized, and call UpdateLayeredWindowIndirect. Both methods seem to be working well on Windows 7 and 10, and so far I haven't found any glitches.
Preventing it from showing on the taskbar was a bit tricky. All the ways I know have drawbacks. What worked best for me was making the layered window owned by the main one. At least that way it will only be visible on the desktop where the program is actually running, unlike other alternatives which would force it to show on every virtual desktop. Finally, because I disable that window, I interact with it by processing WM_SETCURSOR.

Draw OpenGL to an offscreen bitmap

I've inherited a project which renders a 3D scene directly to the window using OpenGL. The code works fine, but we're now drawing an icon onto the 3D view to "Exit 3D view mode". This also works fine, but results in a lot of flickering as the view is rapidly rotated.
I'd like to be able to draw to an off-screen bitmap (ie. without a HWND), then draw my icon to the bitmap, then finally StretchBlt the bitmap to the window using double-buffering. We do this in other contexts (such as zooming into an image which does not need OpenGL) and it works great. My problem is that I am an OpenGL novice and all attempts at starting with the DC of the off-screen bitmap and creating a HWND from this DC fail, usually because of selecting a pixel format for the DC.
There are a few questions asking similar things here on StackOverflow (eg. this question without an accepted answer. Is this possible ? If so is there a relatively straightforward tutorial describing the procedure? If the process is extremely complex requiring detailed OpenGL knowledge, then I may just have to leave it and live with the flickering because it is a rarely used mode in our software.
Just draw the Icon using OpenGL using a textured quad.
All this draw to a bitmap copy to DC StretchBlt involves several roundtrips from and to graphics memory (wastes bandwidth) and StretchBlt will likely not be GPU accelerated. All in all what you want to do is inefficient and may even reduce quality.
I presume you have the icon stored in your executable as a resource. The most simple way to go about it is to create a memory DC (CreateCompatibleDC) with a DIBSECTION (CreateDIBSection), draw the icon to that and load the DIBSECTION data into a OpenGL texture. Then to draw the icon use glViewport to select the destination rectangle in window coordinates, use an identity transform to draw a rectangle covering the whole viewport (position values (-1,1)→(1,1), texture coordinate values (0,0)→(1,1) gives you the right outcome).
Important side fix: In case your program does silly things like setting viewport and the fixed function pipeline GL_PROJECTION matrix in a window resize handler you should clean up that anti pattern and move this to where it belongs: In the drawing code.

glClear() not obeying scissor region [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm drawing Open GL content (direct Win32 - not using GLUT, FreeGLUT, GLFW, etc) using double buffering in an arbitrary Windows 7 window which is already open, for example, a Windows Notepad window. I have the window handle and can draw the content I want as expected, but I am seeing strange behavior with the glClear() function.
It is my understanding that the glClear() function should only affect pixels on the screen which are INSIDE the region defined by the glScissor() function. I have defined the scissor region with glScissor() and then enabled the scissor function using glEnable(GL_SCISSOR_TEST). glClearColor is set to white (0,0,0,1). I'm clearing both color and depth buffers with the glClear() command.
When the SwapBuffers() command is executed in order to render on the screen, my selected clear color of white is painted inside the scissor region as I requested, but the rest of the window OUTSIDE the scissor region is painted black, rather than leaving these pixels untouched as I expected.
As shown in the image, the scissor region (white) and the object (3D cube) are drawn correctly, but the rest of the notepad window's pixels are set to black, and anything previously painted in that Notepad window is covered over.
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // white background
glViewport(0, 0, 300, 300);
glScissor(0, 0, 250, 400);
glEnable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//... draw cube inside glBegin()/glEnd()...
SwapBuffers(hDC);
If I get your description correctly, glClear works as intended.
You must not assume that only because you see something on the screen, it is also present in the back buffer. The contents of the Notepad window that you see is either the front buffer, or a copy of the front buffer that was blitted into DWM's own secret render buffer (depending on whether you have compositing or not). Or, something else, a GDI buffer that was blitted to DWM's buffer, or such. Most likely the latter, since it's using GDI to render.
When you flip buffers, the back buffer is displayed over anything that's on-screen in that regin, and what you get is an all-black buffer (actually uninitialized, but presumably the driver was so kind as to zero the memory) except for the area that you cleared to white.
Which is exactly what you should expect -- your glClear affected only a subregion, and the rest is undefined, it happened to be zero (black).
Incidentially, if no compositing is enabled what you can see on-screen can be copied from the front buffer to the back buffer on most graphic cards, so you would be able to still see the original contents of the Notepad window if you wished to have it that way. You will however never have the contents of a GDI window in your back buffer magically (nor will this work with DWM, nor is it something that is guaranteed to work, it only works incidentially most of the time).
The clean solution, if you want the window's original contents, would be to BitBlt from the DC to memory, create a texture, and draw (or blit) that one into the back buffer.

ID2D1HwndRenderTarget always having black background instead of transparent

I am trying to create a simple transparent window where I can draw with Direct2D.
So far what I have done:
Created window
Set style to WS_EX_LAYERED
Set alpha color key as #FFF
Draw using Windows Graphics a white rectangle
Now window is transparent with per-pixel alpha
Then make a target out of the window and draw using Direct2D
Make ALPHA _PREMULIPLIED target
Clear with #FFF with 0.0f alpha
Window is now black
I just don't know how to make window to transparent. If you can point out my mistake, I would be obliged
Here how it's achievable using DirectComposition API
Russian: http://www.oszone.net/25395/
English: https://msdn.microsoft.com/magazine/dn745861.aspx
Basically what author does is
Sets WS_EX_NOREDIRECTIONBITMAP extended style to remove redirection bitmap of DWM. Content of window is now empty.
Creates DirectComposition device
Creates Composition SwapChain (and not hwnd swapchain)
Places one visual with SwapChain as content as root visual.
Renders into SwapChain using Direct2D API.
It also works well with WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOPMOST for creating event-transparent overlays.
I don't think it's possible with directX. However GDI does work.
Take a look at the source here to see how it's done: http://pastebin.com/NJf8wi2V
In the source you can see that there is an option to attempt to use directx/opengl. However as you can see from running they do not work.