Esempio n. 1
0
        ///*
        //==================
        //CM_TraceThroughTree
        //Traverse all the contacted leafs from the start to the end position.
        //If the trace is a point, they will be exactly in order, but for larger
        //trace volumes it is possible to hit something in a later leaf with
        //a smaller intercept fraction.
        //==================
        //*/
        //void TraceThroughTree(traceWork_t tw, int num, float p1f, float p2f, Vector3 p1, Vector3 p2)
        //{
        //    //TraceTest(0);
        //    if (tw.trace.fraction <= p1f)
        //        return; // already hit something nearer
        //    // if < 0, we are in a leaf node
        //    if (num < 0)
        //    {
        //        TraceThroughLeaf(tw, leafs[-1-num]);
        //        return;
        //    }
        //    //
        //    // find the point distances to the seperating plane
        //    // and the offset for the size of the box
        //    //
        //    dnode_t node = nodes[num];
        //    cplane_t plane = node.plane;
        //    // adjust the plane distance apropriately for mins/maxs
        //    float t1, t2, offset;
        //    if (plane.type < 3)
        //    {
        //        t1 = p1[plane.type] - plane.dist;
        //        t2 = p2[plane.type] - plane.dist;
        //        offset = tw.extents[plane.type];
        //    }
        //    else
        //    {
        //        t1 = Vector3.Dot(plane.normal, p1) - plane.dist;
        //        t2 = Vector3.Dot(plane.normal, p2) - plane.dist;
        //        if (tw.isPoint)
        //            offset = 0;
        //        else
        //        {
        //            offset = (float)(Math.Abs(tw.extents[0] * plane.normal[0]) + Math.Abs(tw.extents[1] * plane.normal[1]) + Math.Abs(tw.extents[2] * plane.normal[2]));
        //            // this is silly
        //            //offset = 2048;
        //        }
        //    }
        //    // see which sides we need to consider
        //    if (t1 > offset + 1 && t2 > offset + 1)
        //    {
        //        TraceThroughTree(tw, node.children[0], p1f, p2f, p1, p2);
        //        return;
        //    }
        //    if (t1 < -offset - 1 && t2 < -offset - 1)
        //    {
        //        TraceThroughTree(tw, node.children[1], p1f, p2f, p1, p2);
        //        return;
        //    }
        //    // put the crosspoint SURFACE_CLIP_EPSILON pixels on the near side
        //    float idist, frac, frac2;
        //    int side;
        //    if (t1 < t2)
        //    {
        //        idist = 1.0f / (t1 - t2);
        //        side = 1;
        //        frac2 = (t1 + offset + EPSILON) * idist;
        //        frac = (t1 - offset + EPSILON) * idist;
        //    }
        //    else if (t1 > t2)
        //    {
        //        idist = 1.0f / (t1 - t2);
        //        side = 0;
        //        frac2 = (t1 - offset - EPSILON) * idist;
        //        frac = (t1 + offset + EPSILON) * idist;
        //    }
        //    else
        //    {
        //        side = 0;
        //        frac = 1;
        //        frac2 = 0;
        //    }
        //    // move up to the node
        //    if (frac < 0f)
        //        frac = 0;
        //    if (frac > 1f)
        //        frac = 1;
        //    float midf = p1f + ((p2f - p1f) * frac);
        //    Vector3 mid = p1 + (p2 - p1) * frac;
        //    TraceThroughTree(tw, node.children[side], p1f, midf, p1, mid);
        //    // go past the node
        //    if (frac2 < 0f)
        //        frac2 = 0;
        //    if (frac2 > 1f)
        //        frac2 = 1f;
        //    midf = p1f + ((p2f - p1f) * frac2);
        //    mid = p1 + (frac2 * (p2 - p1));
        //    TraceThroughTree(tw, node.children[side ^ 1], midf, p2f, mid, p2);
        //}
        void TraceThroughLeaf(traceWork_t tw, int num)
        {
            dleaf_t leaf = leafs[num];
            dbrush_t b;
            // trace line against all brushes in the leaf
            int brushnum = leaf.numleafbrushes;
            if (brushnum == 0)
                brushnum++;
            for (int k = 0; k < brushnum; k++)
            {
                b = brushes[leafbrushes[leaf.firstleafbrush + k]];

                if (b.checkcount == checkcount)
                    continue;   // already checked this brush in another leaf
                b.checkcount = checkcount;

                // Assert that the brush contains the needed contents
                if (((int)b.contents & tw.contents) == 0)
                    continue;

                // Check bounds of brush
                if (!BoundsIntersect(tw.bounds[0], tw.bounds[1], b.boundsmin, b.boundsmax))
                    continue;

                //ClipBoxToBrush(tw, b);
                TraceThroughBrush(tw, b);
                // Return now if we were blocked 100%
                if (tw.trace.fraction == 0.0f)
                    return;
            }
            if (tw.trace.fraction == 0.0f)
                return;
            //// Check displacements
            //if (Renderer.Instance.SourceMap != null)
            //{
            //    World world = Renderer.Instance.SourceMap.world;
            //    leaf = world.leafs[num];
            //    if (leaf.DisplacementIndexes != null)
            //    {
            //        KeyValuePair<int,int>[] indx = leaf.DisplacementIndexes;
            //        for (int i = 0; i < indx.Length; i++)
            //        {

            //            DispCollTree dispTree = world.dispCollTrees[indx[i].Value];

            //            if ((dispTree.m_Contents & tw.contents) == 0)
            //                continue;

            //            TraceToDispTree(dispTree, tw.start, tw.end, tw.size[0], tw.size[1], 0f, 1f, tw.trace, false);

            //            if (tw.trace.fraction == 0f)
            //                break;
            //            //if (face2.lastVisCount != VisCount)
            //            //{
            //            //    face2.lastVisCount = VisCount;
            //            //    visibleRenderItems[face2.item.material.MaterialID].Add(face2.item);
            //            //}
            //        }
            //    }
            //}

            if (tw.trace.fraction != 1.0f)
            {
                //
                // determine whether or not we are in solid
                //
                Vector3 traceDir = tw.end - tw.start;
                if (Vector3.Dot(tw.trace.plane.normal, traceDir) > 0.0f)
                {
                    tw.trace.allsolid = true;
                    tw.trace.startsolid = true;
                }
            }
        }
