mysimulation/server/tso.files/ImageLoader.cs
Tony Bark 8fec258215 Added FSO.Files for use with the API server
Don't ask me. FreeSO is the prime example of dependency hell.
2024-05-01 04:38:12 -04:00

181 lines
6.5 KiB
C#
Executable file

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
using Microsoft.Xna.Framework;
namespace FSO.Files
{
public class ImageLoader
{
public static bool UseSoftLoad = true;
public static int PremultiplyPNG = 0;
public static HashSet<uint> MASK_COLORS = new HashSet<uint>{
new Microsoft.Xna.Framework.Color(0xFF, 0x00, 0xFF, 0xFF).PackedValue,
new Microsoft.Xna.Framework.Color(0xFE, 0x02, 0xFE, 0xFF).PackedValue,
new Microsoft.Xna.Framework.Color(0xFF, 0x01, 0xFF, 0xFF).PackedValue
};
public static Func<GraphicsDevice, Stream, Texture2D> BaseFunction = WinFromStream;
public static Texture2D FromStream(GraphicsDevice gd, Stream str)
{
return BaseFunction(gd, str);
}
private static Texture2D WinFromStream(GraphicsDevice gd, Stream str)
{
return WinFromStreamP(gd, str, 0);
}
public static Texture2D WinFromStreamP(GraphicsDevice gd, Stream str, int premult)
{
//if (!UseSoftLoad)
//{
//attempt monogame load of image
var magic = (str.ReadByte() | (str.ReadByte() << 8));
str.Seek(0, SeekOrigin.Begin);
magic += 0;
if (magic == 0x4D42)
{
try
{
//it's a bitmap.
Texture2D tex;
if (ImageLoaderHelpers.BitmapFunction != null)
{
var bmp = ImageLoaderHelpers.BitmapFunction(str);
if (bmp == null) return null;
tex = new Texture2D(gd, bmp.Item2, bmp.Item3);
tex.SetData(bmp.Item1);
}
else
{
tex = Texture2D.FromStream(gd, str);
}
ManualTextureMaskSingleThreaded(ref tex, MASK_COLORS.ToArray());
return tex;
}
catch (Exception)
{
return null; //bad bitmap :(
}
}
else
{
//test for targa
str.Seek(-18, SeekOrigin.End);
byte[] sig = new byte[16];
str.Read(sig, 0, 16);
str.Seek(0, SeekOrigin.Begin);
if (ASCIIEncoding.Default.GetString(sig) == "TRUEVISION-XFILE")
{
try
{
var tga = new TargaImagePCL.TargaImage(str);
var tex = new Texture2D(gd, tga.Image.Width, tga.Image.Height);
tex.SetData(tga.Image.ToBGRA(true));
return tex;
}
catch (Exception)
{
return null; //bad tga
}
}
else
{
//anything else
try
{
Texture2D tex;
Color[] buffer = null;
if (ImageLoaderHelpers.BitmapFunction != null)
{
var bmp = ImageLoaderHelpers.BitmapFunction(str);
if (bmp == null) return null;
tex = new Texture2D(gd, bmp.Item2, bmp.Item3);
tex.SetData(bmp.Item1);
//buffer = bmp.Item1;
}
else
{
tex = Texture2D.FromStream(gd, str);
}
premult += PremultiplyPNG;
if (premult == 1)
{
if (buffer == null)
{
buffer = new Color[tex.Width * tex.Height];
tex.GetData<Color>(buffer);
}
for (int i = 0; i < buffer.Length; i++)
{
var a = buffer[i].A;
buffer[i] = new Color((byte)((buffer[i].R * a) / 255), (byte)((buffer[i].G * a) / 255), (byte)((buffer[i].B * a) / 255), a);
}
tex.SetData(buffer);
}
else if (premult == -1) //divide out a premultiply... currently needed for dx since it premultiplies pngs without reason
{
if (buffer == null)
{
buffer = new Color[tex.Width * tex.Height];
tex.GetData<Color>(buffer);
}
for (int i = 0; i < buffer.Length; i++)
{
var a = buffer[i].A / 255f;
buffer[i] = new Color((byte)(buffer[i].R / a), (byte)(buffer[i].G / a), (byte)(buffer[i].B / a), buffer[i].A);
}
tex.SetData(buffer);
}
return tex;
}
catch (Exception e)
{
Console.WriteLine("error: " + e.ToString());
return new Texture2D(gd, 1, 1);
}
}
}
}
public static void ManualTextureMaskSingleThreaded(ref Texture2D Texture, uint[] ColorsFrom)
{
var ColorTo = Microsoft.Xna.Framework.Color.Transparent.PackedValue;
var size = Texture.Width * Texture.Height * 4;
byte[] buffer = new byte[size];
Texture.GetData<byte>(buffer);
var didChange = false;
for (int i = 0; i < size; i += 4)
{
if (buffer[i] >= 248 && buffer[i + 2] >= 248 && buffer[i + 1] <= 4)
{
buffer[i] = buffer[i + 1] = buffer[i + 2] = buffer[i + 3] = 0;
didChange = true;
}
}
if (didChange)
{
Texture.SetData(buffer);
}
else return;
}
}
}