示例#1
0
        // Chase_Update
        public void Update()
        {
            // if can't see player, reset
            Vector3 forward, up, right;

            MathLib.AngleVectors(ref this.Host.Client.cl.viewangles, out forward, out right, out up);

            // calc exact destination
            this._Dest   = this.Host.RenderContext.RefDef.vieworg - forward * this.Host.Cvars.Back.Get <float>( ) - right * this.Host.Cvars.Right.Get <float>( );
            this._Dest.Z = this.Host.RenderContext.RefDef.vieworg.Z + this.Host.Cvars.Up.Get <float>( );

            // find the spot the player is looking at
            var dest = this.Host.RenderContext.RefDef.vieworg + forward * 4096;

            Vector3 stop;

            this.TraceLine(ref this.Host.RenderContext.RefDef.vieworg, ref dest, out stop);

            // calculate pitch to look at the same spot from camera
            stop -= this.Host.RenderContext.RefDef.vieworg;
            float dist;

            dist = Vector3.Dot(stop, forward);
            if (dist < 1)
            {
                dist = 1;
            }

            this.Host.RenderContext.RefDef.viewangles.X = ( float )(-Math.Atan(stop.Z / dist) / Math.PI * 180.0);
            //r_refdef.viewangles[PITCH] = -atan(stop[2] / dist) / M_PI * 180;

            // move towards destination
            this.Host.RenderContext.RefDef.vieworg = this._Dest; //VectorCopy(chase_dest, r_refdef.vieworg);
        }
示例#2
0
        /// <summary>
        /// R_SetupFrame
        /// </summary>
        private void SetupFrame( )
        {
            // don't allow cheats in multiplayer
            if (Host.Client.cl.maxclients > 1)
            {
                Host.CVars.Set("r_fullbright", false);
            }

            AnimateLight( );

            _FrameCount++;

            // build the transformation matrix for the given view angles
            Origin = _RefDef.vieworg;

            MathLib.AngleVectors(ref _RefDef.viewangles, out ViewPn, out ViewRight, out ViewUp);

            // current viewleaf
            Occlusion.SetupFrame(ref Origin);
            Host.View.SetContentsColor(Occlusion.ViewLeaf.contents);
            Host.View.CalcBlend( );

            _CacheThrash = false;
            _BrushPolys  = 0;
            _AliasPolys  = 0;
        }
示例#3
0
        /// <summary>
        /// SV_AirMove
        /// </summary>
        private void AirMove()
        {
            var pangles = Utilities.ToVector(ref _Player.v.angles);

            MathLib.AngleVectors(ref pangles, out _Forward, out _Right, out _Up);

            var fmove = _Cmd.forwardmove;
            var smove = _Cmd.sidemove;

            // hack to not let you back into teleporter
            if (sv.time < _Player.v.teleport_time && fmove < 0)
            {
                fmove = 0;
            }

            var wishvel = _Forward * fmove + _Right * smove;

            if (( Int32 )_Player.v.movetype != Movetypes.MOVETYPE_WALK)
            {
                wishvel.Z = _Cmd.upmove;
            }
            else
            {
                wishvel.Z = 0;
            }

            _WishDir   = wishvel;
            _WishSpeed = MathLib.Normalize(ref _WishDir);
            var maxSpeed = Host.Cvars.MaxSpeed.Get <Single>();

            if (_WishSpeed > maxSpeed)
            {
                wishvel   *= maxSpeed / _WishSpeed;
                _WishSpeed = maxSpeed;
            }

            if (_Player.v.movetype == Movetypes.MOVETYPE_NOCLIP)
            {
                // noclip
                MathLib.Copy(ref wishvel, out _Player.v.velocity);
            }
            else if (_OnGround)
            {
                UserFriction();
                Accelerate();
            }
            else
            {   // not on ground, so little effect on velocity
                AirAccelerate(wishvel);
            }
        }
