CubismMaskTilePool.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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 UnityEngine;
  8. namespace Live2D.Cubism.Rendering.Masking
  9. {
  10. /// <summary>
  11. /// Virtual pool allocator for <see cref="CubismMaskTile"/>s.
  12. /// </summary>
  13. internal sealed class CubismMaskTilePool
  14. {
  15. /// <summary>
  16. /// Level of subdivisions.
  17. /// </summary>
  18. private int Subdivisions { get; set; }
  19. /// <summary>
  20. /// Pool slots.
  21. /// </summary>
  22. /// <remarks>
  23. /// <see langword="true"/> slots are in use, <see langword="false"/> are available slots.
  24. /// </remarks>
  25. private bool[] Slots { get; set; }
  26. #region Ctors
  27. /// <summary>
  28. /// Initializes instance.
  29. /// </summary>
  30. /// <param name="subdivisions">Number of <see cref="CubismMaskTexture"/> subdivisions.</param>
  31. /// <param name="channels">Number of <see cref="CubismMaskTexture"/> color channels.</param>
  32. public CubismMaskTilePool(int subdivisions, int channels)
  33. {
  34. Subdivisions = subdivisions;
  35. Slots = new bool[(int)Mathf.Pow(4, subdivisions) * channels];
  36. }
  37. #endregion
  38. /// <summary>
  39. /// Acquires tiles.
  40. /// </summary>
  41. /// <param name="count">Number of tiles to acquire.</param>
  42. /// <returns>Acquired tiles on success; <see langword="null"/> otherwise.</returns>
  43. public CubismMaskTile[] AcquireTiles(int count)
  44. {
  45. var result = new CubismMaskTile[count];
  46. // Populate container.
  47. for (var i = 0; i < count; ++i)
  48. {
  49. var allocationSuccessful = false;
  50. for (var j = 0; j < Slots.Length; ++j)
  51. {
  52. // Skip occupied slots.
  53. if (Slots[j])
  54. {
  55. continue;
  56. }
  57. // Generate tile.
  58. result[i] = ToTile(j);
  59. // Flag slot as occupied.
  60. Slots[j] = true;
  61. // Flag allocation as successful.
  62. allocationSuccessful = true;
  63. break;
  64. }
  65. // Return as soon as one allocation fails.
  66. if (!allocationSuccessful)
  67. {
  68. return null;
  69. }
  70. }
  71. // Return on success.
  72. return result;
  73. }
  74. /// <summary>
  75. /// Releases tiles.
  76. /// </summary>
  77. /// <param name="tiles">Tiles to release.</param>
  78. public void ReturnTiles(CubismMaskTile[] tiles)
  79. {
  80. // Flag slots as available.
  81. for (var i = 0; i < tiles.Length; ++i)
  82. {
  83. Slots[ToIndex(tiles[i])] = false;
  84. }
  85. }
  86. /// <summary>
  87. /// Converts from index to <see cref="CubismMaskTile"/>.
  88. /// </summary>
  89. /// <param name="index">Index to convert.</param>
  90. /// <returns>Mask tile matching index.</returns>
  91. private CubismMaskTile ToTile(int index)
  92. {
  93. var tileCounts = (int)Mathf.Pow(4, Subdivisions - 1);
  94. var tilesPerRow = (int)Mathf.Pow(2, Subdivisions - 1);
  95. var tileSize = 1f / (float)tilesPerRow;
  96. var channel = index / tileCounts;
  97. var currentTilePosition = index - (channel * tileCounts);
  98. var column = currentTilePosition / tilesPerRow;
  99. var rowId = currentTilePosition % tilesPerRow;
  100. return new CubismMaskTile
  101. {
  102. Channel = channel,
  103. Column = column,
  104. Row = rowId,
  105. Size = tileSize
  106. };
  107. }
  108. /// <summary>
  109. /// Converts from <see cref="CubismMaskTile"/> to index.
  110. /// </summary>
  111. /// <param name="tile">Tile to convert.</param>
  112. /// <returns>Tile index.</returns>
  113. private int ToIndex(CubismMaskTile tile)
  114. {
  115. var tileCounts = (int)Mathf.Pow(4, Subdivisions - 1);
  116. var tilesPerRow = (int)Mathf.Pow(2, Subdivisions - 1);
  117. return (int)((tile.Channel * tileCounts) + (tile.Column * tilesPerRow) + tile.Row);
  118. }
  119. }
  120. }