// V_BoundOffsets static void BoundOffsets() { Entity ent = Client.ViewEntity; // absolutely bound refresh reletive to entity clipping hull // so the view can never be inside a solid wall Refdef_t rdef = Render.RefDef; if (rdef.vieworg.X < ent.origin.X - 14) { rdef.vieworg.X = ent.origin.X - 14; } else if (rdef.vieworg.X > ent.origin.X + 14) { rdef.vieworg.X = ent.origin.X + 14; } if (rdef.vieworg.Y < ent.origin.Y - 14) { rdef.vieworg.Y = ent.origin.Y - 14; } else if (rdef.vieworg.Y > ent.origin.Y + 14) { rdef.vieworg.Y = ent.origin.Y + 14; } if (rdef.vieworg.Z < ent.origin.Z - 22) { rdef.vieworg.Z = ent.origin.Z - 22; } else if (rdef.vieworg.Z > ent.origin.Z + 30) { rdef.vieworg.Z = ent.origin.Z + 30; } }
// V_CalcIntermissionRefdef static void CalcIntermissionRefDef() { // ent is the player model (visible when out of body) Entity ent = Client.ViewEntity; // view is the weapon model (only visible from inside body) Entity view = Client.ViewEnt; Refdef_t rdef = Render.RefDef; rdef.vieworg = ent.origin; rdef.viewangles = ent.angles; view.model = null; // allways idle in intermission AddIdle(1); }
// V_CalcViewRoll // // Roll is induced by movement and damage static void CalcViewRoll() { ClientState cl = Client.Cl; Refdef_t rdef = Render.RefDef; float side = CalcRoll(ref Client.ViewEntity.angles, ref cl.velocity); rdef.viewangles.Z += side; if (_DmgTime > 0) { rdef.viewangles.Z += _DmgTime / _KickTime.Value * _DmgRoll; rdef.viewangles.X += _DmgTime / _KickTime.Value * _DmgPitch; _DmgTime -= (float)Host.FrameTime; } if (cl.stats[QStats.STAT_HEALTH] <= 0) { rdef.viewangles.Z = 80; // dead view angle return; } }
// SCR_TileClear static void TileClear() { Refdef_t rdef = Render.RefDef; if (rdef.vrect.x > 0) { // left Drawer.TileClear(0, 0, rdef.vrect.x, _VidDef.height - Sbar.Lines); // right Drawer.TileClear(rdef.vrect.x + rdef.vrect.width, 0, _VidDef.width - rdef.vrect.x + rdef.vrect.width, _VidDef.height - Sbar.Lines); } if (rdef.vrect.y > 0) { // top Drawer.TileClear(rdef.vrect.x, 0, rdef.vrect.x + rdef.vrect.width, rdef.vrect.y); // bottom Drawer.TileClear(rdef.vrect.x, rdef.vrect.y + rdef.vrect.height, rdef.vrect.width, _VidDef.height - Sbar.Lines - (rdef.vrect.height + rdef.vrect.y)); } }
/// <summary> /// CalcGunAngle /// </summary> static void CalcGunAngle() { Refdef_t rdef = Render.RefDef; float yaw = rdef.viewangles.Y; float pitch = -rdef.viewangles.X; yaw = AngleDelta(yaw - rdef.viewangles.Y) * 0.4f; if (yaw > 10) { yaw = 10; } if (yaw < -10) { yaw = -10; } pitch = AngleDelta(-pitch - rdef.viewangles.X) * 0.4f; if (pitch > 10) { pitch = 10; } if (pitch < -10) { pitch = -10; } float move = (float)Host.FrameTime * 20; if (yaw > _OldYaw) { if (_OldYaw + move < yaw) { yaw = _OldYaw + move; } } else { if (_OldYaw - move > yaw) { yaw = _OldYaw - move; } } if (pitch > _OldPitch) { if (_OldPitch + move < pitch) { pitch = _OldPitch + move; } } else { if (_OldPitch - move > pitch) { pitch = _OldPitch - move; } } _OldYaw = yaw; _OldPitch = pitch; ClientState cl = Client.Cl; cl.viewent.angles.Y = rdef.viewangles.Y + yaw; cl.viewent.angles.X = -(rdef.viewangles.X + pitch); float idleScale = _IdleScale.Value; cl.viewent.angles.Z -= (float)(idleScale * Math.Sin(cl.time * _IRollCycle.Value) * _IRollLevel.Value); cl.viewent.angles.X -= (float)(idleScale * Math.Sin(cl.time * _IPitchCycle.Value) * _IPitchLevel.Value); cl.viewent.angles.Y -= (float)(idleScale * Math.Sin(cl.time * _IYawCycle.Value) * _IYawLevel.Value); }
// V_CalcRefdef static void CalcRefDef() { DriftPitch(); // ent is the player model (visible when out of body) Entity ent = Client.ViewEntity; // view is the weapon model (only visible from inside body) Entity view = Client.ViewEnt; // transform the view offset by the model's matrix to get the offset from // model origin for the view ent.angles.Y = Client.Cl.viewangles.Y; // the model should face the view dir ent.angles.X = -Client.Cl.viewangles.X; // the model should face the view dir float bob = CalcBob(); Refdef_t rdef = Render.RefDef; ClientState cl = 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(_IdleScale.Value); // offsets Vector3 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 * _ScrOfsX.Value + right * _ScrOfsY.Value + up * _ScrOfsZ.Value; 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 float viewSize = Scr.ViewSize.Value; // 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[QStats.STAT_WEAPON]]; view.frame = cl.stats[QStats.STAT_WEAPONFRAME]; view.colormap = Scr.vid.colormap; // set up the refresh position rdef.viewangles += cl.punchangle; // smooth out stair step ups if (cl.onground && ent.origin.Z - _OldZ > 0) { float steptime = (float)(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 (Chase.IsActive) { Chase.Update(); } }
/// <summary> /// V_RenderView /// The player's clipping box goes from (-16 -16 -24) to (16 16 32) from /// the entity origin, so any view position inside that will be valid /// </summary> public static void RenderView() { if (Con.ForcedUp) { return; } // don't allow cheats in multiplayer if (Client.Cl.maxclients > 1) { Cvar.Set("scr_ofsx", "0"); Cvar.Set("scr_ofsy", "0"); Cvar.Set("scr_ofsz", "0"); } if (Client.Cl.intermission > 0) { // intermission / finale rendering CalcIntermissionRefDef(); } else if (!Client.Cl.paused) { CalcRefDef(); } Render.PushDlights(); if (_LcdX.Value != 0) { // // render two interleaved views // viddef_t vid = Scr.vid; Refdef_t rdef = Render.RefDef; vid.rowbytes <<= 1; vid.aspect *= 0.5f; rdef.viewangles.Y -= _LcdYaw.Value; rdef.vieworg -= _Right * _LcdX.Value; Render.RenderView(); // ???????? vid.buffer += vid.rowbytes>>1; Render.PushDlights(); rdef.viewangles.Y += _LcdYaw.Value * 2; rdef.vieworg += _Right * _LcdX.Value * 2; Render.RenderView(); // ????????? vid.buffer -= vid.rowbytes>>1; rdef.vrect.height <<= 1; vid.rowbytes >>= 1; vid.aspect *= 2; } else { Render.RenderView(); } }
// SCR_CalcRefdef // // Must be called whenever vid changes // Internal use only static void CalcRefdef() { Scr.FullUpdate = 0; // force a background redraw _VidDef.recalc_refdef = false; // force the status bar to redraw Sbar.Changed(); // bound viewsize if (_ViewSize.Value < 30) { Cvar.Set("viewsize", "30"); } if (_ViewSize.Value > 120) { Cvar.Set("viewsize", "120"); } // bound field of view if (_Fov.Value < 10) { Cvar.Set("fov", "10"); } if (_Fov.Value > 170) { Cvar.Set("fov", "170"); } // intermission is always full screen float size; if (Client.Cl.intermission > 0) { size = 120; } else { size = _ViewSize.Value; } if (size >= 120) { Sbar.Lines = 0; // no status bar at all } else if (size >= 110) { Sbar.Lines = 24; // no inventory } else { Sbar.Lines = 24 + 16 + 8; } bool full = false; if (_ViewSize.Value >= 100.0) { full = true; size = 100.0f; } else { size = _ViewSize.Value; } if (Client.Cl.intermission > 0) { full = true; size = 100; Sbar.Lines = 0; } size /= 100.0f; int h = _VidDef.height - Sbar.Lines; Refdef_t rdef = Render.RefDef; rdef.vrect.width = (int)(_VidDef.width * size); if (rdef.vrect.width < 96) { size = 96.0f / rdef.vrect.width; rdef.vrect.width = 96; // min for icons } rdef.vrect.height = (int)(_VidDef.height * size); if (rdef.vrect.height > _VidDef.height - Sbar.Lines) { rdef.vrect.height = _VidDef.height - Sbar.Lines; } if (rdef.vrect.height > _VidDef.height) { rdef.vrect.height = _VidDef.height; } rdef.vrect.x = (_VidDef.width - rdef.vrect.width) / 2; if (full) { rdef.vrect.y = 0; } else { rdef.vrect.y = (h - rdef.vrect.height) / 2; } rdef.fov_x = _Fov.Value; rdef.fov_y = CalcFov(rdef.fov_x, rdef.vrect.width, rdef.vrect.height); _VRect = rdef.vrect; }