Quake3World.com Forums
     Programming Discussion
        Third person crosshair feature


Post new topicReply to topic
Login | Profile | | FAQ | Search | IRC




Print view Previous topic | Next topic 
Topic Starter Topic: Third person crosshair feature

Commander
Commander
Joined: 08 Jun 2022
Posts: 100
PostPosted: 10-03-2022 01:11 PM           Profile Send private message  E-mail  Edit post Reply with quote


I'm trying to do exactly the same of this: https://streamable.com/u1wogh

The crosshair part only happens when the camera is in third person mode.
I tried to use CG_Trace inside CG_DrawCrosshair function in cg_draw.c.
I manipulated Y-axis for the crosshair, but no success:
Code:
trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w),
      y + trace.endpos[2] /*cg.refdef.y*/ + 0.5 * (cg.refdef.height - h),
      w, h, 0, 0, 1, 1, hShader );

I used ZEQ2-Lite source code looking for the feature, I'm not doing pretty well though.
Possibly, some game mod did the same, but idk and I don't have references of this stuff. BFP is the only game mod I see about.
A guy gave me a tip that the view came from the head and could be extracted from a refEntity_t variable.

I hope to obtain any help to reach this goal.




Last edited by LegendGuard on 10-02-2023 03:00 AM, edited 2 times in total.

Top
                 

Commander
Commander
Joined: 08 Jun 2022
Posts: 100
PostPosted: 10-08-2022 03:06 PM           Profile Send private message  E-mail  Edit post Reply with quote


Yeeeeaaaah! I did it! BFP third person traceable crosshair!

https://github.com/LegendaryGuard/BFP/c ... dfb979b285




Top
                 

Commander
Commander
Joined: 08 Jun 2022
Posts: 100
PostPosted: 09-12-2023 02:09 AM           Profile Send private message  E-mail  Edit post Reply with quote


I update the code here, I just made tweaks to make the crosshair move smoothly and now matches 100% to BFP ones.

These are the commits:
https://github.com/LegendaryGuard/BFP/c ... f4a2a245eb
https://github.com/LegendaryGuard/BFP/c ... 431de86652

Look further to the commits before implementing this feature.

cg_draw.c -CG_DrawCrosshair- full code:

Code:
static void CG_DrawCrosshair(void) {
   float      w, h;
   qhandle_t   hShader;
   float      f;
   float      x, y;
   int         ca;
   trace_t      trace;
   playerState_t   *ps;
   vec3_t      muzzle, forward, up, start, end;
   static float lastPositionY = 480.0f; // BFP - Last Y position for traceable crosshair to move smoothly like BFP vanilla does

   ps = &cg.predictedPlayerState;

   if ( !cg_drawCrosshair.integer ) {
      return;
   }

   if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {
      return;
   }

// BFP - do not brake here when using third person view
#if 0
   if ( cg.renderingThirdPerson ) {
      return;
   }
#endif

#if 0
   // set color based on health
   if ( cg_crosshairHealth.integer ) {
      vec4_t      hcolor;

      CG_ColorForHealth( hcolor );
      trap_R_SetColor( hcolor );
   }
#endif

   // Read: https://www.quake3world.com/forum/viewtopic.php?f=16&t=55019
   CG_SetCrosshairColor(); // BFP - Crosshair color

   w = h = cg_crosshairSize.value;

   // BFP - pulse the size of the crosshair when hitting someone (before: when picking up items)
   f = cg.time - cg.opponentHitBlendTime;
   if ( f > 0 && f < HIT_BLOB_TIME ) {
      f /= HIT_BLOB_TIME;
      // BFP - Make crosshair size starting from biggest to current
      w = LERP( w*2, w, f ); // before: w *= ( 1 + f );
      h = LERP( h*2, h, f ); // before: h *= ( 1 + f );
      if ( cg_crosshairHealth.integer && f <= 0.35f ) { // BFP - BFP crosshair health feature
         trap_R_SetColor( colorRed );
      }
   }

   x = cg_crosshairX.integer;
   y = cg_crosshairY.integer;

   ca = cg_drawCrosshair.integer;
   if (ca < 0) {
      ca = 0;
   }
   hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];

   if ( cg_thirdPerson.integer >= 1 && cg_stableCrosshair.integer <= 0 ) { // BFP - Third person traceable crosshair
      AngleVectors( ps->viewangles, forward, NULL, up );
      VectorCopy( ps->origin, muzzle );
      VectorMA( muzzle, ps->viewheight, up, muzzle );
      VectorMA( muzzle, 14, forward, muzzle );
      VectorCopy( muzzle, start );
      VectorMA( start, 131072, forward, end );
      CG_Trace( &trace, start, NULL, NULL, end, cg.snap->ps.clientNum, CONTENTS_SOLID | CONTENTS_BODY );
      if ( !CG_WorldCoordToScreenCoordFloat( trace.endpos, &x, &y ) ) {
         return;
      }

      CG_AdjustFrom640( &x, &y, &w, &h );

      // BFP - Make the traceable crosshair move smoothly like BFP vanilla does
      // LERP( <last (or initial) position>, <destination>, (float)(cg.frametime / 1000.00f) * <speed factor> );
      y = LERP( lastPositionY, y, (float)(cg.frametime / 1000.00f) * 12.0f );

      trap_R_DrawStretchPic( x - 0.5f * w, // 492.799987
      y - 0.5f * h,
      w, h, 0, 0, 1, 1, hShader );
      lastPositionY = y; // last Y position where it was "lerped"
   } else { // Q3 default crosshair position
      // x: 492.799987
      // y: 364.799987
      CG_AdjustFrom640( &x, &y, &w, &h );
      trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w),
      y + cg.refdef.y + 0.5 * (cg.refdef.height - h),
      w, h, 0, 0, 1, 1, hShader );
   }
}




