Esempio n. 1
0
        public static int BoxOnPlaneSide(ref v3f emins, ref v3f emaxs, mplane_t p)
        {
            float mindist, maxdist;

            switch (p.type)
            {
            case 0:
                mindist = emins.x;
                maxdist = emaxs.x;
                break;

            case 1:
                mindist = emins.y;
                maxdist = emaxs.y;
                break;

            case 2:
                mindist = emins.z;
                maxdist = emaxs.z;
                break;

            default:
                Vector3 mins, maxs;
                Copy(ref emins, out mins);
                Copy(ref emaxs, out maxs);
                return(_BoxOnPlaneSide(ref mins, ref maxs, p));
            }
            return(p.dist <= mindist ? 1 : (p.dist >= maxdist ? 2 : 3));
        }
Esempio n. 2
0
        /// <summary>
        /// SV_HullPointContents
        /// </summary>
        static int HullPointContents(hull_t hull, int num, ref Vector3 p)
        {
            while (num >= 0)
            {
                if (num < hull.firstclipnode || num > hull.lastclipnode)
                {
                    Sys.Error("SV_HullPointContents: bad node number");
                }

                short[]  node_children = hull.clipnodes[num].children;
                mplane_t plane         = hull.planes[hull.clipnodes[num].planenum];
                float    d;
                if (plane.type < 3)
                {
                    d = Mathlib.Comp(ref p, plane.type) - plane.dist;
                }
                else
                {
                    d = Vector3.Dot(plane.normal, p) - plane.dist;
                }
                if (d < 0)
                {
                    num = node_children[1];
                }
                else
                {
                    num = node_children[0];
                }
            }

            return(num);
        }
Esempio n. 3
0
        public static int BoxOnPlaneSide(ref Vector3 emins, ref Vector3 emaxs, mplane_t p)
        {
            float mindist, maxdist;

            switch (p.type)
            {
            case 0:
                mindist = emins.X;
                maxdist = emaxs.X;
                break;

            case 1:
                mindist = emins.Y;
                maxdist = emaxs.Y;
                break;

            case 2:
                mindist = emins.Z;
                maxdist = emaxs.Z;
                break;

            default:
                return(_BoxOnPlaneSide(ref emins, ref emaxs, p));
            }
            return(p.dist <= mindist ? 1 : (p.dist >= maxdist ? 2 : 3));
        }
Esempio n. 4
0
        static byte[] _FatPvs = new byte[BspFile.MAX_MAP_LEAFS / 8]; // fatpvs


        // SV_Init
        public static void Init()
        {
            for (int i = 0; i < _BoxClipNodes.Length; i++)
            {
                _BoxClipNodes[i].children = new short[2];
            }
            for (int i = 0; i < _BoxPlanes.Length; i++)
            {
                _BoxPlanes[i] = new mplane_t();
            }
            for (int i = 0; i < _AreaNodes.Length; i++)
            {
                _AreaNodes[i] = new areanode_t();
            }

            if (_Friction == null)
            {
                _Friction        = new Cvar("sv_friction", "4", false, true);
                _EdgeFriction    = new Cvar("edgefriction", "2");
                _StopSpeed       = new Cvar("sv_stopspeed", "100");
                _Gravity         = new Cvar("sv_gravity", "800", false, true);
                _MaxVelocity     = new Cvar("sv_maxvelocity", "2000");
                _NoStep          = new Cvar("sv_nostep", "0");
                _MaxSpeed        = new Cvar("sv_maxspeed", "320", false, true);
                _Accelerate      = new Cvar("sv_accelerate", "10");
                _Aim             = new Cvar("sv_aim", "0.93");
                _IdealPitchScale = new Cvar("sv_idealpitchscale", "0.8");
            }

            for (int i = 0; i < QDef.MAX_MODELS; i++)
            {
                _LocalModels[i] = "*" + i.ToString();
            }
        }
