Skip to content

Commit

Permalink
CLIENT: Add Chasecam from Vril
Browse files Browse the repository at this point in the history
  • Loading branch information
MotoLegacy committed Dec 7, 2024
1 parent b0f30c3 commit c0bd852
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 2 deletions.
1 change: 1 addition & 0 deletions progs/csqc.src
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ chat.qc
user_input.qc
view_model.qc
particles.qc
chasecam.qc
main.qc
#endlist
159 changes: 159 additions & 0 deletions source/client/chasecam.qc
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
client/chasecam.qc

A pretty direct port of Quake's chase cam to CSQC.

Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 2021-2024 NZ:P Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
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.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to:

Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA

*/

vector chase_pos;
vector chase_angles;

vector chase_dest;
vector chase_dest_angles;

void() Chase_Init =
{
autocvar(chase_back, 100);
autocvar(chase_up, 16);
autocvar(chase_right, 0);
autocvar(chase_active, 0);
autocvar(chase_roll, 0);
autocvar(chase_yaw, 0);
autocvar(chase_pitch, 0);
};

float chase_nodraw;

#define NUM_TESTS 64
#define CHASE_DEST_OFFSET 2.0

void() Chase_Update =
{
int i;
float dist;
vector cl_viewangles, cl_vieworigin;
vector dest, stop;
int best;
int viewcontents;

cl_viewangles = getproperty(VF_ANGLES);
cl_vieworigin = getproperty(VF_ORIGIN);

// if can't see player, reset
makevectors(cl_viewangles);

// calc exact destination
for (i = 0; i < 3; i++) {
chase_dest[i] = cl_vieworigin[i] - v_forward[i] * autocvar_chase_back - v_right[i] * autocvar_chase_right;
}

chase_dest[2] = cl_vieworigin[2] + autocvar_chase_up;

// take contents of the view leaf
viewcontents = pointcontents(cl_vieworigin);

for (best = 0; best < NUM_TESTS; best++) {
vector chase_newdest;

chase_newdest[0] = cl_vieworigin[0] + (chase_dest[0] - cl_vieworigin[0]) * best / NUM_TESTS;
chase_newdest[1] = cl_vieworigin[1] + (chase_dest[1] - cl_vieworigin[1]) * best / NUM_TESTS;
chase_newdest[2] = cl_vieworigin[2] + (chase_dest[2] - cl_vieworigin[2]) * best / NUM_TESTS;

// check for a leaf hit with different contents
if (pointcontents(chase_newdest) != viewcontents)
{
// go back to the previous best as this one is bad
// unless the first one was also bad, (viewleaf contents != viewleaf contents!!!)
if (best > 0) {
best--;
} else {
best = NUM_TESTS;
break;
}
}
}

// certain surfaces can be viewed at an oblique enough angle that they are partially clipped
// by znear, so now we fix that too...
for (; best >= 0; best--) {
// number of matches
int nummatches = 0;

// adjust
chase_dest[0] = cl_vieworigin[0] + (chase_dest[0] - cl_vieworigin[0]) * best / NUM_TESTS;
chase_dest[1] = cl_vieworigin[1] + (chase_dest[1] - cl_vieworigin[1]) * best / NUM_TESTS;
chase_dest[2] = cl_vieworigin[2] + (chase_dest[2] - cl_vieworigin[2]) * best / NUM_TESTS;

// move x to neg
chase_dest[0] -= CHASE_DEST_OFFSET;
if (pointcontents(chase_dest) == viewcontents) nummatches++;
chase_dest[0] += CHASE_DEST_OFFSET;

// move x to pos
chase_dest[0] += CHASE_DEST_OFFSET;
if (pointcontents(chase_dest) == viewcontents) nummatches++;
chase_dest[0] -= CHASE_DEST_OFFSET;

// move y to neg
chase_dest[1] -= CHASE_DEST_OFFSET;
if (pointcontents(chase_dest) == viewcontents) nummatches++;
chase_dest[1] += CHASE_DEST_OFFSET;

// move y to pos
chase_dest[1] += CHASE_DEST_OFFSET;
if (pointcontents(chase_dest) == viewcontents) nummatches++;
chase_dest[1] -= CHASE_DEST_OFFSET;

// move z to neg
chase_dest[2] -= CHASE_DEST_OFFSET;
if (pointcontents(chase_dest) == viewcontents) nummatches++;
chase_dest[2] += CHASE_DEST_OFFSET;

// move z to pos
chase_dest[2] += CHASE_DEST_OFFSET;
if (pointcontents(chase_dest) == viewcontents) nummatches++;
chase_dest[2] -= CHASE_DEST_OFFSET;

// all tests passed so we're good!
if (nummatches == 6) break;
}

// find the spot the player is looking at
dest[0] = cl_vieworigin[0] + 4096 * v_forward[0];
dest[1] = cl_vieworigin[1] + 4096 * v_forward[1];
dest[2] = cl_vieworigin[2] + 4096 * v_forward[2];
traceline(cl_vieworigin, dest, MOVE_NOMONSTERS, world);

// calculate pitch to look at the same spot from camera
stop[0] = cl_vieworigin[0] - trace_endpos[0];
stop[1] = cl_vieworigin[1] - trace_endpos[1];
stop[2] = cl_vieworigin[2] - trace_endpos[2];
dist = dotproduct(stop, v_forward);
if (dist < 1) dist = 1;

cl_viewangles[0] = -atan(stop[2] / dist) / M_PI * 180;

setviewprop(VF_ORIGIN, chase_dest);
//setviewprop(VF_ANGLES, cl_viewangles);
};
4 changes: 4 additions & 0 deletions source/client/main.qc
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,10 @@ noref void(float width, float height, float menushown) CSQC_UpdateView =

setviewprop(VF_ANGLES, camang);

if (cvar("chase_active")) {
Chase_Update();
}

//does what you think it does
renderscene();

Expand Down
2 changes: 1 addition & 1 deletion source/client/particles.qc
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ vector particle_position;
void() Particles_MuzzleflashCallback =
{
// Do not display Muzzleflashes if we're using a Sniper Scope or not drawing the viewmodel.
if (getstatf(STAT_WEAPONZOOM) == 2 || !cvar("r_drawviewmodel"))
if (getstatf(STAT_WEAPONZOOM) == 2 || !cvar("r_drawviewmodel") || cvar("chase_active"))
return;

// Organized storage of optional_field and optional_entity.
Expand Down
2 changes: 1 addition & 1 deletion source/client/view_model.qc
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ void() ViewModel_Draw =
}

// If we're zoomed in with a Sniper scope or r_drawviewmodel is false, early-out.
if (!cvar("r_drawviewmodel") || getstatf(STAT_WEAPONZOOM) == 2)
if (!cvar("r_drawviewmodel") || getstatf(STAT_WEAPONZOOM) == 2 || cvar("chase_active"))
return;

cl_viewent.origin = cl_viewent2.origin = '0 0 0';
Expand Down

0 comments on commit c0bd852

Please sign in to comment.