Camera.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. using Microsoft.Xna.Framework;
  2. using System;
  3. using System.Diagnostics.CodeAnalysis;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Runtime.InteropServices;
  7. namespace OpenVIII.Battle
  8. {
  9. public partial class Camera
  10. {
  11. #region Fields
  12. public bool BMultiShotAnimation;
  13. public CameraStruct Cam;
  14. public uint LastCameraPointer;
  15. private readonly BattleCameraCollection _battleCameraCollection;
  16. private readonly uint _bsCameraPointer;
  17. private readonly int[] _x5D4 = {4,5,9,12,13,14,15,21,22,23,24,26,
  18. 29,32,33,34,35,36,39,40,50,53,55,61,62,63,64,65,66,67,68,69,70,
  19. 71,72,73,75,78,82,83,85,86,87,88,89,90,91,94,96,97,98,99,100,105,
  20. 106,121,122,123,124,125,126,127,135,138,141,144,145,148,149,150,
  21. 151,158,160};
  22. private readonly int[] _x5D8 = {
  23. 0,1,2,3,6,7,10,11,17,18,25,27,28,38,41,42,43,47,49,57,58,59,60,74,
  24. 76,77,80,81,84,93,95,101,102,103,104,109,110,111,112,113,114,115,116,
  25. 117,118,119,120,128,129,130,131,132,133,134,139,140,143,146,152,153,154,
  26. 155,156,159,161,162};
  27. private bool _done;
  28. #endregion Fields
  29. //private BattleCameraSettings _battleCameraSettings;
  30. #region Constructors
  31. public Camera() => _bsCameraPointer = GetCameraPointer();
  32. private Camera(BinaryReader br) : this()
  33. {
  34. br.BaseStream.Seek(_bsCameraPointer + 4, 0);
  35. //uint cCameraHeaderSector = br.ReadUInt16();
  36. //uint pCameraSetting = br.ReadUInt16();
  37. uint pCameraAnimationCollection = br.ReadUInt16();
  38. uint sCameraDataSize = br.ReadUInt16();
  39. //Camera settings parsing?
  40. //var battleCameraSettings = new BattleCameraSettings { unk = br.ReadBytes(24) };
  41. //end of camera settings parsing
  42. br.BaseStream.Seek(pCameraAnimationCollection + _bsCameraPointer, SeekOrigin.Begin);
  43. _battleCameraCollection = new BattleCameraCollection { cAnimCollectionCount = br.ReadUInt16() };
  44. var battleCameraSet = new BattleCameraSet[_battleCameraCollection.cAnimCollectionCount];
  45. _battleCameraCollection.battleCameraSet = battleCameraSet;
  46. for (var i = 0; i < _battleCameraCollection.cAnimCollectionCount; i++)
  47. battleCameraSet[i] = new BattleCameraSet { globalSetPointer = (uint)(br.BaseStream.Position + br.ReadUInt16() - i * 2 - 2) };
  48. _battleCameraCollection.pCameraEOF = br.ReadUInt16();
  49. for (var i = 0; i < _battleCameraCollection.cAnimCollectionCount; i++)
  50. {
  51. br.BaseStream.Seek(_battleCameraCollection.battleCameraSet[i].globalSetPointer, 0);
  52. _battleCameraCollection.battleCameraSet[i].animPointers = new uint[8];
  53. for (var n = 0; n < _battleCameraCollection.battleCameraSet[i].animPointers.Length; n++)
  54. _battleCameraCollection.battleCameraSet[i].animPointers[n] = (uint)(br.BaseStream.Position + br.ReadUInt16() * 2 - n * 2);
  55. }
  56. Cam = Extended.ByteArrayToStructure<CameraStruct>(new byte[Marshal.SizeOf(typeof(CameraStruct))]); //what about this kind of trick to initialize struct with a lot amount of fixed sizes in arrays?
  57. ReadAnimationById(GetRandomCameraN(Memory.Encounters.Current), br);
  58. EndOffset = _bsCameraPointer + sCameraDataSize;
  59. //br.BaseStream.Seek(c.EndOffset, 0); //step out
  60. }
  61. #endregion Constructors
  62. #region Properties
  63. public Vector3 CamPosition { get; set; }
  64. public Vector3 CamTarget { get; set; }
  65. public uint EndOffset { get; set; }
  66. public Matrix ProjectionMatrix { get; set; }
  67. //public Matrix worldMatrix { get; }
  68. public Matrix ViewMatrix { get; set; }
  69. #endregion Properties
  70. #region Methods
  71. /// <summary>
  72. /// Parses camera data into BattleCamera struct. Main purpose of this function is to
  73. /// actually read all the offsets and pointers to human readable form of struct. This
  74. /// function later calls ReadAnimation(n) where n is animation Id (i.e. 9 is camCollection=1
  75. /// and cameraAnim=0)
  76. /// </summary>
  77. public static Camera Read(BinaryReader br) => new Camera(br);
  78. public void ChangeAnimation(byte animId)
  79. {
  80. using (var br = Stage.Open())
  81. if (br != null)
  82. {
  83. Cam.ResetTime();
  84. ReadAnimationById(animId, br);
  85. }
  86. }
  87. public void Update()
  88. {
  89. if (!_done || !Cam.Done)
  90. {
  91. var tuple = Cam.UpdatePosition();
  92. if (tuple.CamPosition != tuple.CamTarget)
  93. {
  94. (CamTarget, CamPosition, ViewMatrix, ProjectionMatrix) = tuple;
  95. //Debug.WriteLine((CamTarget, CamPosition, ViewMatrix, ProjectionMatrix));
  96. }
  97. }
  98. if (Cam.Done)
  99. {
  100. if (!BMultiShotAnimation || Cam.Time == 0)
  101. {
  102. _done = true;
  103. return;
  104. }
  105. using (var br = Stage.Open())
  106. if (br != null)
  107. ReadAnimation(LastCameraPointer - 2, br);
  108. }
  109. else
  110. {
  111. Cam.UpdateTime();
  112. _done = false;
  113. }
  114. }
  115. /// <summary>
  116. /// Returns tuple containing camera animation set pointer and camera animation in that set
  117. /// </summary>
  118. /// <param name="animId">6bit variable containing camera pointer</param>
  119. /// <returns>Tuple with CameraSetPointer, CameraSetPointer[CameraAnimationPointer]</returns>
  120. private static CameraSetAnimGRP GetCameraCollectionPointers(byte animId)
  121. {
  122. var enc = Memory.Encounters.Current;
  123. var pSet = enc.ResolveCameraSet(animId);
  124. var pAnim = enc.ResolveCameraAnimation(animId);
  125. return new CameraSetAnimGRP(pSet, pAnim);
  126. }
  127. /// <summary>
  128. /// Gets random camera from available from encounter- primary or secondary
  129. /// </summary>
  130. /// <param name="encounter">instance of current encounter</param>
  131. /// <returns>Either primary or alternative camera from encounter</returns>
  132. private static byte GetRandomCameraN(Encounter encounter)
  133. {
  134. var camToss = Memory.Random.Next(3) < 2 ? 0 : 1; //primary camera has 2/3 chance of being selected
  135. switch (camToss)
  136. {
  137. case 0:
  138. return encounter.PrimaryCamera;
  139. case 1:
  140. return encounter.AlternativeCamera;
  141. default:
  142. goto case 0;
  143. }
  144. }
  145. /// <summary>
  146. /// Gets vanilla engine camera pointers. A team that rewrote the game into PC just left
  147. /// PlayStation MIPS data inside files and therefore their code is to skip given hardcoded
  148. /// data which in fact are PS compiled instructions This data is naturally read by
  149. /// PlayStation in original console release.
  150. /// </summary>
  151. /// <returns>Camera pointer (data after PlayStation MIPS)</returns>
  152. private uint GetCameraPointer()
  153. {
  154. var scenario = Memory.Encounters.Current.Scenario;
  155. var _5d4 = _x5D4.Any(x => x == scenario);
  156. var _5d8 = _x5D8.Any(x => x == scenario);
  157. if (_5d4) return 0x5D4;
  158. if (_5d8) return 0x5D8;
  159. switch (scenario)
  160. {
  161. case 8:
  162. case 48:
  163. case 79:
  164. return 0x618;
  165. case 16:
  166. return 0x628;
  167. case 19:
  168. return 0x644;
  169. case 20:
  170. return 0x61c;
  171. case 30:
  172. case 31:
  173. return 0x934;
  174. case 37:
  175. return 0xcc0;
  176. case 44:
  177. case 45:
  178. case 46:
  179. return 0x9A4;
  180. case 51:
  181. case 52:
  182. case 107:
  183. case 108:
  184. return 0x600;
  185. case 54:
  186. case 56:
  187. return 0x620;
  188. case 92:
  189. return 0x83c;
  190. case 136:
  191. return 0x5fc;
  192. case 137:
  193. return 0xFDC;
  194. case 142:
  195. return 0x183C;
  196. case 147:
  197. return 0x10f0;
  198. case 157:
  199. return 0x638;
  200. }
  201. throw new Exception("0xFFF, unknown pointer!");
  202. }
  203. /// <summary>
  204. /// This method reads raw animation data in stage file or if br.BaseStream and br == null then br.BaseStream
  205. /// file and stores parsed data into battleCamera struct
  206. /// </summary>
  207. /// <param name="cameraAnimOffset">
  208. /// if (br.BaseStream and br are null) is an offset in current battle stage file for camera animation.
  209. /// If br.BaseStream and _br are provided it's the offset in this file
  210. /// </param>
  211. /// <param name="br">sub-component of ms</param>
  212. /// <param name="br.BaseStream">if null then stage file either this memory stream</param>
  213. /// <remarks See also = BS_Camera_ReadAnimation - 00503AC0></remarks>
  214. /// <returns></returns>
  215. private void ReadAnimation(uint cameraAnimOffset, BinaryReader br)
  216. {
  217. br.BaseStream.Seek(cameraAnimOffset, SeekOrigin.Begin);
  218. Cam.ReadAnimation(br);
  219. LastCameraPointer = (uint)(br.BaseStream.Position + 2);
  220. BMultiShotAnimation = br.ReadInt16() != -1;
  221. }
  222. /// <summary>
  223. /// This method resolves the correct camera pointer and runs ReadAnimation(uint,ms,br) method
  224. /// and returns the final pointer
  225. /// </summary>
  226. /// <param name="animId">
  227. /// Animation Id as of binary mask (0bXXXXYYYY where XXXX= animationSet and YYYY=animationId)
  228. /// </param>
  229. /// <param name="br"></param>
  230. /// <returns></returns>
  231. [SuppressMessage("ReSharper", "CommentTypo")]
  232. private void ReadAnimationById(byte animId, BinaryReader br)
  233. {
  234. Cam.AnimationId = animId;
  235. var tpGetter = GetCameraCollectionPointers(animId);
  236. var battleCameraSetArray = _battleCameraCollection.battleCameraSet;
  237. if (battleCameraSetArray.Length > tpGetter.Set && battleCameraSetArray[tpGetter.Set].animPointers.Length > tpGetter.Anim)
  238. {
  239. var battleCameraSet = battleCameraSetArray[tpGetter.Set];
  240. var cameraAnimationGlobalPointer = battleCameraSet.animPointers[tpGetter.Anim];
  241. ReadAnimation(cameraAnimationGlobalPointer, br);
  242. }
  243. else
  244. {
  245. Memory.Log.WriteLine($"ReadAnimationById::{battleCameraSetArray.Length} < {tpGetter.Set}");
  246. if (battleCameraSetArray.Length > tpGetter.Set)
  247. Memory.Log.WriteLine($" or \n{battleCameraSetArray[tpGetter.Set].animPointers.Length} < {tpGetter.Anim}");
  248. }
  249. }
  250. #endregion Methods
  251. }
  252. }