Esempio n. 2
0
        void TraceThroughBrush(traceWork_t tw, dbrush_t brush)
        {
            float enterFrac = -9999f;
            float leaveFrac = 1f;
            cplane_t clipplane = null;

            if (brush.numsides <= 0)
                return;

            c_brush_traces++;
            bool getout = false;
            bool getoutTemp = false;
            bool startout = false;
            bool startoutTemp = false;
            dbrushside_t leadside = null;
            cplane_t plane = null;
            //
            // compare the trace against all planes of the brush
            // find the latest time the trace crosses a plane towards the interior
            // and the earliest time the trace crosses a plane towards the exterior
            //
            for (int i = 0; i < brush.numsides; ++i)
            {
                dbrushside_t side = brushsides[brush.firstside + i];
                plane = side.plane;

                // sanity check
                if (side.plane.normal.X == 0f && side.plane.normal.Y == 0f && side.plane.normal.Z == 0f)
                    continue;

                float dist;
                if (!tw.isPoint)
                    dist = plane.dist - Vector3.Dot(tw.offsets[plane.signbits], plane.normal);
                else // ray
                {
                    dist = plane.dist;
                    // dont trace rays against bevel planes
                    if (side.bevel > 0)
                        continue;
                }

                float d1 = Vector3.Dot(tw.start, plane.normal) - dist;
                float d2 = Vector3.Dot(tw.end, plane.normal) - dist;

                // if completely in front of face, no intersection
                if (d1 > 0.0f)
                {

                    startout = true;
                    // d1 > 0.f && d2 > 0.f
                    if (d2 > 0.0f)
                        return;

                }
                else
                {
                    // d1 <= 0.f && d2 <= 0.f
                    if (d2 <= 0.0f)
                        continue;

                    // d2 > 0.f
                    getout = true;  // endpoint is not in solid
                }

                //startout = startoutTemp;
                //getout = getoutTemp;

                // crosses face
                if (d1 > d2)    // enter
                {
                    // enter
                    // JAY: This could be negative if d1 is less than the epsilon.
                    // If the trace is short (d1-d2 is small) then it could produce a large
                    // negative fraction.  I can't believe this didn't break Q2!
                    float f = (d1 - EPSILON);
                    if (f < 0.0f)
                        f = 0.0f;
                    f = f / (d1 - d2);
                    if (f > enterFrac)
                    {
                        enterFrac = f;

                        clipplane = plane;
                        leadside = side;

                    }
                }
                else // leave
                {
                    float f = (d1 + EPSILON) / (d1 - d2);
                    //if (f > 1)
                    //    f = 1;
                    if (f < leaveFrac)
                    {
                        leaveFrac = f;

                    }
                }
            }

                ////when this happens, we entered the brush *after* leaving the previous brush.
                //// Therefore, we're still outside!

                //// NOTE: We only do this test against points because fractionleftsolid is
                //// not possible to compute for brush sweeps without a *lot* more computation
                //// So, client code will never get fractionleftsolid for box sweeps
                //if (tw.isPoint && startout)
                //{
                //    // Add a little sludge.  The sludge should already be in the fractionleftsolid
                //    // (for all intents and purposes is a leavefrac value) and enterfrac values.
                //    // Both of these values have +/- DIST_EPSILON values calculated in.  Thus, I
                //    // think the test should be against "0.0."  If we experience new "left solid"
                //    // problems you may want to take a closer look here!
                //    //		if ((trace->fractionleftsolid - enterfrac) > -1e-6)
                //    if (tw.trace.fractionleftsolid - enterFrac > 0.0f)
                //        startout = false;
                //}

            //
            // all planes have been checked, and the trace was not
            // completely outside the brush
            //
            if (!startout)
            {
                // original point was inside brush
                tw.trace.startsolid = true;
                tw.trace.contents = (int)brush.contents;

                if (!getout)
                {
                    tw.trace.allsolid = true;
                    //tw.trace.plane = plane;
                    tw.trace.fraction = 0f;
                    //tw.trace.fractionleftsolid = 1.0f;
                }
                else
                {
                    // if leavefrac == 1, this means it's never been updated or we're in allsolid
                    // the allsolid case was handled above
                    //if ((leaveFrac != 1.0f) && (leaveFrac > tw.trace.fractionleftsolid))
                    //{
                    //    tw.trace.fractionleftsolid = leaveFrac;

                    //    // This could occur if a previous trace didn't start us in solid
                    //    if (tw.trace.fraction <= leaveFrac)
                    //    {
                    //        tw.trace.fraction = 1.0f;
                    //    }
                    //}
                }
                return;
            }

            // We haven't hit anything at all until we've left...
            if (enterFrac < leaveFrac)
            {
                if (enterFrac > -9999.0f && enterFrac < tw.trace.fraction)
                {
                    if (enterFrac < 0)
                        enterFrac = 0;
                    tw.trace.fraction = enterFrac;
                    tw.trace.plane = clipplane;
                    if(leadside.texinfo != -1)
                        tw.trace.surfaceFlags = (int)texinfos[leadside.texinfo].flags;
                    //tw.trace.surfaceFlags = leadside.bevel;
                    tw.trace.contents = (int)brush.contents;

                }
            }
        }
Esempio n. 3
0
        void RecursiveHullCheck(traceWork_t tw, int num, float p1f, float p2f, Vector3 p1, Vector3 p2)
        {
            if (tw.trace.fraction <= p1f)
                return; // already hit something nearer

            dnode_t node = null;
            cplane_t plane;
            float t1 = 0f, t2 = 0f, offset = 0f;

            // find the point distances to the seperating plane
            // and the offset for the size of the box

            // NJS: Hoisted loop invariant comparison to trace_ispoint
            if (tw.isPoint)
            {
                while (num >= 0)
                {
                    node = nodes[num];
                    plane = node.plane;

                    if (plane.type < 3)
                    {
                        t1 = p1[plane.type] - plane.dist;
                        t2 = p2[plane.type] - plane.dist;
                        offset = tw.extents[plane.type];
                    }
                    else
                    {
                        t1 = Vector3.Dot(plane.normal, p1) - plane.dist;
                        t2 = Vector3.Dot(plane.normal, p2) - plane.dist;
                        offset = 0;
                    }

                    // see which sides we need to consider
                    if (t1 > offset && t2 > offset)
                    {
                        num = node.children[0];
                        continue;
                    }
                    if (t1 < -offset && t2 < -offset)
                    {
                        num = node.children[1];
                        continue;
                    }
                    break;

                }
            }
            else
            {
                while (num >= 0)
                {
                    node = nodes[num];
                    plane = node.plane;

                    //Vector3 pl = new Vector3(0.5f, 0.5f, 0);
                    //Vector3 pos = new Vector3(100, 200, -45);
                    //float res = Vector3.Dot(pos,pl);
                    //float sside = res +368;

                    if (plane.type < 3)
                    {
                        t1 = p1[plane.type] - plane.dist;
                        t2 = p2[plane.type] - plane.dist;
                        offset = tw.extents[plane.type];
                    } else {
                        t1 = Vector3.Dot(plane.normal, p1) - plane.dist;
                        t2 = Vector3.Dot(plane.normal, p2) - plane.dist;
                        offset = (float)(Math.Abs(tw.extents[0]*plane.normal[0]) +
                                       Math.Abs(tw.extents[1]*plane.normal[1]) +
                                       Math.Abs(tw.extents[2]*plane.normal[2]));
                    }

                    // see which sides we need to consider
                    if (t1 > offset && t2 > offset)
                    {
                        num = node.children[0];
                        continue;
                    }
                    if (t1 < -offset && t2 < -offset)
                    {
                        num = node.children[1];
                        continue;
                    }
                    break;
                }
            }

            // if < 0, we are in a leaf node
            if (num < 0)
            {
                //TraceToLeaf(tw, -1 - num, p1f, p2f);
                TraceThroughLeaf(tw, -1 - num);
                return;
            }

            // put the crosspoint DIST_EPSILON pixels on the near side
            float idist, frac, frac2;
            int side;
            if (t1 < t2)
            {
                idist = 1.0f / (t1 - t2);
                side = 1;
                frac2 = (t1 + offset + EPSILON) * idist;
                frac = (t1 - offset - EPSILON) * idist;
            }
            else if (t1 > t2)
            {
                idist = 1.0f / (t1 - t2);
                side = 0;
                frac2 = (t1 - offset - EPSILON) * idist;
                frac = (t1 + offset + EPSILON) * idist;
            }
            else
            {
                side = 0;
                frac = 1;
                frac2 = 0;
            }

            // move up to the node
            frac = Clamp(frac, 0, 1);
            float midf = p1f + (p2f - p1f) * frac;
            Vector3 mid = p1 + (p2 - p1) * frac;

            RecursiveHullCheck(tw, node.children[side], p1f, midf, p1, mid);

            // go past the node
            frac2 = Clamp(frac2, 0, 1);
            midf = p1f + (p2f - p1f) * frac2;
            mid = p1 + (p2 - p1) * frac2;

            RecursiveHullCheck(tw, node.children[side ^ 1], midf, p2f, mid, p2);
        }
Esempio n. 4
0
        trace_t Trace(Vector3 start, Vector3 end, Vector3 mins, Vector3 maxs, int model, Vector3 origin, int brushmask)
        {
            //cmodel_t cmod = ClipHandleToModel(model);
            // for multi-check avoidance
            checkcount++;
            // for statistics, may be zeroed
            c_traces++;
            this.tw = new traceWork_t();
            traceWork_t tw = this.tw;
            tw.trace = new trace_t();
            tw.trace.fraction = 1f; // assume it goes the entire distance until shown otherwise
            tw.modelOrigin = origin;

            if (nodes == null || nodes.Length == 0)
            {
                return tw.trace; // map not loaded, shouldn't happen
            }

            // set basic parms
            tw.contents = brushmask;

            // adjust so that mins and maxs are always symetric, which
            // avoids some complications with plane expanding of rotated
            // bmodels
            Vector3 offset = (mins+maxs) * 0.5f;
            tw.size[0] = mins - offset;
            tw.size[1] = maxs - offset;
            tw.start = start + offset;
            tw.end = end + offset;

            tw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2];

            // tw.offsets[signbits] = vector to apropriate corner from origin
            tw.offsets[0][0] = tw.size[0][0];
            tw.offsets[0][1] = tw.size[0][1];
            tw.offsets[0][2] = tw.size[0][2];

            tw.offsets[1][0] = tw.size[1][0];
            tw.offsets[1][1] = tw.size[0][1];
            tw.offsets[1][2] = tw.size[0][2];

            tw.offsets[2][0] = tw.size[0][0];
            tw.offsets[2][1] = tw.size[1][1];
            tw.offsets[2][2] = tw.size[0][2];

            tw.offsets[3][0] = tw.size[1][0];
            tw.offsets[3][1] = tw.size[1][1];
            tw.offsets[3][2] = tw.size[0][2];

            tw.offsets[4][0] = tw.size[0][0];
            tw.offsets[4][1] = tw.size[0][1];
            tw.offsets[4][2] = tw.size[1][2];

            tw.offsets[5][0] = tw.size[1][0];
            tw.offsets[5][1] = tw.size[0][1];
            tw.offsets[5][2] = tw.size[1][2];

            tw.offsets[6][0] = tw.size[0][0];
            tw.offsets[6][1] = tw.size[1][1];
            tw.offsets[6][2] = tw.size[1][2];

            tw.offsets[7][0] = tw.size[1][0];
            tw.offsets[7][1] = tw.size[1][1];
            tw.offsets[7][2] = tw.size[1][2];

            //
            // calculate bounds
            //
            for (int i = 0; i < 3; i++)
            {
                if (tw.start[i] < tw.end[i])
                {
                    tw.bounds[0][i] = tw.start[i] + tw.size[0][i];
                    tw.bounds[1][i] = tw.end[i] + tw.size[1][i];
                }
                else
                {
                    tw.bounds[0][i] = tw.end[i] + tw.size[0][i];
                    tw.bounds[1][i] = tw.start[i] + tw.size[1][i];
                }
            }

            //
            // check for position test special case
            //
            if (start.Equals(end))
            {
                if (model > 0)
                {
                    int test = 2;
                    //TestInLeaf(tw, cmod.leaf);
                }
                else
                {
                    PositionTest(tw);
                }
            }
            else
            {
                //
                // check for point special case
                //
                if (tw.size[0].Equals(Vector3.Zero))
                {
                    tw.isPoint = true;
                    tw.extents = Vector3.Zero;
                }
                else
                {
                    tw.isPoint = false;
                    tw.extents = tw.size[1];
                }

                //
                // general sweeping through world
                //
                if (model > 0)
                {
                    int test = 2;
                    //TraceThroughLeaf(tw, cmod.leaf);
                }
                else
                {
                    RecursiveHullCheck(tw, 0, 0, 1, tw.start, tw.end);
                    //TraceThroughTree(tw, 0, 0, 1, tw.start, tw.end);
                }
            }

            // generate endpos from the original, unmodified start/end
            if (tw.trace.fraction == 1f)
            {
                tw.trace.endpos = end;
            }
            else
            {
                tw.trace.endpos = start + (tw.trace.fraction * (end - start));
            }

            // If allsolid is set (was entirely inside something solid), the plane is not valid.
            // If fraction == 1.0, we never hit anything, and thus the plane is not valid.
            // Otherwise, the normal on the plane should have unit length
            Debug.Assert(tw.trace.allsolid || tw.trace.fraction == 1f || tw.trace.plane.normal.LengthSquared() > 0.9999f);
            return tw.trace;
        }