Esempio n. 5
0
        /// <summary>
        /// SV_FindTouchedLeafs
        /// </summary>
        static void FindTouchedLeafs(edict_t ent, mnodebase_t node)
        {
            if (node.contents == Contents.CONTENTS_SOLID)
            {
                return;
            }

            // add an efrag if the node is a leaf

            if (node.contents < 0)
            {
                if (ent.num_leafs == Progs.MAX_ENT_LEAFS)
                {
                    return;
                }

                mleaf_t leaf    = (mleaf_t)node;
                int     leafnum = Array.IndexOf(sv.worldmodel.leafs, leaf) - 1;

                ent.leafnums[ent.num_leafs] = (short)leafnum;
                ent.num_leafs++;
                return;
            }

            // NODE_MIXED
            mnode_t  n          = (mnode_t)node;
            mplane_t splitplane = n.plane;
            int      sides      = Mathlib.BoxOnPlaneSide(ref ent.v.absmin, ref ent.v.absmax, splitplane);

            // recurse down the contacted sides
            if ((sides & 1) != 0)
            {
                FindTouchedLeafs(ent, n.children[0]);
            }

            if ((sides & 2) != 0)
            {
                FindTouchedLeafs(ent, n.children[1]);
            }
        }
Esempio n. 6
0
        /// <summary>
        /// R_MarkLights
        /// </summary>
        static void MarkLights(dlight_t light, int bit, mnodebase_t node)
        {
            if (node.contents < 0)
            {
                return;
            }

            mnode_t  n          = (mnode_t)node;
            mplane_t splitplane = n.plane;
            float    dist       = Vector3.Dot(light.origin, splitplane.normal) - splitplane.dist;

            if (dist > light.radius)
            {
                MarkLights(light, bit, n.children[0]);
                return;
            }
            if (dist < -light.radius)
            {
                MarkLights(light, bit, n.children[1]);
                return;
            }

            // mark the polygons
            for (int i = 0; i < n.numsurfaces; i++)
            {
                msurface_t surf = Client.cl.worldmodel.surfaces[n.firstsurface + i];
                if (surf.dlightframe != _DlightFrameCount)
                {
                    surf.dlightbits  = 0;
                    surf.dlightframe = _DlightFrameCount;
                }
                surf.dlightbits |= bit;
            }

            MarkLights(light, bit, n.children[0]);
            MarkLights(light, bit, n.children[1]);
        }
Esempio n. 7
0
        /// <summary>
        /// SV_AddToFatPVS
        /// The PVS must include a small area around the client to allow head bobbing
        /// or other small motion on the client side.  Otherwise, a bob might cause an
        /// entity that should be visible to not show up, especially when the bob
        /// crosses a waterline.
        /// </summary>
        static void AddToFatPVS(ref Vector3 org, mnodebase_t node)
        {
            while (true)
            {
                // if this is a leaf, accumulate the pvs bits
                if (node.contents < 0)
                {
                    if (node.contents != Contents.CONTENTS_SOLID)
                    {
                        byte[] pvs = Mod.LeafPVS((mleaf_t)node, sv.worldmodel);
                        for (int i = 0; i < _FatBytes; i++)
                        {
                            _FatPvs[i] |= pvs[i];
                        }
                    }
                    return;
                }

                mnode_t  n     = (mnode_t)node;
                mplane_t plane = n.plane;
                float    d     = Vector3.Dot(org, plane.normal) - plane.dist;
                if (d > 8)
                {
                    node = n.children[0];
                }
                else if (d < -8)
                {
                    node = n.children[1];
                }
                else
                {       // go down both
                    AddToFatPVS(ref org, n.children[0]);
                    node = n.children[1];
                }
            }
        }