示例#4
0
        /// <summary>
        /// SV_AirMove
        /// </summary>
        private void AirMove()
        {
            var pangles = Utilities.ToVector(ref this._Player.v.angles);

            MathLib.AngleVectors(ref pangles, out this._Forward, out this._Right, out this._Up);

            var fmove = this._Cmd.forwardmove;
            var smove = this._Cmd.sidemove;

            // hack to not let you back into teleporter
            if (this.sv.time < this._Player.v.teleport_time && fmove < 0)
            {
                fmove = 0;
            }

            var wishvel = this._Forward * fmove + this._Right * smove;

            if (( int )this._Player.v.movetype != Movetypes.MOVETYPE_WALK)
            {
                wishvel.Z = this._Cmd.upmove;
            }
            else
            {
                wishvel.Z = 0;
            }

            this._WishDir   = wishvel;
            this._WishSpeed = MathLib.Normalize(ref this._WishDir);
            var maxSpeed = this.Host.Cvars.MaxSpeed.Get <float>();

            if (this._WishSpeed > maxSpeed)
            {
                wishvel        *= maxSpeed / this._WishSpeed;
                this._WishSpeed = maxSpeed;
            }

            if (this._Player.v.movetype == Movetypes.MOVETYPE_NOCLIP)
            {
                // noclip
                MathLib.Copy(ref wishvel, out this._Player.v.velocity);
            }
            else if (this._OnGround)
            {
                this.UserFriction();
                this.Accelerate();
            }
            else
            {   // not on ground, so little effect on velocity
                this.AirAccelerate(wishvel);
            }
        }
		/// <summary>
		/// SV_WallFriction
		/// </summary>
		private void WallFriction( MemoryEdict ent, Trace_t trace )
		{
			Vector3 forward, right, up, vangle = Utilities.ToVector( ref ent.v.v_angle );
			MathLib.AngleVectors( ref vangle, out forward, out right, out up );
			var d = Vector3.Dot( trace.plane.normal, forward );

			d += 0.5f;
			if ( d >= 0 )
				return;

			// cut the tangential velocity
			var vel = Utilities.ToVector( ref ent.v.velocity );
			var i = Vector3.Dot( trace.plane.normal, vel );
			var into = trace.plane.normal * i;
			var side = vel - into;

			ent.v.velocity.x = side.X * ( 1 + d );
			ent.v.velocity.y = side.Y * ( 1 + d );
		}
示例#6
0
        /// <summary>
        /// V_CalcRoll
        /// Used by view and sv_user
        /// </summary>
        public Single CalcRoll(ref Vector3 angles, ref Vector3 velocity)
        {
            MathLib.AngleVectors(ref angles, out _Forward, out _Right, out _Up);
            var    side = Vector3.Dot(velocity, _Right);
            Single sign = side < 0 ? -1 : 1;

            side = Math.Abs(side);

            var value = Host.Cvars.ClRollAngle.Get <Single>();

            if (side < Host.Cvars.ClRollSpeed.Get <Single>())
            {
                side = side * value / Host.Cvars.ClRollSpeed.Get <Single>();
            }
            else
            {
                side = value;
            }

            return(side * sign);
        }
示例#7
0
        /// <summary>
        /// V_CalcRoll
        /// Used by view and sv_user
        /// </summary>
        public float CalcRoll(ref Vector3 angles, ref Vector3 velocity)
        {
            MathLib.AngleVectors(ref angles, out this._Forward, out this._Right, out this._Up);
            var   side = Vector3.Dot(velocity, this._Right);
            float sign = side < 0 ? -1 : 1;

            side = Math.Abs(side);

            var value = this.Host.Cvars.ClRollAngle.Get <float>();

            if (side < this.Host.Cvars.ClRollSpeed.Get <float>())
            {
                side = side * value / this.Host.Cvars.ClRollSpeed.Get <float>();
            }
            else
            {
                side = value;
            }

            return(side * sign);
        }
示例#8
0
        /// <summary>
        /// R_DrawSpriteModel
        /// </summary>
        private void DrawSpriteModel(Entity e)
        {
            // don't even bother culling, because it's just a single
            // polygon without a surface cache
            var frame   = GetSpriteFrame(e);
            var psprite = ( msprite_t )e.model.cache.data;  // Uze: changed from _CurrentEntity to e

            Vector3 v_forward, right, up;

            if (psprite.type == SpriteType.Oriented)
            {
                // bullet marks on walls
                MathLib.AngleVectors(ref e.angles, out v_forward, out right, out up);   // Uze: changed from _CurrentEntity to e
            }
            else
            {                      // normal sprite
                up    = ViewUp;    // vup;
                right = ViewRight; // vright;
            }

            var texture = Host.Model.SpriteTextures.Where(t => ((Renderer.OpenGL.Textures.GLTextureDesc)t.Desc).TextureNumber == frame.gl_texturenum).FirstOrDefault();

            Host.Video.Device.Graphics.DrawSpriteModel(texture, frame, up, right, e.origin);
        }
示例#9
0
        /// <summary>
        /// CL_RelinkEntities
        /// </summary>
        private void RelinkEntities()
        {
            // determine partial update time
            var frac = this.LerpPoint();

            this.NumVisEdicts = 0;

            //
            // interpolate player info
            //
            this.cl.velocity = this.cl.mvelocity[1] + frac * (this.cl.mvelocity[0] - this.cl.mvelocity[1]);

            if (this.cls.demoplayback)
            {
                // interpolate the angles
                var angleDelta = this.cl.mviewangles[0] - this.cl.mviewangles[1];
                MathLib.CorrectAngles180(ref angleDelta);
                this.cl.viewangles = this.cl.mviewangles[1] + frac * angleDelta;
            }

            var bobjrotate = MathLib.AngleMod(100 * this.cl.time);

            // start on the entity after the world
            for (var i = 1; i < this.cl.num_entities; i++)
            {
                var ent = this._Entities[i];
                if (ent.model == null)
                {
                    // empty slot
                    if (ent.forcelink)
                    {
                        this.Host.RenderContext.RemoveEfrags(ent);      // just became empty
                    }
                    continue;
                }

                // if the object wasn't included in the last packet, remove it
                if (ent.msgtime != this.cl.mtime[0])
                {
                    ent.model = null;
                    continue;
                }

                var oldorg = ent.origin;

                if (ent.forcelink)
                {
                    // the entity was not updated in the last message
                    // so move to the final spot
                    ent.origin = ent.msg_origins[0];
                    ent.angles = ent.msg_angles[0];
                }
                else
                {
                    // if the delta is large, assume a teleport and don't lerp
                    var f     = frac;
                    var delta = ent.msg_origins[0] - ent.msg_origins[1];
                    if (Math.Abs(delta.X) > 100 || Math.Abs(delta.Y) > 100 || Math.Abs(delta.Z) > 100)
                    {
                        f = 1; // assume a teleportation, not a motion
                    }
                    // interpolate the origin and angles
                    ent.origin = ent.msg_origins[1] + f * delta;
                    var angleDelta = ent.msg_angles[0] - ent.msg_angles[1];
                    MathLib.CorrectAngles180(ref angleDelta);
                    ent.angles = ent.msg_angles[1] + f * angleDelta;
                }

                // rotate binary objects locally
                if (ent.model.Flags.HasFlag(EntityFlags.Rotate))
                {
                    ent.angles.Y = bobjrotate;
                }

                if ((ent.effects & EntityEffects.EF_BRIGHTFIELD) != 0)
                {
                    this.Host.RenderContext.Particles.EntityParticles(this.Host.Client.cl.time, ent.origin);
                }

                if ((ent.effects & EntityEffects.EF_MUZZLEFLASH) != 0)
                {
                    var dl = this.AllocDlight(i);
                    dl.origin    = ent.origin;
                    dl.origin.Z += 16;
                    Vector3 fv, rv, uv;
                    MathLib.AngleVectors(ref ent.angles, out fv, out rv, out uv);
                    dl.origin  += fv * 18;
                    dl.radius   = 200 + (MathLib.Random() & 31);
                    dl.minlight = 32;
                    dl.die      = ( float )this.cl.time + 0.1f;
                }
                if ((ent.effects & EntityEffects.EF_BRIGHTLIGHT) != 0)
                {
                    var dl = this.AllocDlight(i);
                    dl.origin    = ent.origin;
                    dl.origin.Z += 16;
                    dl.radius    = 400 + (MathLib.Random() & 31);
                    dl.die       = ( float )this.cl.time + 0.001f;
                }
                if ((ent.effects & EntityEffects.EF_DIMLIGHT) != 0)
                {
                    var dl = this.AllocDlight(i);
                    dl.origin = ent.origin;
                    dl.radius = 200 + (MathLib.Random() & 31);
                    dl.die    = ( float )this.cl.time + 0.001f;
                }

                if (ent.model.Flags.HasFlag(EntityFlags.Gib))
                {
                    this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 2);
                }
                else if (ent.model.Flags.HasFlag(EntityFlags.ZomGib))
                {
                    this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 4);
                }
                else if (ent.model.Flags.HasFlag(EntityFlags.Tracer))
                {
                    this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 3);
                }
                else if (ent.model.Flags.HasFlag(EntityFlags.Tracer2))
                {
                    this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 5);
                }
                else if (ent.model.Flags.HasFlag(EntityFlags.Rocket))
                {
                    this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 0);
                    var dl = this.AllocDlight(i);
                    dl.origin = ent.origin;
                    dl.radius = 200;
                    dl.die    = ( float )this.cl.time + 0.01f;
                }
                else if (ent.model.Flags.HasFlag(EntityFlags.Grenade))
                {
                    this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 1);
                }
                else if (ent.model.Flags.HasFlag(EntityFlags.Tracer3))
                {
                    this.Host.RenderContext.Particles.RocketTrail(this.Host.Client.cl.time, ref oldorg, ref ent.origin, 6);
                }

                ent.forcelink = false;

                if (i == this.cl.viewentity && !this.Host.ChaseView.IsActive)
                {
                    continue;
                }

                if (this.NumVisEdicts < ClientDef.MAX_VISEDICTS)
                {
                    this._VisEdicts[this.NumVisEdicts] = ent;
                    this.NumVisEdicts++;
                }
            }
        }
