Anyway todays entry is about loading animated gifs in MDX. The process is rather simple since the .Net Bitmap class takes care of all the work [smile].
Currently though it just stores all the seperate frames as individual textures, which seems like a bad idea for batching. What I'd like to do is make it into one big sprite sheet. The problem is that I can't figure out how to read pixels from the bitmap. I tried creating a Graphics object around the Bitmap, but that doesn't seem to do what I want. Anyone have any ideas?
I figured it out. Now it builds a large sprite sheet in memory and generates a texture from that. It reads the frames in a horizontal fashion and makes sure not to go past the maximum texture width, so you can load large animated gifs. Unfortunately if you go past both the max width and max height, then you're totally fucked [grin].
I've left the simpler texture array version below.
Image time(as usual).
The gif I'm loading:
The result:
The (new) codes:
using System;using Diagnostics = System.Diagnostics;using Drawing = System.Drawing;using DirectX = Microsoft.DirectX;using Direct3D = Microsoft.DirectX.Direct3D;namespace Test{ public class GifSprite { public readonly int FrameHeight = 0; public readonly int FramesHorizontal = 0; public readonly int Frames = 0; public readonly int FramesVertical = 0; public readonly int FrameWidth = 0; public readonly int Height = 0; private static Direct3D.Sprite Sprite = null; private Direct3D.Texture Texture = null; private Drawing.Rectangle[] RectangleArray = null; public readonly int Width = 0; public GifSprite( string FileName, Direct3D.Device Device ) { if( Sprite == null ) { Sprite = new Direct3D.Sprite( Device ); } Drawing.Image GifImage = Drawing.Image.FromFile( FileName ); Drawing.Graphics GifImageGraphics = null; FrameWidth = GifImage.Width; FrameHeight = GifImage.Height; Frames = GifImage.GetFrameCount( new Drawing.Imaging.FrameDimension( GifImage.FrameDimensionsList[0] ) ); FramesHorizontal = Device.DeviceCaps.MaxTextureWidth / FrameWidth; if( FramesHorizontal > Frames ) { FramesHorizontal = Frames; FramesVertical = 1; } else { FramesVertical = ( Frames / FramesHorizontal ) + ( ( Frames % FramesHorizontal > 0 ) ? 1 : 0 ); } Width = FramesHorizontal * FrameWidth; Height = FramesVertical * FrameHeight; Drawing.Bitmap Bitmap = new Drawing.Bitmap( Width, Height ); Drawing.Graphics BitmapGraphics = Drawing.Graphics.FromImage( Bitmap ); RectangleArray = new Drawing.Rectangle[Frames]; for( int i = 0; i < Frames; i++ ) { RectangleArray = new Drawing.Rectangle( ( i % FramesHorizontal ) * FrameWidth, ( i / FramesHorizontal ) * FrameHeight, FrameWidth, FrameHeight ); GifImage.SelectActiveFrame( new Drawing.Imaging.FrameDimension( GifImage.FrameDimensionsList[0] ), i ); GifImageGraphics = Drawing.Graphics.FromImage( GifImage ); BitmapGraphics.DrawImage( GifImage, RectangleArray ); } Texture = new Direct3D.Texture( Device, Bitmap, Direct3D.Usage.SoftwareProcessing, Direct3D.Pool.Managed ); return; } ~GifSprite() { if( Texture != null ) { if( Texture.Disposed == false ) { Texture.Dispose(); } } return; } public static void Begin( Direct3D.SpriteFlags SpriteFlags ) { Sprite.Begin( SpriteFlags ); return; } public void Draw( int X, int Y, int Frame, Drawing.Color Color ) { Sprite.Draw( Texture, RectangleArray[Math.Abs(Frame)%Frames], DirectX.Vector3.Empty, new DirectX.Vector3( X, Y, 0.1f ), Color.ToArgb() ); return; } public static void End() { Sprite.End(); return; } } }
Here's what the generated sprite sheet looks like(thanks to Bitmap.Save):
The (old) codes:
using System;using Diagnostics = System.Diagnostics;using Drawing = System.Drawing;using DirectX = Microsoft.DirectX;using Direct3D = Microsoft.DirectX.Direct3D;namespace Test{ public class GifSprite { public int Frames { get { return TextureArray.Length; } } private static Direct3D.Sprite Sprite = null; private Direct3D.Texture[] TextureArray = null; public GifSprite( string FileName, Direct3D.Device Device ) { if( Sprite == null ) { Sprite = new Direct3D.Sprite( Device ); } Drawing.Bitmap Bitmap = new Drawing.Bitmap( FileName ); TextureArray = new Direct3D.Texture[ Bitmap.GetFrameCount( new Drawing.Imaging.FrameDimension(Bitmap.FrameDimensionsList[0] ) ) ]; for( int i = 0; i < Frames; i++ ) { Bitmap.SelectActiveFrame( new Drawing.Imaging.FrameDimension( Bitmap.FrameDimensionsList[0] ), i ); TextureArray = new Direct3D.Texture( Device, Bitmap, Direct3D.Usage.SoftwareProcessing, Direct3D.Pool.Managed ); } return; } public static void Begin( Direct3D.SpriteFlags SpriteFlags ) { Sprite.Begin( SpriteFlags ); return; } public void Draw( int X, int Y, int Frame, Drawing.Color Color ) { Sprite.Draw( TextureArray[Math.Abs(Frame)%Frames], DirectX.Vector3.Empty, new DirectX.Vector3( X, Y, 0.1f ), Color.ToArgb() ); return; } public static void End() { Sprite.End(); return; } } }
The great benefit of using this method is that MDX would take care of any conversions that need to take place from the bitmap format to the texture format.
Also, cool gif.
Hope this helps :)