Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions docs/pages/cvars-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,11 @@ Controls the displayed bunnyhopping practice tools. The desired value of `show_b
* `8` - display acceleration during recent frames; the display is logarithmic (so small gains in speed are visible).
* `16` - display precision of forward keypresses and strafe accuracy, as a bar. Top bar displays forward accuracy, while the bottom bar displays the left direction on top and right on bottom. When strafes are synced, colors mix to yellow.
* `32` - display under the crosshair the bar signifying where you needed to look to gain speed in air, as well as a history over recent frames. The closer aligned the center bar and the red line are, the more accurate your turning was.
* `64` - display above crosshair some number stats on each jump (gained speed in air, loss due to friction, time spent on ground and velocity of prestrafe), as well as multiple boxes more clearly marking forward tap accuracy. It shows the ground frame above the crosshair, and frames preceding and after the last ground touch; the amount of frames shown in both direction is controlled with the variable `show_bhop_frames`.
* `64` - display above crosshair some number stats on each jump (gained speed in air, loss due to friction)
* `128` - display above crosshair multiple boxes more clearly marking forward tap accuracy. It shows the ground frame above the crosshair, and frames preceding and after the last ground touch; the amount of frames shown in both direction is controlled with the variable `show_bhop_frames`.
* `256` - display above crosshair a bar showing prestrafe success. The bar fills up from 320 to 480; prestrafes above 480 are assumed to be 'nearly perfect.' The bar's color changes in a gradient from red to green; the 'sharpness' of the gradient is controlled by the variable `show_bhop_prestrafe_diff`: the higher the value above 1.0, the more aggressively close to 480 the prestrafe speed needs to be to produce a green hue. The speed after jump is shown on the left side of the bar; the other value shown are the frames taken for the prestrafe. The frame count is approximate, because it counts the prestrafe from the moment you cross the 320 speed barrier. Nevertheless, quickening it is also a good goal.
* `512` - display above crosshair a bar showing midair strafe sync, and straight path efficiency. The path efficiency takes the same place prestrafe info did: it displays the distance of the current jump, and the ratio of distance in a straight line to the curved distance actually traversed between jumps. In addition, the strafe display detects midair strafe direction changes, in the form of boxes divided into quadrants. The amount of columns of boxes is each mid-air strafe direction change. For each column, each row is composed of 4 boxes: the top boxes give mouse direction (left/right); the bottom give strafe keys pressed (left/right). Each box corresponds to one physics frame. When things are in sync, they are displayed as green; if they are completely desynced (left mouse and right kb or vice versa), they're red; when something is wrong (mouse but no key, key but no mouse, or both strafe keys pressed at once) they are colored yellow. The displayed frames are from the last pre-turn synced frame to the first post-turn synced frame: other correctly synced frames in the middle of each strafe are skipped for brevity. In general, the better your straight path efficiency, the better. More midair strafes improve your straight path efficiency; the fewer rows in each strafe switch, the better. So more columns good and fewer rows good.
* `1024` - display a circle with the speed, speed gain, wishdir direction - inspired by "The code behind Quake's movement tricks explained (bunny-hopping, wall-running, and zig-zagging)" - https://www.youtube.com/watch?v=v3zT3Z5apaM

`_x` and `_y` control the position of the graphs.

Expand All @@ -925,11 +929,12 @@ The amount of frames shown for the graph displays is controlled by `show_bhop_wi
Stats are also shown in intermission; the display shows everything that is in recorded history. The amount of frames stored is controlled by `show_bhop_histlen`.

The defaults are as follows:
* `show_bhop_stats` is `0`, signifying no display. To set everything on, use `127`. The displays are all turned off during demo recording, regardless of setting.
* `show_bhop_stats` is `0`, signifying no display. To set everything on, use `511`. The displays are all turned off during demo recording, regardless of setting.
* `show_bhop_stats_x,y` are `1` and `4` respectively.
* `show_bhop_window` is `144`, corresponding to two seconds. This is the max effective value of this variable.
* `show_bhop_histlen` is `0`, corresponding to storing everything until the intermission.
* `show_bhop_frames` is `7`.
* `show_bhop_prestrafe_diff` is `8`. This makes green show up around 465-ish prestrafes, a decent goal for most players. If you're very new, setting to 1 will make green appear around 400. If you're very advanced, you might want to pop it up even higher: 16 for 475-ish, and maybe 100 to redden anything but perfect prestrafes.