示例#10
0
        // V_CalcRefdef
        private void CalcRefDef( )
        {
            DriftPitch();

            // ent is the player model (visible when out of body)
            var ent = Host.Client.ViewEntity;
            // view is the weapon model (only visible from inside body)
            var view = Host.Client.ViewEnt;

            // transform the view offset by the model's matrix to get the offset from
            // model origin for the view
            ent.angles.Y = Host.Client.cl.viewangles.Y;             // the model should face the view dir
            ent.angles.X = -Host.Client.cl.viewangles.X;            // the model should face the view dir

            var bob = CalcBob();

            var rdef = Host.RenderContext.RefDef;
            var cl   = Host.Client.cl;

            // refresh position
            rdef.vieworg    = ent.origin;
            rdef.vieworg.Z += cl.viewheight + bob;

            // never let it sit exactly on a node line, because a water plane can
            // dissapear when viewed with the eye exactly on it.
            // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis
            rdef.vieworg   += SmallOffset;
            rdef.viewangles = cl.viewangles;

            CalcViewRoll();
            AddIdle(Host.Cvars.IdleScale.Get <Single>());

            // offsets
            var angles = ent.angles;

            angles.X = -angles.X;             // because entity pitches are actually backward

            Vector3 forward, right, up;

            MathLib.AngleVectors(ref angles, out forward, out right, out up);

            rdef.vieworg += forward * Host.Cvars.ScrOfsX.Get <Single>() + right * Host.Cvars.ScrOfsY.Get <Single>() + up * Host.Cvars.ScrOfsZ.Get <Single>();

            BoundOffsets();

            // set up gun position
            view.angles = cl.viewangles;

            CalcGunAngle();

            view.origin    = ent.origin;
            view.origin.Z += cl.viewheight;
            view.origin   += forward * bob * 0.4f;
            view.origin.Z += bob;

            // fudge position around to keep amount of weapon visible
            // roughly equal with different FOV
            var viewSize = Host.Screen.ViewSize.Get <Single>();            // scr_viewsize

            if (viewSize == 110)
            {
                view.origin.Z += 1;
            }
            else if (viewSize == 100)
            {
                view.origin.Z += 2;
            }
            else if (viewSize == 90)
            {
                view.origin.Z += 1;
            }
            else if (viewSize == 80)
            {
                view.origin.Z += 0.5f;
            }

            view.model    = cl.model_precache[cl.stats[QStatsDef.STAT_WEAPON]];
            view.frame    = cl.stats[QStatsDef.STAT_WEAPONFRAME];
            view.colormap = Host.Screen.vid.colormap;

            // set up the refresh position
            rdef.viewangles += cl.punchangle;

            // smooth out stair step ups
            if (cl.onground && ent.origin.Z - _OldZ > 0)
            {
                var steptime = ( Single )(cl.time - cl.oldtime);
                if (steptime < 0)
                {
                    steptime = 0;
                }

                _OldZ += steptime * 80;
                if (_OldZ > ent.origin.Z)
                {
                    _OldZ = ent.origin.Z;
                }
                if (ent.origin.Z - _OldZ > 12)
                {
                    _OldZ = ent.origin.Z - 12;
                }
                rdef.vieworg.Z += _OldZ - ent.origin.Z;
                view.origin.Z  += _OldZ - ent.origin.Z;
            }
            else
            {
                _OldZ = ent.origin.Z;
            }

            if (Host.ChaseView.IsActive)
            {
                Host.ChaseView.Update();
            }
        }
