/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
using UnityEngine;
namespace Live2D.Cubism.Rendering.Masking
{
///
/// Virtual pool allocator for s.
///
internal sealed class CubismMaskTilePool
{
///
/// Level of subdivisions.
///
private int Subdivisions { get; set; }
///
/// Pool slots.
///
///
/// slots are in use, are available slots.
///
private bool[] Slots { get; set; }
#region Ctors
///
/// Initializes instance.
///
/// Number of subdivisions.
/// Number of color channels.
public CubismMaskTilePool(int subdivisions, int channels)
{
Subdivisions = subdivisions;
Slots = new bool[(int)Mathf.Pow(4, subdivisions) * channels];
}
#endregion
///
/// Acquires tiles.
///
/// Number of tiles to acquire.
/// Acquired tiles on success; otherwise.
public CubismMaskTile[] AcquireTiles(int count)
{
var result = new CubismMaskTile[count];
// Populate container.
for (var i = 0; i < count; ++i)
{
var allocationSuccessful = false;
for (var j = 0; j < Slots.Length; ++j)
{
// Skip occupied slots.
if (Slots[j])
{
continue;
}
// Generate tile.
result[i] = ToTile(j);
// Flag slot as occupied.
Slots[j] = true;
// Flag allocation as successful.
allocationSuccessful = true;
break;
}
// Return as soon as one allocation fails.
if (!allocationSuccessful)
{
return null;
}
}
// Return on success.
return result;
}
///
/// Releases tiles.
///
/// Tiles to release.
public void ReturnTiles(CubismMaskTile[] tiles)
{
// Flag slots as available.
for (var i = 0; i < tiles.Length; ++i)
{
Slots[ToIndex(tiles[i])] = false;
}
}
///
/// Converts from index to .
///
/// Index to convert.
/// Mask tile matching index.
private CubismMaskTile ToTile(int index)
{
var tileCounts = (int)Mathf.Pow(4, Subdivisions - 1);
var tilesPerRow = (int)Mathf.Pow(2, Subdivisions - 1);
var tileSize = 1f / (float)tilesPerRow;
var channel = index / tileCounts;
var currentTilePosition = index - (channel * tileCounts);
var column = currentTilePosition / tilesPerRow;
var rowId = currentTilePosition % tilesPerRow;
return new CubismMaskTile
{
Channel = channel,
Column = column,
Row = rowId,
Size = tileSize
};
}
///
/// Converts from to index.
///
/// Tile to convert.
/// Tile index.
private int ToIndex(CubismMaskTile tile)
{
var tileCounts = (int)Mathf.Pow(4, Subdivisions - 1);
var tilesPerRow = (int)Mathf.Pow(2, Subdivisions - 1);
return (int)((tile.Channel * tileCounts) + (tile.Column * tilesPerRow) + tile.Row);
}
}
}