111 lines
4.2 KiB
C#
111 lines
4.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text.Json;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
|
|
namespace FreedomFighter;
|
|
|
|
/// <summary>
|
|
/// Equivalent of a TOmegaImageList item: a texture subdivided into equally-sized
|
|
/// patterns (frames), drawn by pattern index. Also builds alpha masks for
|
|
/// pixel-perfect collision (Omega's DoPixelCheck).
|
|
/// </summary>
|
|
public class OmegaImage
|
|
{
|
|
public string Name = "";
|
|
public Texture2D Texture = null!;
|
|
public int TileWidth;
|
|
public int TileHeight;
|
|
public int Columns;
|
|
public int PatternCount;
|
|
public bool[] OpaqueMask = null!; // per-pixel alpha>0, whole texture, row-major
|
|
|
|
public static OmegaImage Load(GraphicsDevice gd, string file, int tileW, int tileH, string name)
|
|
{
|
|
using var fs = File.OpenRead(file);
|
|
var tex = Texture2D.FromStream(gd, fs);
|
|
int tw = tileW > 0 ? tileW : tex.Width;
|
|
int th = tileH > 0 ? tileH : tex.Height;
|
|
|
|
var pixels = new Color[tex.Width * tex.Height];
|
|
tex.GetData(pixels);
|
|
var mask = new bool[pixels.Length];
|
|
for (int i = 0; i < pixels.Length; i++)
|
|
mask[i] = pixels[i].A > 0;
|
|
|
|
return new OmegaImage
|
|
{
|
|
Name = name,
|
|
Texture = tex,
|
|
TileWidth = tw,
|
|
TileHeight = th,
|
|
Columns = Math.Max(1, tex.Width / tw),
|
|
PatternCount = Math.Max(1, tex.Width / tw) * Math.Max(1, tex.Height / th),
|
|
OpaqueMask = mask,
|
|
};
|
|
}
|
|
|
|
public Rectangle PatternRect(int pattern)
|
|
{
|
|
if (pattern < 0 || pattern >= PatternCount) pattern = 0;
|
|
return new Rectangle(pattern % Columns * TileWidth, pattern / Columns * TileHeight, TileWidth, TileHeight);
|
|
}
|
|
|
|
/// <summary>Is the pixel at (px,py) within the given pattern opaque? Coordinates are pattern-local.</summary>
|
|
public bool IsOpaque(int pattern, int px, int py)
|
|
{
|
|
if (px < 0 || py < 0 || px >= TileWidth || py >= TileHeight) return false;
|
|
var r = PatternRect(pattern);
|
|
int x = r.X + px, y = r.Y + py;
|
|
if (x >= Texture.Width || y >= Texture.Height) return false;
|
|
return OpaqueMask[y * Texture.Width + x];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Full Omega draw. X,Y is the top-left of the pattern; rotation (degrees, clockwise)
|
|
/// pivots around (centerX, centerY) as a fraction of the pattern size.
|
|
/// </summary>
|
|
public void Draw(SpriteBatch sb, float x, float y, float rotation = 0,
|
|
float centerX = 0, float centerY = 0, float scaleX = 1, float scaleY = 1,
|
|
int red = 255, int green = 255, int blue = 255, int alpha = 255, int pattern = 0)
|
|
{
|
|
var src = PatternRect(pattern);
|
|
var origin = new Vector2(centerX * TileWidth, centerY * TileHeight);
|
|
var pos = new Vector2(x + origin.X * scaleX, y + origin.Y * scaleY);
|
|
var color = new Color(red, green, blue, alpha);
|
|
sb.Draw(Texture, pos, src, color, MathHelper.ToRadians(rotation), origin,
|
|
new Vector2(scaleX, scaleY), SpriteEffects.None, 0);
|
|
}
|
|
}
|
|
|
|
/// <summary>Loads the image lists extracted from GameU.dfm via gfx/manifest.json.</summary>
|
|
public class ImageLists
|
|
{
|
|
readonly Dictionary<string, List<OmegaImage>> _lists = new();
|
|
|
|
public List<OmegaImage> IL1 => _lists["OmegaImageList1"];
|
|
public List<OmegaImage> IL2 => _lists["OmegaImageList2"];
|
|
public List<OmegaImage> IL3 => _lists["OmegaImageList3"];
|
|
public List<OmegaImage> IL4 => _lists["OmegaImageList4"];
|
|
public List<OmegaImage> IL5 => _lists["OmegaImageList5"];
|
|
|
|
record ManifestItem(int Index, string Name, string File, int TileWidth, int TileHeight);
|
|
|
|
public ImageLists(GraphicsDevice gd, string contentDir)
|
|
{
|
|
string gfxDir = Path.Combine(contentDir, "gfx");
|
|
var manifest = JsonSerializer.Deserialize<Dictionary<string, List<ManifestItem>>>(
|
|
File.ReadAllText(Path.Combine(gfxDir, "manifest.json")))!;
|
|
|
|
foreach (var (listName, items) in manifest)
|
|
{
|
|
var list = new List<OmegaImage>();
|
|
foreach (var item in items)
|
|
list.Add(OmegaImage.Load(gd, Path.Combine(gfxDir, item.File), item.TileWidth, item.TileHeight, item.Name));
|
|
_lists[listName] = list;
|
|
}
|
|
}
|
|
}
|