Esempio n. 8
0
        /// <summary>
        /// SV_RecursiveHullCheck
        /// </summary>
        public static bool RecursiveHullCheck(hull_t hull, int num, float p1f, float p2f, ref Vector3 p1, ref Vector3 p2, trace_t trace)
        {
            // check for empty
            if (num < 0)
            {
                if (num != Contents.CONTENTS_SOLID)
                {
                    trace.allsolid = false;
                    if (num == Contents.CONTENTS_EMPTY)
                    {
                        trace.inopen = true;
                    }
                    else
                    {
                        trace.inwater = true;
                    }
                }
                else
                {
                    trace.startsolid = true;
                }
                return(true);            // empty
            }

            if (num < hull.firstclipnode || num > hull.lastclipnode)
            {
                Sys.Error("SV_RecursiveHullCheck: bad node number");
            }

            //
            // find the point distances
            //
            short[]  node_children = hull.clipnodes[num].children;
            mplane_t plane = hull.planes[hull.clipnodes[num].planenum];
            float    t1, t2;

            if (plane.type < 3)
            {
                t1 = Mathlib.Comp(ref p1, plane.type) - plane.dist;
                t2 = Mathlib.Comp(ref p2, plane.type) - plane.dist;
            }
            else
            {
                t1 = Vector3.Dot(plane.normal, p1) - plane.dist;
                t2 = Vector3.Dot(plane.normal, p2) - plane.dist;
            }

            if (t1 >= 0 && t2 >= 0)
            {
                return(RecursiveHullCheck(hull, node_children[0], p1f, p2f, ref p1, ref p2, trace));
            }
            if (t1 < 0 && t2 < 0)
            {
                return(RecursiveHullCheck(hull, node_children[1], p1f, p2f, ref p1, ref p2, trace));
            }

            // put the crosspoint DIST_EPSILON pixels on the near side
            float frac;

            if (t1 < 0)
            {
                frac = (t1 + DIST_EPSILON) / (t1 - t2);
            }
            else
            {
                frac = (t1 - DIST_EPSILON) / (t1 - t2);
            }
            if (frac < 0)
            {
                frac = 0;
            }
            if (frac > 1)
            {
                frac = 1;
            }

            float   midf = p1f + (p2f - p1f) * frac;
            Vector3 mid  = p1 + (p2 - p1) * frac;

            int side = (t1 < 0) ? 1 : 0;

            // move up to the node
            if (!RecursiveHullCheck(hull, node_children[side], p1f, midf, ref p1, ref mid, trace))
            {
                return(false);
            }

            if (HullPointContents(hull, node_children[side ^ 1], ref mid) != Contents.CONTENTS_SOLID)
            {
                // go past the node
                return(RecursiveHullCheck(hull, node_children[side ^ 1], midf, p2f, ref mid, ref p2, trace));
            }

            if (trace.allsolid)
            {
                return(false);           // never got out of the solid area
            }
            //==================
            // the other side of the node is solid, this is the impact point
            //==================
            if (side == 0)
            {
                trace.plane.normal = plane.normal;
                trace.plane.dist   = plane.dist;
            }
            else
            {
                trace.plane.normal = -plane.normal;
                trace.plane.dist   = -plane.dist;
            }

            while (HullPointContents(hull, hull.firstclipnode, ref mid) == Contents.CONTENTS_SOLID)
            {
                // shouldn't really happen, but does occasionally
                frac -= 0.1f;
                if (frac < 0)
                {
                    trace.fraction = midf;
                    trace.endpos   = mid;
                    Con.DPrint("backup past 0\n");
                    return(false);
                }
                midf = p1f + (p2f - p1f) * frac;
                mid  = p1 + (p2 - p1) * frac;
            }

            trace.fraction = midf;
            trace.endpos   = mid;

            return(false);
        }
Esempio n. 9
0
        static int RecursiveLightPoint(mnodebase_t node, ref Vector3 start, ref Vector3 end)
        {
            if (node.contents < 0)
            {
                return(-1);              // didn't hit anything
            }
            mnode_t n = (mnode_t)node;

            // calculate mid point

            // FIXME: optimize for axial
            mplane_t plane = n.plane;
            float    front = Vector3.Dot(start, plane.normal) - plane.dist;
            float    back  = Vector3.Dot(end, plane.normal) - plane.dist;
            int      side  = front < 0 ? 1 : 0;

            if ((back < 0 ? 1 : 0) == side)
            {
                return(RecursiveLightPoint(n.children[side], ref start, ref end));
            }

            float   frac = front / (front - back);
            Vector3 mid  = start + (end - start) * frac;

            // go down front side
            int r = RecursiveLightPoint(n.children[side], ref start, ref mid);

            if (r >= 0)
            {
                return(r);               // hit something
            }
            if ((back < 0 ? 1 : 0) == side)
            {
                return(-1);              // didn't hit anuthing
            }
            // check for impact on this node
            _LightSpot  = mid;
            _LightPlane = plane;

            msurface_t[] surf   = Client.cl.worldmodel.surfaces;
            int          offset = n.firstsurface;

            for (int i = 0; i < n.numsurfaces; i++, offset++)
            {
                if ((surf[offset].flags & Surf.SURF_DRAWTILED) != 0)
                {
                    continue;   // no lightmaps
                }
                mtexinfo_t tex = surf[offset].texinfo;

                int s = (int)(Vector3.Dot(mid, tex.vecs[0].Xyz) + tex.vecs[0].W);
                int t = (int)(Vector3.Dot(mid, tex.vecs[1].Xyz) + tex.vecs[1].W);

                if (s < surf[offset].texturemins[0] || t < surf[offset].texturemins[1])
                {
                    continue;
                }

                int ds = s - surf[offset].texturemins[0];
                int dt = t - surf[offset].texturemins[1];

                if (ds > surf[offset].extents[0] || dt > surf[offset].extents[1])
                {
                    continue;
                }

                if (surf[offset].sample_base == null)
                {
                    return(0);
                }

                ds >>= 4;
                dt >>= 4;

                byte[]  lightmap = surf[offset].sample_base;
                int     lmOffset = surf[offset].sampleofs;
                short[] extents  = surf[offset].extents;
                r = 0;
                if (lightmap != null)
                {
                    lmOffset += dt * ((extents[0] >> 4) + 1) + ds;

                    for (int maps = 0; maps < BspFile.MAXLIGHTMAPS && surf[offset].styles[maps] != 255; maps++)
                    {
                        int scale = _LightStyleValue[surf[offset].styles[maps]];
                        r        += lightmap[lmOffset] * scale;
                        lmOffset += ((extents[0] >> 4) + 1) * ((extents[1] >> 4) + 1);
                    }

                    r >>= 8;
                }

                return(r);
            }

            // go down back side
            return(RecursiveLightPoint(n.children[side == 0 ? 1 : 0], ref mid, ref end));
        }
