Skip to content

Instantly share code, notes, and snippets.

@Jjagg
Last active June 14, 2020 20:25
Show Gist options
  • Save Jjagg/771ef52e9bcfc89a6abc4331efe22a72 to your computer and use it in GitHub Desktop.
Save Jjagg/771ef52e9bcfc89a6abc4331efe22a72 to your computer and use it in GitHub Desktop.
Create a GIF with ImageSharp in MonoGame by storing old frames. MIT license: https://opensource.org/licenses/MIT
using System;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.PixelFormats;
namespace ImageSharpMg
{
/// <summary>
/// Render frames to render targets and create a GIF by pressing 'S'.
/// </summary>
public class Game1 : Game
{
[STAThread]
static void Main()
{
using (var game = new Game1())
game.Run();
}
private const int FrameCount = 180;
private const int Width = 320;
private const int Height = 180;
private const float Speed = 0.5f;
private SpriteBatch _spriteBatch;
private Texture2D _blank;
private int _currentIndex;
private Color[][] _frameBuffers;
private RenderTarget2D _renderTarget;
private Rgba32[] _rgbaBuffer;
private const int SquareSize = 32;
private float _squarePos = -32;
private KeyboardState _prevKeyboardState;
private KeyboardState _keyboardState;
public Game1()
{
var graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
graphics.PreferredBackBufferWidth = Width;
graphics.PreferredBackBufferHeight = Height;
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
_blank = new Texture2D(GraphicsDevice, 1, 1);
_blank.SetData(new[] {Color.White.PackedValue});
_renderTarget = new RenderTarget2D(GraphicsDevice, Width, Height);
_frameBuffers = new Color[FrameCount][];
for (var i = 0; i < FrameCount; i++)
_frameBuffers[i] = new Color[Width * Height];
_rgbaBuffer = new Rgba32[Width * Height];
}
private void SaveImage()
{
using (var image = new Image<Rgba32>(Width, Height))
{
var frames = image.Frames;
for (var i = 1; i <= FrameCount; i++)
{
var frameIndex = (_currentIndex + i) % FrameCount;
ConvertColorData(_frameBuffers[frameIndex], _rgbaBuffer);
var frame = frames.AddFrame(_rgbaBuffer);
frame.MetaData.FrameDelay = 2;
}
var encoder = new GifEncoder();
using (var stream = File.OpenWrite("test.gif"))
image.SaveAsGif(stream, encoder);
}
}
private static void ConvertColorData(Color[] mgBuffer, Rgba32[] isBuffer)
{
for (var i = 0; i < mgBuffer.Length; i++)
{
var c = mgBuffer[i];
isBuffer[i] = new Rgba32(c.R, c.G, c.B, c.A);
}
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
_prevKeyboardState = _keyboardState;
_keyboardState = Keyboard.GetState();
if (_prevKeyboardState.IsKeyUp(Keys.S) && _keyboardState.IsKeyDown(Keys.S))
SaveImage();
_squarePos += Speed;
if (_squarePos > Width)
_squarePos = -32f;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
// render the scene to the active render target
GraphicsDevice.SetRenderTarget(_renderTarget);
GraphicsDevice.Clear(Color.CornflowerBlue);
_spriteBatch.Begin();
_spriteBatch.Draw(_blank, new Rectangle((int) _squarePos, 74, SquareSize, SquareSize), Color.White);
_spriteBatch.End();
// Render it to the backbuffer
GraphicsDevice.SetRenderTarget(null);
_spriteBatch.Begin();
_spriteBatch.Draw(_renderTarget, Vector2.Zero, Color.White);
_spriteBatch.End();
// store the pixel data
_renderTarget.GetData(_frameBuffers[_currentIndex]);
_currentIndex = (_currentIndex + 1) % FrameCount;
base.Draw(gameTime);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment