public void ReleaseAndMerge(Atlas3DNodePool pool)
            {
                Int16 n = m_Self;

                do
                {
                    pool.m_Nodes[n].ReleaseChildren(pool);
                    pool.m_Nodes[n].ClearIsOccupied();
                    n = pool.m_Nodes[n].m_Parent;
                }while (n >= 0 && pool.m_Nodes[n].IsMergeNeeded(pool));
            }
            public void ReleaseChildren(Atlas3DNodePool pool)
            {
                if (IsLeafNode())
                {
                    return;
                }
                pool.m_Nodes[m_LeftChild].ReleaseChildren(pool);
                pool.m_Nodes[m_RightChild].ReleaseChildren(pool);

                pool.Atlas3DNodeFree(m_LeftChild);
                pool.Atlas3DNodeFree(m_RightChild);
                m_LeftChild  = -1;
                m_RightChild = -1;
            }
        public Atlas3DAllocatorDynamic(int width, int height, int depth, int capacityAllocations)
        {
            // In an evenly split binary tree, the nodeCount == leafNodeCount * 2
            int capacityNodes = capacityAllocations * 2;

            Debug.Assert(capacityNodes < (1 << 16), "Error: Atlas3DAllocatorDynamic: Attempted to allocate a capacity of " + capacityNodes + ", which is greater than our 16-bit indices can support. Please request a capacity <=" + (1 << 16));
            m_Pool = new Atlas3DNodePool((Int16)capacityNodes);

            m_NodeFromID = new Dictionary <int, Int16>(capacityAllocations);

            Int16 rootParent = -1;

            m_Root = m_Pool.Atlas3DNodeCreate(rootParent);
            m_Pool.m_Nodes[m_Root].m_RectSize   = new Vector3(width, height, depth);
            m_Pool.m_Nodes[m_Root].m_RectOffset = Vector3.zero;
            m_Width  = width;
            m_Height = height;
            m_Depth  = depth;

            // string debug = "";
            // DebugStringFromNode(ref debug, m_Root);
            // Debug.Log("Allocating atlas = " + debug);
        }
 public bool IsMergeNeeded(Atlas3DNodePool pool)
 {
     return(pool.m_Nodes[m_LeftChild].IsLeafNode() && (!pool.m_Nodes[m_LeftChild].IsOccupied()) &&
            pool.m_Nodes[m_RightChild].IsLeafNode() && (!pool.m_Nodes[m_RightChild].IsOccupied()));
 }
            public Int16 Allocate(Atlas3DNodePool pool, int width, int height, int depth)
            {
                if (Mathf.Min(Mathf.Min(width, height), depth) < 1)
                {
                    // Degenerate allocation requested.
                    Debug.Assert(false, "Error: Texture3DAtlasDynamic: Attempted to allocate a degenerate region. Please ensure width and height are >= 1");
                    return(-1);
                }

                // not a leaf node, try children
                // TODO: Rather than always going left, then right, we might want to always attempt to allocate in the smaller child, then larger.
                if (!IsLeafNode())
                {
                    Int16 node = pool.m_Nodes[m_LeftChild].Allocate(pool, width, height, depth);
                    if (node == -1)
                    {
                        node = pool.m_Nodes[m_RightChild].Allocate(pool, width, height, depth);
                    }
                    return(node);
                }

                // leaf node, check for fit
                if (IsOccupied())
                {
                    return(-1);
                }
                if (width > m_RectSize.x || height > m_RectSize.y || depth > m_RectSize.z)
                {
                    return(-1);
                }

                // perform the split
                Debug.Assert(m_LeftChild == -1);
                Debug.Assert(m_RightChild == -1);
                m_LeftChild  = pool.Atlas3DNodeCreate(m_Self);
                m_RightChild = pool.Atlas3DNodeCreate(m_Self);
                // Debug.Log("m_LeftChild = " + m_LeftChild);
                // Debug.Log("m_RightChild = " + m_RightChild);

                Debug.Assert(m_LeftChild >= 0 && m_LeftChild < pool.m_Nodes.Length);
                Debug.Assert(m_RightChild >= 0 && m_RightChild < pool.m_Nodes.Length);

                // Debug.Log("Rect = {" + m_RectSize.x + ", " + m_RectSize.y + ", " + m_RectSize.z + ", " + m_RectOffset.x + ", " + m_RectOffset.y + "," + m_RectOffset.z + "}");

                float deltaX = m_RectSize.x - width;
                float deltaY = m_RectSize.y - height;
                float deltaZ = m_RectSize.z - depth;

                // Debug.Log("deltaX = " + deltaX);
                // Debug.Log("deltaY = " + deltaY);
                // Debug.Log("deltaZ = " + deltaZ);

                if (deltaX >= deltaY && deltaX >= deltaZ)
                {
                    // Debug.Log("Split X");
                    //
                    //     +--------+------+
                    //    /        /      /|
                    //   /        /      / |
                    //  +--------+------+  |
                    //  |        |      |  |
                    //  |        |      |  +
                    //  |        |      | /
                    //  |        |      |/
                    //  +--------+------+
                    //
                    pool.m_Nodes[m_LeftChild].m_RectSize   = new Vector3(width, m_RectSize.y, m_RectSize.z);
                    pool.m_Nodes[m_LeftChild].m_RectOffset = m_RectOffset;

                    pool.m_Nodes[m_RightChild].m_RectSize   = new Vector3(deltaX, m_RectSize.y, m_RectSize.z);
                    pool.m_Nodes[m_RightChild].m_RectOffset = new Vector3(m_RectOffset.x + width, m_RectOffset.y, m_RectOffset.z);

                    if (Mathf.Max(deltaY, deltaZ) < 1)
                    {
                        pool.m_Nodes[m_LeftChild].SetIsOccupied();
                        return(m_LeftChild);
                    }
                    else
                    {
                        Int16 node = pool.m_Nodes[m_LeftChild].Allocate(pool, width, height, depth);
                        if (node >= 0)
                        {
                            pool.m_Nodes[node].SetIsOccupied();
                        }
                        return(node);
                    }
                }
                else if (deltaY >= deltaX && deltaY >= deltaZ)
                {
                    // Debug.Log("Split Y.");
                    //
                    //     +---------------+
                    //    /               /|
                    //   /               / +
                    //  +---------------+ /|
                    //  |               |/ |
                    //  +---------------+  +
                    //  |               | /
                    //  |               |/
                    //  +---------------+
                    //
                    pool.m_Nodes[m_LeftChild].m_RectSize   = new Vector3(m_RectSize.x, height, m_RectSize.z);
                    pool.m_Nodes[m_LeftChild].m_RectOffset = m_RectOffset;

                    pool.m_Nodes[m_RightChild].m_RectSize   = new Vector3(m_RectSize.x, deltaY, m_RectSize.z);
                    pool.m_Nodes[m_RightChild].m_RectOffset = new Vector3(m_RectOffset.x, m_RectOffset.y + height, m_RectOffset.z);

                    if (Math.Max(deltaX, deltaZ) < 1)
                    {
                        pool.m_Nodes[m_LeftChild].SetIsOccupied();
                        return(m_LeftChild);
                    }
                    else
                    {
                        Int16 node = pool.m_Nodes[m_LeftChild].Allocate(pool, width, height, depth);
                        if (node >= 0)
                        {
                            pool.m_Nodes[node].SetIsOccupied();
                        }
                        return(node);
                    }
                }
                else // deltaZ >= deltaX && deltaZ >= deltaY
                {
                    // Debug.Log("Split Z.");
                    //
                    //     +---------------+
                    //    +---------------+|
                    //   /               /||
                    //  +---------------+ ||
                    //  |               | ||
                    //  |               | |+
                    //  |               | +
                    //  |               |/
                    //  +---------------+
                    //
                    pool.m_Nodes[m_LeftChild].m_RectSize   = new Vector3(m_RectSize.x, m_RectSize.y, depth);
                    pool.m_Nodes[m_LeftChild].m_RectOffset = m_RectOffset;

                    pool.m_Nodes[m_RightChild].m_RectSize   = new Vector3(m_RectSize.x, m_RectSize.y, deltaZ);
                    pool.m_Nodes[m_RightChild].m_RectOffset = new Vector3(m_RectOffset.x, m_RectOffset.y, m_RectOffset.z + depth);

                    if (Math.Max(deltaX, deltaY) < 1)
                    {
                        pool.m_Nodes[m_LeftChild].SetIsOccupied();
                        return(m_LeftChild);
                    }
                    else
                    {
                        Int16 node = pool.m_Nodes[m_LeftChild].Allocate(pool, width, height, depth);
                        if (node >= 0)
                        {
                            pool.m_Nodes[node].SetIsOccupied();
                        }
                        return(node);
                    }
                }
            }