How do I draw transparent DirectX content in a transparent window?
Asked Answered
K

4

5

I want to draw DirectX content so that it appears to be floating over top of the desktop and any other applications that are running. I also need to be able to make the directx content semi-transparent, so other things show through. Is there a way of doing this?

I am using Managed DX with C#.

Kyoko answered 29/9, 2008 at 11:5 Comment(2)
Aren't layered windows an option?Decidua
msdn.microsoft.com/en-us/library/ms997507.aspxDecidua
K
5

I found a solution which works on Vista, starting from the link provided by OregonGhost. This is the basic process, in C# syntax. This code is in a class inheriting from Form. It doesn't seem to work if in a UserControl:

//this will allow you to import the necessary functions from the .dll
using System.Runtime.InteropServices;

//this imports the function used to extend the transparent window border.
[DllImport("dwmapi.dll")]
static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMargins);

//this is used to specify the boundaries of the transparent area
internal struct Margins {
    public int Left, Right, Top, Bottom;
}
private Margins marg;

//Do this every time the form is resized. It causes the window to be made transparent.
marg.Left = 0;
marg.Top = 0;
marg.Right = this.Width;
marg.Bottom = this.Height;
DwmExtendFrameIntoClientArea(this.Handle, ref marg);

//This initializes the DirectX device. It needs to be done once.
//The alpha channel in the backbuffer is critical.
PresentParameters presentParameters = new PresentParameters();
presentParameters.Windowed = true;
presentParameters.SwapEffect = SwapEffect.Discard;
presentParameters.BackBufferFormat = Format.A8R8G8B8;

Device device = new Device(0, DeviceType.Hardware, this.Handle,
CreateFlags.HardwareVertexProcessing, presentParameters);

//the OnPaint functions maked the background transparent by drawing black on it.
//For whatever reason this results in transparency.
protected override void OnPaint(PaintEventArgs e) {
    Graphics g = e.Graphics;

    // black brush for Alpha transparency
    SolidBrush blackBrush = new SolidBrush(Color.Black);
    g.FillRectangle(blackBrush, 0, 0, Width, Height);
    blackBrush.Dispose();

    //call your DirectX rendering function here
}

//this is the dx rendering function. The Argb clearing function is important,
//as it makes the directx background transparent.
protected void dxrendering() {
    device.Clear(ClearFlags.Target, Color.FromArgb(0, 0, 0, 0), 1.0f, 0);

    device.BeginScene();
    //draw stuff here.
    device.EndScene();
    device.Present();
}

Lastly, a Form with default setting will have a glassy looking partially transparent background. Set the FormBorderStyle to "none" and it will be 100% transparent with only your content floating above everything.

Kyoko answered 30/9, 2008 at 8:57 Comment(0)
N
6

You can either use DirectComposition, LayeredWindows, DesktopWindowManager or WPF. All methods come with their advantages and disadvantages:

-DirectComposition is the most efficient one, but needs Windows 8 and is limited to 60Hz.

-LayeredWindows are tricky to get working with D3D via Direct2D-interop using DXGI.

-WPF is relatively easy to use via D3DImage, but is also limited to 60Hz and DX9 and no MSAA. Interops to higher DX-Versions via DXGI are possible, also MSAA can be used when the MSAA-Rendertarget is resolved to the native nonMSAA surface.

-DesktopWindowManager is great for high performance available since Windows Vista, but DirectX-Versions seem to be limited by the Version the DWM uses (still DX9 on Vista). Workarounds for higher DX-Versions should be possible via DXGI where available.

If you don't need per pixel aplha, you can also use the opacity-value of a semi-transparent form.

Or you use the native Win32 method for the Window global alpha (Remember a alpha of 0 will not catch the mouse input):

SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
COLORREF color = 0;
BYTE alpha = 128;
SetLayeredWindowAttributes(hWnd, color, alpha, LWA_ALPHA);

I have been able to use all of the described techniques with C# and SharpDX, but in case of DirectComposition, LayeredWindows and native Win32 a little C++-Wrappercode was needed. For starters I would suggest to go via WPF.

Neurogram answered 18/1, 2015 at 13:2 Comment(0)
K
5

I found a solution which works on Vista, starting from the link provided by OregonGhost. This is the basic process, in C# syntax. This code is in a class inheriting from Form. It doesn't seem to work if in a UserControl:

//this will allow you to import the necessary functions from the .dll
using System.Runtime.InteropServices;

//this imports the function used to extend the transparent window border.
[DllImport("dwmapi.dll")]
static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMargins);

//this is used to specify the boundaries of the transparent area
internal struct Margins {
    public int Left, Right, Top, Bottom;
}
private Margins marg;

//Do this every time the form is resized. It causes the window to be made transparent.
marg.Left = 0;
marg.Top = 0;
marg.Right = this.Width;
marg.Bottom = this.Height;
DwmExtendFrameIntoClientArea(this.Handle, ref marg);

//This initializes the DirectX device. It needs to be done once.
//The alpha channel in the backbuffer is critical.
PresentParameters presentParameters = new PresentParameters();
presentParameters.Windowed = true;
presentParameters.SwapEffect = SwapEffect.Discard;
presentParameters.BackBufferFormat = Format.A8R8G8B8;

Device device = new Device(0, DeviceType.Hardware, this.Handle,
CreateFlags.HardwareVertexProcessing, presentParameters);

//the OnPaint functions maked the background transparent by drawing black on it.
//For whatever reason this results in transparency.
protected override void OnPaint(PaintEventArgs e) {
    Graphics g = e.Graphics;

    // black brush for Alpha transparency
    SolidBrush blackBrush = new SolidBrush(Color.Black);
    g.FillRectangle(blackBrush, 0, 0, Width, Height);
    blackBrush.Dispose();

    //call your DirectX rendering function here
}

//this is the dx rendering function. The Argb clearing function is important,
//as it makes the directx background transparent.
protected void dxrendering() {
    device.Clear(ClearFlags.Target, Color.FromArgb(0, 0, 0, 0), 1.0f, 0);

    device.BeginScene();
    //draw stuff here.
    device.EndScene();
    device.Present();
}

Lastly, a Form with default setting will have a glassy looking partially transparent background. Set the FormBorderStyle to "none" and it will be 100% transparent with only your content floating above everything.

Kyoko answered 30/9, 2008 at 8:57 Comment(0)
L
2

I guess that will be hard without using the Desktop Window Manager, i.e. if you want to support Windows XP. With the DWM, it seems to be rather easy though.

If speed is not an issue, you may get away with rendering to a surface and then copying the rendered image to a layered window. Don't expect that to be fast though.

Latia answered 29/9, 2008 at 11:12 Comment(1)
A pain that only works with dx9, since DWM in Vista is dx9. Windows 7 will use dx10, so that will be nice.Doublehung
P
1

WPF is also another option.

Developed by Microsoft, the Windows Presentation Foundation (or WPF) is a computer-software graphical subsystem for rendering user interfaces in Windows-based applications.

Photobathic answered 27/10, 2008 at 10:7 Comment(2)
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes.Diplocardiac
Notice how this was answered nearly 4 years ago, during the beta? Questions and answers back then were experimental. This is certainly not a brilliant answer, but it is an answer and a viable one at that. The link is valid as is the content.Photobathic

© 2022 - 2024 — McMap. All rights reserved.