227 lines
11 KiB
C#
Raw Normal View History

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace RBG_Server
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
2021-10-17 16:04:08 +13:00
public static App Context { get; private set; }
public GameServer BoardGameServer {get;}
2021-10-17 16:04:08 +13:00
public CommunicationHandler GameCommunicationHandler { get; private set;}
protected static readonly SolidColorBrush RED_BRUSH = new(Color.FromRgb(255, 0, 0));
protected static readonly SolidColorBrush BLUE_BRUSH = new(Color.FromRgb(0, 0, 255));
protected static readonly SolidColorBrush GREEN_BRUSH = new(Color.FromRgb(0, 255, 0));
public const string MIP_LOW = "_mip_low";
public const string MIP_MEDIUM = "_mip_med";
public const string MIP_HIGH = "_mip_high";
public const string MIP_RAW = "_mip_raw";
/// <summary>
/// Loads the specified files from disk, creating mip maps as appropriate
/// </summary>
/// <param name="selectedFiles"></param>
/// <param name="isSprite"></param>
/// <param name="spriteLimit"></param>
void LoadFiles(string[] selectedFiles, bool isSprite=false, int spriteLimit=128)
{
// Continue in parallel
_ = Parallel.ForEach(selectedFiles, (file) =>
{
LoadFile(file);
});
}
/// <summary>
/// Loads a singular file from disk, generating Mip maps as required
/// </summary>
/// <param name="path"></param>
void LoadFile(string path, bool isSprite=true)
{
// Check if the file is a .gif, first.
using FileStream fs = File.OpenRead(path);
LoadStream(fs, path, isSprite);
}
public void LoadStream(Stream source, string path, bool isSprite)
{
long srcStart = source.Position;
byte[] vs = new byte[6]; // First 6 bytes is the gif specifier
source.Read(vs, 0, 6);
source.Position = srcStart;
string magicNumber = Encoding.ASCII.GetString(vs);
if (magicNumber == "GIF87a" || magicNumber == "GIF89a")
{
// Gif file, replace with a layered .png
GifBitmapDecoder decoder = new(source, BitmapCreateOptions.None, BitmapCacheOption.Default);
// Obtain each .gif frame
BitmapFrame[] frames = new BitmapFrame[decoder.Frames.Count];
decoder.Frames.CopyTo(frames, 0);
// Get frame sizes
int height = frames[0].PixelHeight;
int width = frames[0].PixelWidth;
// The lowest mip is static, using either the thumb or first frame
if (decoder.Thumbnail != null)
{
double scaleRate = 32 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(decoder.Thumbnail, scaleRate);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
else
{
double scaleRate = 32 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(frames[0], scaleRate);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
// The remaining mips are animated
if (width >= 128 || height >= 128)
{
double scaleRate = 128 / (double)Math.Max(height, width);
MemoryStream ms = ScaleAnimatedImage(frames, scaleRate);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_MEDIUM + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
if (width >= 512 || height >= 512)
{
double scaleRate = 512 / (double)Math.Max(height, width);
MemoryStream ms = ScaleAnimatedImage(frames, scaleRate);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_HIGH + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
if (width >= 512 || height >= 512)
{
// Just re-encode the gif to .png
PngBitmapEncoder encoder = new();
foreach (BitmapFrame frame in frames)
{
encoder.Frames.Add(frame);
}
MemoryStream ms = new();
encoder.Save(ms);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_RAW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
}
else
{
// Regular image file
// Create the bitmap to get the current intrinsics
BitmapImage bitmapImage = new();
bitmapImage.BeginInit();
bitmapImage.StreamSource = source;
bitmapImage.CacheOption = BitmapCacheOption.None;
bitmapImage.EndInit();
int height = bitmapImage.PixelHeight;
int width = bitmapImage.PixelWidth;
// Behaviour depends on the required image
if (isSprite)
{
// Sprites should have a low mip-map, and the medium
// Low = 32*32
// Medium = 128*128
// High = 512*512 or image size if less than 1024
if (width >= 32 || height >= 32)
{
double scaleRate = 32 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
if (width >= 128 || height >= 128)
{
double scaleRate = 128 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_MEDIUM + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
if (width >= 512 || height >= 512)
{
double scaleRate = 512 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_HIGH + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
if (width >= 512 || height >= 512)
{
MemoryStream ms = new();
source.CopyTo(ms);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_RAW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
}
else
{
// Non-sprites should have a low mip-map, and the medium, but at a larger size than the sprites
// Low = 128*128
// Medium = 512*512
// High = 2048*2048
if (width >= 128 || height >= 128)
{
double scaleRate = 128 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_LOW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
if (width >= 512 || height >= 512)
{
double scaleRate = 512 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_MEDIUM + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
if (width >= 2048 || height >= 2048)
{
double scaleRate = 2048 / (double)Math.Max(height, width);
MemoryStream ms = ScaleImage(bitmapImage, scaleRate);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_HIGH + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
if (width >= 2048 || height >= 2048)
{
MemoryStream ms = new();
source.CopyTo(ms);
_ = GameCommunicationHandler.ImageCollection.TryAdd(Path.GetFileNameWithoutExtension(path) + MIP_RAW + Path.GetExtension(path), new CachedByteArray(ms.ToArray()));
}
// Destroy old board if we are replacing
if (!string.IsNullOrEmpty(GameCommunicationHandler.BoardName))
{
GameCommunicationHandler.ImageCollection.Remove(GameCommunicationHandler.BoardName, out CachedByteArray val);
val.Dispose();
}
GameCommunicationHandler.BoardName = path;
}
GameCommunicationHandler.ImageList.Add(path);
}
}
MemoryStream ScaleImage(BitmapSource source, double scaleRate)
{
TransformedBitmap modified = new(source, new ScaleTransform(source.PixelWidth * scaleRate, source.PixelHeight * scaleRate));
PngBitmapEncoder encoder = new();
encoder.Frames.Add(BitmapFrame.Create(modified));
MemoryStream ms = new();
encoder.Save(ms);
return ms;
}
MemoryStream ScaleAnimatedImage(BitmapFrame[] frames, double scaleRate)
{
PngBitmapEncoder encoder = new();
foreach (BitmapFrame frame in frames)
{
TransformedBitmap modified = new(frame, new ScaleTransform(frame.PixelWidth * scaleRate, frame.PixelHeight * scaleRate));
encoder.Frames.Add(BitmapFrame.Create(modified));
}
MemoryStream ms = new();
encoder.Save(ms);
return ms;
}
}
}