]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - view.c
view.c, cl_parse.c, cl_main.c, gl_rmain.c - trying to remove all uses of origin,...
[xonotic/darkplaces.git] / view.c
diff --git a/view.c b/view.c
index 5b0da1ee968a8c9bf5c854f63598e274e388558e..121b922a34eca47d10928d9ef00d976b65e9a1a5 100644 (file)
--- a/view.c
+++ b/view.c
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -30,34 +30,30 @@ when crossing a water boudnary.
 
 */
 
-cvar_t cl_rollspeed = {"cl_rollspeed", "200"};
-cvar_t cl_rollangle = {"cl_rollangle", "2.0"};
+cvar_t cl_rollspeed = {0, "cl_rollspeed", "200"};
+cvar_t cl_rollangle = {0, "cl_rollangle", "2.0"};
 
-cvar_t cl_bob = {"cl_bob","0.02", false};
-cvar_t cl_bobcycle = {"cl_bobcycle","0.6", false};
-cvar_t cl_bobup = {"cl_bobup","0.5", false};
+cvar_t cl_bob = {0, "cl_bob","0.02"};
+cvar_t cl_bobcycle = {0, "cl_bobcycle","0.6"};
+cvar_t cl_bobup = {0, "cl_bobup","0.5"};
 
-cvar_t v_kicktime = {"v_kicktime", "0.5", false};
-cvar_t v_kickroll = {"v_kickroll", "0.6", false};
-cvar_t v_kickpitch = {"v_kickpitch", "0.6", false};
+cvar_t v_kicktime = {0, "v_kicktime", "0.5"};
+cvar_t v_kickroll = {0, "v_kickroll", "0.6"};
+cvar_t v_kickpitch = {0, "v_kickpitch", "0.6"};
 
-cvar_t v_punch = {"v_punch", "1", false};
+cvar_t v_iyaw_cycle = {0, "v_iyaw_cycle", "2"};
+cvar_t v_iroll_cycle = {0, "v_iroll_cycle", "0.5"};
+cvar_t v_ipitch_cycle = {0, "v_ipitch_cycle", "1"};
+cvar_t v_iyaw_level = {0, "v_iyaw_level", "0.3"};
+cvar_t v_iroll_level = {0, "v_iroll_level", "0.1"};
+cvar_t v_ipitch_level = {0, "v_ipitch_level", "0.3"};
 
-cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", false};
-cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", false};
-cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", false};
-cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", false};
-cvar_t v_iroll_level = {"v_iroll_level", "0.1", false};
-cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", false};
+cvar_t v_idlescale = {0, "v_idlescale", "0"};
 
-cvar_t v_idlescale = {"v_idlescale", "0", false};
+cvar_t crosshair = {CVAR_SAVE, "crosshair", "0"};
 
-cvar_t crosshair = {"crosshair", "0", true};
-cvar_t cl_crossx = {"cl_crossx", "0", false};
-cvar_t cl_crossy = {"cl_crossy", "0", false};
-
-//cvar_t       gl_cshiftpercent = {"gl_cshiftpercent", "100", false};
-cvar_t gl_polyblend = {"gl_polyblend", "1", true};
+cvar_t v_centermove = {0, "v_centermove", "0.15"};
+cvar_t v_centerspeed = {0, "v_centerspeed","500"};
 
 float  v_dmg_time, v_dmg_roll, v_dmg_pitch;
 
@@ -75,74 +71,56 @@ float V_CalcRoll (vec3_t angles, vec3_t velocity)
        float   sign;
        float   side;
        float   value;
-       
+
        AngleVectors (angles, NULL, right, NULL);
        side = DotProduct (velocity, right);
        sign = side < 0 ? -1 : 1;
        side = fabs(side);
-       
+
        value = cl_rollangle.value;
-//     if (cl.inwater)
-//             value *= 6;
 
        if (side < cl_rollspeed.value)
                side = side * value / cl_rollspeed.value;
        else
                side = value;
-       
+
        return side*sign;
-       
+
 }
 
+static float V_CalcBob (void)
+{
+       double bob, cycle;
 
-/*
-===============
-V_CalcBob
+       // LordHavoc: easy case
+       if (cl_bob.value == 0)
+               return 0;
+       if (cl_bobcycle.value == 0)
+               return 0;
 
-===============
-*/
-float V_CalcBob (void)
-{
-       float   bob;
-       float   cycle;
-       
-       cycle = cl.time - (int)(cl.time/cl_bobcycle.value)*cl_bobcycle.value;
-       cycle /= cl_bobcycle.value;
+       // LordHavoc: FIXME: this code is *weird*, redesign it sometime
+       cycle = cl.time  / cl_bobcycle.value;
+       cycle -= (int) cycle;
        if (cycle < cl_bobup.value)
                cycle = M_PI * cycle / cl_bobup.value;
        else
                cycle = M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value);
 
-// bob is proportional to velocity in the xy plane
-// (don't count Z, or jumping messes it up)
+       // bob is proportional to velocity in the xy plane
+       // (don't count Z, or jumping messes it up)
 
        bob = sqrt(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]) * cl_bob.value;
