Ejemplo n.º 1
0
            public SEntry(ref BoundingBox query, uint res, Vector2I cell, ContainmentType result, uint level)
            {
                Box2I box = new Box2I(ref query, res);

                cell *= HeightmapNode.HEIGHTMAP_BRANCH_FACTOR;
                Box2I cellb = new Box2I(cell, cell + HeightmapNode.HEIGHTMAP_BRANCH_FACTOR - 1);

                box.Intersect(ref cellb);

                Bounds = box;
                Next   = box.Min;

                Level = level;

                Result       = result;
                Intersection = result;
                Continue     = false;
            }
Ejemplo n.º 2
0
        public void GetBounds(ref BoundingBox query)
        {
            float maxSize = Math.Max(query.Width, query.Height);


            if (maxSize < m_pixelSizeFour || PruningTree == null || PruningTree.Length == 0)
            {
                // compute an inflated box so we account for smoothing :)
                Box2I bb = new Box2I(ref query, (uint)Resolution);
                bb.Min -= 1;
                bb.Max += 1;
                bb.Intersect(ref m_bounds);

                ushort height;

                GetValue(bb.Min.X, bb.Min.Y, out height);

                int mmin = ushort.MaxValue, mmax = 0;

                for (int y = bb.Min.Y; y <= bb.Max.Y; ++y)
                {
                    for (int x = bb.Min.X; x <= bb.Max.X; ++x)
                    {
                        GetValue(x, y, out height);

                        if (height > mmax)
                        {
                            mmax = height;
                        }
                        if (height < mmin)
                        {
                            mmin = height;
                        }
                    }
                }

                int diff = mmax - mmin;

                diff = (diff * 2) / 3;

                mmax += diff;

                mmin -= diff;

                query.Min.Z = mmin * MyCubemapHelpers.USHORT_RECIP;
                query.Max.Z = mmax * MyCubemapHelpers.USHORT_RECIP;
                return;
            }

            // Switch to floor to grab some closer precision
            double log = Math.Log(Resolution / (maxSize * HeightmapNode.HEIGHTMAP_LEAF_SIZE)) / Math.Log(HeightmapNode.HEIGHTMAP_BRANCH_FACTOR);

            uint level = (uint)PruningTree.Length - 1 - (uint)MathHelper.Clamp(log, 0, PruningTree.Length - 1);

            Box2I rootBounds  = new Box2I(Vector2I.Zero, new Vector2I((int)PruningTree[level].Res - 1));
            Box2I queryBounds = new Box2I(ref query, PruningTree[level].Res);

            queryBounds.Intersect(ref rootBounds);

            query.Min.Z = float.PositiveInfinity;
            query.Max.Z = float.NegativeInfinity;

            int lres = (int)PruningTree[level].Res;

            for (int y = queryBounds.Min.Y; y <= queryBounds.Max.Y; ++y)
            {
                for (int x = queryBounds.Min.X; x <= queryBounds.Max.X; ++x)
                {
                    var cell = PruningTree[level].Nodes[y * lres + x];
                    if (query.Min.Z > cell.Min)
                    {
                        query.Min.Z = cell.Min;
                    }
                    if (query.Max.Z < cell.Max)
                    {
                        query.Max.Z = cell.Max;
                    }
                }
            }
        }