示例#11
0
        // V_ParseDamage
        public void ParseDamage( )
        {
            var armor = Host.Network.Reader.ReadByte();
            var blood = Host.Network.Reader.ReadByte();
            var from  = Host.Network.Reader.ReadCoords();

            var count = blood * 0.5f + armor * 0.5f;

            if (count < 10)
            {
                count = 10;
            }

            var cl = Host.Client.cl;

            cl.faceanimtime = ( Single )cl.time + 0.2f;              // put sbar face into pain frame

            cl.cshifts[ColorShift.CSHIFT_DAMAGE].percent += ( Int32 )(3 * count);
            if (cl.cshifts[ColorShift.CSHIFT_DAMAGE].percent < 0)
            {
                cl.cshifts[ColorShift.CSHIFT_DAMAGE].percent = 0;
            }
            if (cl.cshifts[ColorShift.CSHIFT_DAMAGE].percent > 150)
            {
                cl.cshifts[ColorShift.CSHIFT_DAMAGE].percent = 150;
            }

            if (armor > blood)
            {
                cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[0] = 200;
                cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[1] = 100;
                cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[2] = 100;
            }
            else if (armor != 0)
            {
                cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[0] = 220;
                cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[1] = 50;
                cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[2] = 50;
            }
            else
            {
                cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[0] = 255;
                cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[1] = 0;
                cl.cshifts[ColorShift.CSHIFT_DAMAGE].destcolor[2] = 0;
            }

            //
            // calculate view angle kicks
            //
            var ent = Host.Client.Entities[cl.viewentity];

            from -= ent.origin;             //  VectorSubtract (from, ent->origin, from);
            MathLib.Normalize(ref from);

            Vector3 forward, right, up;

            MathLib.AngleVectors(ref ent.angles, out forward, out right, out up);

            var side = Vector3.Dot(from, right);

            _DmgRoll = count * side * Host.Cvars.KickRoll.Get <Single>();

            side      = Vector3.Dot(from, forward);
            _DmgPitch = count * side * Host.Cvars.KickPitch.Get <Single>();

            _DmgTime = Host.Cvars.KickTime.Get <Single>();
        }
示例#12
0
        /// <summary>
        /// SV_WaterMove
        /// </summary>
        private void WaterMove()
        {
            //
            // user intentions
            //
            var pangle = Utilities.ToVector(ref this._Player.v.v_angle);

            MathLib.AngleVectors(ref pangle, out this._Forward, out this._Right, out this._Up);
            var wishvel = this._Forward * this._Cmd.forwardmove + this._Right * this._Cmd.sidemove;

            if (this._Cmd.forwardmove == 0 && this._Cmd.sidemove == 0 && this._Cmd.upmove == 0)
            {
                wishvel.Z -= 60;                // drift towards bottom
            }
            else
            {
                wishvel.Z += this._Cmd.upmove;
            }

            var wishspeed = wishvel.Length();
            var maxSpeed  = this.Host.Cvars.MaxSpeed.Get <float>();

            if (wishspeed > maxSpeed)
            {
                wishvel  *= maxSpeed / wishspeed;
                wishspeed = maxSpeed;
            }
            wishspeed *= 0.7f;

            //
            // water friction
            //
            float newspeed, speed = MathLib.Length(ref this._Player.v.velocity);

            if (speed != 0)
            {
                newspeed = ( float )(speed - this.Host.FrameTime * speed * this.Host.Cvars.Friction.Get <float>( ));
                if (newspeed < 0)
                {
                    newspeed = 0;
                }
                MathLib.VectorScale(ref this._Player.v.velocity, newspeed / speed, out this._Player.v.velocity);
            }
            else
            {
                newspeed = 0;
            }

            //
            // water acceleration
            //
            if (wishspeed == 0)
            {
                return;
            }

            var addspeed = wishspeed - newspeed;

            if (addspeed <= 0)
            {
                return;
            }

            MathLib.Normalize(ref wishvel);
            var accelspeed = ( float )(this.Host.Cvars.Accelerate.Get <float>( ) * wishspeed * this.Host.FrameTime);

            if (accelspeed > addspeed)
            {
                accelspeed = addspeed;
            }

            wishvel *= accelspeed;
            this._Player.v.velocity.X += wishvel.X;
            this._Player.v.velocity.Y += wishvel.Y;
            this._Player.v.velocity.Z += wishvel.Z;
        }
