| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- using Microsoft.Xna.Framework;
- using Microsoft.Xna.Framework.Graphics;
- using System;
- using System.Collections;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- namespace OpenVIII
- {
- public class EntryGroup : IEnumerator, IEnumerable
- {
- private const int minx = -1000;
- private const int miny = -360;
- #region Fields
- private List<Entry> list;
- private Rectangle rectangle;
- public bool Trimmed { get; set; } = false;
- public EntryGroup(int capacity = 1)
- {
- list = new List<Entry>(capacity);
- rectangle = new Rectangle();
- }
- public EntryGroup(params Entry[] entries)
- {
- list = new List<Entry>(entries.Length);
- rectangle = new Rectangle();
- Add(entries);
- }
- #endregion Fields
- #region Properties
- public int Count => list.Count;
- //public int Height { get => Rectangle.Height; private set => Rectangle = new Rectangle(Rectangle.X, Rectangle.Y, value, Rectangle.Height); }
- //public int Width { get => Rectangle.Width; private set => Rectangle = new Rectangle(Rectangle.X,Rectangle.Y, value,Rectangle.Width); }
- public int Height { get => rectangle.Height; set => rectangle.Height = value; }
- public int Width { get => rectangle.Width; set => rectangle.Width = value; }
- public Rectangle GetRectangle => rectangle;
- public object Current => list[position - 1];
- #endregion Properties
- #region Indexers
- /// <summary>
- /// donno if this works for assigning. perfer add.
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- public Entry this[int id] => list[id]; /*set { if (list.Count - 1 < ID) Add(value); else list[ID] = value; }*/
- #endregion Indexers
- #region Methods
- private Vector2 nag_Offset = new Vector2();
- private Vector2 pos_Offset = new Vector2();
- public void Add(params Entry[] entries)
- {
- foreach (var entry in entries)
- {
- //TODO fix math
- if (list.Count >= 1)
- {
- //DiscFix
- if (entry.Height < float.Epsilon)
- {
- entry.Height = Height; // one item had a missing height.
- if (Math.Abs(nag_Offset.X) + pos_Offset.X + entry.Offset.X < float.Epsilon) //assumes if the items are overlapping put them next to each other instead.
- entry.Offset.X = (short)Width;
- }
- //BarFix
- //has 2 sides and no filling.
- //if(entry.CurrentPos == 1872)
- if (list.Capacity == 2 && list.Count == 1 && (list[0].Width * 2) + list[0].X == entry.X && list[0].Y == entry.Y)
- Add(new Entry
- {
- X = entry.X - list[0].Width,
- Y = entry.Y,
- Size = list[0].Size,
- Tile = Vector2.UnitX,
- Offset = new Vector2((int)list[0].Width, 0),
- End = new Vector2((int)-list[0].Width, 0)
- });
- }
- list.Add(entry);
- var size = Abs(entry.Offset) + entry.Size;
- if (Width < size.X) Width = (int)size.X;
- if (Height < size.Y) Height = (int)size.Y;
- }
- }
- private object locker = new object();
- private ConcurrentDictionary<int, Color> Average;
- public Color MostSaturated(TextureHandler tex, int palette = 0)
- {
- if (Count >= 1)
- {
- lock (locker)
- {
- if (Average == null)
- Average = new ConcurrentDictionary<int, Color>();
- }
- if (!(Average.TryGetValue(palette, out var ret)))
- {
- var r = this[0].GetRectangle;
- for (var i = 1; i < Count; i++)
- r = Rectangle.Union(r, this[i].GetRectangle);
- r = r.Scale(tex.ScaleFactor);
- var t = (Texture2D)tex;
- if (t == null) return default;
- var tc = new Color[r.Width * r.Height];
- t.GetData(0, r, tc, 0, tc.Length);
- HSL test, last;
- last.S = 0;
- last.L = 0;
- ret = Color.TransparentBlack;
- foreach (var p in tc)
- {
- if (p.A >= 250)
- {
- test = p;
- if (ret == Color.TransparentBlack)
- last = test;
- if (test.S > .25f && last.S <= test.S)
- {
- if (ret == Color.TransparentBlack)
- ret = p;
- else
- {
- ret = Color.Lerp(ret, p, .5f);
- last = test;
- }
- }
- else if (test.L > .25f && last.L <= test.L)
- {
- if (ret == Color.TransparentBlack)
- ret = p;
- else
- {
- ret = Color.Lerp(ret, p, .5f);
- last = test;
- }
- }
- }
- }
- if (!Average.TryAdd(palette, ret))
- throw new Exception("failed to cache color");
- }
- return ret;
- }
- throw new Exception("Count is <1");
- }
- public void Trim(TextureHandler tex)
- {
- if (!Trimmed)
- {
- if (Count >= 1)
- {
- Width = 0;
- Height = 0;
- Trimmed = true;
- var offset = new Vector2(float.MaxValue);
- if (Count == 1)
- this[0].Offset = Vector2.Zero;
- for (var i = 0; i < Count; i++)
- {
- var ret = tex.Trim(this[i].GetRectangle);
- this[i].SetTrim_1stPass(ret, Count == 1 ? true : false);
- if (Count > 1)
- {
- if (this[i].Offset.X < offset.X) offset.X = this[i].Offset.X;
- if (this[i].Offset.Y < offset.Y) offset.Y = this[i].Offset.Y;
- }
- }
- for (var i = 0; i < Count; i++)
- {
- if (offset != Vector2.Zero && Count > 1)
- this[i].SetTrim_2ndPass(offset);
- var size = new Point((int)(this[i].Width + Math.Abs(this[i].Offset.X)), (int)(this[i].Height + Math.Abs(this[i].Offset.Y)));
- if (Width < size.X) Width = size.X;
- if (Height < size.Y) Height = size.Y;
- }
- }
- }
- }
- public static Vector2 Abs(Vector2 v2) => new Vector2(Math.Abs(v2.X), Math.Abs(v2.Y));
- public static Point RoundedPoint(Vector2 v) => v.RoundedPoint();
- public void Draw(List<TextureHandler> textures, int palette, Rectangle inputdst, Vector2 inscale, float fade = 1f, Color? color = null) =>
- Draw(textures, list, palette, inputdst, inscale, fade, new Point(Width, Height), color);
- public static int GetChange(int tot, int goal, float scale = 1f) => (int)Math.Round(Math.Abs(tot * scale - goal));
- public static void Draw(List<TextureHandler> textures, List<Entry> elist, int palette, Rectangle inputdst, Vector2 inscale, float fade, Point totalSize, Color? color_ = null)
- {
- var color = color_ ?? Color.White;
- Rectangle dst;
- inscale = Abs(inscale);
- inputdst.Width = Math.Abs(inputdst.Width);
- inputdst.Height = Math.Abs(inputdst.Height);
- if (inputdst.Right < minx || inputdst.Bottom < miny)
- return;
- var autoscale = new Vector2((float)inputdst.Width / totalSize.X, (float)inputdst.Height / totalSize.Y);
- Vector2 scale;
- if (inscale == Vector2.Zero || inscale == Vector2.UnitX)
- scale = new Vector2(autoscale.X);
- #pragma warning disable IDE0045 // Convert to conditional expression
- else if (inscale == Vector2.UnitY)
- #pragma warning restore IDE0045 // Convert to conditional expression
- scale = new Vector2(autoscale.Y);
- else
- scale = inscale;
- foreach (var e in elist)
- {
- if (totalSize == new Point(0))
- {
- totalSize.X = (int)e.Width;
- totalSize.Y = (int)e.Height;
- }
- var cpalette = e.CustomPalette < 0 || e.CustomPalette >= textures.Count ? palette : e.CustomPalette;
- dst = inputdst;
- var Offset = e.Offset * scale;
- var offset2 = RoundedPoint(e.End * scale);
- dst.Offset(e.Snap_Right ? inputdst.Width : 0, e.Snap_Bottom ? inputdst.Height : 0);
- dst.Offset(RoundedPoint(Offset));
- dst.Size = RoundedPoint(e.Size * scale);
- var src = e.GetRectangle;
- var testY = false;
- var testX = false;
- CorrectX(inputdst, totalSize, ref dst, autoscale, ref scale, e, ref src);
- CorrectY(inputdst, totalSize, ref dst, autoscale, ref scale, e, ref src);
- if (dst.Width <= 0 || dst.Height <= 0) continue; //infinate loop prevention
- if (e.Tile != Vector2.Zero)
- {
- do
- {
- do
- {
- var correction = Correction(inputdst, dst, offset2);
- testY = testYfunct(dst, inputdst, offset2);
- testX = testXfunct(dst, inputdst, offset2);
- TileBounds(correction, ref dst, scale, e, ref src, ref testY, ref testX);
- textures[cpalette].Draw(dst, src, color * fade);
- dst = TileShift(dst, e);
- }
- while (e.Tile.Y > 0 && testY);
- }
- while (e.Tile.X > 0 && testX);
- }
- else
- textures[cpalette].Draw(dst, src, color * fade);
- }
- }
- private static void CorrectY(Rectangle inputdst, Point totalSize, ref Rectangle dst, Vector2 autoscale, ref Vector2 scale, Entry e, ref Rectangle src)
- {
- if (inputdst.Height != 0 && dst.Bottom > inputdst.Bottom)
- {
- var change = GetChange(totalSize.Y, inputdst.Height, scale.Y); ;
- src.Height -= (int)Math.Round(change / scale.Y);
- dst.Height -= change;
- }
- else if (e.Fill.Y > 0 && autoscale.Y > scale.Y)
- {
- scale.Y = autoscale.Y;
- dst.Height = (int)Math.Ceiling((src.Height * autoscale.Y + 0.5f));
- }
- }
- private static void CorrectX(Rectangle inputdst, Point totalSize, ref Rectangle dst, Vector2 autoscale, ref Vector2 scale, Entry e, ref Rectangle src)
- {
- if ((inputdst.Width != 0) && dst.Right > inputdst.Right)
- {
- var change = GetChange(totalSize.X, inputdst.Width, scale.X);
- src.Width -= (int)Math.Round(change / scale.X);
- dst.Width -= change;
- }
- else if (e.Fill.X > 0 && autoscale.X > scale.X)
- {
- scale.X = autoscale.X;
- dst.Width = (int)Math.Ceiling((src.Width * autoscale.X + 0.5f));
- }
- }
- private static void TileBounds(Point correction, ref Rectangle dst, Vector2 scale, Entry e, ref Rectangle src, ref bool testY, ref bool testX)
- {
- if (e.Tile.Y > 0 && !testY)
- {
- dst.Height += correction.Y;
- src.Height += (int)Math.Round(correction.Y / scale.Y);
- }
- if (e.Tile.X > 0 && !testX)
- {
- dst.Width += correction.X;
- src.Width += (int)Math.Round(correction.X / scale.X);
- }
- }
- private static bool testXfunct(Rectangle dst, Rectangle inputdst, Point offset2) => (dst.Right) < (inputdst.Right + offset2.X);
- private static bool testYfunct(Rectangle dst, Rectangle inputdst, Point offset2) => (dst.Bottom) < (inputdst.Bottom + offset2.Y);
- private static Point Correction(Rectangle inputdst, Rectangle dst, Point offset2) => new Point((inputdst.Right + offset2.X) - (dst.Right), (inputdst.Bottom + offset2.Y) - (dst.Bottom));
- private static Rectangle TileShift(Rectangle dst, Entry e)
- {
- if (e.Tile.Y > 0)
- {
- dst.Y += dst.Height;
- }
- if (e.Tile.X > 0)
- {
- dst.X += dst.Width;
- }
- return dst;
- }
- private int position = 0;
- public bool MoveNext() => ++position <= list.Count;
- public void Reset() => position = 0;
- public IEnumerator GetEnumerator() => this;
- #endregion Methods
- }
- }
|