Top
                 

Commander
Commander
Joined: 08 Jun 2022
Posts: 100
PostPosted: 10-02-2023 03:03 AM           Profile Send private message  E-mail  Edit post Reply with quote


I just implemented the ESF (Earth Special Forces) style if someone wanna play it:
Code:
#define ESF_STYLE   1   // BFP - That isn't BFP, it's Earth Special Forces (ESF) style :P
static void CG_DrawCrosshair(void) {
   float      w, h;
   qhandle_t   hShader;
   float      f;
   float      x, y;
   int         ca;
   trace_t      trace;
   playerState_t   *ps;
   vec3_t      muzzle, forward, up, start, end;
#if ESF_STYLE
   static float lastPositionX = 640.0f; // BFP - Last X position for traceable crosshair to move smoothly like ESF does
#endif
   static float lastPositionY = 480.0f; // BFP - Last Y position for traceable crosshair to move smoothly like BFP vanilla does

   // BFP - TODO: BFP doesn't use the crosshair as player view,
   // e.g. if the camera angle is 90º, the crosshair should look what's in this view,
   // not what the player sees

   ps = &cg.predictedPlayerState;

   if ( !cg_drawCrosshair.integer ) {
      return;
   }

   if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {
      return;
   }

   // Read: https://www.quake3world.com/forum/viewtopic.php?f=16&t=55019
   CG_SetCrosshairColor(); // BFP - Crosshair color

   w = h = cg_crosshairSize.value;

   // BFP - pulse the size of the crosshair when hitting someone (before: when picking up items)
   f = cg.time - cg.opponentHitBlendTime;
   if ( f > 0 && f < HIT_BLOB_TIME ) {
      f /= HIT_BLOB_TIME;
      // BFP - Make crosshair size starting from biggest to current
      w = LERP( w*2, w, f ); // before: w *= ( 1 + f );
      h = LERP( h*2, h, f ); // before: h *= ( 1 + f );
      if ( cg_crosshairHealth.integer && f <= 0.35f ) { // BFP - BFP crosshair health feature
         trap_R_SetColor( colorRed );
      }
   }

   x = cg_crosshairX.integer;
   y = cg_crosshairY.integer;

   ca = cg_drawCrosshair.integer;
   if (ca < 0) {
      ca = 0;
   }
   hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];

   if ( cg_thirdPerson.integer >= 1 && cg_stableCrosshair.integer <= 0 ) { // BFP - Third person traceable crosshair
#if ESF_STYLE
      AngleVectors( cg.snap->ps.viewangles, forward, NULL, up );
      VectorCopy( cg.snap->ps.origin, muzzle );
      VectorMA( muzzle, cg.snap->ps.viewheight, up, muzzle );
#else
      AngleVectors( ps->viewangles, forward, NULL, up );
      VectorCopy( ps->origin, muzzle );
      VectorMA( muzzle, ps->viewheight, up, muzzle );
#endif
      VectorMA( muzzle, 14, forward, muzzle );
      VectorCopy( muzzle, start );
      VectorMA( start, 131072, forward, end );
      CG_Trace( &trace, start, NULL, NULL, end, cg.snap->ps.clientNum, CONTENTS_SOLID | CONTENTS_BODY );
      if ( !CG_WorldCoordToScreenCoordFloat( trace.endpos, &x, &y ) ) {
         return;
      }

      CG_AdjustFrom640( &x, &y, &w, &h );

      // BFP - Make the traceable crosshair move smoothly like BFP vanilla does
      // LERP( <last (or initial) position>, <destination>, (float)(cg.frametime / 1000.00f) * <speed factor> );
#if ESF_STYLE
      x = LERP( lastPositionX, x, (float)(cg.frametime / 1000.00f) * 18.0f );
      y = LERP( lastPositionY, y, (float)(cg.frametime / 1000.00f) * 18.0f );
#else
      y = LERP( lastPositionY, y, (float)(cg.frametime / 1000.00f) * 12.0f );
#endif

      trap_R_DrawStretchPic( x - 0.5f * w, // 492.799987
      y - 0.5f * h,
      w, h, 0, 0, 1, 1, hShader );
#if ESF_STYLE
      lastPositionX = x; // last X position where it was "lerped"
#endif
      lastPositionY = y; // last Y position where it was "lerped"
   } else { // Q3 default crosshair position
      // x: 492.799987
      // y: 364.799987
      CG_AdjustFrom640( &x, &y, &w, &h );
      trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w),
      y + cg.refdef.y + 0.5 * (cg.refdef.height - h),
      w, h, 0, 0, 1, 1, hShader );
   }
}




Top
                 
Quake3World.com | Forum Index | Programming Discussion


Post new topic Reply to topic


cron
Quake3World.com
© ZeniMax. Zenimax, QUAKE III ARENA, Id Software and associated trademarks are trademarks of the ZeniMax group of companies. All rights reserved.
This is an unofficial fan website without any affiliation with or endorsement by ZeniMax.
All views and opinions expressed are those of the author.