示例#13
0
        /// <summary>
        /// SV_WaterMove
        /// </summary>
        private void WaterMove()
        {
            //
            // user intentions
            //
            var pangle = Utilities.ToVector(ref _Player.v.v_angle);

            MathLib.AngleVectors(ref pangle, out _Forward, out _Right, out _Up);
            var wishvel = _Forward * _Cmd.forwardmove + _Right * _Cmd.sidemove;

            if (_Cmd.forwardmove == 0 && _Cmd.sidemove == 0 && _Cmd.upmove == 0)
            {
                wishvel.Z -= 60;                // drift towards bottom
            }
            else
            {
                wishvel.Z += _Cmd.upmove;
            }

            var wishspeed = wishvel.Length;
            var maxSpeed  = Host.Cvars.MaxSpeed.Get <Single>();

            if (wishspeed > maxSpeed)
            {
                wishvel  *= maxSpeed / wishspeed;
                wishspeed = maxSpeed;
            }
            wishspeed *= 0.7f;

            //
            // water friction
            //
            Single newspeed, speed = MathLib.Length(ref _Player.v.velocity);

            if (speed != 0)
            {
                newspeed = ( Single )(speed - Host.FrameTime * speed * Host.Cvars.Friction.Get <Single>( ));
                if (newspeed < 0)
                {
                    newspeed = 0;
                }
                MathLib.VectorScale(ref _Player.v.velocity, newspeed / speed, out _Player.v.velocity);
            }
            else
            {
                newspeed = 0;
            }

            //
            // water acceleration
            //
            if (wishspeed == 0)
            {
                return;
            }

            var addspeed = wishspeed - newspeed;

            if (addspeed <= 0)
            {
                return;
            }

            MathLib.Normalize(ref wishvel);
            var accelspeed = ( Single )(Host.Cvars.Accelerate.Get <Single>( ) * wishspeed * Host.FrameTime);

            if (accelspeed > addspeed)
            {
                accelspeed = addspeed;
            }

            wishvel *= accelspeed;
            _Player.v.velocity.x += wishvel.X;
            _Player.v.velocity.y += wishvel.Y;
            _Player.v.velocity.z += wishvel.Z;
        }
示例#14
0
        /// <summary>
        /// R_DrawBrushModel
        /// </summary>
        private void DrawBrushModel(Entity e)
        {
            _CurrentEntity = e;
            Host.DrawingContext.CurrentTexture = -1;

            var     clmodel = ( BrushModelData )e.model;
            var     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.BoundsMin;
                maxs = e.origin + clmodel.BoundsMax;
            }

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

            Array.Clear(_LightMapPolys, 0, _LightMapPolys.Length);
            _ModelOrg = _RefDef.vieworg - e.origin;
            if (rotated)
            {
                var     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 && !Host.Cvars.glFlashBlend.Get <Boolean>( ))
            {
                for (var k = 0; k < ClientDef.MAX_DLIGHTS; k++)
                {
                    if ((Host.Client.DLights[k].die < Host.Client.cl.time) || (Host.Client.DLights[k].radius == 0))
                    {
                        continue;
                    }

                    MarkLights(Host.Client.DLights[k], 1 << k, clmodel.Nodes[clmodel.Hulls[0].firstclipnode]);
                }
            }

            Host.Video.Device.PushMatrix( );
            e.angles.X = -e.angles.X;               // stupid quake bug
            Host.Video.Device.RotateForEntity(e.origin, e.angles);
            e.angles.X = -e.angles.X;               // stupid quake bug

            var surfOffset = clmodel.FirstModelSurface;
            var psurf      = clmodel.Surfaces;        //[clmodel.firstmodelsurface];

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

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

                // draw the polygon
                var planeBack = (psurf[surfOffset].flags & ( Int32 )Q1SurfaceFlags.PlaneBack) != 0;
                if ((planeBack && (dot < -QDef.BACKFACE_EPSILON)) || (!planeBack && (dot > QDef.BACKFACE_EPSILON)))
                {
                    if (Host.Cvars.glTexSort.Get <Boolean>( ))
                    {
                        RenderBrushPoly(psurf[surfOffset]);
                    }
                    else
                    {
                        DrawSequentialPoly(psurf[surfOffset]);
                    }
                }
            }

            BlendLightmaps( );

            Host.Video.Device.PopMatrix( );
        }