Esempio n. 10
0
        //Returns 1, 2, or 1 + 2
        static int _BoxOnPlaneSide(ref Vector3 emins, ref Vector3 emaxs, mplane_t p)
        {
            // general case
            float dist1, dist2;

            switch (p.signbits)
            {
            case 0:
                dist1 = p.normal.X * emaxs.X + p.normal.Y * emaxs.Y + p.normal.Z * emaxs.Z;
                dist2 = p.normal.X * emins.X + p.normal.Y * emins.Y + p.normal.Z * emins.Z;
                break;

            case 1:
                dist1 = p.normal.X * emins.X + p.normal.Y * emaxs.Y + p.normal.Z * emaxs.Z;
                dist2 = p.normal.X * emaxs.X + p.normal.Y * emins.Y + p.normal.Z * emins.Z;
                break;

            case 2:
                dist1 = p.normal.X * emaxs.X + p.normal.Y * emins.Y + p.normal.Z * emaxs.Z;
                dist2 = p.normal.X * emins.X + p.normal.Y * emaxs.Y + p.normal.Z * emins.Z;
                break;

            case 3:
                dist1 = p.normal.X * emins.X + p.normal.Y * emins.Y + p.normal.Z * emaxs.Z;
                dist2 = p.normal.X * emaxs.X + p.normal.Y * emaxs.Y + p.normal.Z * emins.Z;
                break;

            case 4:
                dist1 = p.normal.X * emaxs.X + p.normal.Y * emaxs.Y + p.normal.Z * emins.Z;
                dist2 = p.normal.X * emins.X + p.normal.Y * emins.Y + p.normal.Z * emaxs.Z;
                break;

            case 5:
                dist1 = p.normal.X * emins.X + p.normal.Y * emaxs.Y + p.normal.Z * emins.Z;
                dist2 = p.normal.X * emaxs.X + p.normal.Y * emins.Y + p.normal.Z * emaxs.Z;
                break;

            case 6:
                dist1 = p.normal.X * emaxs.X + p.normal.Y * emins.Y + p.normal.Z * emins.Z;
                dist2 = p.normal.X * emins.X + p.normal.Y * emaxs.Y + p.normal.Z * emaxs.Z;
                break;

            case 7:
                dist1 = p.normal.X * emins.X + p.normal.Y * emins.Y + p.normal.Z * emins.Z;
                dist2 = p.normal.X * emaxs.X + p.normal.Y * emaxs.Y + p.normal.Z * emaxs.Z;
                break;

            default:
                dist1 = dist2 = 0;              // shut up compiler
                Sys.Error("BoxOnPlaneSide:  Bad signbits");
                break;
            }

            int sides = 0;

            if (dist1 >= p.dist)
            {
                sides = 1;
            }
            if (dist2 < p.dist)
            {
                sides |= 2;
            }

#if PARANOID
            if (sides == 0)
            {
                Sys.Error("BoxOnPlaneSide: sides==0");
            }
#endif

            return(sides);
        }
