Icons.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using System;
  4. using System.Collections.Concurrent;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Linq;
  8. namespace OpenVIII
  9. {
  10. /// <summary>
  11. /// Images of parts of most of the menus and ui.
  12. /// </summary>
  13. public sealed partial class Icons : SP2
  14. {
  15. #region Fields
  16. private static readonly ID[] NumberStarts = { ID.Num_8x8_0_0, ID.Num_8x8_1_0, ID.Num_8x8_2_0, ID.Num_8x16_0_0, ID.Num_8x16_1_0, ID.Num_16x16_0_0 };
  17. private static ConcurrentDictionary<int, ID[]> _numbersIDs;
  18. private Rectangle _dataSize;
  19. // ReSharper disable once InconsistentNaming
  20. private new Dictionary<ID, EntryGroup> Entries;
  21. #endregion Fields
  22. #region Enums
  23. public enum NumType
  24. {
  25. // ReSharper disable once UnusedMember.Global
  26. Num8X8,
  27. // ReSharper disable once UnusedMember.Global
  28. Num8X8A,
  29. Num8X8B,
  30. Num8X16,
  31. Num8X16A,
  32. // ReSharper disable once UnusedMember.Global
  33. Num16X16,
  34. SysFntBig,
  35. SysFnt,
  36. MenuFont
  37. }
  38. #endregion Enums
  39. #region Properties
  40. public new uint Count => (uint)Entries.Count;
  41. public Rectangle DataSize { get => _dataSize; private set => _dataSize = value; }
  42. // ReSharper disable once UnusedMember.Global
  43. public new uint EntriesPerTexture { get; } = (uint)Enum.GetValues(typeof(ID)).Cast<ID>().Max();
  44. public new uint PaletteCount => (uint)Textures.Count;
  45. // ReSharper disable once UnusedMember.Local
  46. private new uint TextureStartOffset { get; } = 0;
  47. #endregion Properties
  48. #region Indexers
  49. public new EntryGroup this[Enum id] => GetEntryGroup(id);
  50. #endregion Indexers
  51. #region Methods
  52. public static Icons Load()
  53. {
  54. var r = Load<Icons>();
  55. Memory.MainThreadOnlyActions.Enqueue(r.Trim);
  56. return r;
  57. }
  58. public Rectangle Draw(int number, NumType type, int palette, string format, Vector2 location, Vector2 scale, float fade = 1f, Font.ColorID color = Font.ColorID.White, bool blink = false, bool skipDraw = false)
  59. {
  60. switch (type)
  61. {
  62. case NumType.SysFnt:
  63. DataSize = Memory.Font.RenderBasicText(number.ToString(), location.ToPoint(), scale, Font.Type.sysfnt, Fade: fade, color: color, blink: blink, skipdraw: skipDraw);
  64. return DataSize;
  65. case NumType.SysFntBig:
  66. DataSize = Memory.Font.RenderBasicText(number.ToString(), location.ToPoint(), scale, Font.Type.sysFntBig, Fade: fade, color: color, blink: blink, skipdraw: skipDraw);
  67. return DataSize;
  68. case NumType.MenuFont:
  69. DataSize = Memory.Font.RenderBasicText(number.ToString(), location.ToPoint(), scale, Font.Type.menuFont, Fade: fade, color: color, blink: blink, skipdraw: skipDraw);
  70. return DataSize;
  71. case NumType.Num8X8:
  72. case NumType.Num8X8A:
  73. case NumType.Num8X8B:
  74. case NumType.Num8X16:
  75. case NumType.Num8X16A:
  76. case NumType.Num16X16:
  77. break;
  78. default:
  79. throw new ArgumentOutOfRangeException(nameof(type), type, null);
  80. }
  81. if (_numbersIDs == null)
  82. {
  83. _numbersIDs = new ConcurrentDictionary<int, ID[]>();
  84. var j = 0;
  85. foreach (var id in NumberStarts)
  86. _numbersIDs.TryAdd(j++, Enumerable.Range((int)id, 10).Select(x => checked((ID)x)).ToArray());
  87. }
  88. var intList = number.ToString(format).Select(digit => int.Parse(digit.ToString()));
  89. var dst = new Rectangle { Location = location.ToPoint() };
  90. DataSize = dst;
  91. if (Entries == null) return DataSize;
  92. foreach (var i in intList)
  93. {
  94. if (_numbersIDs == null) continue;
  95. if (!skipDraw)
  96. Draw(_numbersIDs[(int)type][i], palette, dst, scale, fade,
  97. blink
  98. ? Color.Lerp(Font.ColorID2Color[color], Font.ColorID2Blink[color], Menu.Blink_Amount)
  99. : Font.ColorID2Color[color]);
  100. var width = Entries[_numbersIDs[(int)type][i]].GetRectangle.Width * scale.X;
  101. var height = Entries[_numbersIDs[(int)type][i]].GetRectangle.Height * scale.Y;
  102. dst.Offset(width, 0);
  103. _dataSize.Width += (int)width;
  104. if (_dataSize.Height < (int)height)
  105. _dataSize.Height = (int)height;
  106. }
  107. return DataSize;
  108. }
  109. public void Draw(Enum id, int palette, Rectangle dst, Vector2 scale, float fade = 1f, Color? color = null)
  110. {
  111. if ((ID)id != ID.None && Textures.Count > 0)
  112. Entries?[(ID)id].Draw(Textures, palette, dst, scale, fade, color);
  113. }
  114. public override void Draw(Enum id, Rectangle dst, float fade = 1) => Draw((ID)id, 2, dst, Vector2.One, fade);
  115. public Entry GetEntry(Enum id, int index) => Entries?[(ID)id]?[index];
  116. public override Entry GetEntry(Enum id) => Entries[(ID)id][0];
  117. public EntryGroup GetEntryGroup(Enum id) => (ID)id != ID.None ? Entries?[(ID)id] : null;
  118. public Color MostSaturated(Enum ic, byte pal)
  119. {
  120. if (Textures.Count <= pal) return default;
  121. var eg = this[(ID)ic];
  122. if (eg == null) return default;
  123. var tex = Textures[pal];
  124. return eg.MostSaturated(tex, pal);
  125. }
  126. public override void Trim(Enum ic, byte pal)
  127. {
  128. var eg = this[(ID)ic];
  129. if (Textures != null && Textures.Count > pal)
  130. eg.Trim(Textures[pal]);
  131. }
  132. protected override void DefaultValues()
  133. {
  134. base.DefaultValues();
  135. var red = new Color[16];
  136. var yellow = new Color[16];
  137. red[15] = new Color(255, 30, 30, 255); //red
  138. red[14] = new Color(140, 30, 30, 255); //dark red
  139. red[13] = new Color(37, 37, 37, 255); //gray
  140. yellow[15] = new Color(222, 222, 8, 255); //yellow
  141. yellow[14] = new Color(131, 131, 24, 255); //dark yellow
  142. yellow[13] = new Color(41, 41, 41, 255); //gray
  143. //FORCE_ORIGINAL = true;
  144. Props = new List<TexProps>
  145. {
  146. // ReSharper disable StringLiteralTypo
  147. new TexProps{Filename = "icon.tex",Count = 1,Big = new List<BigTexProps>{ new BigTexProps{Filename = "iconfl{0:00}.TEX",Split = 4} } }, //0-15 palette
  148. new TexProps{Filename = "icon.tex",Count = 1,Colors = red,Big = new List<BigTexProps>{ new BigTexProps{Filename = "iconfl{0:00}.TEX",Split = 4,Colors = red } } },//16 palette
  149. new TexProps{Filename = "icon.tex",Count = 1,Colors = yellow,Big = new List<BigTexProps>{ new BigTexProps { Filename = "iconfl{0:00}.TEX", Split = 4, Colors = yellow } } }//17 palette
  150. // ReSharper restore StringLiteralTypo
  151. };
  152. IndexFilename = "icon.sp1";
  153. }
  154. protected override void InitEntries(ArchiveBase aw = null)
  155. {
  156. if (Entries != null) return;
  157. //read from icon.sp1
  158. MemoryStream ms;
  159. var buffer = aw.GetBinaryFile(IndexFilename);
  160. if (buffer == null) return;
  161. using (var br = new BinaryReader(ms = new MemoryStream(buffer)))
  162. {
  163. var locations = new Loc[br.ReadUInt32()];
  164. for (var i = 0; i < locations.Length; i++)
  165. {
  166. locations[i] = (br.ReadUInt16(), br.ReadUInt16());
  167. }
  168. Entries = new Dictionary<ID, EntryGroup>(locations.Length + 10);
  169. for (var i = 0; i < locations.Length; i++)
  170. {
  171. ms.Seek(locations[i].Seek, SeekOrigin.Begin);
  172. var c = (byte)locations[i].Length;
  173. Entries[(ID)i] = new EntryGroup(c);
  174. for (var e = 0; e < c; e++)
  175. {
  176. var tmp = new Entry();
  177. tmp.LoadfromStreamSP1(br);
  178. tmp.Part = (byte)e;
  179. tmp.SetLoc(locations[i]);
  180. Entries[(ID)i].Add(tmp);
  181. }
  182. }
  183. }
  184. }
  185. protected override void InitTextures<T>(ArchiveBase aw = null)
  186. {
  187. Textures = new List<TextureHandler>();
  188. foreach (var texProps in Props)
  189. {
  190. var buffer = aw.GetBinaryFile(texProps.Filename);
  191. if (buffer == null) continue;
  192. var tex = new T();
  193. tex.Load(buffer);
  194. void add(ushort cult, Color[] colors = null)
  195. {
  196. void oneImage() => Textures.Add(TextureHandler.Create(texProps.Filename, tex, 1, 1, cult, colors));
  197. if (ForceOriginal == false && texProps.Big != null && texProps.Big.Count > 0)
  198. {
  199. var textureHandler = TextureHandler.Create(texProps.Big[0].Filename, tex, 2,
  200. texProps.Big[0].Split / 2,
  201. cult, colors);
  202. if (textureHandler.AllTexture2Ds.FirstOrDefault() == default ||
  203. textureHandler.AllTexture2Ds.Any(x => x == null))
  204. {
  205. textureHandler.Dispose();
  206. oneImage();
  207. }
  208. else
  209. Textures.Add(textureHandler);
  210. }
  211. else oneImage();
  212. }
  213. if (texProps.Colors == null || texProps.Colors.Length == 0)
  214. for (ushort cult = 0; cult < tex.GetClutCount; cult++)
  215. add(cult);
  216. else
  217. add((ushort)Textures.Count, texProps.Big?[0]?.Colors ?? texProps.Colors); // Unsure if the big check here is worth doing... or if it'll cause issues.
  218. }
  219. }
  220. protected override VertexPositionTexture_Texture2D Quad(Enum ic, byte pal, float scale = 0.25F, Box_Options options = Box_Options.Center | Box_Options.Middle, float z = 0f)
  221. {
  222. Trim(ic, pal);
  223. var eg = this[(ID)ic];
  224. var r = Quad(eg[0], Textures[pal], scale, eg.Count == 1 ? options : options | Box_Options.UseOffset);
  225. if (eg.Count <= 1) return r;
  226. var tmp = new List<VertexPositionTexture>(r.VPT.Length * eg.Count);
  227. tmp.AddRange(r.VPT);
  228. for (var i = 1; i < eg.Count; i++)
  229. tmp.AddRange(Quad(eg[0], Textures[pal], scale, options | Box_Options.UseOffset, i * 0.001f).VPT);
  230. return new VertexPositionTexture_Texture2D(tmp.ToArray(), r.Texture);
  231. }
  232. private void Trim()
  233. {
  234. Trim(ID.Bar_Fill, 5);
  235. //trim checks to see if it's ran once before.
  236. //so no need to check if it's already ran.
  237. //will throw exception if not in main thread.
  238. for (byte i = 0; i <= 7; i++)
  239. Trim(ID._0_Hit_ + i, 2);
  240. Trim(ID.Trigger_, 2);
  241. Trim(ID.Perfect__, 2);
  242. Trim(ID.Renzokuken_Seperator, 6);
  243. }
  244. #endregion Methods
  245. }
  246. }