Q2 Client Side Effect - a 3rd Person Camera

 

Copyright info

All code in this tutorial is protected by the [GPL License].
All text in this tutorial is protected by the [FDL License].

 

Tutorial by: psychospaz

Mailto: psychospaz@telefragged.com

STEP 1:

[cl_main.c,client.h :: set up the variables]

-open "cl_main.c" add this at top with other cvar declarations...

 
 
                   cvar_t    *cl_3dcam;
                   cvar_t    *cl_3dcam_angle;
                   cvar_t    *cl_3dcam_dist;
 
     

-then find the function CL_InitLocal() and add this inside...

 
 
                   cl_3dcam = Cvar_Get ("cl_3dcam", "0", CVAR_ARCHIVE);
                   cl_3dcam_angle = Cvar_Get ("cl_3dcam_angle", "30", CVAR_ARCHIVE);
                   cl_3dcam_dist = Cvar_Get ("cl_3dcam_dist", "50", CVAR_ARCHIVE);
 
     

-now go into "client.h" and add this anywhere...

 
 
                   extern    cvar_t    *cl_3dcam;
                   extern    cvar_t    *cl_3dcam_angle;
                   extern    cvar_t    *cl_3dcam_dist;
 
     

STEP 2:

[cl_ents.c :: set up the view angles ]

-find the "CL_CalcViewValues" function and add this to the bottom of it...

 
 
          if (cl_3dcam->value)
          {
                   vec3_t end, oldorg, camPos;
                   float dist_up, dist_back, angle;
 
                   if (cl_3dcam_angle->value<0)
                             Cvar_SetValue( "cl_3dcam_angle", 0 );
                   if (cl_3dcam_angle->value>60)
                             Cvar_SetValue( "cl_3dcam_angle", 60 );
 
                   if (cl_3dcam_dist->value<0)
                             Cvar_SetValue( "cl_3dcam_dist", 0 );
 
                   //this'll use polar coords for cam offset
                   angle = M_PI * cl_3dcam_angle->value/180.0f;
                   dist_up = cl_3dcam_dist->value * sin( angle );
                   dist_back =  cl_3dcam_dist->value * cos ( angle );
 
                   VectorCopy(cl.refdef.vieworg, oldorg);
 
                   VectorMA(cl.refdef.vieworg, -dist_back, cl.v_forward, end);
                   VectorMA(end, dist_up, cl.v_up, end);
 
                   ClipCam (cl.refdef.vieworg, end, camPos);
 
                   //now we will adjust aim...
                   {
                             vec3_t newDir, dir;
 
                             //find where 1st person view is aiming
                             VectorMA(cl.refdef.vieworg, 8000, cl.v_forward, dir);
                             ClipCam (cl.refdef.vieworg, dir, newDir);
 
                             VectorSubtract(newDir, camPos, dir);
                             VectorNormalize(dir);
                             vectoangles2(dir, newDir);
 
                             //now look there from the camera
                             AngleVectors(newDir, cl.v_forward, cl.v_right, cl.v_up);
                             VectorCopy(newDir, cl.refdef.viewangles);
                   }
 
                   VectorCopy(camPos, cl.refdef.vieworg);
          }
 
     

STEP 3:

[cl_ents.c :: add client side clipping]

-put this at the top of the file after includes and var/function decalarations...

 
 
          trace_t CL_Trace (vec3_t start, vec3_t end, float size,  int contentmask)
          {
                   vec3_t maxs, mins;
 
                   VectorSet(maxs, size, size, size);
                   VectorSet(mins, -size, -size, -size);
 
                   return CM_BoxTrace (start, end, mins, maxs, 0, contentmask);
          }
          void ClipCam (vec3_t start, vec3_t end, vec3_t newpos)
          {
                   trace_t tr = CL_Trace (start, end, 5, -1);
                   VectorCopy(tr.endpos, newpos);
          }
 
     

STEP 4:

[cl_ents.c :: remove the 1st person model]

-put this at the top of the "void CL_AddViewWeapon(*,*)" function after variable declarations...

 
          
          //dont draw if outside body...
          if (cl_3dcam->value)
                   return;
 
     

