SP2.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. namespace FF8
  8. {
  9. internal abstract class SP2
  10. {
  11. #region Constructors
  12. protected SP2()
  13. {
  14. Count = 0;
  15. PalletCount = 1;
  16. TextureCount = new int[] { 1 };
  17. EntriesPerTexture = 1;
  18. TextureFilename = new string [] {""};
  19. TextureBigFilename = null;
  20. TextureBigSplit = null;
  21. Scale = null;
  22. TextureStartOffset = 0;
  23. IndexFilename = "";
  24. Textures = null;
  25. Entries = null;
  26. ArchiveString = Memory.Archives.A_MENU;
  27. }
  28. #endregion Constructors
  29. #region Enums
  30. /// <summary>
  31. /// enum to be added to class when implemented
  32. /// </summary>
  33. public enum ID { NotImplemented }
  34. #endregion Enums
  35. #region Properties
  36. /// <summary>
  37. /// If true disable mods and high res textures.
  38. /// </summary>
  39. protected bool FORCE_ORIGINAL { get; set; } = false;
  40. /// <summary>
  41. /// Number of Entries
  42. /// </summary>
  43. public uint Count { get; protected set; }
  44. /// <summary>
  45. /// Entries per texture,ID MOD EntriesPerTexture to get current entry to use on this texture
  46. /// </summary>
  47. protected virtual int EntriesPerTexture { get; set; }
  48. /// <summary>
  49. /// Number of Pallets
  50. /// </summary>
  51. public uint PalletCount { get; protected set; }
  52. /// <summary>
  53. /// Number of Textures
  54. /// </summary>
  55. public int[] TextureCount { get; protected set; }
  56. /// <summary>
  57. /// Dictionary of Entries
  58. /// </summary>
  59. protected virtual Dictionary<uint, Entry> Entries { get; set; }
  60. protected string ArchiveString { get; set; }
  61. /// <summary>
  62. /// *.sp1 or *.sp2 that contains the entries or entrygroups. With Rectangle and offset information.
  63. /// </summary>
  64. protected string IndexFilename { get; set; }
  65. /// <summary>
  66. /// Should be Vector2.One unless reading a high res version of textures.
  67. /// </summary>
  68. protected Dictionary<uint, Vector2> Scale { get; set; }
  69. /// <summary>
  70. /// Texture filename. To match more than one number use {0:00} or {00:00} for ones with
  71. /// leading zeros.
  72. /// </summary>
  73. /// TODO make array maybe to add support for highres versions. the array will need to come
  74. /// with a scale factor
  75. protected string[] TextureFilename { get; set; }
  76. /// <summary>
  77. /// For big textures.
  78. /// </summary>
  79. protected string[] TextureBigFilename { get; set; }
  80. /// <summary>
  81. /// Big versions of textures take the file and split it into multiple. How many splits per BigFilename.
  82. /// Value to be interval of 2. As these files are all 2 cols wide. And must be >= 2
  83. /// </summary>
  84. protected uint[] TextureBigSplit { get; set; }
  85. /// <summary>
  86. /// List of textures
  87. /// </summary>
  88. protected virtual List<TextureHandler> Textures { get; set; }
  89. /// <summary>
  90. /// Some textures start with 1 and some start with 0. This is added to the current number in
  91. /// when reading the files in.
  92. /// </summary>
  93. protected int TextureStartOffset { get; set; }
  94. #endregion Properties
  95. #region Indexers
  96. public Entry this[Enum id] => GetEntry(id);
  97. #endregion Indexers
  98. #region Methods
  99. /// <summary>
  100. /// Draw Item
  101. /// </summary>
  102. /// <param name="id"></param>
  103. /// <param name="dst"></param>
  104. /// <param name="fade"></param>
  105. public virtual void Draw(Enum id, Rectangle dst, float fade = 1)
  106. {
  107. Rectangle src = GetEntry(id).GetRectangle;
  108. TextureHandler tex = GetTexture(id);
  109. tex.Draw(dst, src, Color.White * fade);
  110. }
  111. public virtual void Draw(Enum id, Rectangle dst, Vector2 fill, float fade = 1)
  112. {
  113. Rectangle src = GetEntry(id).GetRectangle;
  114. if (fill == Vector2.UnitX)
  115. {
  116. float r = (float)dst.Height / dst.Width;
  117. src.Height = (int)Math.Round(src.Height * r);
  118. }
  119. else if (fill == Vector2.UnitY)
  120. {
  121. float r = (float)dst.Width / dst.Height;
  122. src.Width = (int)Math.Round(src.Width * r);
  123. }
  124. TextureHandler tex = GetTexture(id);
  125. tex.Draw(dst, src, Color.White * fade);
  126. }
  127. private TextureHandler GetTexture(Enum id) => GetTexture(id,out Vector2 scale);
  128. public virtual Entry GetEntry(Enum id)
  129. {
  130. if (Entries.ContainsKey(Convert.ToUInt32(id)))
  131. return Entries[Convert.ToUInt32(id)];
  132. if (Entries.ContainsKey((uint)(Convert.ToUInt32(id) % EntriesPerTexture)))
  133. return Entries[(uint)(Convert.ToUInt32(id) % EntriesPerTexture)];
  134. return null;
  135. }
  136. public virtual TextureHandler GetTexture(Enum id, out Vector2 scale)
  137. {
  138. uint pos = Convert.ToUInt32(id);
  139. uint File = GetEntry(id).File;
  140. //check if we set a custom file and we have a pos more then set entriespertexture
  141. if (File == 0 && EntriesPerTexture > 0 && pos > EntriesPerTexture)
  142. File = (uint)(pos / EntriesPerTexture);
  143. if (File > 0)
  144. {
  145. uint j = (uint)TextureCount.Sum();
  146. if (File >= j)
  147. {
  148. File %= j;
  149. }
  150. }
  151. scale = Scale[File];
  152. return Textures[(int)File];
  153. }
  154. protected virtual void Init()
  155. {
  156. ArchiveWorker aw = new ArchiveWorker(ArchiveString);
  157. InitEntries(aw);
  158. InitTextures(aw);
  159. InsertCustomEntries();
  160. }
  161. protected virtual void InsertCustomEntries() {}
  162. protected virtual void InitEntries(ArchiveWorker aw = null)
  163. {
  164. if (Entries == null)
  165. {
  166. if (aw == null)
  167. aw = new ArchiveWorker(ArchiveString);
  168. using (MemoryStream ms = new MemoryStream(ArchiveWorker.GetBinaryFile(ArchiveString,
  169. aw.GetListOfFiles().First(x => x.IndexOf(IndexFilename, StringComparison.OrdinalIgnoreCase) >= 0))))
  170. {
  171. ushort[] locs;
  172. using (BinaryReader br = new BinaryReader(ms))
  173. {
  174. Count = br.ReadUInt32();
  175. locs = new ushort[Count];//br.ReadUInt32(); 32 valid values in face.sp2 rest is invalid
  176. Entries = new Dictionary<uint, Entry>((int)Count);
  177. for (uint i = 0; i < Count; i++)
  178. {
  179. locs[i] = br.ReadUInt16();
  180. ms.Seek(2, SeekOrigin.Current);
  181. }
  182. byte fid = 0;
  183. Entry Last = null;
  184. for (uint i = 0; i < Count; i++)
  185. {
  186. ms.Seek(locs[i] + 6, SeekOrigin.Begin);
  187. byte t = br.ReadByte();
  188. if (t == 0 || t == 96) // known invalid entries in sp2 files have this value. there might be more to it.
  189. {
  190. Count = i;
  191. break;
  192. }
  193. Entries[i] = new Entry();
  194. Entries[i].LoadfromStreamSP2(br, locs[i], Last, ref fid);
  195. Last = Entries[i];
  196. }
  197. }
  198. }
  199. }
  200. }
  201. protected virtual void InitTextures(ArchiveWorker aw = null)
  202. {
  203. if (Textures == null)
  204. Textures = new List<TextureHandler>(TextureCount.Sum());
  205. if (Textures.Count <= 0)
  206. {
  207. if (aw == null)
  208. aw = new ArchiveWorker(ArchiveString);
  209. TEX tex;
  210. Scale = new Dictionary<uint, Vector2>(TextureCount.Sum());
  211. int b = 0;
  212. for (int j =0; j< TextureCount.Length; j++)
  213. for (uint i = 0; i < TextureCount[j]; i++)
  214. {
  215. string path = aw.GetListOfFiles().First(x => x.ToLower().Contains(string.Format(TextureFilename[j], i + TextureStartOffset)));
  216. tex = new TEX(ArchiveWorker.GetBinaryFile(ArchiveString, path));
  217. if (TextureBigFilename != null && FORCE_ORIGINAL == false && b< TextureBigFilename.Length && b< TextureBigSplit.Length)
  218. {
  219. TextureHandler th = new TextureHandler(TextureBigFilename[b], tex, 2, TextureBigSplit[b++] / 2);
  220. Textures.Add(th);
  221. Scale[i] = Vector2.One;//th.GetScale();
  222. }
  223. else
  224. {
  225. TextureHandler th = new TextureHandler(path, tex);
  226. Textures.Add(th);
  227. Scale[i] = th.GetScale();
  228. }
  229. }
  230. }
  231. }
  232. #endregion Methods
  233. }
  234. }