예제 #1
0
        /// <summary>
        /// R_MirrorChain
        /// </summary>
        //private void MirrorChain( MemorySurface s )
        //{
        //    if( _IsMirror )
        //        return;
        //    _IsMirror = true;
        //    _MirrorPlane = s.plane;
        //}

        /// <summary>
        /// R_RecursiveWorldNode
        /// </summary>
        private void RecursiveWorldNode(MemoryNodeBase node)
        {
            Occlusion.RecursiveWorldNode(node, _ModelOrg, _FrameCount, ref _Frustum, (surf) =>
            {
                DrawSequentialPoly(surf);
            }, (efrags) =>
            {
                StoreEfrags(efrags);
            });
        }
예제 #2
0
        /// <summary>
        /// R_MarkLeaves
        /// </summary>
        public void MarkLeaves( )
        {
            if (this.OldViewLeaf == this.ViewLeaf && !this.Host.Cvars.NoVis.Get <bool>())
            {
                return;
            }

            //if( _IsMirror )
            //  return;

            this.VisFrameCount++;
            this.OldViewLeaf = this.ViewLeaf;

            byte[] vis;
            if (this.Host.Cvars.NoVis.Get <bool>())
            {
                vis = new byte[4096];
                Utilities.FillArray <byte>(vis, 0xff);                  // todo: add count parameter?
                //memset(solid, 0xff, (cl.worldmodel->numleafs + 7) >> 3);
            }
            else
            {
                vis = this.Host.Client.cl.worldmodel.LeafPVS(this.ViewLeaf);
            }

            var world = this.Host.Client.cl.worldmodel;

            for (var i = 0; i < world.NumLeafs; i++)
            {
                if ((vis[i >> 3] != 0) & (1 << (i & 7) != 0))
                {
                    MemoryNodeBase node = world.Leaves[i + 1];
                    do
                    {
                        if (node.visframe == this.VisFrameCount)
                        {
                            break;
                        }
                        node.visframe = this.VisFrameCount;
                        node          = node.parent;
                    } while (node != null);
                }
            }
        }
예제 #3
0
        /// <summary>
        /// SV_FindTouchedLeafs
        /// </summary>
        private void FindTouchedLeafs(MemoryEdict ent, MemoryNodeBase node)
        {
            if (node.contents == ( Int32 )Q1Contents.Solid)
            {
                return;
            }

            // add an efrag if the node is a leaf

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

                var leaf    = ( MemoryLeaf )node;
                var leafnum = Array.IndexOf(sv.worldmodel.Leaves, leaf) - 1;

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

            // NODE_MIXED
            var n          = ( MemoryNode )node;
            var splitplane = n.plane;
            var 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]);
            }
        }
예제 #4
0
        /// <summary>
        /// R_MarkLights
        /// </summary>
        private void MarkLights(dlight_t light, int bit, MemoryNodeBase node)
        {
            if (node.contents < 0)
            {
                return;
            }

            var n          = ( MemoryNode )node;
            var splitplane = n.plane;
            var dist       = Vector3.Dot(light.origin, splitplane.normal) - splitplane.dist;

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

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

            this.MarkLights(light, bit, n.children[0]);
            this.MarkLights(light, bit, n.children[1]);
        }
예제 #5
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>
        private void AddToFatPVS(ref Vector3 org, MemoryNodeBase node)
        {
            while (true)
            {
                // if this is a leaf, accumulate the pvs bits
                if (node.contents < 0)
                {
                    if (node.contents != ( int )Q1Contents.Solid)
                    {
                        var pvs = this.sv.worldmodel.LeafPVS(( MemoryLeaf )node);
                        for (var i = 0; i < this._FatBytes; i++)
                        {
                            this._FatPvs[i] |= pvs[i];
                        }
                    }
                    return;
                }

                var n     = ( MemoryNode )node;
                var plane = n.plane;
                var 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
                    this.AddToFatPVS(ref org, n.children[0]);
                    node = n.children[1];
                }
            }
        }
