示例#1
0
 public void Reset(HitKd hitOct)
 {
     _children = null;
     _hitOct   = hitOct;
     Start     = 0;
     Items     = 0;
 }
        /* istanbul ignore never next executed below the "magic" check (https://www.vpforums.org/index.php?showtopic=42690) */
        public void CreateNextLevel(int level, int levelEmpty, HitKd hitOct)
        {
            var orgItems = Items & 0x3FFFFFFF;

            // !! magic
            if (orgItems <= 4 || level >= 128 / 2)
            {
                return;
            }

            var vDiag = new Vertex3D(
                RectBounds.Right - RectBounds.Left,
                RectBounds.Bottom - RectBounds.Top,
                RectBounds.ZHigh - RectBounds.ZLow
                );

            int axis;

            if (vDiag.X > vDiag.Y && vDiag.X > vDiag.Z)
            {
                if (vDiag.X < 0.0001)
                {
                    return;
                }
                axis = 0;
            }
            else if (vDiag.Y > vDiag.Z)
            {
                if (vDiag.Y < 0.0001)
                {
                    return;
                }
                axis = 1;
            }
            else
            {
                if (vDiag.Z < 0.0001)
                {
                    return;
                }

                axis = 2;
            }

            //!! weight this with ratio of elements going to middle vs left&right! (avoids volume split that goes directly through object)

            // create children, calc bboxes
            _children = hitOct.AllocTwoNodes();
            if (_children.Length == 0)
            {
                // ran out of nodes - abort
                return;
            }

            _children[0].RectBounds = RectBounds;
            _children[1].RectBounds = RectBounds;

            var vCenter = new Vertex3D(
                (RectBounds.Left + RectBounds.Right) * 0.5f,
                (RectBounds.Top + RectBounds.Bottom) * 0.5f,
                (RectBounds.ZLow + RectBounds.ZHigh) * 0.5f
                );

            if (axis == 0)
            {
                _children[0].RectBounds.Right = vCenter.X;
                _children[1].RectBounds.Left  = vCenter.X;
            }
            else if (axis == 1)
            {
                _children[0].RectBounds.Bottom = vCenter.Y;
                _children[1].RectBounds.Top    = vCenter.Y;
            }
            else
            {
                _children[0].RectBounds.ZHigh = vCenter.Z;
                _children[1].RectBounds.ZLow  = vCenter.Z;
            }

            _children[0].Items     = 0;
            _children[0]._children = null;
            _children[1].Items     = 0;
            _children[1]._children = null;

            // determine amount of items that cross splitplane, or are passed on to the children
            if (axis == 0)
            {
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var pho = hitOct.GetItemAt(i);

                    if (pho.HitBBox.Right < vCenter.X)
                    {
                        _children[0].Items++;
                    }
                    else if (pho.HitBBox.Left > vCenter.X)
                    {
                        _children[1].Items++;
                    }
                }
            }
            else if (axis == 1)
            {
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var pho = hitOct.GetItemAt(i);

                    if (pho.HitBBox.Bottom < vCenter.Y)
                    {
                        _children[0].Items++;
                    }
                    else if (pho.HitBBox.Top > vCenter.Y)
                    {
                        _children[1].Items++;
                    }
                }
            }
            else
            {
                // axis == 2
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var pho = hitOct.GetItemAt(i);

                    if (pho.HitBBox.ZHigh < vCenter.Z)
                    {
                        _children[0].Items++;
                    }
                    else if (pho.HitBBox.ZLow > vCenter.Z)
                    {
                        _children[1].Items++;
                    }
                }
            }

            // check if at least two nodes feature objects, otherwise don"t bother subdividing further
            var countEmpty = 0;

            if (_children[0].Items == 0)
            {
                countEmpty = 1;
            }

            if (_children[1].Items == 0)
            {
                ++countEmpty;
            }

            if (orgItems - _children[0].Items - _children[1].Items == 0)
            {
                ++countEmpty;
            }

            if (countEmpty >= 2)
            {
                ++levelEmpty;
            }
            else
            {
                levelEmpty = 0;
            }

            if (levelEmpty > 8)
            {
                // If 8 levels were all just subdividing the same objects without luck, exit & Free the nodes again (but at least empty space was cut off)
                hitOct.NumNodes -= 2;
                _children        = null;
                return;
            }

            _children[0].Start = Start + orgItems - _children[0].Items - _children[1].Items;
            _children[1].Start = _children[0].Start + _children[0].Items;

            var items = 0;

            _children[0].Items = 0;
            _children[1].Items = 0;

            switch (axis)
            {
            // sort items that cross splitplane in-place, the others are sorted into a temporary
            case 0: {
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var pho = hitOct.GetItemAt(i);

                    if (pho.HitBBox.Right < vCenter.X)
                    {
                        hitOct.Indices[_children[0].Start + _children[0].Items++] = hitOct.OrgIdx[i];
                    }
                    else if (pho.HitBBox.Left > vCenter.X)
                    {
                        hitOct.Indices[_children[1].Start + _children[1].Items++] = hitOct.OrgIdx[i];
                    }
                    else
                    {
                        hitOct.OrgIdx[Start + items++] = hitOct.OrgIdx[i];
                    }
                }

                break;
            }

            case 1: {
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var pho = hitOct.GetItemAt(i);

                    if (pho.HitBBox.Bottom < vCenter.Y)
                    {
                        hitOct.Indices[_children[0].Start + _children[0].Items++] = hitOct.OrgIdx[i];
                    }
                    else if (pho.HitBBox.Top > vCenter.Y)
                    {
                        hitOct.Indices[_children[1].Start + _children[1].Items++] = hitOct.OrgIdx[i];
                    }
                    else
                    {
                        hitOct.OrgIdx[Start + items++] = hitOct.OrgIdx[i];
                    }
                }

                break;
            }

            default: {                     // axis == 2
                for (var i = Start; i < Start + orgItems; ++i)
                {
                    var pho = hitOct.GetItemAt(i);

                    if (pho.HitBBox.ZHigh < vCenter.Z)
                    {
                        hitOct.Indices[_children[0].Start + _children[0].Items++] = hitOct.OrgIdx[i];
                    }
                    else if (pho.HitBBox.ZLow > vCenter.Z)
                    {
                        hitOct.Indices[_children[1].Start + _children[1].Items++] = hitOct.OrgIdx[i];
                    }
                    else
                    {
                        hitOct.OrgIdx[Start + items++] = hitOct.OrgIdx[i];
                    }
                }

                break;
            }
            }

            // The following assertions hold after this step:
            //assert( this.Start + items == this.Children[0].This.Start );
            //assert( this.Children[0].This.Start + this.Children[0].This.Items == this.Children[1].This.Start );
            //assert( this.Children[1].This.Start + this.Children[1].This.Items == this.Start + org_items );
            //assert( this.Start + org_items <= this.HitOct->tmp.Size() );

            Items = items | (axis << 30);

            // copy temporary back //!! could omit this by doing everything inplace
            for (var i = 0; i < _children[0].Items; i++)
            {
                hitOct.OrgIdx[_children[0].Start + i] = hitOct.Indices[_children[0].Start + i];
            }

            for (var i = 0; i < _children[1].Items; i++)
            {
                hitOct.OrgIdx[_children[1].Start + i] = hitOct.Indices[_children[1].Start + i];
            }
            //memcpy(&this.HitOct->m_org_idx[this.Children[0].Start], &this.HitOct->tmp[this.Children[0].Start], this.Children[0].Items*sizeof(unsigned int));
            //memcpy(&this.HitOct->m_org_idx[this.Children[1].Start], &this.HitOct->tmp[this.Children[1].Start], this.Children[1].This.Items*sizeof(unsigned int));

            _children[0].CreateNextLevel(level + 1, levelEmpty, hitOct);
            _children[1].CreateNextLevel(level + 1, levelEmpty, hitOct);
        }
        public void HitTestBall(Ball ball, CollisionEvent coll, PlayerPhysics physics, HitKd hitOct)
        {
            var orgItems = Items & 0x3FFFFFFF;
            var axis     = Items >> 30;

            for (var i = Start; i < Start + orgItems; i++)
            {
                var pho = hitOct.GetItemAt(i);
                if (ball.Hit != pho && pho.HitBBox.IntersectSphere(ball.State.Pos, ball.Hit.HitRadiusSqr))
                {
                    pho.DoHitTest(ball, coll, physics);
                }
            }

            if (_children != null)
            {
                switch (axis)
                {
                // not a leaf
                case 0: {
                    var vCenter = (RectBounds.Left + RectBounds.Right) * 0.5f;
                    if (ball.Hit.HitBBox.Left <= vCenter)
                    {
                        _children[0].HitTestBall(ball, coll, physics, hitOct);
                    }

                    if (ball.Hit.HitBBox.Right >= vCenter)
                    {
                        _children[1].HitTestBall(ball, coll, physics, hitOct);
                    }
                    break;
                }

                case 1: {
                    var vCenter = (RectBounds.Top + RectBounds.Bottom) * 0.5f;
                    if (ball.Hit.HitBBox.Top <= vCenter)
                    {
                        _children[0].HitTestBall(ball, coll, physics, hitOct);
                    }

                    if (ball.Hit.HitBBox.Bottom >= vCenter)
                    {
                        _children[1].HitTestBall(ball, coll, physics, hitOct);
                    }
                    break;
                }

                default: {
                    var vCenter = (RectBounds.ZLow + RectBounds.ZHigh) * 0.5f;
                    if (ball.Hit.HitBBox.ZLow <= vCenter)
                    {
                        _children[0].HitTestBall(ball, coll, physics, hitOct);
                    }

                    if (ball.Hit.HitBBox.ZHigh >= vCenter)
                    {
                        _children[1].HitTestBall(ball, coll, physics, hitOct);
                    }
                    break;
                }
                }
            }
        }
示例#4
0
        private HitKd _hitOct;                                                         // m_hitoct

        public HitKdNode(HitKd hitOct)
        {
            _hitOct = hitOct;
        }