TextureBuffer.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Windows.Forms;
  9. namespace OpenVIII
  10. {
  11. public class TextureBuffer : Texture_Base, ICloneable, ICollection, IStructuralComparable, IStructuralEquatable
  12. {
  13. #region Fields
  14. private static bool show_message_box = true;
  15. #endregion Fields
  16. #region Constructors
  17. public TextureBuffer(int width, int height, bool alert = true)
  18. {
  19. Height = height;
  20. Width = width;
  21. Colors = new Color[height * width];
  22. Alert = alert;
  23. }
  24. #endregion Constructors
  25. #region Properties
  26. public bool Alert { get; set; }
  27. public Color[] Colors { get; }
  28. public int Count => ((ICollection)Colors).Count;
  29. public override byte GetBytesPerPixel => 4;
  30. public override int GetClutCount => 0;
  31. public override int GetClutSize => 0;
  32. public override int GetColorsCountPerPalette => 0;
  33. public override int GetHeight => Height;
  34. public override int GetOrigX => 0;
  35. public override int GetOrigY => 0;
  36. public override int GetWidth => Width;
  37. public int Height { get; }
  38. public bool IsSynchronized => Colors.IsSynchronized;
  39. public int Length => Colors?.Length ?? 0;
  40. public object SyncRoot => Colors.SyncRoot;
  41. public int Width { get; }
  42. #endregion Properties
  43. #region Indexers
  44. public Color this[int i]
  45. {
  46. get => Colors[i]; set
  47. {
  48. byte Diff(byte original, byte replace)
  49. {
  50. if (original >= replace)
  51. return (byte)(original - replace);
  52. else
  53. return (byte)(replace - original);
  54. }
  55. bool DiffColor(Color original, Color replace)
  56. {
  57. const byte threshold = 10;
  58. return Diff(original.R, replace.R) <= threshold
  59. && Diff(original.G, replace.G) <= threshold
  60. && Diff(original.B, replace.B) <= threshold
  61. && Diff(original.A, replace.A) <= threshold;
  62. }
  63. if (Colors[i] != value)
  64. {
  65. if (show_message_box && Alert && Colors[i] != Color.TransparentBlack && !DiffColor(Colors[i], value))
  66. {
  67. //replace exception with MessageBox.
  68. var message = "There is an overlapping color!" +
  69. "\nFrom:\t" + Colors[i].ToString() +
  70. "\nTo:\t" + value.ToString() +
  71. "\nTo if you want to Exit press Abort and Contact OpenVIII team providing images if it's a problem!" +
  72. "\nTo continue press Retry" +
  73. "\nTo disable this message press Ignore";
  74. var caption = "Possible Issue";
  75. var buttons = MessageBoxButtons.AbortRetryIgnore;
  76. // Displays the MessageBox.
  77. var result = MessageBox.Show(message, caption, buttons);
  78. if(result == DialogResult.Abort)
  79. {
  80. Memory.QuitNextUpdate = true;
  81. show_message_box = false;
  82. }
  83. else if(result == DialogResult.Retry)
  84. {
  85. }
  86. else if (result == DialogResult.Ignore)
  87. {
  88. show_message_box = false;
  89. }
  90. }
  91. Colors[i] = value;
  92. }
  93. }
  94. }
  95. public Color this[int x, int y]
  96. {
  97. get
  98. {
  99. var i = x + (y * Width);
  100. if (i < Count && i >= 0)
  101. return Colors[i];
  102. Memory.Log.WriteLine($"{nameof(TextureBuffer)} :: this[int x, int y] => get :: {nameof(IndexOutOfRangeException)} :: {new Point(x, y)} = {i}");
  103. return Color.TransparentBlack; // fail silent...
  104. }
  105. set
  106. {
  107. var i = x + (y * Width);
  108. if (i < Count && i >= 0)
  109. this[i] = value;
  110. else
  111. Memory.Log.WriteLine($"{nameof(TextureBuffer)} :: this[int x, int y] => set :: {nameof(IndexOutOfRangeException)} :: {new Point(x, y)} = {i} :: {nameof(value)} :: {value}");
  112. }
  113. }
  114. public Color[] this[Rectangle rectangle]
  115. {
  116. get => this[rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height];
  117. set => this[rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height] = value;
  118. }
  119. public Color[] this[int x, int y, int width, int height]
  120. {
  121. get
  122. {
  123. var pos = (x + y * Width);
  124. var r = new List<Color>(width * height);
  125. var row = 0;
  126. while (r.Count < width * height)
  127. {
  128. r.AddRange(Colors.Skip(pos + row * Width).Take(width));
  129. row++;
  130. }
  131. return r.ToArray();
  132. }
  133. set
  134. {
  135. for (var loopY = y; (loopY - y) < height; loopY++)
  136. for (var loopX = x; (loopX - x) < width; loopX++)
  137. {
  138. var pos = (loopX + loopY * Width);
  139. Colors[pos] = value[(loopX - x) + (loopY - y) * width];
  140. }
  141. }
  142. }
  143. #endregion Indexers
  144. #region Methods
  145. public static explicit operator Texture2D(TextureBuffer @in)
  146. {
  147. if (Memory.Graphics?.GraphicsDevice != null && @in.Width > 0 && @in.Height > 0)
  148. {
  149. var tex = new Texture2D(Memory.Graphics.GraphicsDevice, @in.Width, @in.Height);
  150. @in.SetData(tex);
  151. return tex;
  152. }
  153. return null;
  154. }
  155. public static explicit operator Texture2DWrapper(TextureBuffer @in) => new Texture2DWrapper(@in.GetTexture());
  156. public static explicit operator TextureBuffer(Texture2D @in)
  157. {
  158. var texture = new TextureBuffer(@in.Width, @in.Height);
  159. @in.GetData(texture.Colors);
  160. return texture;
  161. }
  162. public static explicit operator TextureBuffer(Texture2DWrapper @in)
  163. {
  164. var texture = new TextureBuffer(@in.GetWidth, @in.GetHeight);
  165. var tex = @in.GetTexture();
  166. tex.GetData(texture.Colors);
  167. return texture;
  168. }
  169. public static implicit operator Color[] (TextureBuffer @in) => @in.Colors;
  170. public object Clone() => Colors.Clone();
  171. public int CompareTo(object other, IComparer comparer) => ((IStructuralComparable)Colors).CompareTo(other, comparer);
  172. public void CopyTo(Array array, int index) => Colors.CopyTo(array, index);
  173. public bool Equals(object other, IEqualityComparer comparer) => ((IStructuralEquatable)Colors).Equals(other, comparer);
  174. public override void ForceSetClutColors(ushort newNumOfColors)
  175. {
  176. }
  177. public override void ForceSetClutCount(ushort newClut)
  178. {
  179. }
  180. public override Color[] GetClutColors(ushort clut) => null;
  181. public void GetData(Texture2D tex) => tex.GetData(Colors);
  182. public IEnumerator GetEnumerator() => Colors.GetEnumerator();
  183. public int GetHashCode(IEqualityComparer comparer) => ((IStructuralEquatable)Colors).GetHashCode(comparer);
  184. public override Texture2D GetTexture() => (Texture2D)this;
  185. public override Texture2D GetTexture(Color[] colors) => (Texture2D)this;
  186. public override Texture2D GetTexture(ushort clut) => (Texture2D)this;
  187. public override void Load(byte[] buffer, uint offset = 0) => throw new NotImplementedException();
  188. public override void Save(string path)
  189. {
  190. using (var tex = GetTexture())
  191. Extended.Save_As_PNG(tex, path, tex.Width, tex.Height);
  192. }
  193. public override void SaveCLUT(string path)
  194. {
  195. }
  196. public void SetData(Texture2D tex) => tex.SetData(Colors);
  197. #endregion Methods
  198. }
  199. }