Esempio n. 11
0
        /// <summary>
        /// R_RecursiveWorldNode
        /// </summary>
        static void RecursiveWorldNode(mnodebase_t node)
        {
            if (node.contents == Contents.CONTENTS_SOLID)
            {
                return;         // solid
            }
            if (node.visframe != _VisFrameCount)
            {
                return;
            }
            if (CullBox(ref node.mins, ref node.maxs))
            {
                return;
            }

            int c;

            // if a leaf node, draw stuff
            if (node.contents < 0)
            {
                mleaf_t      pleaf = (mleaf_t)node;
                msurface_t[] marks = pleaf.marksurfaces;
                int          mark  = pleaf.firstmarksurface;
                c = pleaf.nummarksurfaces;

                if (c != 0)
                {
                    do
                    {
                        marks[mark].visframe = _FrameCount;
                        mark++;
                    } while (--c != 0);
                }

                // deal with model fragments in this leaf
                if (pleaf.efrags != null)
                {
                    StoreEfrags(pleaf.efrags);
                }

                return;
            }

            // node is just a decision point, so go down the apropriate sides

            mnode_t n = (mnode_t)node;

            // find which side of the node we are on
            mplane_t plane = n.plane;
            double   dot;

            switch (plane.type)
            {
            case Planes.PLANE_X:
                dot = _ModelOrg.X - plane.dist;
                break;

            case Planes.PLANE_Y:
                dot = _ModelOrg.Y - plane.dist;
                break;

            case Planes.PLANE_Z:
                dot = _ModelOrg.Z - plane.dist;
                break;

            default:
                dot = Vector3.Dot(_ModelOrg, plane.normal) - plane.dist;
                break;
            }

            int side = (dot >= 0 ? 0 : 1);

            // recurse down the children, front side first
            RecursiveWorldNode(n.children[side]);

            // draw stuff
            c = n.numsurfaces;

            if (c != 0)
            {
                msurface_t[] surf   = Client.cl.worldmodel.surfaces;
                int          offset = n.firstsurface;

                if (dot < 0 - QDef.BACKFACE_EPSILON)
                {
                    side = Surf.SURF_PLANEBACK;
                }
                else if (dot > QDef.BACKFACE_EPSILON)
                {
                    side = 0;
                }

                for (; c != 0; c--, offset++)
                {
                    if (surf[offset].visframe != _FrameCount)
                    {
                        continue;
                    }

                    // don't backface underwater surfaces, because they warp
                    if ((surf[offset].flags & Surf.SURF_UNDERWATER) == 0 && ((dot < 0) ^ ((surf[offset].flags & Surf.SURF_PLANEBACK) != 0)))
                    {
                        continue;               // wrong side
                    }
                    // if sorting by texture, just store it out
                    if (_glTexSort.Value != 0)
                    {
                        if (!_IsMirror || surf[offset].texinfo.texture != Client.cl.worldmodel.textures[_MirrorTextureNum])
                        {
                            surf[offset].texturechain = surf[offset].texinfo.texture.texturechain;
                            surf[offset].texinfo.texture.texturechain = surf[offset];
                        }
                    }
                    else if ((surf[offset].flags & Surf.SURF_DRAWSKY) != 0)
                    {
                        surf[offset].texturechain = _SkyChain;
                        _SkyChain = surf[offset];
                    }
                    else if ((surf[offset].flags & Surf.SURF_DRAWTURB) != 0)
                    {
                        surf[offset].texturechain = _WaterChain;
                        _WaterChain = surf[offset];
                    }
                    else
                    {
                        DrawSequentialPoly(surf[offset]);
                    }
                }
            }

            // recurse down the back side
            RecursiveWorldNode(n.children[side == 0 ? 1 : 0]);
        }