Ejemplo n.º 3
0
        /**
         * Scan pruning tree for intersection with a bounding box.
         *
         * This method is a iterative implementation of the following algorithm:
         *
         * procedure scan(level, box, result)
         * for each $cell in $level
         *     $inter = intersects($cell, $box)
         *
         *     if $inter = INTERSECTS and $cell is not contained and $level != 0
         *         $inter = scan($level -1, box, $result)
         *
         *     switch on $inter
         *         case INTERSECTS
         *             return INTERSECTS
         *
         *         case CONTAINED
         *             if $result == DISJOINT
         *                 return INTERSECTS
         *             $result = CONTAINED
         *
         *         case DISJOINT
         *             if $result == CONTAINED
         *                 return INTERSECTS
         *             $result = DISJOINT
         * return $result
         */
        public ContainmentType QueryHeight(ref BoundingBox query)
        {
            // Fallback in case the user loads a bad heightmap.
            if (PruningTree == null)
            {
                return(ContainmentType.Intersects);
            }

            if (m_queryStack == null || m_queryStack.Length < PruningTree.Length)
            {
                m_queryStack = new SEntry[PruningTree.Length];
            }

            if (query.Min.Z > Root.Max)
            {
                return(ContainmentType.Disjoint);
            }
            if (query.Max.Z < Root.Min)
            {
                return(ContainmentType.Contains);
            }

            if (query.Max.X < 0 || query.Max.Y < 0 || query.Min.X > 1 || query.Min.Y > 1)
            {
                return(ContainmentType.Disjoint);
            }

            // Handle minimum size heightmaps
            if (PruningTree.Length == 0)
            {
                return(ContainmentType.Intersects);
            }

            if (query.Max.X == 1.0)
            {
                query.Max.X = .99999999f;
            }
            if (query.Max.Y == 1.0)
            {
                query.Max.Y = .99999999f;
            }

            // state variables;
            ContainmentType result = ContainmentType.Intersects;

            float maxSize = Math.Max(query.Width, query.Height);

            // If the box is really small we can be even more precise by checking the heightmap directly.
            if (maxSize < m_pixelSizeFour)
            {
                // compute an inflated box so we account for smoothing :)
                Box2I bb = new Box2I(ref query, (uint)Resolution);
                bb.Min -= 1;
                bb.Max += 1;
                bb.Intersect(ref m_bounds);

                int min = (int)(query.Min.Z * ushort.MaxValue);
                int max = (int)(query.Max.Z * ushort.MaxValue);

                ushort height;

                GetValue(bb.Min.X, bb.Min.Y, out height);

                if (height > max)
                {
                    result = ContainmentType.Contains;
                }
                else if (height < min)
                {
                    result = ContainmentType.Disjoint;
                }
                else
                {
                    return(ContainmentType.Intersects);
                }

                int mmin = ushort.MaxValue, mmax = 0;

                for (int y = bb.Min.Y; y <= bb.Max.Y; ++y)
                {
                    for (int x = bb.Min.X; x <= bb.Max.X; ++x)
                    {
                        GetValue(x, y, out height);

                        if (height > mmax)
                        {
                            mmax = height;
                        }
                        if (height < mmin)
                        {
                            mmin = height;
                        }
                    }
                }

                int diff = mmax - mmin;

                diff += diff >> 1;

                mmax += diff;

                mmin -= diff;

                if (min > mmax)
                {
                    return(ContainmentType.Disjoint);
                }
                if (max < mmin)
                {
                    return(ContainmentType.Contains);
                }

                return(ContainmentType.Intersects);
            }

            double log = Math.Log(maxSize * (Resolution / HeightmapNode.HEIGHTMAP_LEAF_SIZE)) / Math.Log(HeightmapNode.HEIGHTMAP_BRANCH_FACTOR);

            uint level = (uint)MathHelper.Clamp(log, 0, PruningTree.Length - 1);

            // stack index
            int ss = 0;
            var st = m_queryStack;

            Box2I rootBounds = new Box2I(Vector2I.Zero, new Vector2I((int)PruningTree[level].Res - 1));

            st[0].Bounds = new Box2I(ref query, PruningTree[level].Res);
            st[0].Bounds.Intersect(ref rootBounds);
            st[0].Next     = st[0].Bounds.Min;
            st[0].Level    = level;
            st[0].Result   = result;
            st[0].Continue = false;

scan:
            while (true)
            {
                SEntry state;
                if (ss == -1)
                {
                    break;
                }
                else
                {
                    state = st[ss];
                }

                for (int y = state.Next.Y; y <= state.Bounds.Max.Y; ++y)
                {
                    for (int x = state.Bounds.Min.X; x <= state.Bounds.Max.X; ++x)
                    {
                        if (!state.Continue)
                        {
                            state.Intersection = PruningTree[state.Level].Intersect(x, y, ref query);

                            if (state.Intersection == ContainmentType.Intersects && PruningTree[state.Level].IsCellNotContained(x, y, ref query) &&
                                state.Level != 0)
                            {
                                state.Next     = new Vector2I(x, y);
                                state.Continue = true;
                                st[ss]         = state;
                                ss++;
                                st[ss] = new SEntry(ref query, PruningTree[state.Level - 1].Res, new Vector2I(x, y), state.Result, state.Level - 1);
                                goto scan;
                            }
                        }
                        else
                        {
                            state.Continue = false;
                            x = state.Next.X;
                        }

                        switch (state.Intersection)
                        {
                        case ContainmentType.Intersects:
                            state.Result = ContainmentType.Intersects;
                            goto ret;
                            break;

                        case ContainmentType.Disjoint:
                            if (state.Result == ContainmentType.Contains)
                            {
                                state.Result = ContainmentType.Intersects;
                                goto ret;
                            }
                            state.Result = ContainmentType.Disjoint;
                            break;

                        case ContainmentType.Contains:
                            if (state.Result == ContainmentType.Disjoint)
                            {
                                state.Result = ContainmentType.Intersects;
                                goto ret;
                            }
                            state.Result = ContainmentType.Contains;
                            break;
                        }
                    }
                }

                ret :;
                result = state.Result;
                ss--;
                if (ss >= 0)
                {
                    st[ss].Intersection = result;
                }
            }

            return(result);
        }
