From: terencehill Date: Fri, 4 Mar 2016 15:50:24 +0000 (+0100) Subject: Dynamic hud: HUD moves around following player's movement (effect shared with cl_foll... X-Git-Tag: xonotic-v0.8.2~882^2~18 X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=f6c3bdca476ec02614e987feca72f86925bf8e82 Dynamic hud: HUD moves around following player's movement (effect shared with cl_followmodel, can be enabled independently from it though) Moved cl_followmodel, cl_leanmodel and cl_bobmodel code to their own functions The frametime used is now the global one. --- diff --git a/_hud_common.cfg b/_hud_common.cfg index 70900762f7..e58a449a26 100644 --- a/_hud_common.cfg +++ b/_hud_common.cfg @@ -63,6 +63,9 @@ alias hud_panel_radar_maximized "cl_cmd hud radar" // other hud cvars seta hud_panel_update_interval 2 "how often (in seconds) common panel cvars are reloaded" +seta hud_dynamic_follow 1 "HUD moves around following player's movement (effect shared with cl_followmodel, can be enabled independently from it though)" +seta hud_dynamic_follow_scale 0.01 "HUD following scale" + seta hud_showbinds 1 "what to show in the HUD to indicate certain keys to press: 0 display commands, 1 bound keys, 2 both" seta hud_showbinds_limit 2 "maximum number of bound keys to show for a command. 0 for unlimited" set _hud_showbinds_reload 0 "set it to 1 to reload binds if you changed any. It is reset to 0 automatically" diff --git a/qcsrc/client/hud/hud.qc b/qcsrc/client/hud/hud.qc index b0f2b9ea65..6523dfd339 100644 --- a/qcsrc/client/hud/hud.qc +++ b/qcsrc/client/hud/hud.qc @@ -451,6 +451,22 @@ void HUD_Reset() HUD_Mod_CTF_Reset(); } +void calc_followmodel_ofs(entity view); +void Hud_Dynamic_Frame() +{ + hud_dynamic_ofs = '0 0 0'; + if (autocvar_hud_dynamic_follow) + { + entity view = CSQCModel_server2csqc(player_localentnum - 1); + calc_followmodel_ofs(view); + hud_dynamic_ofs -= cl_followmodel_ofs * autocvar_hud_dynamic_follow_scale; + } + + if (fabs(hud_dynamic_ofs.x) < 0.001) hud_dynamic_ofs.x = 0; + if (fabs(hud_dynamic_ofs.y) < 0.001) hud_dynamic_ofs.y = 0; + if (fabs(hud_dynamic_ofs.z) < 0.001) hud_dynamic_ofs.z = 0; +} + void HUD_Main() { int i; @@ -481,6 +497,8 @@ void HUD_Main() return; } + Hud_Dynamic_Frame(); + // Drawing stuff if (hud_skin_prev != autocvar_hud_skin) { diff --git a/qcsrc/client/hud/hud.qh b/qcsrc/client/hud/hud.qh index 45dd4887f2..b80698ccf4 100644 --- a/qcsrc/client/hud/hud.qh +++ b/qcsrc/client/hud/hud.qh @@ -146,6 +146,15 @@ float chat_sizey; float current_player; +float autocvar_hud_dynamic_follow; +float autocvar_hud_dynamic_follow_scale; + +// shared across viewmodel effects and dynamic hud code +vector cl_followmodel_ofs; +float cl_followmodel_time; + +vector hud_dynamic_ofs; + float stringwidth_colors(string s, vector theSize); float stringwidth_nocolors(string s, vector theSize); void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag); @@ -384,6 +393,14 @@ REGISTER_HUD_PANEL(QUICKMENU, HUD_QuickMenu, quickmenu, PANEL_CO panel_bg_padding = panel.current_panel_bg_padding; \ panel_fg_alpha = panel.current_panel_fg_alpha * hud_fade_alpha; \ } \ + if(hud_dynamic_ofs.y) panel_pos.x += hud_dynamic_ofs.y * vid_conwidth; \ + if(hud_dynamic_ofs.z) panel_pos.y += hud_dynamic_ofs.z * vid_conheight; \ + if(hud_dynamic_ofs.x) { \ + panel_size.x += hud_dynamic_ofs.x * panel_size.x; \ + panel_size.y += hud_dynamic_ofs.x * panel_size.y; \ + panel_pos.x += hud_dynamic_ofs.x * (panel_pos.x - vid_conwidth * 0.5); \ + panel_pos.y += hud_dynamic_ofs.x * (panel_pos.y - vid_conheight * 0.5); \ + } \ } MACRO_END #define HUD_Panel_UpdatePosSize() MACRO_BEGIN { \ diff --git a/qcsrc/client/view.qc b/qcsrc/client/view.qc index edf56a87d0..a13fb2d8a0 100644 --- a/qcsrc/client/view.qc +++ b/qcsrc/client/view.qc @@ -109,117 +109,152 @@ float autocvar_cl_leanmodel_lowpass = 0.05; highpass(value.z, frac, ref_store.z, ref_out.z); \ } MACRO_END -void viewmodel_animate(entity this) +void calc_followmodel_ofs(entity view) { - static float prevtime; - float frametime = (time - prevtime); - prevtime = time; + if(cl_followmodel_time == time) + return; // cl_followmodel_ofs already calculated for this frame - if (autocvar_chase_active) return; - if (STAT(HEALTH) <= 0) return; + float frac; + vector gunorg = '0 0 0'; + static vector vel_average; + static vector gunorg_prev = '0 0 0'; + static vector gunorg_adjustment_highpass; + static vector gunorg_adjustment_lowpass; + + vector vel; + if (autocvar_cl_followmodel_velocity_absolute) + vel = view.velocity; + else + { + vector forward, right = '0 0 0', up = '0 0 0'; + MAKEVECTORS(makevectors, view_angles, forward, right, up); + vel.x = view.velocity * forward; + vel.y = view.velocity * right * -1; + vel.z = view.velocity * up; + } - entity view = CSQCModel_server2csqc(player_localentnum - 1); + vel.x = bound(vel_average.x - autocvar_cl_followmodel_limit, vel.x, vel_average.x + autocvar_cl_followmodel_limit); + vel.y = bound(vel_average.y - autocvar_cl_followmodel_limit, vel.y, vel_average.y + autocvar_cl_followmodel_limit); + vel.z = bound(vel_average.z - autocvar_cl_followmodel_limit, vel.z, vel_average.z + autocvar_cl_followmodel_limit); - bool clonground = !(view.anim_implicit_state & ANIMIMPLICITSTATE_INAIR); - static bool oldonground; - static float hitgroundtime; - if (clonground) + frac = avg_factor(autocvar_cl_followmodel_velocity_lowpass); + lowpass3(vel, frac, vel_average, gunorg); + + gunorg *= -autocvar_cl_followmodel_speed * 0.042; + + // perform highpass/lowpass on the adjustment vectors (turning velocity into acceleration!) + // trick: we must do the lowpass LAST, so the lowpass vector IS the final vector! + frac = avg_factor(autocvar_cl_followmodel_highpass); + highpass3(gunorg, frac, gunorg_adjustment_highpass, gunorg); + frac = avg_factor(autocvar_cl_followmodel_lowpass); + lowpass3(gunorg, frac, gunorg_adjustment_lowpass, gunorg); + + if (autocvar_cl_followmodel_velocity_absolute) { - float f = time; // cl.movecmd[0].time - if (!oldonground) - hitgroundtime = f; + vector fixed_gunorg; + vector forward, right = '0 0 0', up = '0 0 0'; + MAKEVECTORS(makevectors, view_angles, forward, right, up); + fixed_gunorg.x = gunorg * forward; + fixed_gunorg.y = gunorg * right * -1; + fixed_gunorg.z = gunorg * up; + gunorg = fixed_gunorg; } - oldonground = clonground; + cl_followmodel_ofs = gunorg; + cl_followmodel_time = time; +} - bool teleported = view.csqcmodel_teleported; - +vector leanmodel_ofs(entity view) +{ float frac; - if(autocvar_cl_followmodel) - { - vector gunorg = '0 0 0'; - static vector vel_average; - static vector gunorg_prev = '0 0 0'; - static vector gunorg_adjustment_highpass; - static vector gunorg_adjustment_lowpass; + vector gunangles = '0 0 0'; + static vector gunangles_prev = '0 0 0'; + static vector gunangles_highpass = '0 0 0'; + static vector gunangles_adjustment_highpass; + static vector gunangles_adjustment_lowpass; - vector vel; - if(autocvar_cl_followmodel_velocity_absolute) - vel = view.velocity; - else - { - vector forward, right = '0 0 0', up = '0 0 0'; - MAKEVECTORS(makevectors, view_angles, forward, right, up); - vel.x = view.velocity * forward; - vel.y = view.velocity * right * -1; - vel.z = view.velocity * up; - } + if (view.csqcmodel_teleported) + gunangles_prev = view_angles; - vel.x = bound(vel_average.x - autocvar_cl_followmodel_limit, vel.x, vel_average.x + autocvar_cl_followmodel_limit); - vel.y = bound(vel_average.y - autocvar_cl_followmodel_limit, vel.y, vel_average.y + autocvar_cl_followmodel_limit); - vel.z = bound(vel_average.z - autocvar_cl_followmodel_limit, vel.z, vel_average.z + autocvar_cl_followmodel_limit); + // in the highpass, we _store_ the DIFFERENCE to the actual view angles... + gunangles_highpass += gunangles_prev; + PITCH(gunangles_highpass) += 360 * floor((PITCH(view_angles) - PITCH(gunangles_highpass)) / 360 + 0.5); + YAW(gunangles_highpass) += 360 * floor((YAW(view_angles) - YAW(gunangles_highpass)) / 360 + 0.5); + ROLL(gunangles_highpass) += 360 * floor((ROLL(view_angles) - ROLL(gunangles_highpass)) / 360 + 0.5); + frac = avg_factor(autocvar_cl_leanmodel_highpass1); + highpass2_limited(view_angles, frac, autocvar_cl_leanmodel_limit, gunangles_highpass, gunangles); + gunangles_prev = view_angles; + gunangles_highpass -= gunangles_prev; - frac = avg_factor(autocvar_cl_followmodel_velocity_lowpass); - lowpass3(vel, frac, vel_average, gunorg); + PITCH(gunangles) *= -autocvar_cl_leanmodel_speed; + YAW(gunangles) *= -autocvar_cl_leanmodel_speed; - gunorg *= -autocvar_cl_followmodel_speed * 0.042; + // we assume here: PITCH = 0, YAW = 1, ROLL = 2 + frac = avg_factor(autocvar_cl_leanmodel_highpass); + highpass2(gunangles, frac, gunangles_adjustment_highpass, gunangles); + frac = avg_factor(autocvar_cl_leanmodel_lowpass); + lowpass2(gunangles, frac, gunangles_adjustment_lowpass, gunangles); - // perform highpass/lowpass on the adjustment vectors (turning velocity into acceleration!) - // trick: we must do the lowpass LAST, so the lowpass vector IS the final vector! - frac = avg_factor(autocvar_cl_followmodel_highpass); - highpass3(gunorg, frac, gunorg_adjustment_highpass, gunorg); - frac = avg_factor(autocvar_cl_followmodel_lowpass); - lowpass3(gunorg, frac, gunorg_adjustment_lowpass, gunorg); + gunangles.x = -gunangles.x; // pitch was inverted, now that actually matters - if(autocvar_cl_followmodel_velocity_absolute) - { - vector fixed_gunorg; - vector forward, right = '0 0 0', up = '0 0 0'; - MAKEVECTORS(makevectors, view_angles, forward, right, up); - fixed_gunorg.x = gunorg * forward; - fixed_gunorg.y = gunorg * right * -1; - fixed_gunorg.z = gunorg * up; - gunorg = fixed_gunorg; - } + return gunangles; +} - this.origin += gunorg; +vector bobmodel_ofs(entity view) +{ + bool clonground = !(view.anim_implicit_state & ANIMIMPLICITSTATE_INAIR); + static bool oldonground; + static float hitgroundtime; + if (clonground) + { + float f = time; // cl.movecmd[0].time + if (!oldonground) + hitgroundtime = f; } + oldonground = clonground; - if(autocvar_cl_leanmodel) + // calculate for swinging gun model + // the gun bobs when running on the ground, but doesn't bob when you're in the air. + vector gunorg = '0 0 0'; + static float bobmodel_scale = 0; + static float time_ofs = 0; // makes the effect always restart in the same way + if (clonground) { - vector gunangles = '0 0 0'; - static vector gunangles_prev = '0 0 0'; - static vector gunangles_highpass = '0 0 0'; - static vector gunangles_adjustment_highpass; - static vector gunangles_adjustment_lowpass; + if (time - hitgroundtime > 0.05) + bobmodel_scale = min(1, bobmodel_scale + frametime * 5); + } + else + bobmodel_scale = max(0, bobmodel_scale - frametime * 5); - if (teleported) - gunangles_prev = view_angles; + float xyspeed = bound(0, vlen(vec2(view.velocity)), 400); + if (bobmodel_scale && xyspeed) + { + float bspeed = xyspeed * 0.01 * autocvar_cl_viewmodel_scale * bobmodel_scale; + float s = (time - time_ofs) * autocvar_cl_bobmodel_speed; + gunorg.y = bspeed * autocvar_cl_bobmodel_side * sin(s); + gunorg.z = bspeed * autocvar_cl_bobmodel_up * cos(s * 2); + } + else + time_ofs = time; - // in the highpass, we _store_ the DIFFERENCE to the actual view angles... - gunangles_highpass += gunangles_prev; - PITCH(gunangles_highpass) += 360 * floor((PITCH(view_angles) - PITCH(gunangles_highpass)) / 360 + 0.5); - YAW(gunangles_highpass) += 360 * floor((YAW(view_angles) - YAW(gunangles_highpass)) / 360 + 0.5); - ROLL(gunangles_highpass) += 360 * floor((ROLL(view_angles) - ROLL(gunangles_highpass)) / 360 + 0.5); - frac = avg_factor(autocvar_cl_leanmodel_highpass1); - highpass2_limited(view_angles, frac, autocvar_cl_leanmodel_limit, gunangles_highpass, gunangles); - gunangles_prev = view_angles; - gunangles_highpass -= gunangles_prev; + return gunorg; +} - PITCH(gunangles) *= -autocvar_cl_leanmodel_speed; - YAW(gunangles) *= -autocvar_cl_leanmodel_speed; +void viewmodel_animate(entity this) +{ + if (autocvar_chase_active) return; + if (STAT(HEALTH) <= 0) return; - // we assume here: PITCH = 0, YAW = 1, ROLL = 2 - frac = avg_factor(autocvar_cl_leanmodel_highpass); - highpass2(gunangles, frac, gunangles_adjustment_highpass, gunangles); - frac = avg_factor(autocvar_cl_leanmodel_lowpass); - lowpass2(gunangles, frac, gunangles_adjustment_lowpass, gunangles); + entity view = CSQCModel_server2csqc(player_localentnum - 1); - gunangles.x = -gunangles.x; // pitch was inverted, now that actually matters - this.angles += gunangles; + if (autocvar_cl_followmodel) + { + calc_followmodel_ofs(view); + this.origin += cl_followmodel_ofs; } - float xyspeed = bound(0, vlen(vec2(view.velocity)), 400); + if (autocvar_cl_leanmodel) + this.angles += leanmodel_ofs(view); // vertical view bobbing code // TODO: cl_bob @@ -233,31 +268,7 @@ void viewmodel_animate(entity this) // gun model bobbing code if (autocvar_cl_bobmodel) - { - // calculate for swinging gun model - // the gun bobs when running on the ground, but doesn't bob when you're in the air. - static float bobmodel_scale = 0; - static float time_ofs = 0; // makes the effect always restart in the same way - if (clonground) - { - if (time - hitgroundtime > 0.05) - bobmodel_scale = min(1, bobmodel_scale + frametime * 5); - } - else - bobmodel_scale = max(0, bobmodel_scale - frametime * 5); - if(bobmodel_scale && xyspeed) - { - float bspeed = xyspeed * 0.01 * autocvar_cl_viewmodel_scale * bobmodel_scale; - float s = (time - time_ofs) * autocvar_cl_bobmodel_speed; - vector gunorg = '0 0 0'; - gunorg.y = bspeed * autocvar_cl_bobmodel_side * sin(s); - gunorg.z = bspeed * autocvar_cl_bobmodel_up * cos(s * 2); - - this.origin += gunorg; - } - else - time_ofs = time; - } + this.origin += bobmodel_ofs(view); } .vector viewmodel_origin, viewmodel_angles;