Esempio n. 12
0
        /// <summary>
        /// R_DrawBrushModel
        /// </summary>
        private static void DrawBrushModel(entity_t e)
        {
            _CurrentEntity        = e;
            Drawer.CurrentTexture = -1;

            model_t clmodel = e.model;
            bool    rotated = false;
            Vector3 mins, maxs;

            if (e.angles.X != 0 || e.angles.Y != 0 || e.angles.Z != 0)
            {
                rotated = true;
                mins    = e.origin;
                mins.X -= clmodel.radius;
                mins.Y -= clmodel.radius;
                mins.Z -= clmodel.radius;
                maxs    = e.origin;
                maxs.X += clmodel.radius;
                maxs.Y += clmodel.radius;
                maxs.Z += clmodel.radius;
            }
            else
            {
                mins = e.origin + clmodel.mins;
                maxs = e.origin + clmodel.maxs;
            }

            if (CullBox(ref mins, ref maxs))
            {
                return;
            }

            GL.Color3(1f, 1, 1);
            Array.Clear(_LightMapPolys, 0, _LightMapPolys.Length);
            _ModelOrg = _RefDef.vieworg - e.origin;
            if (rotated)
            {
                Vector3 temp = _ModelOrg;
                Vector3 forward, right, up;
                Mathlib.AngleVectors(ref e.angles, out forward, out right, out up);
                _ModelOrg.X = Vector3.Dot(temp, forward);
                _ModelOrg.Y = -Vector3.Dot(temp, right);
                _ModelOrg.Z = Vector3.Dot(temp, up);
            }

            // calculate dynamic lighting for bmodel if it's not an
            // instanced model
            if (clmodel.firstmodelsurface != 0 && _glFlashBlend.Value == 0)
            {
                for (int k = 0; k < Client.MAX_DLIGHTS; k++)
                {
                    if ((Client.DLights[k].die < Client.cl.time) || (Client.DLights[k].radius == 0))
                    {
                        continue;
                    }

                    MarkLights(Client.DLights[k], 1 << k, clmodel.nodes[clmodel.hulls[0].firstclipnode]);
                }
            }

            GL.PushMatrix();
            e.angles.X = -e.angles.X;   // stupid quake bug
            RotateForEntity(e);
            e.angles.X = -e.angles.X;   // stupid quake bug

            int surfOffset = clmodel.firstmodelsurface;

            msurface_t[] psurf = clmodel.surfaces; //[clmodel.firstmodelsurface];

            //
            // draw texture
            //
            for (int i = 0; i < clmodel.nummodelsurfaces; i++, surfOffset++)
            {
                // find which side of the node we are on
                mplane_t pplane = psurf[surfOffset].plane;

                float dot = Vector3.Dot(_ModelOrg, pplane.normal) - pplane.dist;

                // draw the polygon
                bool planeBack = (psurf[surfOffset].flags & Surf.SURF_PLANEBACK) != 0;
                if ((planeBack && (dot < -QDef.BACKFACE_EPSILON)) || (!planeBack && (dot > QDef.BACKFACE_EPSILON)))
                {
                    if (_glTexSort.Value != 0)
                    {
                        RenderBrushPoly(psurf[surfOffset]);
                    }
                    else
                    {
                        DrawSequentialPoly(psurf[surfOffset]);
                    }
                }
            }

            BlendLightmaps();

            GL.PopMatrix();
        }
Esempio n. 13
0
        /// <summary>
        /// R_SplitEntityOnNode
        /// </summary>
        static void SplitEntityOnNode(mnodebase_t node)
        {
            if (node.contents == Contents.CONTENTS_SOLID)
                return;

            // add an efrag if the node is a leaf
            if (node.contents < 0)
            {
                if (_EfragTopNode == null)
                    _EfragTopNode = node as mnode_t;

                mleaf_t leaf = (mleaf_t)(object)node;

                // grab an efrag off the free list
                efrag_t ef = Client.cl.free_efrags;
                if (ef == null)
                {
                    Con.Print("Too many efrags!\n");
                    return;	// no free fragments...
                }
                Client.cl.free_efrags = Client.cl.free_efrags.entnext;

                ef.entity = _AddEnt;

                // add the entity link
                // *lastlink = ef;
                if (_LastObj is entity_t)
                {
                    ((entity_t)_LastObj).efrag = ef;
                }
                else
                {
                    ((efrag_t)_LastObj).entnext = ef;
                }
                _LastObj = ef; // lastlink = &ef->entnext;
                ef.entnext = null;

                // set the leaf links
                ef.leaf = leaf;
                ef.leafnext = leaf.efrags;
                leaf.efrags = ef;

                return;
            }

            // NODE_MIXED
            mnode_t n = node as mnode_t;
            if (n == null)
                return;
            
            mplane_t splitplane = n.plane;
            int sides = Mathlib.BoxOnPlaneSide(ref _EMins, ref _EMaxs, splitplane);

            if (sides == 3)
            {
                // split on this plane
                // if this is the first splitter of this bmodel, remember it
                if (_EfragTopNode == null)
                    _EfragTopNode = n;
            }

            // recurse down the contacted sides
            if ((sides & 1) != 0)
                SplitEntityOnNode(n.children[0]);

            if ((sides & 2) != 0)
                SplitEntityOnNode(n.children[1]);
        }