-//Con_Printf ("speed: %5.1f\n", Length(cl.velocity));
        bob = bob*0.3 + bob*0.7*sin(cycle);
-       if (bob > 4)
-               bob = 4;
-       else if (bob < -7)
-               bob = -7;
+       bob = bound(-7, bob, 4);
        return bob;
-       
-}
-
-
-//=============================================================================
-
-
-cvar_t v_centermove = {"v_centermove", "0.15", false};
-cvar_t v_centerspeed = {"v_centerspeed","500"};
 
+}
 
 void V_StartPitchDrift (void)
 {
-#if 1
        if (cl.laststop == cl.time)
-       {
                return;         // something else is keeping it from drifting
-       }
-#endif
+
        if (cl.nodrift || !cl.pitchvel)
        {
                cl.pitchvel = v_centerspeed.value;
@@ -168,10 +146,10 @@ If the user is adjusting pitch manually, either with lookup/lookdown,
 mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.
 
 Drifting is enabled when the center view key is hit, mlook is released and
-lookspring is non 0, or when 
+lookspring is non 0, or when
 ===============
 */
-void V_DriftPitch (void)
+static void V_DriftPitch (void)
 {
        float           delta, move;
 
@@ -189,14 +167,14 @@ void V_DriftPitch (void)
                        cl.driftmove = 0;
                else
                        cl.driftmove += cl.frametime;
-       
+
                if ( cl.driftmove > v_centermove.value)
                {
                        V_StartPitchDrift ();
                }
                return;
        }
-       
+
        delta = cl.idealpitch - cl.viewangles[PITCH];
 
        if (!delta)
@@ -207,8 +185,6 @@ void V_DriftPitch (void)
 
        move = cl.frametime * cl.pitchvel;
        cl.pitchvel += cl.frametime * v_centerspeed.value;
-       
-//Con_Printf ("move: %f (%f)\n", move, cl.frametime);
 
        if (delta > 0)
        {
@@ -231,25 +207,14 @@ void V_DriftPitch (void)
 }
 
 
+/*
+==============================================================================
 
+                                               SCREEN FLASHES
 
+==============================================================================
+*/
 
-/*
-============================================================================== 
-                                               SCREEN FLASHES 
-============================================================================== 
-*/ 
-cshift_t       cshift_empty = { {130,80,50}, 0 };
-cshift_t       cshift_water = { {130,80,50}, 128 };
-cshift_t       cshift_slime = { {0,25,5}, 150 };
-cshift_t       cshift_lava = { {255,80,0}, 150 };
-
-byte           ramps[3][256];
-float          v_blend[4];             // rgba 0.0 - 1.0
 
 /*
 ===============
@@ -258,14 +223,14 @@ V_ParseDamage
 */
 void V_ParseDamage (void)
 {
-       int             armor, blood;
-       vec3_t  from;
-       int             i;
-       vec3_t  forward, right;
-       entity_t        *ent;
-       float   side;
-       float   count;
-       
+       int i, armor, blood;
+       vec3_t from;
+       //vec3_t forward, right;
+       vec3_t localfrom;
+       entity_t *ent;
+       //float side;
+       float count;
+
        armor = MSG_ReadByte ();
        blood = MSG_ReadByte ();
        for (i=0 ; i<3 ; i++)
@@ -277,65 +242,68 @@ void V_ParseDamage (void)
 
        cl.faceanimtime = cl.time + 0.2;                // put sbar face into pain frame
 
-       if (gl_polyblend.value)
-       {
-               cl.cshifts[CSHIFT_DAMAGE].percent += 3*count;
-               if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
-                       cl.cshifts[CSHIFT_DAMAGE].percent = 0;
-               if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)
-                       cl.cshifts[CSHIFT_DAMAGE].percent = 150;
+       cl.cshifts[CSHIFT_DAMAGE].percent += 3*count;
+       if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
+               cl.cshifts[CSHIFT_DAMAGE].percent = 0;
+       if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)
+               cl.cshifts[CSHIFT_DAMAGE].percent = 150;
 
-               if (armor > blood)              
-               {
-                       cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;
-                       cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;
-                       cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;
-               }
-               else if (armor)
-               {
-                       cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;
-                       cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;
-                       cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;
-               }
-               else
-               {
-                       cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;
-                       cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;
-                       cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;
-               }
+       if (armor > blood)
+       {
+               cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;
+               cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;
+               cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;
+       }
+       else if (armor)
+       {
+               cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;
+               cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;
+               cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;
+       }
+       else
+       {
+               cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;
+               cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;
+               cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;
        }
 
 //
 // calculate view angle kicks
 //
        ent = &cl_entities[cl.viewentity];
-       
-       VectorSubtract (from, ent->render.origin, from);
-       VectorNormalize (from);
-       
-       AngleVectors (ent->render.angles, forward, right, NULL);
-
-       side = DotProduct (from, right);
-       v_dmg_roll = count*side*v_kickroll.value;
-       
-       side = DotProduct (from, forward);
-       v_dmg_pitch = count*side*v_kickpitch.value;
-
+       Matrix4x4_Transform(&ent->render.inversematrix, from, localfrom);
+       VectorNormalize(localfrom);
+       v_dmg_pitch = count * localfrom[0] * v_kickpitch.value;
+       v_dmg_roll = count * localfrom[1] * v_kickroll.value;
        v_dmg_time = v_kicktime.value;
+
+       //VectorSubtract (from, ent->render.origin, from);
+       //VectorNormalize (from);
+
+       //AngleVectors (ent->render.angles, forward, right, NULL);
+
+       //side = DotProduct (from, right);
+       //v_dmg_roll = count*side*v_kickroll.value;
+
+       //side = DotProduct (from, forward);
+       //v_dmg_pitch = count*side*v_kickpitch.value;
+
+       //v_dmg_time = v_kicktime.value;
 }
 
+static cshift_t v_cshift;
 
 /*
 ==================
 V_cshift_f
 ==================
 */
-void V_cshift_f (void)
+static void V_cshift_f (void)
 {
-       cshift_empty.destcolor[0] = atoi(Cmd_Argv(1));
-       cshift_empty.destcolor[1] = atoi(Cmd_Argv(2));
-       cshift_empty.destcolor[2] = atoi(Cmd_Argv(3));
-       cshift_empty.percent = atoi(Cmd_Argv(4));
+       v_cshift.destcolor[0] = atoi(Cmd_Argv(1));
+       v_cshift.destcolor[1] = atoi(Cmd_Argv(2));
+       v_cshift.destcolor[2] = atoi(Cmd_Argv(3));
+       v_cshift.percent = atoi(Cmd_Argv(4));
 }
 
 
@@ -346,78 +314,76 @@ V_BonusFlash_f
 When you run over an item, the server sends this command
 ==================
 */
-void V_BonusFlash_f (void)
+static void V_BonusFlash_f (void)
 {
-       if (gl_polyblend.value)
-       {
-               cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
-               cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
-               cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;
-               cl.cshifts[CSHIFT_BONUS].percent = 50;
-       }
+       cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
+       cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
+       cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;
+       cl.cshifts[CSHIFT_BONUS].percent = 50;
 }
 
 /*
 =============
-V_SetContentsColor
-
-Underwater, lava, etc each has a color shift
+V_UpdateBlends
 =============
 */
-void V_SetContentsColor (int contents)
+void V_UpdateBlends (void)
 {
-       cshift_t* c;
-       c = &cl.cshifts[CSHIFT_CONTENTS]; // just to shorten the code below
-       if (!gl_polyblend.value)
+       float   r, g, b, a, a2;
+       int             j;
+
+       if (cls.signon != SIGNONS)
        {
-               c->percent = 0;
+               cl.cshifts[CSHIFT_DAMAGE].percent = 0;
+               cl.cshifts[CSHIFT_BONUS].percent = 0;
+               cl.cshifts[CSHIFT_CONTENTS].percent = 0;
+               cl.cshifts[CSHIFT_POWERUP].percent = 0;
+               r_refdef.viewblend[0] = 0;
+               r_refdef.viewblend[1] = 0;
+               r_refdef.viewblend[2] = 0;
+               r_refdef.viewblend[3] = 0;
                return;
        }
-       switch (contents)
+
+       // drop the damage value
+       cl.cshifts[CSHIFT_DAMAGE].percent -= (cl.time - cl.oldtime)*150;
+       if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
+               cl.cshifts[CSHIFT_DAMAGE].percent = 0;
+
+       // drop the bonus value
+       cl.cshifts[CSHIFT_BONUS].percent -= (cl.time - cl.oldtime)*100;
+       if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
+               cl.cshifts[CSHIFT_BONUS].percent = 0;
+
+       // set contents color
+       switch (Mod_PointContents (r_refdef.vieworg, cl.worldmodel))
        {
        case CONTENTS_EMPTY:
        case CONTENTS_SOLID:
-               //cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
-               c->destcolor[0] = cshift_empty.destcolor[0];
-               c->destcolor[1] = cshift_empty.destcolor[1];
-               c->destcolor[2] = cshift_empty.destcolor[2];
-               c->percent = cshift_empty.percent;
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = v_cshift.destcolor[0];
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = v_cshift.destcolor[1];
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = v_cshift.destcolor[2];
+               cl.cshifts[CSHIFT_CONTENTS].percent = v_cshift.percent;
                break;
        case CONTENTS_LAVA:
-               //cl.cshifts[CSHIFT_CONTENTS] = cshift_lava;
-               c->destcolor[0] = cshift_lava.destcolor[0];
-               c->destcolor[1] = cshift_lava.destcolor[1];
-               c->destcolor[2] = cshift_lava.destcolor[2];
-               c->percent = cshift_lava.percent;
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 255;
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80;
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0;
+               cl.cshifts[CSHIFT_CONTENTS].percent = 150 >> 1;
                break;
        case CONTENTS_SLIME:
-               //cl.cshifts[CSHIFT_CONTENTS] = cshift_slime;
-               c->destcolor[0] = cshift_slime.destcolor[0];
-               c->destcolor[1] = cshift_slime.destcolor[1];
-               c->destcolor[2] = cshift_slime.destcolor[2];
-               c->percent = cshift_slime.percent;
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0;
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 25;
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 5;
+               cl.cshifts[CSHIFT_CONTENTS].percent = 150 >> 1;
                break;
        default:
-               //cl.cshifts[CSHIFT_CONTENTS] = cshift_water;
-               c->destcolor[0] = cshift_water.destcolor[0];
-               c->destcolor[1] = cshift_water.destcolor[1];
-               c->destcolor[2] = cshift_water.destcolor[2];
-               c->percent = cshift_water.percent;
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 130;
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80;
+               cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 50;
+               cl.cshifts[CSHIFT_CONTENTS].percent = 128 >> 1;
        }
-}
 
-/*
-=============
-V_CalcPowerupCshift
-=============
-*/
-void V_CalcPowerupCshift (void)
-{
-       if (!gl_polyblend.value)
-       {
-               cl.cshifts[CSHIFT_POWERUP].percent = 0;
-               return;
-       }
        if (cl.items & IT_QUAD)
        {
                cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
@@ -448,206 +414,48 @@ void V_CalcPowerupCshift (void)
        }
        else
                cl.cshifts[CSHIFT_POWERUP].percent = 0;
-}
-
-/*
-=============
-V_CalcBlend
-=============
-*/
-// LordHavoc: fixed V_CalcBlend
-void V_CalcBlend (void)
-{
-       float   r, g, b, a, a2;
-       int             j;
 
+       // LordHavoc: fixed V_CalcBlend
        r = 0;
        g = 0;
        b = 0;
        a = 0;
 
-//     if (gl_cshiftpercent.value)
-//     {
-               for (j=0 ; j<NUM_CSHIFTS ; j++) 
-               {
-//                     a2 = ((cl.cshifts[j].percent * gl_cshiftpercent.value) / 100.0) / 255.0;
-                       a2 = cl.cshifts[j].percent * (1.0f / 255.0f);
-
-                       if (!a2)
-                               continue;
-                       if (a2 > 1)
-                               a2 = 1;
-                       r += (cl.cshifts[j].destcolor[0]-r) * a2;
-                       g += (cl.cshifts[j].destcolor[1]-g) * a2;
-                       b += (cl.cshifts[j].destcolor[2]-b) * a2;
-                       a = 1 - (1 - a) * (1 - a2); // correct alpha multiply...  took a while to find it on the web
-               }
-               // saturate color (to avoid blending in black)
-               if (a)
-               {
-                       a2 = 1 / a;
-                       r *= a2;
-                       g *= a2;
-                       b *= a2;
-               }
-//     }
-
-       v_blend[0] = bound(0, r * (1.0/255.0), 1);
-       v_blend[1] = bound(0, g * (1.0/255.0), 1);
-       v_blend[2] = bound(0, b * (1.0/255.0), 1);
-       v_blend[3] = bound(0, a              , 1);
-}
-
-/*
-=============
-V_UpdateBlends
-=============
-*/
-void V_UpdateBlends (void)
-{
-       int             i, j;
-       qboolean        new;
-
-       V_CalcPowerupCshift ();
-       
-       new = false;
-       
-       for (i=0 ; i<NUM_CSHIFTS ; i++)
+       for (j=0 ; j<NUM_CSHIFTS ; j++)
        {
-               if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
-               {
-                       new = true;
-                       cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
-               }
-               for (j=0 ; j<3 ; j++)
-                       if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
-                       {
-                               new = true;
-                               cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
-                       }
+               a2 = cl.cshifts[j].percent * (1.0f / 255.0f);
+
+               if (a2 < 0)
+                       continue;
+               if (a2 > 1)
+                       a2 = 1;
+               r += (cl.cshifts[j].destcolor[0]-r) * a2;
+               g += (cl.cshifts[j].destcolor[1]-g) * a2;
+               b += (cl.cshifts[j].destcolor[2]-b) * a2;
+               a = 1 - (1 - a) * (1 - a2); // correct alpha multiply...  took a while to find it on the web
        }
-       
-// drop the damage value
-       cl.cshifts[CSHIFT_DAMAGE].percent -= (cl.time - cl.oldtime)*150;
-       if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
-               cl.cshifts[CSHIFT_DAMAGE].percent = 0;
-
-// drop the bonus value
-       cl.cshifts[CSHIFT_BONUS].percent -= (cl.time - cl.oldtime)*100;
-       if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
-               cl.cshifts[CSHIFT_BONUS].percent = 0;
-
-       if (!new)
-               return;
-
-       V_CalcBlend ();
-}
-
-/* 
-============================================================================== 
-                                               VIEW RENDERING 
-============================================================================== 
-*/ 
-
-float angledelta (float a)
-{
-       a = ANGLEMOD(a);
-       if (a > 180)
-               a -= 360;
-       return a;
-}
-
-/*
-==================
-CalcGunAngle
-==================
-*/
-void CalcGunAngle (void)
-{      
-       /*
-       float   yaw, pitch, move;
-       static float oldyaw = 0;
-       static float oldpitch = 0;
-       
-       yaw = r_refdef.viewangles[YAW];
-       pitch = -r_refdef.viewangles[PITCH];
-
-       yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4;
-       if (yaw > 10)
-               yaw = 10;
-       if (yaw < -10)
-               yaw = -10;
-       pitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4;
-       if (pitch > 10)
-               pitch = 10;
-       if (pitch < -10)
-               pitch = -10;
-       move = cl.frametime*20;
-       if (yaw > oldyaw)
+       // saturate color (to avoid blending in black)
+       if (a)
        {
-               if (oldyaw + move < yaw)
-                       yaw = oldyaw + move;
+               a2 = 1 / a;
+               r *= a2;
+               g *= a2;
+               b *= a2;
        }
-       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;
-
-       cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw;
-       cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch);
-       */
-       cl.viewent.render.angles[YAW] = r_refdef.viewangles[YAW];
-       cl.viewent.render.angles[PITCH] = -r_refdef.viewangles[PITCH];
-
-       cl.viewent.render.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
-       cl.viewent.render.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
-       cl.viewent.render.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
+
+       r_refdef.viewblend[0] = bound(0, r * (1.0/255.0), 1);
+       r_refdef.viewblend[1] = bound(0, g * (1.0/255.0), 1);
+       r_refdef.viewblend[2] = bound(0, b * (1.0/255.0), 1);
+       r_refdef.viewblend[3] = bound(0, a              , 1);
 }
 
 /*
-==============
-V_BoundOffsets
-==============
-*/
-void V_BoundOffsets (void)
-{
-       entity_t        *ent;
-       
-       ent = &cl_entities[cl.viewentity];
+==============================================================================
 
-// absolutely bound refresh relative to entity clipping hull
-// so the view can never be inside a solid wall
-
-       if (r_refdef.vieworg[0] < ent->render.origin[0] - 14)
-               r_refdef.vieworg[0] = ent->render.origin[0] - 14;
-       else if (r_refdef.vieworg[0] > ent->render.origin[0] + 14)
-               r_refdef.vieworg[0] = ent->render.origin[0] + 14;
-       if (r_refdef.vieworg[1] < ent->render.origin[1] - 14)
-               r_refdef.vieworg[1] = ent->render.origin[1] - 14;
-       else if (r_refdef.vieworg[1] > ent->render.origin[1] + 14)
-               r_refdef.vieworg[1] = ent->render.origin[1] + 14;
-       if (r_refdef.vieworg[2] < ent->render.origin[2] - 22)
-               r_refdef.vieworg[2] = ent->render.origin[2] - 22;
-       else if (r_refdef.vieworg[2] > ent->render.origin[2] + 30)
-               r_refdef.vieworg[2] = ent->render.origin[2] + 30;
-}
+                                               VIEW RENDERING
+
+==============================================================================
+*/
 
 /*
 ==============
@@ -656,69 +464,50 @@ V_AddIdle
 Idle swaying
 ==============
 */
-void V_AddIdle (void)
+static void V_AddIdle (float idle)
 {
-       r_refdef.viewangles[ROLL] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
-       r_refdef.viewangles[PITCH] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
-       r_refdef.viewangles[YAW] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
+       r_refdef.viewangles[ROLL] += idle * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
+       r_refdef.viewangles[PITCH] += idle * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
+       r_refdef.viewangles[YAW] += idle * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
 }
 
-
-/*
-==============
-V_CalcViewRoll
-
-Roll is induced by movement and damage
-==============
-*/
-void V_CalcViewRoll (void)
+#define MAXVIEWMODELS 32
+extern int numviewmodels;
+extern entity_t *viewmodels[MAXVIEWMODELS];
+void V_LinkViewEntities(void)
 {
-       float           side;
-               
-       side = V_CalcRoll (cl_entities[cl.viewentity].render.angles, cl.velocity);
-       r_refdef.viewangles[ROLL] += side;
+       int i;
+       //float v[3];
+       entity_t *ent;
+       matrix4x4_t matrix, matrix2;
 
-       if (v_dmg_time > 0)
-       {
-               r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
-               r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
-               v_dmg_time -= cl.frametime;
-       }
+       if (numviewmodels <= 0)
+               return;
 
-       if (cl.stats[STAT_HEALTH] <= 0)
+       //Matrix4x4_CreateRotate(&matrix, 1, 0, 0, r_refdef.viewangles[0]);
+       //Matrix4x4_CreateRotate(&matrix, 0, 1, 0, r_refdef.viewangles[0]);
+       //Matrix4x4_CreateRotate(&matrix, 0, 0, 1, r_refdef.viewangles[0]);
+       Matrix4x4_CreateFromQuakeEntity(&matrix, r_refdef.vieworg[0], r_refdef.vieworg[1], r_refdef.vieworg[2], r_refdef.viewangles[0], r_refdef.viewangles[1], r_refdef.viewangles[2], 0.3);
+       for (i = 0;i < numviewmodels && r_refdef.numentities < r_refdef.maxentities;i++)
        {
-               r_refdef.viewangles[ROLL] = 80; // dead view angle
-               return;
+               ent = viewmodels[i];
+               r_refdef.entities[r_refdef.numentities++] = &ent->render;
+
+               //VectorCopy(ent->render.origin, v);
+               //ent->render.origin[0] = v[0] * vpn[0] + v[1] * vright[0] + v[2] * vup[0] + r_refdef.vieworg[0];
+               //ent->render.origin[1] = v[0] * vpn[1] + v[1] * vright[1] + v[2] * vup[1] + r_refdef.vieworg[1];
+               //ent->render.origin[2] = v[0] * vpn[2] + v[1] * vright[2] + v[2] * vup[2] + r_refdef.vieworg[2];
+               //ent->render.angles[0] = ent->render.angles[0] + r_refdef.viewangles[0];
+               //ent->render.angles[1] = ent->render.angles[1] + r_refdef.viewangles[1];
+               //ent->render.angles[2] = ent->render.angles[2] + r_refdef.viewangles[2];
+               //ent->render.scale *= 0.3;
+
+               //Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, ent->render.origin[0], ent->render.origin[1], ent->render.origin[2], ent->render.angles[0], ent->render.angles[1], ent->render.angles[2], ent->render.scale);
+               matrix2 = ent->render.matrix;
+               Matrix4x4_Concat(&ent->render.matrix, &matrix, &matrix2);
+               Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
+               CL_BoundingBoxForEntity(&ent->render);
        }
-
-}
-
-
-/*
-==================
-V_CalcIntermissionRefdef
-
-==================
-*/
-void V_CalcIntermissionRefdef (void)
-{
-       entity_t        *ent, *view;
-       float           old;
-
-// ent is the player model (visible when out of body)
-       ent = &cl_entities[cl.viewentity];
-// view is the weapon model (only visible from inside body)
-       view = &cl.viewent;
-
-       VectorCopy (ent->render.origin, r_refdef.vieworg);
-       VectorCopy (ent->render.angles, r_refdef.viewangles);
-       view->render.model = NULL;
-
-// always idle in intermission
-       old = v_idlescale.value;
-       v_idlescale.value = 1;
-       V_AddIdle ();
-       v_idlescale.value = old;
 }
 
 /*
@@ -729,133 +518,87 @@ V_CalcRefdef
 */
 void V_CalcRefdef (void)
 {
-       entity_t        *ent, *view;
-       int                     i;
-       vec3_t          forward;
-       vec3_t          angles;
-       float           bob;
-//     static float oldz = 0;
+       entity_t *ent, *view;
 
-       V_DriftPitch ();
+       if (cls.state != ca_connected || cls.signon != SIGNONS)
+               return;
 
-// ent is the player model (visible when out of body)
+       // ent is the player model (visible when out of body)
        ent = &cl_entities[cl.viewentity];
-// view is the weapon model (only visible from inside body)
+       // view is the weapon model (only visible from inside body)
        view = &cl.viewent;
-       
 
-// transform the view offset by the model's matrix to get the offset from model origin for the view
-       if (!chase_active.value) // LordHavoc: get rid of angle problems in chase_active mode
-       {
-               ent->render.angles[YAW] = cl.viewangles[YAW];   // the model should face the view dir
-               ent->render.angles[PITCH] = -cl.viewangles[PITCH];      // the model should face the view dir
-       }
-                                                                               
-       
-       bob = V_CalcBob ();
-       
-// refresh position
-       VectorCopy (ent->render.origin, r_refdef.vieworg);
-       r_refdef.vieworg[2] += cl.viewheight + bob;
-
-       // LordHavoc: the protocol has changed...  so this is an obsolete approach
-// 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
-//     r_refdef.vieworg[0] += 1.0/32;
-//     r_refdef.vieworg[1] += 1.0/32;
-//     r_refdef.vieworg[2] += 1.0/32;
+       V_DriftPitch ();
 
+       VectorCopy (cl.viewentorigin, r_refdef.vieworg);
        if (!intimerefresh)
                VectorCopy (cl.viewangles, r_refdef.viewangles);
-       V_CalcViewRoll ();
-       V_AddIdle ();
-
-// offsets
-       angles[PITCH] = -ent->render.angles[PITCH];     // because entity pitches are actually backward
-       angles[YAW] = ent->render.angles[YAW];
-       angles[ROLL] = ent->render.angles[ROLL];
-
-       AngleVectors (angles, forward, NULL, NULL);
-
-       V_BoundOffsets ();
-               
-// set up gun position
-       VectorCopy (cl.viewangles, view->render.angles);
-       
-       CalcGunAngle ();
-
-       VectorCopy (ent->render.origin, view->render.origin);
-       view->render.origin[2] += cl.viewheight;
 
-       for (i=0 ; i<3 ; i++)
+       if (cl.intermission)
        {
-               view->render.origin[i] += forward[i]*bob*0.4;
-//             view->render.origin[i] += right[i]*bob*0.4;
-//             view->render.origin[i] += up[i]*bob*0.8;
+               view->render.model = NULL;
+               VectorCopy (ent->render.angles, r_refdef.viewangles);
+               V_AddIdle (1);
        }
-       view->render.origin[2] += bob;
-
-       view->render.model = cl.model_precache[cl.stats[STAT_WEAPON]];
-       view->render.frame = cl.stats[STAT_WEAPONFRAME];
-       view->render.colormap = -1; // no special coloring
-
-// set up the refresh position
-
-       // LordHavoc: this never looked all that good to begin with...
-       /*
-// smooth out stair step ups
-if (cl.onground && ent->render.origin[2] - oldz > 0)
-{
-       float steptime;
-       
-       steptime = cl.time - cl.oldtime;
-       if (steptime < 0)
-//FIXME                I_Error ("steptime < 0");
-               steptime = 0;
-
-       oldz += steptime * 80;
-       if (oldz > ent->render.origin[2])
-               oldz = ent->render.origin[2];
-       if (ent->render.origin[2] - oldz > 12)
-               oldz = ent->render.origin[2] - 12;
-       r_refdef.vieworg[2] += oldz - ent->render.origin[2];
-       view->render.origin[2] += oldz - ent->render.origin[2];
-}
-else
-       oldz = ent->render.origin[2];
-       */
-
-// LordHavoc: origin view kick added
-       if (!intimerefresh && v_punch.value)
+       else if (chase_active.value)
        {
-               VectorAdd(r_refdef.viewangles, cl.punchangle, r_refdef.viewangles);
-               VectorAdd(r_refdef.vieworg, cl.punchvector, r_refdef.vieworg);
+               view->render.model = NULL;
+               r_refdef.vieworg[2] += cl.viewheight;
+               Chase_Update ();
+               V_AddIdle (v_idlescale.value);
        }
+       else
+       {
+               r_refdef.viewangles[ROLL] += V_CalcRoll (cl.viewangles, cl.velocity);
 
-       if (chase_active.value)
-               Chase_Update ();
-}
+               if (v_dmg_time > 0)
+               {
+                       r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
+                       r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
+                       v_dmg_time -= cl.frametime;
+               }
 
-/*
-==================
-V_RenderView
+               if (cl.stats[STAT_HEALTH] <= 0)
+                       r_refdef.viewangles[ROLL] = 80; // dead view angle
 
-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
-==================
-*/
-void V_RenderView (void)
-{
-       if (con_forcedup)
-               return;
+               V_AddIdle (v_idlescale.value);
 
-       if (cl.intermission)
-               V_CalcIntermissionRefdef ();    
-       else
-               V_CalcRefdef ();
+               r_refdef.vieworg[2] += cl.viewheight + V_CalcBob ();
+
+               // LordHavoc: origin view kick added
+               if (!intimerefresh)
+               {
+                       VectorAdd(r_refdef.viewangles, cl.punchangle, r_refdef.viewangles);
+                       VectorAdd(r_refdef.vieworg, cl.punchvector, r_refdef.vieworg);
+               }
 
-       R_RenderView ();
+               // set up gun
+               // (FIXME! this should be in cl_main.c with the other linking code, not view.c!)
+               view->state_current.modelindex = cl.stats[STAT_WEAPON];
+               view->state_current.frame = cl.stats[STAT_WEAPONFRAME];
+               //VectorCopy(r_refdef.vieworg, view->render.origin);
+               //view->render.angles[PITCH] = r_refdef.viewangles[PITCH] + v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
+               //view->render.angles[YAW] = r_refdef.viewangles[YAW] - v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
+               //view->render.angles[ROLL] = r_refdef.viewangles[ROLL] - v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
+               //view->render.scale = 1.0 / 3.0;
+               Matrix4x4_CreateFromQuakeEntity(&view->render.matrix, r_refdef.vieworg[0], r_refdef.vieworg[1], r_refdef.vieworg[2], r_refdef.viewangles[PITCH] + v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value, r_refdef.viewangles[YAW] - v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value, r_refdef.viewangles[ROLL] - v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value, 0.3);
+               Matrix4x4_Invert_Simple(&view->render.inversematrix, &view->render.matrix);
+               CL_BoundingBoxForEntity(&view->render);
+               // FIXME: this setup code is somewhat evil (CL_LerpUpdate should be private?)
+               CL_LerpUpdate(view);
+               view->render.colormap = -1; // no special coloring
+               view->render.alpha = ent->render.alpha; // LordHavoc: if the player is transparent, so is the gun
+               view->render.effects = ent->render.effects;
+               AngleVectors(r_refdef.viewangles, vpn, vright, vup);
+
+               // link into render entities list
+               if (r_drawviewmodel.integer && !chase_active.integer && !envmap && r_drawentities.integer && !(cl.items & IT_INVISIBILITY) && cl.stats[STAT_HEALTH] > 0)
+               {
+                       if (r_refdef.numentities < r_refdef.maxentities && view->render.model != NULL)
+                               r_refdef.entities[r_refdef.numentities++] = &view->render;
+                       V_LinkViewEntities();
+               }
+       }
 }
 
 //============================================================================
@@ -867,7 +610,7 @@ V_Init
 */
 void V_Init (void)
 {
-       Cmd_AddCommand ("v_cshift", V_cshift_f);        
+       Cmd_AddCommand ("v_cshift", V_cshift_f);
        Cmd_AddCommand ("bf", V_BonusFlash_f);
        Cmd_AddCommand ("centerview", V_StartPitchDrift);
 
@@ -883,10 +626,6 @@ void V_Init (void)
 
        Cvar_RegisterVariable (&v_idlescale);
        Cvar_RegisterVariable (&crosshair);
-       Cvar_RegisterVariable (&cl_crossx);
-       Cvar_RegisterVariable (&cl_crossy);
-//     Cvar_RegisterVariable (&gl_cshiftpercent);
-       Cvar_RegisterVariable (&gl_polyblend);
 
        Cvar_RegisterVariable (&cl_rollspeed);
        Cvar_RegisterVariable (&cl_rollangle);
@@ -896,9 +635,6 @@ void V_Init (void)
 
        Cvar_RegisterVariable (&v_kicktime);
        Cvar_RegisterVariable (&v_kickroll);
-       Cvar_RegisterVariable (&v_kickpitch);   
-
-       Cvar_RegisterVariable (&v_punch);
+       Cvar_RegisterVariable (&v_kickpitch);
 }
 
-