Font.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. using System.Text;
  8. namespace FF8
  9. {
  10. public class Font
  11. {
  12. private Texture2D sysfnt; //21x10 characters; char is always 12x12
  13. private TextureHandler sysfntbig; //21x10 characters; char is always 24x24; 2 files side by side; sysfnt00 is same as sysfld00, but sysfnt00 is missing sysfnt01
  14. private Texture2D menuFont;
  15. public enum ColorID
  16. {
  17. Dark_Gray, Grey, Yellow, Red, Green, Blue, Purple, White
  18. }
  19. public static Dictionary<ColorID, Color> ColorID2Color = new Dictionary<ColorID, Color>
  20. {
  21. { ColorID.Dark_Gray, new Color(41,49,41,255) },
  22. { ColorID.Grey, new Color(148,148,164,255) },
  23. { ColorID.Yellow, new Color(222,222,8,255) },
  24. { ColorID.Red, new Color(255,24,24,255) },
  25. { ColorID.Green, new Color(0,255,0,255) },
  26. { ColorID.Blue, new Color(106,180,238,255) },
  27. { ColorID.Purple, new Color(255,0,255,255) },
  28. { ColorID.White, Color.White }
  29. };
  30. public Font() => LoadFonts();
  31. public void LoadFonts()
  32. {
  33. ArchiveWorker aw = new ArchiveWorker(Memory.Archives.A_MENU);
  34. string sysfntTdwFilepath = aw.GetListOfFiles().First(x => x.ToLower().Contains("sysfnt.tdw"));
  35. string sysfntFilepath = aw.GetListOfFiles().First(x => x.ToLower().Contains("sysfnt.tex"));
  36. TEX tex = new TEX(ArchiveWorker.GetBinaryFile(Memory.Archives.A_MENU, sysfntFilepath));
  37. sysfnt = tex.GetTexture((int)ColorID.White);
  38. sysfntbig = new TextureHandler("sysfld{0:00}.tex", tex, 2, 1, (int)ColorID.White);
  39. ReadTdw(ArchiveWorker.GetBinaryFile(Memory.Archives.A_MENU, sysfntTdwFilepath));
  40. }
  41. public void ReadTdw(byte[] Tdw)
  42. {
  43. uint widthPointer = BitConverter.ToUInt32(Tdw, 0);
  44. uint dataPointer = BitConverter.ToUInt32(Tdw, 4);
  45. getWidths(Tdw, widthPointer, dataPointer - widthPointer);
  46. TIM2 tim = new TIM2(Tdw, dataPointer);
  47. menuFont = new Texture2D(Memory.graphics.GraphicsDevice, tim.GetWidth, tim.GetHeight);
  48. menuFont.SetData(tim.CreateImageBuffer(tim.GetClutColors(ColorID.White)));
  49. }
  50. public void getWidths(byte[] Tdw, uint offset, uint length)
  51. {
  52. using (MemoryStream os = new MemoryStream((int)length * 2))
  53. using (BinaryWriter bw = new BinaryWriter(os))
  54. using (MemoryStream ms = new MemoryStream(Tdw))
  55. using (BinaryReader br = new BinaryReader(ms))
  56. {
  57. //bw.Write((byte)10);//width of space
  58. ms.Seek(offset, SeekOrigin.Begin);
  59. while (ms.Position < offset + length)
  60. {
  61. byte b = br.ReadByte();
  62. byte low = (byte)(b & 0x0F);
  63. byte high = (byte)(b >> 4);
  64. bw.Write(low);
  65. bw.Write(high);
  66. }
  67. charWidths = os.ToArray();
  68. }
  69. }
  70. private byte[] charWidths;
  71. public enum Type
  72. {
  73. sysFntBig,
  74. sysfnt,
  75. menuFont,
  76. }
  77. public Rectangle RenderBasicText(FF8String buffer, Vector2 pos, Vector2 zoom, Type whichFont = 0, float Fade = 1.0f, int lineSpacing = 0, bool skipdraw = false, ColorID color = ColorID.White)
  78. {
  79. if (buffer == null) return new Rectangle();
  80. Rectangle ret = new Rectangle(pos.RoundedPoint(), new Point(0));
  81. Point real = pos.RoundedPoint();
  82. int charCountWidth = 21;
  83. int charSize = 12; //pixelhandler does the 2x scaling on the fly.
  84. Point size = (new Vector2(0, charSize) * zoom).RoundedPoint();
  85. int width;
  86. foreach (byte cs in buffer)
  87. {
  88. byte[] expanded = cs > 0xE1 && FF8String.BytetoStr.ContainsKey(cs)?
  89. FF8String.BytetoStr[cs].Value : new byte[] { cs };
  90. foreach (byte c in expanded)
  91. {
  92. if (c == 0) continue;
  93. int deltaChar = (c - 32);
  94. if (deltaChar >= 0 && deltaChar < charWidths.Length)
  95. {
  96. width = charWidths[deltaChar];
  97. size.X = (int)(charWidths[deltaChar] * zoom.X);
  98. }
  99. else
  100. {
  101. width = charSize;
  102. size.X = (int)(charSize * zoom.X);
  103. }
  104. Point curSize = size;
  105. int verticalPosition = deltaChar / charCountWidth;
  106. //i.e. 1280 is 100%, 640 is 50% and therefore 2560 is 200% which means multiply by 0.5f or 2.0f
  107. if (c == 0x02)// \n
  108. {
  109. real.X = (int)pos.X;
  110. real.Y += size.Y + lineSpacing;
  111. continue;
  112. }
  113. Rectangle destRect = new Rectangle(real, size);
  114. // if you use Memory.SpriteBatchStartAlpha(SamplerState.PointClamp); you won't need
  115. // to trim last pixel. but it doesn't look good on low res fonts.
  116. if (!skipdraw)
  117. {
  118. Rectangle sourceRect = new Rectangle((deltaChar - (verticalPosition * charCountWidth)) * charSize,
  119. verticalPosition * charSize,
  120. width,
  121. charSize);
  122. switch (whichFont)
  123. {
  124. case Type.menuFont:
  125. case Type.sysfnt:
  126. //trim pixels to remove texture filtering artifacts.
  127. sourceRect.Width -= 1;
  128. sourceRect.Height -= 1;
  129. Memory.spriteBatch.Draw(whichFont == Type.menuFont ? menuFont : sysfnt,
  130. destRect,
  131. sourceRect,
  132. ColorID2Color[color] * Fade);
  133. break;
  134. case Type.sysFntBig:
  135. if (!sysfntbig.Modded)
  136. {
  137. Rectangle ShadowdestRect = new Rectangle(destRect.Location, destRect.Size);
  138. ShadowdestRect.Offset(zoom);
  139. sysfntbig.Draw(ShadowdestRect, sourceRect, Color.Black * Fade * .5f);
  140. }
  141. sysfntbig.Draw(destRect, sourceRect, ColorID2Color[color] * Fade);
  142. break;
  143. }
  144. }
  145. real.X += size.X;
  146. int curWidth = real.X - (int)pos.X;
  147. if (curWidth > ret.Width)
  148. ret.Width = curWidth;
  149. }
  150. }
  151. ret.Height = size.Y + (real.Y - (int)pos.Y);
  152. return ret;
  153. }
  154. public Rectangle RenderBasicText(FF8String buffer, Point pos, Vector2 zoom, Type whichFont = 0, float Fade = 1.0f, int lineSpacing = 0, bool skipdraw = false, ColorID color = ColorID.White)
  155. => RenderBasicText(buffer, pos.ToVector2(), zoom, whichFont, Fade, lineSpacing, skipdraw, color);
  156. public Rectangle RenderBasicText(FF8String buffer, int x, int y, float zoomWidth = 2.545455f, float zoomHeight = 3.0375f, Type whichFont = 0, float Fade = 1.0f, int lineSpacing = 0, bool skipdraw = false, ColorID color = ColorID.White)
  157. => RenderBasicText(buffer, new Vector2(x, y), new Vector2(zoomWidth, zoomHeight), whichFont, Fade, lineSpacing, skipdraw, color);
  158. }
  159. }