To display some of the graphs, a lot of rectangles are drawn. So you might lose some FPS due to that.

Expand Down Expand Up @@ -1069,6 +1074,12 @@ The line will not be drawn if the length between the frames is larger than this

Default: `160`

##### `pathtracer_record_samplerate`

If this is zero then the pathtracer will only record physics frames from the player. If set to 1 it will record every frame it will record at `cl_maxfps` rate.

Default: `0`

#### Demo browser

##### `demo_browser_vim`
Expand Down Expand Up @@ -1361,6 +1372,10 @@ This command currently does not work on the win32 build.
Like `freefly_copycam`, but append commands to the provided filename instead.
This command is available on all builds.

##### `freefly_print_entities

Print's the ID, distance from camera and model of entities near the freefly camera. Can be used to indentify entities for use in ReMaic recams.

##### `togglezoom`

Toggles between zoomed in and zoomed out views.
Expand Down
234 changes: 230 additions & 4 deletions trunk/bhop/practice.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ void Bhop_GatherData(void)
if (sv_player->v.health <= 0 || cl.intermission)
return;

vec3_t vel, angles;
vec3_t vel;
bhop_data_t * data_frame = malloc(sizeof(bhop_data_t));
bhop_mark_t bar;
float focal_len = (vid.width / 2.0) / tan( r_refdef.fov_x * M_PI / 360.0);
Expand Down Expand Up @@ -486,14 +486,14 @@ void Bhop_GatherData(void)
last_ground_speed = data_frame->speed;
}

VectorCopy(sv_player->v.angles, angles);
VectorCopy(sv_player->v.angles, data_frame->angles);

if(!data_frame->on_ground){
VectorCopy(pre_sv_velocity, vel);
bar = Bhop_CalcAirBar(vel, angles, focal_len);
bar = Bhop_CalcAirBar(vel, data_frame->angles, focal_len);
} else if (data_frame->on_ground) {
VectorCopy(post_friction_velocity, vel);
bar = Bhop_CalcGroundBar(vel, angles, focal_len);
bar = Bhop_CalcGroundBar(vel, data_frame->angles, focal_len);
}

/* flip angles if moving to the left */
Expand Down Expand Up @@ -767,6 +767,226 @@ void Bhop_DrawCrosshairPrestrafe(bhop_data_t *history, int x, int y, int scale,
Draw_String (x * scale + 1 * charsize, y * scale, str, true);
}

// Interpolate between two colors (r,g,b) in [0,255]
static void interpolate_color(float t, int r1, int g1, int b1, int r2, int g2, int b2, int* r, int* g, int* b) {
*r = (int)(r1 + (r2 - r1) * t);
*g = (int)(g1 + (g2 - g1) * t);
*b = (int)(b1 + (b2 - b1) * t);
}