Ejemplo n.º 4
0
        public unsafe ContainmentType QueryHeight(ref BoundingBox query)
        {
            ContainmentType intersects;
            int             num3;

            SEntry[] queryStack;
            SEntry   entry;
            int      y;
            int      x;

            if (this.PruningTree == null)
            {
                return(ContainmentType.Intersects);
            }
            if ((m_queryStack == null) || (m_queryStack.Length < this.PruningTree.Length))
            {
                m_queryStack = new SEntry[this.PruningTree.Length];
            }
            if (query.Min.Z > this.Root.Max)
            {
                return(ContainmentType.Disjoint);
            }
            if (query.Max.Z < this.Root.Min)
            {
                return(ContainmentType.Contains);
            }
            if (query.Max.X < 0f)
            {
                goto TR_0003;
            }
            else if (query.Max.Y < 0f)
            {
                goto TR_0003;
            }
            else if ((query.Min.X <= 1f) && (query.Min.Y <= 1f))
            {
                if (this.PruningTree.Length == 0)
                {
                    return(ContainmentType.Intersects);
                }
                if (query.Max.X == 1.0)
                {
                    query.Max.X = 1f;
                }
                if (query.Max.Y == 1.0)
                {
                    query.Max.Y = 1f;
                }
                intersects = ContainmentType.Intersects;
                float num = Math.Max(query.Width, query.Height);
                if (num < this.m_pixelSizeFour)
                {
                    ushort    num6;
                    Box2I     boxi2       = new Box2I(ref query, (uint)this.Resolution);
                    Vector2I *vectoriPtr1 = (Vector2I *)ref boxi2.Min;
                    vectoriPtr1[0] -= 1;
                    Vector2I *vectoriPtr2 = (Vector2I *)ref boxi2.Max;
                    vectoriPtr2[0] += 1;
                    boxi2.Intersect(ref this.m_bounds);
                    int num4 = (int)(query.Min.Z * 65535f);
                    int num5 = (int)(query.Max.Z * 65535f);
                    this.GetValue(boxi2.Min.X, boxi2.Min.Y, out num6);
                    if (num6 > num5)
                    {
                        intersects = ContainmentType.Contains;
                    }
                    else
                    {
                        if (num6 >= num4)
                        {
                            return(ContainmentType.Intersects);
                        }
                        intersects = ContainmentType.Disjoint;
                    }
                    int num7 = 0xffff;
                    int num8 = 0;
                    int y    = boxi2.Min.Y;
                    while (y <= boxi2.Max.Y)
                    {
                        int x = boxi2.Min.X;
                        while (true)
                        {
                            if (x > boxi2.Max.X)
                            {
                                y++;
                                break;
                            }
                            this.GetValue(x, y, out num6);
                            if (num6 > num8)
                            {
                                num8 = num6;
                            }
                            if (num6 < num7)
                            {
                                num7 = num6;
                            }
                            x++;
                        }
                    }
                    int num9 = num8 - num7;
                    num9 += num9 >> 1;
                    num7 -= num9;
                    return((num4 <= (num8 + num9)) ? ((num5 >= num7) ? ContainmentType.Intersects : ContainmentType.Contains) : ContainmentType.Disjoint);
                }
                uint index = (uint)MathHelper.Clamp(Math.Log((double)(num * (this.Resolution / HeightmapNode.HEIGHTMAP_LEAF_SIZE))) / Math.Log((double)HeightmapNode.HEIGHTMAP_BRANCH_FACTOR), 0.0, (double)(this.PruningTree.Length - 1));
                num3       = 0;
                queryStack = m_queryStack;
                Box2I other = new Box2I(Vector2I.Zero, new Vector2I(((int)this.PruningTree[index].Res) - 1));
                queryStack[0].Bounds = new Box2I(ref query, this.PruningTree[index].Res);
                queryStack[0].Bounds.Intersect(ref other);
                queryStack[0].Next     = queryStack[0].Bounds.Min;
                queryStack[0].Level    = index;
                queryStack[0].Result   = intersects;
                queryStack[0].Continue = false;
            }
            else
            {
                goto TR_0003;
            }
            goto TR_0035;
TR_0003:
            return(ContainmentType.Disjoint);

TR_001A:
            intersects = entry.Result;
            num3--;
            if (num3 >= 0)
            {
                queryStack[num3].Intersection = intersects;
            }
            goto TR_0035;
TR_001E:
            x++;
            goto TR_002E;
TR_0026:
            switch (entry.Intersection)
            {
            case ContainmentType.Disjoint:
                if (entry.Result != ContainmentType.Contains)
                {
                    entry.Result = ContainmentType.Disjoint;
                    goto TR_001E;
                }
                else
                {
                    entry.Result = ContainmentType.Intersects;
                }
                break;

            case ContainmentType.Contains:
                if (entry.Result != ContainmentType.Disjoint)
                {
                    entry.Result = ContainmentType.Contains;
                    goto TR_001E;
                }
                else
                {
                    entry.Result = ContainmentType.Intersects;
                }
                break;

            case ContainmentType.Intersects:
                entry.Result = ContainmentType.Intersects;
                break;

            default:
                goto TR_001E;
            }
            goto TR_001A;
TR_002E:
            while (true)
            {
                if (x <= entry.Bounds.Max.X)
                {
                    if (entry.Continue)
                    {
                        entry.Continue = false;
                        x = entry.Next.X;
                        goto TR_0026;
                    }
                    else
                    {
                        SEntry *entryPtr1 = (SEntry *)ref entry;
                        entryPtr1->Intersection = this.PruningTree[entry.Level].Intersect(x, y, ref query);
                        if (entry.Intersection != ContainmentType.Intersects)
                        {
                            goto TR_0026;
                        }
                        else
                        {
                            if (this.PruningTree[entry.Level].IsCellNotContained(x, y, ref query) && (entry.Level != 0))
                            {
                                entry.Next       = new Vector2I(x, y);
                                entry.Continue   = true;
                                queryStack[num3] = entry;
                                num3++;
                                queryStack[num3] = new SEntry(ref query, this.PruningTree[((int)entry.Level) - 1].Res, new Vector2I(x, y), entry.Result, entry.Level - 1);
                                break;
                            }
                            goto TR_0026;
                        }
                    }
                }
                else
                {
                    y++;
                    goto TR_0031;
                }
                break;
            }
            goto TR_0035;
TR_0031:
            while (true)
            {
                if (y <= entry.Bounds.Max.Y)
                {
                    x = entry.Bounds.Min.X;
                }
                else
                {
                    goto TR_001A;
                }
                break;
            }
            goto TR_002E;
TR_0035:
            while (true)
            {
                if (num3 == -1)
                {
                    return(intersects);
                }
                entry = queryStack[num3];
                y     = entry.Next.Y;
                break;
            }
            goto TR_0031;
        }
