Last active
June 14, 2020 20:25
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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