예제 #6
0
        /// <summary>
        /// R_RecursiveWorldNode
        /// </summary>
        public void RecursiveWorldNode(MemoryNodeBase node, Vector3 modelOrigin, int frameCount, ref Plane[] frustum, Action <MemorySurface> onDrawSurface, Action <EFrag> onStoreEfrags)
        {
            if (node.contents == ( int )Q1Contents.Solid)
            {
                return;                     // solid
            }
            if (node.visframe != this.VisFrameCount)
            {
                return;
            }

            if (Utilities.CullBox(ref node.mins, ref node.maxs, ref frustum))
            {
                return;
            }

            int c;

            // if a leaf node, draw stuff
            if (node.contents < 0)
            {
                var pleaf = ( MemoryLeaf )node;
                var marks = pleaf.marksurfaces;
                var 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)
                {
                    onStoreEfrags(pleaf.efrags);
                }

                return;
            }

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

            var n = ( MemoryNode )node;

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

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

            case PlaneDef.PLANE_Y:
                dot = modelOrigin.Y - plane.dist;
                break;

            case PlaneDef.PLANE_Z:
                dot = modelOrigin.Z - plane.dist;
                break;

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

            var side = dot >= 0 ? 0 : 1;

            // recurse down the children, front side first
            this.RecursiveWorldNode(n.children[side], modelOrigin, frameCount, ref frustum, onDrawSurface, onStoreEfrags);

            // draw stuff
            c = n.numsurfaces;

            if (c != 0)
            {
                var surf   = this.Host.Client.cl.worldmodel.Surfaces;
                int offset = n.firstsurface;

                if (dot < 0 - QDef.BACKFACE_EPSILON)
                {
                    side = ( int )Q1SurfaceFlags.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 & ( int )Q1SurfaceFlags.Underwater) == 0 && (dot < 0) ^ ((surf[offset].flags & ( int )Q1SurfaceFlags.PlaneBack) != 0))
                    {
                        continue;                               // wrong side
                    }
                    // if sorting by texture, just store it out
                    if (this.Host.Cvars.glTexSort.Get <bool>())
                    {
                        //if( !_IsMirror || surf[offset].texinfo.texture != Host.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 & ( int )Q1SurfaceFlags.Sky) != 0)
                    {
                        surf[offset].texturechain   = this.TextureChains.SkyChain;
                        this.TextureChains.SkyChain = surf[offset];
                    }
                    else if ((surf[offset].flags & ( int )Q1SurfaceFlags.Turbulence) != 0)
                    {
                        surf[offset].texturechain     = this.TextureChains.WaterChain;
                        this.TextureChains.WaterChain = surf[offset];
                    }
                    else
                    {
                        onDrawSurface(surf[offset]);
                    }
                }
            }

            // recurse down the back side
            this.RecursiveWorldNode(n.children[side == 0 ? 1 : 0], modelOrigin, frameCount, ref frustum, onDrawSurface, onStoreEfrags);
        }
예제 #7
0
        /// <summary>
        /// R_SplitEntityOnNode
        /// </summary>
        private void SplitEntityOnNode(MemoryNodeBase node)
        {
            if (node.contents == ( int )Q1Contents.Solid)
            {
                return;
            }

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

                var leaf = (MemoryLeaf)( object )node;

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

                this.Host.Client.cl.free_efrags = this.Host.Client.cl.free_efrags.entnext;

                ef.entity = this._AddEnt;

                // add the entity link
                // *lastlink = ef;
                if (this._LastObj is Entity)
                {
                    ((Entity)this._LastObj).efrag = ef;
                }
                else
                {
                    ((EFrag)this._LastObj).entnext = ef;
                }

                this._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
            var n = node as MemoryNode;

            if (n == null)
            {
                return;
            }

            var splitplane = n.plane;
            var sides      = MathLib.BoxOnPlaneSide(ref this._EMins, ref this._EMaxs, splitplane);

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

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

            if ((sides & 2) != 0)
            {
                this.SplitEntityOnNode(n.children[1]);
            }
        }
예제 #8
0
        private int RecursiveLightPoint(MemoryNodeBase node, ref Vector3 start, ref Vector3 end)
        {
            if (node.contents < 0)
            {
                return(-1);                     // didn't hit anything
            }
            var n = ( MemoryNode )node;

            // calculate mid point

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

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

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

            // go down front side
            var r = this.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
            this._LightSpot  = mid;
            this._LightPlane = plane;

            var surf   = this.Host.Client.cl.worldmodel.Surfaces;
            int offset = n.firstsurface;

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

                var s = ( int )(Vector3.Dot(mid, new(tex.vecs[0].X, tex.vecs[0].Y, tex.vecs[0].Z) ) + tex.vecs[0].W);
                var t = ( int )(Vector3.Dot(mid, new(tex.vecs[1].X, tex.vecs[1].Y, tex.vecs[1].Z) ) + tex.vecs[1].W);

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

                var ds = s - surf[offset].texturemins[0];
                var 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;

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

                    for (var maps = 0; maps < BspDef.MAXLIGHTMAPS && surf[offset].styles[maps] != 255; maps++)
                    {
                        var scale = this._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(this.RecursiveLightPoint(n.children[side == 0 ? 1 : 0], ref mid, ref end));
        }