Tile.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.IO;
  6. namespace OpenVIII.Fields
  7. {
  8. public partial class Background
  9. {
  10. #region Classes
  11. private class Tile
  12. {
  13. #region Fields
  14. public const int size = 16;
  15. /// <summary>
  16. /// Size of Texture Segment
  17. /// </summary>
  18. public static readonly Vector2 TextureSize = new Vector2(fourBitTexturePageWidth, fourBitTexturePageWidth);
  19. public byte AnimationID = 0xFF;
  20. public byte AnimationState;
  21. public byte blend1;
  22. public BlendMode BlendMode = BlendMode.none;
  23. public byte Depth;
  24. /// <summary>
  25. /// Layer ID, Used to control which parts draw.
  26. /// </summary>
  27. public byte LayerID;
  28. /// <summary>
  29. /// Gets +1 if Overlaps() == true;
  30. /// </summary>
  31. public byte OverLapID = 0;
  32. public byte PaletteID;
  33. /// <summary>
  34. /// for outputting the source tiles to texture pages. some tiles have the same source rectangle. So skip.
  35. /// </summary>
  36. public bool Skip = false;
  37. /// <summary>
  38. /// Source X from Texture Data
  39. /// </summary>
  40. public ushort SourceX;
  41. //[6-10]
  42. /// <summary>
  43. /// Source Y from Texture Data
  44. /// </summary>
  45. public ushort SourceY;
  46. public byte TextureID;
  47. public int TileID;
  48. /// <summary>
  49. /// Distance from left side
  50. /// </summary>
  51. public short X;
  52. /// <summary>
  53. /// Distance from top side
  54. /// </summary>
  55. public short Y;
  56. /// <summary>
  57. /// Larger number is farther away. So OrderByDecending for draw order.
  58. /// </summary>
  59. public ushort Z;
  60. //public byte[] PaletteID4Bit => new byte[] { };
  61. private uint pupuID;
  62. #endregion Fields
  63. #region Properties
  64. public bool Is4Bit => !Is8Bit;
  65. public bool Is8Bit => Depth >= 4;
  66. /// <summary>
  67. /// Pupu goes in a loop and +1 the id when it detects an overlap.
  68. /// There are some wasted bits
  69. /// </summary>
  70. public uint PupuID
  71. {
  72. get
  73. {
  74. if (pupuID == 0)
  75. pupuID = ((uint)(LayerID) << 24) + (((uint)BlendMode & 0x2) << 20) + ((uint)AnimationID << 12) + ((uint)(AnimationState & 0xF) << 4);
  76. return pupuID;
  77. }
  78. set => pupuID = value;
  79. }
  80. public byte SourceOverLapID { get; internal set; }
  81. /// <summary>
  82. /// TopLeft UV
  83. /// </summary>
  84. public Vector2 UV => new Vector2(SourceX, SourceY) / TextureSize;
  85. // 4 bits
  86. public float Zfloat => Z / 4096f;
  87. #endregion Properties
  88. #region Methods
  89. /// <summary>
  90. /// TopLeft Cord
  91. /// </summary>
  92. /// <param name="in"></param>
  93. public static implicit operator Vector2(Tile @in) => new Vector2(@in.SourceX, @in.SourceY);
  94. public static implicit operator Vector3(Tile @in) => new Vector3(@in.X, @in.Y, @in.Zfloat);
  95. public static Tile Load(BinaryReader pbsmap, int id, byte type)
  96. {
  97. long p = pbsmap.BaseStream.Position;
  98. Tile t = new Tile { X = pbsmap.ReadInt16() };
  99. if (t.X == 0x7FFF)
  100. return null;
  101. t.Y = pbsmap.ReadInt16();
  102. if (type == 1)
  103. {
  104. t.Z = pbsmap.ReadUInt16();// (ushort)(4096 - pbsmap.ReadUShort());
  105. byte texIdBuffer = pbsmap.ReadByte();
  106. t.TextureID = (byte)(texIdBuffer & 0xF);
  107. // pbsmap.BaseStream.Seek(-1, SeekOrigin.Current);
  108. pbsmap.BaseStream.Seek(1, SeekOrigin.Current);
  109. t.PaletteID = (byte)((pbsmap.ReadInt16() >> 6) & 0xF);
  110. t.SourceX = pbsmap.ReadByte();
  111. t.SourceY = pbsmap.ReadByte();
  112. t.LayerID = (byte)(pbsmap.ReadByte() >> 1/*& 0x7F*/);
  113. t.BlendMode = (BlendMode)pbsmap.ReadByte();
  114. t.AnimationID = pbsmap.ReadByte();
  115. t.AnimationState = pbsmap.ReadByte();
  116. t.blend1 = (byte)((texIdBuffer >> 4) & 0x1);
  117. t.Depth = (byte)(texIdBuffer >> 5);
  118. t.TileID = id;
  119. }
  120. else if (type == 2)
  121. {
  122. t.SourceX = pbsmap.ReadUInt16();
  123. t.SourceY = pbsmap.ReadUInt16();
  124. t.Z = pbsmap.ReadUInt16();
  125. byte texIdBuffer = pbsmap.ReadByte();
  126. t.TextureID = (byte)(texIdBuffer & 0xF);
  127. pbsmap.BaseStream.Seek(1, SeekOrigin.Current);
  128. t.PaletteID = (byte)((pbsmap.ReadInt16() >> 6) & 0xF);
  129. t.AnimationID = pbsmap.ReadByte();
  130. t.AnimationState = pbsmap.ReadByte();
  131. t.blend1 = (byte)((texIdBuffer >> 4) & 0x1);
  132. t.Depth = (byte)(texIdBuffer >> 5);
  133. t.TileID = id;
  134. }
  135. Debug.Assert(p - pbsmap.BaseStream.Position == -16);
  136. return t;
  137. }
  138. public Rectangle GetRectangle() => new Rectangle(X, Y, size, size);
  139. public bool Intersect(Tile tile, bool rev = false)
  140. {
  141. bool flip = !rev && tile.Intersect(this, !rev);
  142. bool ret = flip ||
  143. X >= tile.X &&
  144. X < tile.X + size &&
  145. Y >= tile.Y &&
  146. Y < tile.Y + size &&
  147. Z == tile.Z &&
  148. LayerID == tile.LayerID &&
  149. BlendMode == tile.BlendMode &&
  150. AnimationID == tile.AnimationID &&
  151. AnimationState == tile.AnimationState;
  152. return ret;
  153. }
  154. public bool SourceIntersect(Tile tile, bool rev = false)
  155. {
  156. bool flip = !rev && tile.SourceIntersect(this, !rev);
  157. if (!flip && tile.TextureID == TextureID)
  158. {
  159. return Rectangle.Intersect(SourceRectangle(), tile.SourceRectangle()) != Rectangle.Empty;
  160. }
  161. return flip;
  162. }
  163. public Rectangle SourceRectangle() => new Rectangle(SourceX, SourceY, size, size);
  164. private List<VertexPositionTexture> GetCorners(float scale)
  165. {
  166. Vector2 sizeVertex = new Vector2(size,size)/scale;
  167. Vector2 sizeUV = new Vector2(size) / TextureSize;
  168. List<VertexPositionTexture> r = new List<VertexPositionTexture>(4);
  169. for (int i = 0; i < r.Capacity; i++)
  170. {
  171. VertexPositionTexture vpt = new VertexPositionTexture(((Vector3)this) / scale, UV);
  172. switch (i)
  173. {
  174. case 0://top left
  175. break;
  176. case 1://top right
  177. vpt.Position.X += sizeVertex.X;
  178. break;
  179. case 2://bottom right
  180. vpt.Position.X += sizeVertex.X;
  181. vpt.Position.Y += sizeVertex.Y;
  182. break;
  183. case 3://bottom left
  184. vpt.Position.Y += sizeVertex.Y;
  185. break;
  186. }
  187. switch (i)
  188. {
  189. case 0://top left
  190. break;
  191. case 1://top right
  192. vpt.TextureCoordinate.X += sizeUV.X;
  193. break;
  194. case 2://bottom right
  195. vpt.TextureCoordinate.X += sizeUV.X;
  196. vpt.TextureCoordinate.Y += sizeUV.Y;
  197. break;
  198. case 3://bottom left
  199. vpt.TextureCoordinate.Y += sizeUV.Y;
  200. break;
  201. }
  202. Vector3 vectorflip = new Vector3(-1, -1, 1);
  203. vpt.Position *= vectorflip;
  204. r.Add(vpt);
  205. }
  206. return r;
  207. }
  208. public VertexPositionTexture[] GetQuad(float scale)
  209. {
  210. List<VertexPositionTexture> vpts = GetCorners(scale); // 4 unique corners.
  211. //create 2 triangles
  212. List<VertexPositionTexture> r = new List<VertexPositionTexture>
  213. {
  214. vpts[3],
  215. vpts[1],
  216. vpts[0],
  217. vpts[3],
  218. vpts[2],
  219. vpts[1],
  220. };
  221. return r.ToArray();
  222. }
  223. #endregion Methods
  224. }
  225. #endregion Classes
  226. }
  227. }