Someone the other day tweeted a link to some very cool animated gifs. I love animated gifs !!
I have always wanted animated gifs in Silverlight/WPF BUT for reasons unknown they never came. They would have been perfect for A LOT of scenarios where creating storyboard animations would have been overkill.
Well turns out WinRT XAML, firmly rooted in Silverlight XAML, also doesn’t have GIF support nor will it probably ever get it. BUT it does have WinRT support and it has access to DirectX & WIC via SharpDx!!
And today on Twitter Jeremiah Morrill tweeted that WIC has support for GIF’s, this intrigued me. Can I build my own support for animated gifs in XAML using DirectX & WIC (via SharpDx) ?!
Challenge is on ……
This is the animated gif I will try to render…
Source : “Savannah Rain” (frommetoyou)
Default XAML/C# metro app project + SharpDx
I created an empty managed metro project and added the necessary SharpDx bits, basically like I have been over the last several posts.
As always this project has a effect renderer that will render to a (Direct2D or Direct3D) surface via a (SwapChainBackgroundPanel or SurfaceImageSource). Again this is what I’ve been doing in all my SharpDx posts to date so just go back to those or the samples if you’ve forgotten
Animated GIF resource
Now just add the Animated GIF as a content resource to the project. I could load it in via a URI BUT I thought it would be easier to just include it for now .
Load GIF via WIC
Ok this is where it gets interesting, SharpDx gives us access to WIC from C#. Question is does it have the GIF bits.
As I’ve said many times before SharpDx is a very thin/performant wrapper over C++ libraries (but just to clarify there will always be an overhead to using WIC via this wrapper even thou it is small). This wrapper is a metadata mapping generated api so technically the GIF bits of WIC should have come across. Lets test it out.
Lets instantiate a WIC GIFDecoder that will be used to read the animated GIF resource. The “asset” is simple the internal uri to the gif content.
Next when we animate this gif we need to know how many frames to animate. The GIF spec defines this…
Now for each frame we want to get the bitmap of that layer and store it for rendering. There is a lot going on in this code BUT in a nutshell an object is created that lets us get at the bytes of data for a particular frame in the gif. (its easy to follow just step through the code , that’s how I learnt
As it turns out for GIFS the first layer normally has the entire bitmap contents of the GIF and all the other frames above that contain delta information.. Also the ‘delta’ frames are all offseted so we need to get the offset (left,top) of those frames and store them for rendering of that frame later on..
So assuming that SharpDx’s GIF WIC works fine that’s basically all we need information wise.. We just need a way to store those frames and render them to the UI.
…. hello SpriteBatch
The best way to render a series of textures in the graphics world is via a spritebatch. Lets create a very very dirty one that will serve our purposes ..
I’m not going to go into too much detail of how this dirty spritebatch works, it’s not in the truest sense a spritebatch BUT it will do for now..
This spritebatch will keep a cache of the GIFs frames that I will render on a DirectX Surface. I’ve defined 2 lists to store the static frames ( 0 ) and the rotating frames ( 1 – 7 )
I’ve created a way to add sprites (frames) to my spritebatch via the methods
1. DrawAlways – sprites that will always get rendered on each loop of the rendering pipeline eg. frame 0 of the aimated gif
2. DrawRotating – sprites that will rotate there appearance with each loop of the rendering pipeline eg. frames 1 to 7 of the animated gif
These methods are called when we are decoding our GIF (the section prior to this outlined this process)
The sprite batch, as expected, has the ability to render itself and all it’s sprites. In my example it will render on a D2D surface and will use the much loved BitmapEffect to render the layer .
Also note that the offset(_texturesRotatedOffset) for the layer needs to be rendered for the 1-7 frames
Now if you don’t understand the above just step through the code, it will all make sense..
Does this all work ?!
Does SharpDx’s support for WIC GIF’s work for animated gifs ?!
Running the demo
Here’s some awesome gifs from a very cool site
Here’s the metro xaml/c# demo running one of those animated gifs. Note that the framerate is low because of the simultaneous video recording going on. Without it it runs buttery smooth at 65-70fps.
I started out this experiment fully expecting it NOT to work… I was so surprised that it actually did . Animated gifs in a XAML managed metro app!!! Damn!!
XAML/WinRT + DirectX/WIC (via SharpDx) is turning into a killer combination of features for building pretty amazing new experiences. I’m only now getting familiar with the frameworks, I can’t wait to see what I’ll be creating a month from now!
I’m loving XAML/DirectX …