Esempio n. 5
0
        //int FindParentNode(int nodeid)
        //{
        //    //System.Console.WriteLine("Parent for " + nodeid);
        //    if (nodeid == 0)
        //        return 0;
        //    for (int i = 0; i < nodes.Length; i++)
        //    {
        //        if (nodes[i].children[0] == nodeid)
        //            return FindParentNode(i);
        //        else if (nodes[i].children[1] == nodeid)
        //            return FindParentNode(i);
        //    }
        //    return -1;
        //}
        void PositionTest(traceWork_t tw)
        {
            // identify the leafs we are touching
            ll.bounds[0] = tw.start - tw.size[0];
            ll.bounds[1] = tw.end - tw.size[1];

            for (int i = 0; i < 3; i++)
            {
                ll.bounds[0][i] -= 1;
                ll.bounds[1][i] += 1;
            }

            ll.count = 0;
            ll.maxcount = 1024;
            ll.list = lleafs;
            //ll.StoreLeaf += new StoreLeafDelegate(StoreLeafs);
            ll.lastLeaf = 0;
            ll.overflowed = false;

            checkcount++;

            BoxLeafnums(ll, 0);

            checkcount++;

            // test the contents of the leafs
            for (int i = 0; i < ll.count; i++)
            {
                TraceThroughLeaf(tw, lleafs[i]);
                if (tw.trace.allsolid)
                    break;
            }
        }