// Draws a colored circle/arc with per-segment color based on values[] in [-1,1]
void Draw_CircleWithColoredSegments(int x_center, int y_center, float radius, float segment_start, float segment_end, float thickness, const float* values, int num_segments, float rotate, qboolean colorize) {
float angle_range = segment_end - segment_start;
float angle_step = -angle_range / num_segments;
glDisable(GL_TEXTURE_2D);

glEnable(GL_BLEND);
glDisable(GL_ALPHA_TEST);

glBegin(GL_LINES);
glLineWidth(thickness);

for (int i = 0; i < num_segments; ++i) {
float angle0 = segment_start + i * angle_step + rotate;
float angle1 = segment_start + (i + 1) * angle_step + rotate;

float v = values[i];
if (v < -1.0f) v = -1.0f;
else if (v < 1000.0f && v > 1.0f) v = 1.0f;

int r, g, b;
if (v < 0.0f) {
if (colorize)
// TODO PK: replace color values with constants as defined in practice.h
interpolate_color(v + 1.0f, 255, 0, 0, 128, 128, 128, &r, &g, &b);
else
interpolate_color(v + 1.0f, 10, 10, 10, 128, 128, 128, &r, &g, &b);
}
else if (v >= 1000.f) {
if (colorize) {
r = 0;
g = 0;
b = 255;
}
else
interpolate_color(v, 10, 10, 10, 10, 10, 10, &r, &g, &b);
}
else {
if (colorize)
interpolate_color(v, 128, 128, 128, 0, 255, 0, &r, &g, &b);
else
interpolate_color(v, 10, 10, 10, 10, 10, 10, &r, &g, &b);
}

glColor4ub(r, g, b, 255);

glVertex2f(x_center + cosf(angle0) * radius, y_center + sinf(angle0) * radius);
glVertex2f(x_center + cosf(angle1) * radius, y_center + sinf(angle1) * radius);
}
glEnd();

glLineWidth(1.0f); // Reset to default
glEnable(GL_TEXTURE_2D);
glEnable(GL_ALPHA_TEST);
glDisable(GL_BLEND);

}

void Bhop_CalculateAirAcceleration(vec3_t velocity, vec3_t angles, vec3_t velocity_new, vec3_t wishvel_original, vec3_t velocity_increase)
{
vec3_t wishdir, wishvel, fwd_vec, right_vec, up_vec;
float addspeed, currentspeed, wishspd, accelspeed;

AngleVectors(angles, fwd_vec, right_vec, up_vec);

for (int i = 0; i < 3; i++)
wishvel[i] = fwd_vec[i] * cmd.forwardmove + right_vec[i] * cmd.sidemove;
wishvel[2] = 0;

VectorCopy(wishvel, wishvel_original);
VectorCopy(wishvel, wishdir);
float wishspeed = VectorNormalize(wishdir);

wishspd = VectorNormalize(wishvel);
if (wishspd > 30)
wishspd = 30;

currentspeed = DotProduct(velocity, wishvel);
addspeed = wishspd - currentspeed;

VectorCopy(velocity, velocity_new);

if (addspeed <= 0) {
addspeed = 0;
for (int i = 0; i < 3; i++)
velocity_increase[i] = 0.f;
}
else {
// accelspeed = sv_accelerate.value * sv_frametime;
accelspeed = sv_accelerate.value * wishspeed * sv_frametime;
if (accelspeed > addspeed)
accelspeed = addspeed;

for (int i = 0; i < 3; i++) {
velocity_increase[i] = accelspeed * wishvel[i];
velocity_new[i] += velocity_increase[i];
}
}
}