Ejemplo n.º 5
0
        public unsafe void GetBounds(ref BoundingBox query)
        {
            float num = Math.Max(query.Width, query.Height);

            if (((num >= this.m_pixelSizeFour) && (this.PruningTree != null)) && (this.PruningTree.Length != 0))
            {
                double num2  = Math.Log((double)(((float)this.Resolution) / (num * HeightmapNode.HEIGHTMAP_LEAF_SIZE))) / Math.Log((double)HeightmapNode.HEIGHTMAP_BRANCH_FACTOR);
                uint   index = ((uint)(this.PruningTree.Length - 1)) - ((uint)MathHelper.Clamp(num2, 0.0, (double)(this.PruningTree.Length - 1)));
                Box2I  other = new Box2I(Vector2I.Zero, new Vector2I(((int)this.PruningTree[index].Res) - 1));
                Box2I  boxi2 = new Box2I(ref query, this.PruningTree[index].Res);
                boxi2.Intersect(ref other);
                query.Min.Z = float.PositiveInfinity;
                query.Max.Z = float.NegativeInfinity;
                int res = (int)this.PruningTree[index].Res;
                int y   = boxi2.Min.Y;
                while (y <= boxi2.Max.Y)
                {
                    int x = boxi2.Min.X;
                    while (true)
                    {
                        if (x > boxi2.Max.X)
                        {
                            y++;
                            break;
                        }
                        HeightmapNode node = this.PruningTree[index].Nodes[(y * res) + x];
                        if (query.Min.Z > node.Min)
                        {
                            query.Min.Z = node.Min;
                        }
                        if (query.Max.Z < node.Max)
                        {
                            query.Max.Z = node.Max;
                        }
                        x++;
                    }
                }
            }
            else
            {
                ushort    num5;
                Box2I     boxi3       = new Box2I(ref query, (uint)this.Resolution);
                Vector2I *vectoriPtr1 = (Vector2I *)ref boxi3.Min;
                vectoriPtr1[0] -= 1;
                Vector2I *vectoriPtr2 = (Vector2I *)ref boxi3.Max;
                vectoriPtr2[0] += 1;
                boxi3.Intersect(ref this.m_bounds);
                this.GetValue(boxi3.Min.X, boxi3.Min.Y, out num5);
                int num6 = 0xffff;
                int num7 = 0;
                int y    = boxi3.Min.Y;
                while (y <= boxi3.Max.Y)
                {
                    int x = boxi3.Min.X;
                    while (true)
                    {
                        if (x > boxi3.Max.X)
                        {
                            y++;
                            break;
                        }
                        this.GetValue(x, y, out num5);
                        if (num5 > num7)
                        {
                            num7 = num5;
                        }
                        if (num5 < num6)
                        {
                            num6 = num5;
                        }
                        x++;
                    }
                }
                int num8 = ((num7 - num6) * 2) / 3;
                num7       += num8;
                num6       -= num8;
                query.Min.Z = num6 * 1.525902E-05f;
                query.Max.Z = num7 * 1.525902E-05f;
            }
        }