/// <summary>
        /// Virtually expands the atlas from its initial size to its maximum size.
        /// </summary>
        /// <remarks>
        /// The areas are built by doubling horizontally and vertically, over and over. Consider the following example,
        /// where the initial atlas size is 64x64 and the maximum size is 256x256. The resulting 5 areas would be:
        /// 1: First area determined by the initial atlas size
        /// 2: Area generated by horizontal expansion
        /// 3: Area generated by vertical expansion
        /// 4: Area generated by horizontal expansion
        /// 5: Area generated by vertical expansion - final expansion
        ///  _______________________
        /// |                       |
        /// |                       |
        /// |           5           |
        /// |                       |
        /// |                       |
        /// |_______________________|
        /// |           |           |
        /// |     3     |           |
        /// |___________|     4     |
        /// |     |     |           |
        /// |  1  |  2  |           |
        /// |_____|_____|___________|
        ///
        /// Because of the exponential nature of this process, we don't need to worry about very large textures. For
        /// example, from 64x64 to 4096x4096, only 12 iterations are required, leading to 13 areas.
        /// </remarks>
        private void BuildAreas()
        {
            AreaNode current = m_FirstUnpartitionedArea;

            while (virtualWidth < maxAtlasSize || virtualHeight < maxAtlasSize)
            {
                RectInt newArea;
                if (virtualWidth > virtualHeight)
                {
                    // Double Vertically.
                    newArea        = new RectInt(0, virtualHeight, virtualWidth, virtualHeight);
                    virtualHeight *= 2;
                }
                else
                {
                    // Double Horizontally.
                    newArea       = new RectInt(virtualWidth, 0, virtualWidth, virtualHeight);
                    virtualWidth *= 2;
                }

                var newAreaNode = AreaNode.Acquire(newArea);
                newAreaNode.AddAfter(current);
                current = newAreaNode;
            }
        }
Example #2
0
        /// <param name="initialAtlasSize">Initial size of the atlas (POT).</param>
        /// <param name="maxAtlasSize">Maximum size of the atlas (POT).</param>
        public UIRAtlasAllocator(int initialAtlasSize, int maxAtlasSize, int sidePadding = 1)
        {
            // Validate Size Coherence.
            Assert.IsTrue(initialAtlasSize > 0 && initialAtlasSize <= maxAtlasSize);

            // Validate POT
            Assert.IsTrue(initialAtlasSize == Mathf.NextPowerOfTwo(initialAtlasSize));
            Assert.IsTrue(maxAtlasSize == Mathf.NextPowerOfTwo(maxAtlasSize));

            m_1SidePadding    = sidePadding;
            m_2SidePadding    = sidePadding << 1;
            this.maxAtlasSize = maxAtlasSize;
            maxImageWidth     = maxAtlasSize;
            maxImageHeight    = (initialAtlasSize == maxAtlasSize) ? maxAtlasSize / 2 + m_2SidePadding : maxAtlasSize / 4 + m_2SidePadding;
            virtualWidth      = initialAtlasSize;
            virtualHeight     = initialAtlasSize;

            int maxOpenRows = GetLog2OfNextPower(maxAtlasSize) + 1;

            m_OpenRows = new Row[maxOpenRows];

            var area = new RectInt(0, 0, initialAtlasSize, initialAtlasSize);

            m_FirstUnpartitionedArea = AreaNode.Acquire(area);
            BuildAreas();
        }