/*
* draw wishdir chart
*/
void Bhop_DrawWishDir(bhop_data_t* history)
{
// TODO PK: replace color values with constants as defined in practice.h
color_t velocity_color = RGBA_TO_COLOR(255, 255, 255, 255);
color_t wish_color = RGBA_TO_COLOR(255, 0, 0, 255);
color_t velocity_increase_color = RGBA_TO_COLOR(0, 255, 0, 255);
color_t onground_color = RGBA_TO_COLOR(10, 10, 10, 255);
vec3_t velocity;
vec3_t center = { 0.f, 0.f, 0.f };
vec3_t velocity_pointer;
vec3_t wishvel_pointer;
vec3_t velocity_increase_pointer;
vec3_t velocity_new_pointer;
vec3_t angles;

vec3_t velocity_new, velocity_increase, wishvel_original;

if (!history)
return;

VectorCopy(history->velocity, velocity);
VectorCopy(history->angles, angles);

Bhop_CalculateAirAcceleration(velocity, angles, velocity_new, wishvel_original, velocity_increase);
float speed = VectorLength(velocity);
float speed_diff[360];
memset(speed_diff, 0, sizeof(speed_diff));
float max_test_speed_left = -10.f;
int max_test_segment_index_left = -10000;
float max_test_speed_right = -10.f;
int max_test_segment_index_right = -10000;
for (int i = -180; i < 180; i++) { // test all segments to see how much speed they would yield or lose
vec3_t test_angles;
vec3_t test_velocity_new, test_velocity_increase, test_wishvel_original;
VectorCopy(history->angles, test_angles);
test_angles[1] += i;
if (test_angles[1] >= 180.f)
test_angles[1] -= 360.f;
if (test_angles[1] < -180.f)
test_angles[1] += 360.f;
Bhop_CalculateAirAcceleration(velocity, test_angles, test_velocity_new, test_wishvel_original, test_velocity_increase);
float test_speed = VectorLength(test_velocity_new);
VectorNormalize(test_wishvel_original);
vectoangles(test_wishvel_original, test_angles);
int segment_index = (int)(test_angles[1]);
segment_index %= 360; // vectoangles allow 360 as a result, turn it into a zero to avoid index out of range error
speed_diff[segment_index] = (test_speed - speed) * 1.f;
if (i >= 0 && speed_diff[segment_index] > max_test_speed_left) {
max_test_speed_left = speed_diff[segment_index];
max_test_segment_index_left = segment_index;
}
if (i < 0 && speed_diff[segment_index] > max_test_speed_right) {
max_test_speed_right = speed_diff[segment_index];
max_test_segment_index_right = segment_index;
}
}

// highlight the best segments
if (max_test_segment_index_left != -10000)
speed_diff[max_test_segment_index_left] = 1000.f;
if (max_test_segment_index_right != -10000)
speed_diff[max_test_segment_index_right] = 1000.f;

center[0] = scr_vrect.x + scr_vrect.width / 2;
center[1] = scr_vrect.y + scr_vrect.height / 2;

vec3_t rotation_vector;
vectoangles(velocity, rotation_vector);
float rotate = rotation_vector[1] - 90.f; // rotate all vectors and the circle to make velocity point up
if (rotate > 180.f)
rotate -= 360.f;
if (rotate < -180.f)
rotate += 360.f;

// flip x axis, so that they match the mouse movement direction
velocity[0] = -velocity[0];
velocity_new[0] = -velocity_new[0];
wishvel_original[0] = -wishvel_original[0];
velocity_increase[0] = -velocity_increase[0];

vec3_t up = { 0.f, 0.f, 1 }; // rotate around z axis
vec3_t tmp_vector;
VectorCopy(velocity, tmp_vector); RotatePointAroundVector(velocity, up, tmp_vector, rotate);
VectorCopy(velocity_new, tmp_vector); RotatePointAroundVector(velocity_new, up, tmp_vector, rotate);
VectorCopy(wishvel_original, tmp_vector); RotatePointAroundVector(wishvel_original, up, tmp_vector, rotate);
VectorCopy(velocity_increase, tmp_vector); RotatePointAroundVector(velocity_increase, up, tmp_vector, rotate);

float ui_scale = 0.5f; // vectors get too large for the screen
VectorScale(velocity, ui_scale, velocity);
VectorScale(velocity_new, ui_scale, velocity_new);
VectorScale(wishvel_original, ui_scale, wishvel_original);
VectorScale(velocity_increase, ui_scale, velocity_increase);

// add vectors to center
VectorSubtract(center, velocity, velocity_pointer);
VectorSubtract(center, velocity_new, velocity_new_pointer);
VectorSubtract(center, wishvel_original, wishvel_pointer);
VectorSubtract(velocity_pointer, velocity_increase, velocity_increase_pointer);

// draw vectors
Draw_AlphaLineRGB(center[0], center[1], velocity_pointer[0], velocity_pointer[1], 2, history->on_ground ? onground_color : velocity_color);
Draw_AlphaLineRGB(center[0], center[1], velocity_new_pointer[0], velocity_new_pointer[1], 2, history->on_ground ? onground_color : velocity_color);
Draw_AlphaLineRGB(center[0], center[1], wishvel_pointer[0], wishvel_pointer[1], 2, history->on_ground ? onground_color : wish_color);
Draw_AlphaLineRGB(velocity_pointer[0], velocity_pointer[1], velocity_increase_pointer[0], velocity_increase_pointer[1], 4, history->on_ground ? onground_color : velocity_increase_color);

// TODO PK: convert parameters to degrees instead radians for consistency
// draw acceleration circle
Draw_CircleWithColoredSegments(center[0], center[1], 200.f, 0.f, 2 * M_PI, 1, speed_diff, 360, rotate * (float)(M_PI / 180.0f), !history->on_ground);
}

