TIM2.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. using Microsoft.Xna.Framework;
  2. using System;
  3. using System.Collections.Generic;
  4. namespace FF8
  5. {
  6. //upgraded TIM class, because that first one is a trash
  7. public class TIM2
  8. {
  9. public struct Texture
  10. {
  11. public ushort PaletteX;
  12. public ushort PaletteY;
  13. public ushort NumOfColours;
  14. public ushort NumOfCluts;
  15. public uint clutSize;
  16. public byte[] ClutData;
  17. public ushort ImageOrgX;
  18. public ushort ImageOrgY;
  19. public ushort Width;
  20. public ushort Height;
  21. }
  22. public struct Color
  23. {
  24. public byte Red;
  25. public byte Green;
  26. public byte Blue;
  27. public byte Alpha;
  28. }
  29. private int bpp = -1;
  30. private Texture texture;
  31. private PseudoBufferedStream pbs;
  32. private uint textureDataPointer;
  33. private uint timOffset;
  34. public TIM2(byte[] buffer, uint offset = 0)
  35. {
  36. pbs = new PseudoBufferedStream(buffer);
  37. timOffset = offset;
  38. pbs.Seek(offset, System.IO.SeekOrigin.Begin);
  39. pbs.Seek(4, System.IO.SeekOrigin.Current); //clutID
  40. byte bppIndicator = pbs.ReadByte();
  41. bppIndicator = (byte)(bppIndicator == 0x08 ? 4 :
  42. bppIndicator == 0x09 ? 8 :
  43. bppIndicator == 0x02 ? 16 :
  44. bppIndicator == 0x03 ? 24 : 8);
  45. bpp = bppIndicator;
  46. texture = new Texture();
  47. ReadParameters(bppIndicator);
  48. }
  49. public void KillStreams() => pbs.DisposeAll();
  50. private void ReadParameters(byte _bpp)
  51. {
  52. pbs.Seek(3, System.IO.SeekOrigin.Current);
  53. if (_bpp == 4)
  54. {
  55. texture.clutSize = pbs.ReadUInt() - 12;
  56. texture.PaletteX = pbs.ReadUShort();
  57. texture.PaletteY = pbs.ReadUShort();
  58. texture.NumOfColours = pbs.ReadUShort();
  59. texture.NumOfCluts = pbs.ReadUShort();
  60. int bppMultiplier = 16;
  61. if (texture.NumOfColours != 16 || texture.clutSize != (texture.NumOfCluts * bppMultiplier)) //wmsetus uses 4BPP, but sets 256 colours, but actually is 16, but num of clut is 2* 256/16 WTF?
  62. {
  63. texture.NumOfCluts = (ushort)(texture.NumOfColours / 16 * texture.NumOfCluts);
  64. bppMultiplier = 32;
  65. }
  66. byte[] buffer = new byte[texture.NumOfCluts * bppMultiplier];
  67. for (int i = 0; i != buffer.Length; i++)
  68. buffer[i] = pbs.ReadByte();
  69. texture.ClutData = buffer;
  70. pbs.Seek(4, System.IO.SeekOrigin.Current);
  71. texture.ImageOrgX = pbs.ReadUShort();
  72. texture.ImageOrgY = pbs.ReadUShort();
  73. texture.Width = (ushort)(pbs.ReadUShort() * 4);
  74. texture.Height = pbs.ReadUShort();
  75. textureDataPointer = (uint)pbs.Tell();
  76. return;
  77. }
  78. if (_bpp == 8)
  79. {
  80. pbs.Seek(4, System.IO.SeekOrigin.Current);
  81. texture.PaletteX = pbs.ReadUShort();
  82. texture.PaletteY = pbs.ReadUShort();
  83. pbs.Seek(2, System.IO.SeekOrigin.Current);
  84. texture.NumOfCluts = pbs.ReadUShort();
  85. byte[] buffer = new byte[texture.NumOfCluts * 512];
  86. for (int i = 0; i != buffer.Length; i++)
  87. buffer[i] = pbs.ReadByte();
  88. texture.ClutData = buffer;
  89. pbs.Seek(4, System.IO.SeekOrigin.Current);
  90. texture.ImageOrgX = pbs.ReadUShort();
  91. texture.ImageOrgY = pbs.ReadUShort();
  92. texture.Width = (ushort)(pbs.ReadUShort() * 2);
  93. texture.Height = pbs.ReadUShort();
  94. textureDataPointer = (uint)pbs.Tell();
  95. return;
  96. }
  97. if (_bpp == 16)
  98. {
  99. pbs.Seek(4, System.IO.SeekOrigin.Current);
  100. texture.ImageOrgX = pbs.ReadUShort();
  101. texture.ImageOrgY = pbs.ReadUShort();
  102. texture.Width = pbs.ReadUShort();
  103. texture.Height = pbs.ReadUShort();
  104. textureDataPointer = (uint)pbs.Tell();
  105. return;
  106. }
  107. if (_bpp != 24) return;
  108. pbs.Seek(4, System.IO.SeekOrigin.Current);
  109. texture.ImageOrgX = pbs.ReadUShort();
  110. texture.ImageOrgY = pbs.ReadUShort();
  111. texture.Width = (ushort)(pbs.ReadUShort() / 1.5);
  112. texture.Height = pbs.ReadUShort();
  113. textureDataPointer = (uint)pbs.Tell();
  114. }
  115. public Color[] GetClutColors(Font.ColorID clut) => GetClutColors((ushort)clut);
  116. public Color[] GetClutColors(int clut) => GetClutColors((ushort)clut);
  117. public Color[] GetClutColors(ushort clut)
  118. {
  119. if (clut > texture.NumOfCluts)
  120. throw new Exception("TIM_v2::GetClutColors::given clut is bigger than texture number of cluts");
  121. List<Color> colorPixels = new List<Color>();
  122. if (bpp == 8)
  123. {
  124. pbs.Seek(timOffset + 20 + (512 * clut), System.IO.SeekOrigin.Begin);
  125. for (int i = 0; i < 512 / 2; i++)
  126. {
  127. ushort clutPixel = pbs.ReadUShort();
  128. byte red = (byte)((clutPixel) & 0x1F);
  129. byte green = (byte)((clutPixel >> 5) & 0x1F);
  130. byte blue = (byte)((clutPixel >> 10) & 0x1F);
  131. red = (byte)MathHelper.Clamp((red * bpp), 0, 255);
  132. green = (byte)MathHelper.Clamp((green * bpp), 0, 255);
  133. blue = (byte)MathHelper.Clamp((blue * bpp), 0, 255);
  134. colorPixels.Add(new Color() { Red = red, Green = green, Blue = blue });
  135. }
  136. }
  137. if (bpp == 4)
  138. {
  139. pbs.Seek(timOffset + 20 + (32 * clut), System.IO.SeekOrigin.Begin);
  140. for (int i = 0; i < 16; i++)
  141. {
  142. ushort clutPixel = pbs.ReadUShort();
  143. byte red = (byte)((clutPixel) & 0x1F);
  144. byte green = (byte)((clutPixel >> 5) & 0x1F);
  145. byte blue = (byte)((clutPixel >> 10) & 0x1F);
  146. byte alpha = (byte)(clutPixel >> 11 & 1);
  147. red = (byte)MathHelper.Clamp((red * bpp * 4), 0, 255);
  148. green = (byte)MathHelper.Clamp((green * bpp * 4), 0, 255);
  149. blue = (byte)MathHelper.Clamp((blue * bpp * 4), 0, 255);
  150. colorPixels.Add(new Color { Red = red, Green = green, Blue = blue, Alpha = alpha });
  151. }
  152. }
  153. if (bpp > 8) throw new Exception("TIM that has bpp mode higher than 8 has no clut data!");
  154. return colorPixels.ToArray();
  155. }
  156. public byte[] CreateImageBuffer(Color[] palette = null, bool bIgnoreSize = false)
  157. {
  158. pbs.Seek(textureDataPointer, System.IO.SeekOrigin.Begin);
  159. byte[] buffer = new byte[texture.Width * texture.Height * 4]; //ARGB
  160. if (bpp == 8)
  161. {
  162. if (!bIgnoreSize)
  163. if ((buffer.Length) / 4 != pbs.Length - pbs.Tell())
  164. throw new Exception("TIM_v2::CreateImageBuffer::TIM texture buffer has size incosistency.");
  165. for (int i = 0; i < buffer.Length; i++)
  166. {
  167. byte pixel = pbs.ReadByte();
  168. Color ColoredPixel = palette[pixel];
  169. buffer[i] = ColoredPixel.Red;
  170. buffer[++i] = ColoredPixel.Green;
  171. buffer[++i] = ColoredPixel.Blue;
  172. buffer[++i] = (byte)((ColoredPixel.Red == 0 && ColoredPixel.Green == 0 && ColoredPixel.Blue == 0) ? 0x00 : 0xFF);
  173. }
  174. }
  175. if (bpp == 4)
  176. {
  177. if (!bIgnoreSize)
  178. if ((buffer.Length) / 8 != pbs.Length - pbs.Tell())
  179. throw new Exception("TIM_v2::CreateImageBuffer::TIM texture buffer has size incosistency.");
  180. for (int i = 0; i < buffer.Length; i++)
  181. {
  182. byte pixel = pbs.ReadByte();
  183. Color ColoredPixel = palette[pixel & 0xf];
  184. buffer[i] = ColoredPixel.Red;
  185. buffer[++i] = ColoredPixel.Green;
  186. buffer[++i] = ColoredPixel.Blue;
  187. buffer[++i] = ColoredPixel.Alpha;
  188. ColoredPixel = palette[pixel >> 4];
  189. buffer[++i] = ColoredPixel.Red;
  190. buffer[++i] = ColoredPixel.Green;
  191. buffer[++i] = ColoredPixel.Blue;
  192. buffer[++i] = ColoredPixel.Alpha;
  193. }
  194. }
  195. //Then in bs debug where ReadTexture store for all cluts
  196. //data and then create Texture2D from there. (array of e.g. 15 texture2D)
  197. return buffer;
  198. }
  199. public int GetClutCount => texture.NumOfCluts;
  200. public int GetWidth => texture.Width;
  201. public int GetHeight => texture.Height;
  202. }
  203. }