Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mimicking Acrylic in a Win32 app

Microsoft recently announced Acrylic, the glass-like material in Fluent Design. It's presented as XAML / UWP only, but looks very similar to glass, except it can be arbitrarily tinted and can apply in-app to flyover controls as well as to the app's standalone windows.

The 'recipe' makes it appear as though it's implemented in XAML itself, not being exposed to the wider system.

Microsoft's recipe for making acrylic: background, blue, blend, tint, noise

A related SO question confirms this (it's devoid of concrete, technical answers, but implies acrylic isn't available through the WinAPI the way glass is.)

How would someone mimic this in a plain old Win32 app? Using glass, and blending? (Which APIs, and what's possible in Win10 Fall Update's glass APIs that was not in Win7?) If the app was created with Win32 but used a DirectX surface for rendering, would it open more possibilities?

like image 339
David Avatar asked May 16 '17 11:05

David


4 Answers

As mentioned in @zett42's answer, I think it is implemented using DirectComposition.

A little bit of history: With Vista, Microsoft introduced the Desktop Window Manager, DWM, which is a compositing engine for the Desktop. With DWM, windows draw to textures, which are then combined in the DWM. The benefits are that you can get fancy effects like 3D animations, transparency, etc. and everything is double-buffered, so you get no rendering artifacts.

The DWM originally was based on MIL (Media integration layer), which was a scenegraph API I think. Interestingly, WPF which was introduced around that time also used MIL. This was really cool because DWM could see the scene graph of a WPF window, and when it would so effects, such as zooming in a window, it would see it as vectors and not as a bitmap, so it could scale it without artifacts. However, at some point Microsoft forked the version of MIL used in WPF, and this integration was lost.

Fast forward a few years to Windows 8. Microsoft introduced new "Metro" apps (later "Modern", and now "UWP"). Under the hood, these modern apps use a new API for composition, DirectComposition. This API is also available to Win32 apps, and it is now used by DWM itself. If you look at the public DWM functions, some related to MIL are deprecated, so it supports my theory that MS moved away from MIL and towards DC. So now that we are in the initial situation again where apps as well as the DWM use the same infrastructure, we can easily add some interesting effects.

At some point, MS has introduced new blending effects to DirectComposition, provided by the IDCompositionDevice3 interface. Among those is a gaussan blur effect, but also noise, tint, and other effects neccessary. I found a way to apply these effects within my window, but I don't know how to apply them to my window. Unfortunately, I don't have access to my code right now, I'll update my answer when I do.

I based my exploration on the article Efficient Alpha-Blended Windows: DirectComposition. Basically, you have a "Device" corresponding to the screen, and a "Visual" corresponding your window contents. What you have to change is:

  • Your Device can create Effects for you. Remember to QueryInterface it to IDCompositionDevice3.
  • Then, you can call SetEffect on your IDCompositionVisual3.

However, as I said, this only applies to the window contents. I think there must be a secret API to get a parent Visual to the current window from the DWM, and then it should be just a matter of calling SetEffect on that Visual to get the effect. If somebody is skilled with a debugger, it should be possible to find that API by tracing a UWP app that uses the Acyllic effect.

As a shot in the blue, I would look at the GetWindowCompositionAttribute function. It recently gained some interesting sounding flags, such as WCA_VISUAL_OWNER.

like image 168
jdm Avatar answered Nov 20 '22 08:11

jdm


In Latest windows 10 device we can combine DWM API and Direct Composition API to recreate the acrylic effect in Win32. In newer Windows we can copy the contents of DWM Thumnail into IDComposition Visual and it can be used to recreate the backdrop for acrylic.

Then the backdrop can be transferred to IDCompositionGaussianBlurEffect to blur the backdrop.

Here is a working Example :Win32 Acrylic Effect

But I highly don't recommend it for production.

like image 20
trickymind Avatar answered Nov 20 '22 08:11

trickymind


Rafael Rivera posted a small demo app how to use Acrylic Blur in Desktop applications since Windows 10 v1803 (Build 17134.x - RS4 - April 2018 Update)

enter image description here

Basically the enum AccentState has a new entry ACCENT_ENABLE_ACRYLICBLURBEHIND = 4.

like image 9
magicandre1981 Avatar answered Nov 20 '22 08:11

magicandre1981


I think it would be possible to mimic this using Win32 API or at least create a result that comes close.

  • The blur and tinting could be achieved using undocumented SetWindowCompositionAttribute(), which you already linked. This functionality has to be provided by DWM, which is certainly true even for the XAML implementation.
  • I'm not sure what the exclusion blend is supposed to do, at least from the downscaled screenshots on the MS page, it appears to be neglible.
  • The noise texture should be straightforward to do as it's propably just alpha-blended... well... noise. Use a random generator or maybe some perlin noise function?

You may also look into Direct Composition, possibly combined with the WS_EX_NOREDIRECTIONBITMAP extended window style, as explained in the article "High-Performance Window Layering Using the Windows Composition Engine". I have not used this technology yet, but the article states that XAML is based on Direct Composition, which should open up all possibilities.

like image 5
zett42 Avatar answered Nov 20 '22 09:11

zett42