/*
* BHOP_Init() initialises cvars and global vars
*/
Expand Down Expand Up @@ -897,6 +1117,12 @@ void SCR_DrawBHOP (void)
y += (2 + BHOP_GAP + BHOP_MEDIUM) * scale;
}


if ((int)show_bhop_stats.value & BHOP_CIRCLE) {
Bhop_DrawWishDir(bhop_history);
}


if (frames){
free(frames);
frames = NULL;
Expand Down
4 changes: 4 additions & 0 deletions trunk/bhop/practice.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ typedef struct bhop_data_s

qboolean on_ground;
vec3_t velocity;
vec3_t angles;

float speed;
float speed_gain;
Expand Down Expand Up @@ -92,6 +93,9 @@ extern bhop_data_t *bhop_history;
#define BHOP_ANGLE_MARK 1<<5 /* mark in viewport showing where the optimal direction is, last tick */
#define BHOP_CROSSHAIR_INFO 1<<6 /* info above crosshair */

/* bhop circle chart */
#define BHOP_CIRCLE 1<<10 /* draw bhop circle */

/* color constants for convenience */
#define BHOP_GREEN 184 /* actually blue because the green sucks shit */
#define BHOP_LRED 224
Expand Down
24 changes: 18 additions & 6 deletions trunk/pathtracer/pathtracer.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "../quakedef.h"

static cvar_t pathtracer_record_player = { "pathtracer_record_player", "0" };
static cvar_t pathtracer_record_samplerate = { "pathtracer_record_samplerate", "0" };
static cvar_t pathtracer_show_player = { "pathtracer_show_player", "0" };
static cvar_t pathtracer_show_demo = { "pathtracer_show_demo", "0" };
static cvar_t pathtracer_show_ghost = { "pathtracer_show_ghost", "0" };
Expand All @@ -15,6 +16,7 @@ static cvar_t pathtracer_line_skip_threshold = { "pathtracer_line_skip_threshold
static ghost_level_t* demo_current_level = NULL;

static double prev_cltime = -1;
extern qboolean physframe;

ghost_info_t player_record_info;
ghost_level_t* player_record_current_level = NULL;
Expand Down Expand Up @@ -287,12 +289,21 @@ void PathTracer_Sample_Each_Frame(void) {

// Determine if we should sample
qboolean track = false;
if (cl.time > prev_cltime + 1.f / cl_maxfps.value) {
track = true;
prev_cltime = cl.time;
}
else {
track = false;
if (pathtracer_record_samplerate.value == 0.f) {
// sample each physics frame
if (physframe)
track = true;
else
track = false;
} else {
// sample each cl_maxfps frame
if (cl.time > prev_cltime + 1.f / cl_maxfps.value) {
track = true;
prev_cltime = cl.time;
}
else {
track = false;
}
}

// Sample movement
Expand Down Expand Up @@ -354,6 +365,7 @@ void PathTracer_Load(void)
void PathTracer_Init (void)
{
Cvar_Register (&pathtracer_record_player);
Cvar_Register (&pathtracer_record_samplerate);
Cvar_Register (&pathtracer_show_player);
Cvar_Register (&pathtracer_show_ghost);
Cvar_Register (&pathtracer_show_demo);
Expand Down