/** * 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); } } }