PKHeX/PKHeX.WinForms/Controls/SAV Editor/BitmapAnimator.cs
Kurt 94baab1c45
Split off image generation to separate project (#2395)
With the approaching games, PKM sprites are a different size from the 3DS era (as already hinted by LGPE, which has 56x68). It'll be a little easier to manage with this portion of the library walled off from the rest of the codebase.

Eventually the net46 target will use fody or something to merge in these extra dependency dll's automatically to not disturb the usual exe/dll experience.
2019-09-29 09:47:06 -07:00

107 lines
No EOL
3.5 KiB
C#

using System;
using System.Drawing;
using System.Timers;
using System.Windows.Forms;
using PKHeX.Drawing;
using Timer = System.Timers.Timer;
namespace PKHeX.WinForms.Controls
{
public sealed class BitmapAnimator : Timer
{
public BitmapAnimator(Image extraLayer = null)
{
ExtraLayer = extraLayer;
Elapsed += TimerElapsed;
}
private int imgWidth;
private int imgHeight;
private byte[] GlowData;
private readonly Image ExtraLayer;
private Image[] GlowCache;
public Image OriginalBackground;
private readonly object Lock = new object();
private PictureBox pb;
private int GlowInterval;
private int GlowCounter;
public int GlowFps { get; set; } = 60;
public Color GlowToColor { get; set; } = Color.LightSkyBlue;
public Color GlowFromColor { get; set; } = Color.White;
public new void Start() => throw new ArgumentException();
public new void Stop()
{
if (pb == null || !Enabled)
return;
lock (Lock)
{
Enabled = false;
pb.BackgroundImage = OriginalBackground;
}
// reset logic
GlowCounter = 0;
for (int i = 0; i < GlowCache.Length; i++)
GlowCache[i] = null;
}
public void Start(PictureBox pbox, Image baseImage, byte[] glowData, Image original)
{
Enabled = false;
imgWidth = baseImage.Width;
imgHeight = baseImage.Height;
GlowData = glowData;
GlowCounter = 0;
GlowCache = new Image[GlowFps];
GlowInterval = 1000 / GlowFps;
Interval = GlowInterval;
lock (Lock)
{
pb = pbox;
OriginalBackground = original;
}
Enabled = true;
}
private void TimerElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{
if (!Enabled)
return; // timer canceled, was waiting to proceed
GlowCounter = (GlowCounter + 1) % (GlowInterval * 2); // loop backwards
int frameIndex = GlowCounter >= GlowInterval ? (GlowInterval * 2) - GlowCounter : GlowCounter;
lock (Lock)
{
if (!Enabled)
return;
try { pb.BackgroundImage = GetFrame(frameIndex); } // drawing GDI can be silly sometimes #2072
catch (AccessViolationException ex) { System.Diagnostics.Debug.WriteLine(ex.Message); }
}
}
private Image GetFrame(int frameIndex)
{
var frame = GlowCache[frameIndex];
if (frame != null)
return frame;
var elapsedFraction = (double)frameIndex / GlowInterval;
var frameColor = GetFrameColor(elapsedFraction);
var frameData = (byte[])GlowData.Clone();
ImageUtil.ChangeAllColorTo(frameData, frameColor);
frame = ImageUtil.GetBitmap(frameData, imgWidth, imgHeight);
if (ExtraLayer != null)
frame = ImageUtil.LayerImage(frame, ExtraLayer, 0, 0);
frame = ImageUtil.LayerImage(OriginalBackground, frame, 0, 0);
return GlowCache[frameIndex] = frame;
}
private Color GetFrameColor(double elapsedFraction) => ImageUtil.Blend(GlowToColor, GlowFromColor, elapsedFraction);
}
}