STEP 5:

[cl_ents.c :: add the client model to the render list]

-find the funtion void "CL_AddPacketEntities(*)"

-find this line...

 
 
          for (pnum = 0 ; pnumnum_entities ; pnum++)
          {
 
     

-and add this right after it...

 
 
                   qboolean isclientviewer = false;
 
     

-now replace this...

 
 
          if (s1->number == cl.playernum+1)
          {
                   ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
 
                   // FIXME: still pass to refresh
                   if (effects & EF_FLAG1)
                             V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1);
                   else if (effects & EF_FLAG2)
                             V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0);
                   else if (effects & EF_TAGTRAIL)                                                    //PGM
                             V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);          //PGM
                   else if (effects & EF_TRACKERTRAIL)                                      //PGM
                             V_AddLight (ent.origin, 225, -1.0, -1.0, -1.0);     //PGM
 
                   continue;
          }
 
     

-with this...

 
 
          if (s1->number == cl.playernum+1)
          {
                   ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
                   isclientviewer = true;
 
                   // FIXME: still pass to refresh
                   if (effects & EF_FLAG1)
                             V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1);
                   else if (effects & EF_FLAG2)
                             V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0);
                   else if (effects & EF_TAGTRAIL)                                                    //PGM
                             V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);          //PGM
                   else if (effects & EF_TRACKERTRAIL)                                      //PGM
                             V_AddLight (ent.origin, 225, -1.0, -1.0, -1.0);     //PGM
 
                   if (!cl_3dcam->value)
                             continue;
          }
 
     

-now after this line...

 
 
          if (s1->modelindex2)
          {
 
     

-add this...

 
 
          if (isclientviewer)
                   ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
 
     

-also after this...

 
 
          if (s1->modelindex3)
          {
 
     

-add this..

 
 
          if (isclientviewer)
                   ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
 
     

-and lastly after this...

 
 
          if (s1->modelindex4)
          {
 
     

add this again...

 
 
          if (isclientviewer)
                   ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
 
     

STEP 6:

[cl_view.c :: make the 3rd person model visible]

-find the funtion void "V_AddEntity(*)"

-add this in at the top of the function...

 
 
          if (ent->flags&RF_VIEWERMODEL) //here is our client
          {         
                   int i; 
                   for (i=0;i<3;i++)
                             ent->oldorigin[i] = ent->origin[i] = cl.predicted_origin[i];
 
                   if (cl_3dcam->value)
                             ent->flags&=~RF_VIEWERMODEL;
          }
 
     

STEP 7:

[cl_ents.c :: smooth out prediction]

-find the funtion void "CL_CalcViewValues()"

-replace this...

 
 
          // calculate the origin
          if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
          {         // use predicted values
                   unsigned  delta;
 
                   backlerp = 1.0 - lerp;
                   for (i=0 ; i<3 ; i++)
                   {
                             cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i] 
                                      + cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i])
                                      - backlerp * cl.prediction_error[i];
                   }
 
                   // smooth out stair climbing
                   delta = cls.realtime - cl.predicted_step_time;
                   if (delta < 100)
                   {
                             cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
                   }
          }
 
     

-with this (adding in cl.predicted_origin[] smoothing)...

 
 
          // calculate the origin
          if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
          {         // use predicted values
                   unsigned  delta;
 
                   backlerp = 1.0 - lerp;
                   for (i=0 ; i<3 ; i++)
                   {
                             cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i] 
                                      + cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i])
                                      - backlerp * cl.prediction_error[i];
 
                             //this smooths out platform riding
                             cl.predicted_origin[i] -= backlerp * cl.prediction_error[i];
                   }
 
                   // smooth out stair climbing
                   delta = cls.realtime - cl.predicted_step_time;
                   if (delta < 100)
                   {
                             cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
                             cl.predicted_origin[2] -= cl.predicted_step * (100 - delta) * 0.01;
                   }
          }
 
     

FINISH:

[test :: play the game]

- Play with the cvars to get the cam how you like it

- Tweak until content

 

 

Tutorial Originally found at: