CubismTaskableModel.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /**
  2. * Copyright(c) Live2D Inc. All rights reserved.
  3. *
  4. * Use of this source code is governed by the Live2D Open Software license
  5. * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
  6. */
  7. using Live2D.Cubism.Core.Unmanaged;
  8. using System.Threading;
  9. using UnityEngine;
  10. namespace Live2D.Cubism.Core
  11. {
  12. /// <summary>
  13. /// 'Atomic' <see cref="CubismModel"/> update task.
  14. /// </summary>
  15. internal sealed class CubismTaskableModel : ICubismTask
  16. {
  17. #region Factory Methods
  18. /// <summary>
  19. /// Creates a <see cref="CubismTaskableModel"/> from a <see cref="CubismMoc"/>.
  20. /// </summary>
  21. /// <param name="moc">Moc source.</param>
  22. /// <returns>Instance.</returns>
  23. public static CubismTaskableModel CreateTaskableModel(CubismMoc moc)
  24. {
  25. return new CubismTaskableModel(moc);
  26. }
  27. #endregion
  28. /// <summary>
  29. /// Handle to unmanaged model.
  30. /// </summary>
  31. public CubismUnmanagedModel UnmanagedModel { get; private set; }
  32. /// <summary>
  33. /// <see cref="CubismMoc"/> the model was instantiated from.
  34. /// </summary>
  35. public CubismMoc Moc { get; private set; }
  36. private CubismDynamicDrawableData[] _dynamicDrawableData;
  37. /// <summary>
  38. /// Buffer to write dynamic data to.
  39. /// </summary>
  40. public CubismDynamicDrawableData[] DynamicDrawableData
  41. {
  42. get
  43. {
  44. CubismDynamicDrawableData[] dynamicDrawableData = null;
  45. if (Monitor.TryEnter(Lock))
  46. {
  47. dynamicDrawableData = _dynamicDrawableData;
  48. Monitor.Exit(Lock);
  49. }
  50. return dynamicDrawableData;
  51. }
  52. private set
  53. {
  54. _dynamicDrawableData = value;
  55. }
  56. }
  57. /// <summary>
  58. /// True if task is currently executing.
  59. /// </summary>
  60. public bool IsExecuting
  61. {
  62. get
  63. {
  64. var isExecuting = false;
  65. if (Monitor.TryEnter(Lock))
  66. {
  67. isExecuting = (State == TaskState.Enqueued || State == TaskState.Executing);
  68. Monitor.Exit(Lock);
  69. }
  70. return isExecuting;
  71. }
  72. }
  73. /// <summary>
  74. /// True if did run to completion at least once.
  75. /// </summary>
  76. public bool DidExecute
  77. {
  78. get
  79. {
  80. var didExecute = false;
  81. if (Monitor.TryEnter(Lock))
  82. {
  83. didExecute = (State == TaskState.Executed);
  84. Monitor.Exit(Lock);
  85. }
  86. return didExecute;
  87. }
  88. }
  89. /// <summary>
  90. /// True if unmanaged model and moc should be released.
  91. /// </summary>
  92. private bool ShouldReleaseUnmanaged { get; set; }
  93. #region Constructor
  94. /// <summary>
  95. /// Initializes instance.
  96. /// </summary>
  97. /// <param name="moc">Moc unmanaged model was instantiated from.</param>
  98. public CubismTaskableModel(CubismMoc moc)
  99. {
  100. Moc = moc;
  101. // Instantiate unmanaged model.
  102. var unmanagedMoc = moc.AcquireUnmanagedMoc();
  103. UnmanagedModel = CubismUnmanagedModel.FromMoc(unmanagedMoc);
  104. if (UnmanagedModel == null)
  105. {
  106. Debug.LogError("This .moc3 file version is \"Unknown\"!!\n" +
  107. "It may be broken or you are trying to use a higher version of Moc than Cubism Core.\n" +
  108. "Check the supported versions at CubismMoc.LatestVersion.\n" +
  109. "The \"CoreDll\" constants indicate which Moc version the numbers are assigned to.");
  110. return;
  111. }
  112. Lock = new object();
  113. State = TaskState.Idle;
  114. DynamicDrawableData = CubismDynamicDrawableData.CreateData(UnmanagedModel);
  115. ShouldReleaseUnmanaged = false;
  116. }
  117. #endregion
  118. /// <summary>
  119. /// Tries to read parameters into a buffer.
  120. /// </summary>
  121. /// <param name="parameters">Buffer to write to.</param>
  122. /// <returns><see langword="true"/> on success; <see langword="false"/> otherwise.</returns>
  123. public bool TryReadParameters(CubismParameter[] parameters)
  124. {
  125. var didRead = false;
  126. if (Monitor.TryEnter(Lock))
  127. {
  128. try
  129. {
  130. if (State == TaskState.Executed)
  131. {
  132. parameters.ReadFrom(UnmanagedModel);
  133. didRead = true;
  134. }
  135. }
  136. finally
  137. {
  138. Monitor.Exit(Lock);
  139. }
  140. }
  141. return didRead;
  142. }
  143. /// <summary>
  144. /// Tries to write parameters to a buffer.
  145. /// </summary>
  146. /// <param name="parameters">Buffer to read from.</param>
  147. /// <param name="parts">Buffer to read from.</param>
  148. /// <returns><see langword="true"/> on success; <see langword="false"/> otherwise.</returns>
  149. public bool TryWriteParametersAndParts(CubismParameter[] parameters, CubismPart[] parts)
  150. {
  151. var didWrite = false;
  152. if (Monitor.TryEnter(Lock))
  153. {
  154. try
  155. {
  156. if (State != TaskState.Executing)
  157. {
  158. parameters.WriteTo(UnmanagedModel);
  159. parts.WriteTo(UnmanagedModel);
  160. didWrite = true;
  161. }
  162. }
  163. finally
  164. {
  165. Monitor.Exit(Lock);
  166. }
  167. }
  168. return didWrite;
  169. }
  170. /// <summary>
  171. /// Dispatches the task for (maybe async) execution.
  172. /// </summary>
  173. public void Update()
  174. {
  175. // Validate state.
  176. lock (Lock)
  177. {
  178. if (State == TaskState.Enqueued || State == TaskState.Executing)
  179. {
  180. return;
  181. }
  182. // Update state.
  183. State = TaskState.Enqueued;
  184. }
  185. CubismTaskQueue.Enqueue(this);
  186. }
  187. /// <summary>
  188. /// Forces the task to run now to completion.
  189. /// </summary>
  190. public bool UpdateNow()
  191. {
  192. // Validate state.
  193. lock (Lock)
  194. {
  195. if (State == TaskState.Enqueued || State == TaskState.Executing)
  196. {
  197. return false;
  198. }
  199. // Update state.
  200. State = TaskState.Enqueued;
  201. }
  202. // Run execution directly.
  203. Execute();
  204. return true;
  205. }
  206. /// <summary>
  207. /// Releases unmanaged resource.
  208. /// </summary>
  209. public void ReleaseUnmanaged()
  210. {
  211. ShouldReleaseUnmanaged = true;
  212. // Return if task is ongoing.
  213. lock (Lock)
  214. {
  215. if (State == TaskState.Enqueued || State == TaskState.Executing)
  216. {
  217. return;
  218. }
  219. }
  220. OnReleaseUnmanaged();
  221. ShouldReleaseUnmanaged = false;
  222. }
  223. /// <summary>
  224. /// Runs the task.
  225. /// </summary>
  226. private void Execute()
  227. {
  228. // Validate state.
  229. lock (Lock)
  230. {
  231. State = TaskState.Executing;
  232. }
  233. // Update native backend.
  234. UnmanagedModel.Update();
  235. // Get results.
  236. DynamicDrawableData.ReadFrom(UnmanagedModel);
  237. // Update state.
  238. lock (Lock)
  239. {
  240. State = TaskState.Executed;
  241. // Release native if requested.
  242. if (ShouldReleaseUnmanaged)
  243. {
  244. OnReleaseUnmanaged();
  245. }
  246. }
  247. }
  248. /// <summary>
  249. /// Actually releases native resource(s).
  250. /// </summary>
  251. private void OnReleaseUnmanaged()
  252. {
  253. UnmanagedModel.Release();
  254. Moc.ReleaseUnmanagedMoc();
  255. UnmanagedModel = null;
  256. }
  257. #region Implementation of ICubismTask
  258. void ICubismTask.Execute()
  259. {
  260. Execute();
  261. }
  262. #endregion
  263. #region Threading
  264. /// <summary>
  265. /// Task states.
  266. /// </summary>
  267. private enum TaskState
  268. {
  269. /// <summary>
  270. /// Idle state.
  271. /// </summary>
  272. Idle,
  273. /// <summary>
  274. /// Waiting-for-execution state.
  275. /// </summary>
  276. Enqueued,
  277. /// <summary>
  278. /// Executing state.
  279. /// </summary>
  280. Executing,
  281. /// <summary>
  282. /// Executed state.
  283. /// </summary>
  284. Executed
  285. }
  286. /// <summary>
  287. /// Lock.
  288. /// </summary>
  289. private object Lock { get; set; }
  290. /// <summary>
  291. /// Internal state.
  292. /// </summary>
  293. private TaskState State { get; set; }
  294. #endregion
  295. }
  296. }