Third person crosshair feature

Locked
User avatar
LegendGuard
Posts: 121
Joined: Thu Jun 09, 2022 7:35 am

Third person crosshair feature

Post by LegendGuard »

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: Select all

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 Mon Oct 02, 2023 11:00 am, edited 2 times in total.
User avatar
LegendGuard
Posts: 121
Joined: Thu Jun 09, 2022 7:35 am

Re: Third person crosshair functionality

Post by LegendGuard »

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

https://github.com/LegendaryGuard/BFP/c ... dfb979b285
User avatar
LegendGuard
Posts: 121
Joined: Thu Jun 09, 2022 7:35 am

Re: Third person crosshair functionality

Post by LegendGuard »

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: Select all

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 );
	}
}
User avatar
LegendGuard
Posts: 121
Joined: Thu Jun 09, 2022 7:35 am

Re: Third person crosshair feature

Post by LegendGuard »

I just implemented the ESF (Earth Special Forces) style if someone wanna play it:

Code: Select all

#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 );
	}
}
Locked