d45aea2c1109248b171c8ae0b316d4dc88aa3e3f
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hud / panel / physics.qc
1 #include "physics.qh"
2
3 #include <client/autocvars.qh>
4 #include <client/defs.qh>
5 #include <client/miscfunctions.qh>
6 #include <client/main.qh>
7 #include <common/gamemodes/_mod.qh>
8 #include <common/mapinfo.qh>
9 #include <lib/csqcmodel/cl_player.qh>
10
11 // Physics (#15)
12
13 void HUD_Physics_Export(int fh)
14 {
15         // allow saving cvars that aesthetically change the panel into hud skin files
16         HUD_Write_Cvar("hud_panel_physics_speed_unit_show");
17         HUD_Write_Cvar("hud_panel_physics_speed_max");
18         HUD_Write_Cvar("hud_panel_physics_speed_vertical");
19         HUD_Write_Cvar("hud_panel_physics_topspeed");
20         HUD_Write_Cvar("hud_panel_physics_topspeed_time");
21         HUD_Write_Cvar("hud_panel_physics_acceleration_max");
22         HUD_Write_Cvar("hud_panel_physics_acceleration_vertical");
23         HUD_Write_Cvar("hud_panel_physics_flip");
24         HUD_Write_Cvar("hud_panel_physics_baralign");
25         HUD_Write_Cvar("hud_panel_physics_progressbar");
26         HUD_Write_Cvar("hud_panel_physics_acceleration_progressbar_mode");
27         HUD_Write_Cvar("hud_panel_physics_acceleration_progressbar_scale");
28         HUD_Write_Cvar("hud_panel_physics_acceleration_progressbar_nonlinear");
29         HUD_Write_Cvar("hud_panel_physics_text");
30         HUD_Write_Cvar("hud_panel_physics_text_scale");
31 }
32
33 vector acc_prevspeed;
34 float acc_prevtime, acc_avg, top_speed, top_speed_time;
35 float physics_update_time, discrete_speed, discrete_acceleration;
36 void HUD_Physics()
37 {
38         if(!autocvar__hud_configure)
39         {
40                 if(!autocvar_hud_panel_physics) return;
41                 if(spectatee_status == -1 && (autocvar_hud_panel_physics == 1 || autocvar_hud_panel_physics == 3)) return;
42                 if(autocvar_hud_panel_physics == 3 && !MUTATOR_CALLHOOK(HUD_Physics_showoptional)) return;
43         }
44
45         HUD_Panel_LoadCvars();
46
47         draw_beginBoldFont();
48
49         if (autocvar_hud_panel_physics_dynamichud)
50                 HUD_Scale_Enable();
51         else
52                 HUD_Scale_Disable();
53         HUD_Panel_DrawBg();
54         if(panel_bg_padding)
55         {
56                 panel_pos += '1 1 0' * panel_bg_padding;
57                 panel_size -= '2 2 0' * panel_bg_padding;
58         }
59
60         float acceleration_progressbar_scale = 0;
61         if(autocvar_hud_panel_physics_progressbar && autocvar_hud_panel_physics_acceleration_progressbar_scale > 1)
62                 acceleration_progressbar_scale = autocvar_hud_panel_physics_acceleration_progressbar_scale;
63
64         float text_scale;
65         if (autocvar_hud_panel_physics_text_scale <= 0)
66                 text_scale = 1;
67         else
68                 text_scale = min(autocvar_hud_panel_physics_text_scale, 1);
69
70         //compute speed
71         float speed, conversion_factor = GetSpeedUnitFactor(autocvar_hud_panel_physics_speed_unit);
72         string unit = GetSpeedUnit(autocvar_hud_panel_physics_speed_unit);
73         vector vel = (csqcplayer ? csqcplayer.velocity : pmove_vel);
74
75         float max_speed = floor( autocvar_hud_panel_physics_speed_max * conversion_factor + 0.5 );
76         if (autocvar__hud_configure)
77                 speed = floor( max_speed * 0.65 + 0.5 );
78         else if(autocvar_hud_panel_physics_speed_vertical)
79                 speed = floor( vlen(vel) * conversion_factor + 0.5 );
80         else
81                 speed = floor( vlen(vel - vel.z * '0 0 1') * conversion_factor + 0.5 );
82
83         //compute acceleration
84         float acceleration, f;
85         if (autocvar__hud_configure)
86                 acceleration = autocvar_hud_panel_physics_acceleration_max * 0.3;
87         else
88         {
89                 // 1 m/s = 0.0254 qu/s; 1 g = 9.80665 m/s^2
90                 f = time - acc_prevtime;
91                 if(autocvar_hud_panel_physics_acceleration_vertical)
92                         acceleration = (vlen(vel) - vlen(acc_prevspeed));
93                 else
94                         acceleration = (vlen(vel - '0 0 1' * vel.z) - vlen(acc_prevspeed - '0 0 1' * acc_prevspeed.z));
95
96                 acceleration = acceleration * (1 / max(0.0001, f)) * (0.0254 / 9.80665);
97
98                 acc_prevspeed = vel;
99                 acc_prevtime = time;
100
101                 if(autocvar_hud_panel_physics_acceleration_movingaverage)
102                 {
103                         f = bound(0, f * 10, 1);
104                         acc_avg = acc_avg * (1 - f) + acceleration * f;
105                         acceleration = acc_avg;
106                 }
107         }
108
109         const int acc_decimals = 2;
110         if(time > physics_update_time)
111         {
112                 discrete_acceleration = acceleration;
113                 // workaround for ftos_decimals returning a negative 0
114                 if(discrete_acceleration > -1 / (10 ** acc_decimals) && discrete_acceleration < 0)
115                         discrete_acceleration = 0;
116                 discrete_speed = speed;
117                 physics_update_time += autocvar_hud_panel_physics_update_interval;
118                 if(physics_update_time < time)
119                         physics_update_time = time + autocvar_hud_panel_physics_update_interval;
120         }
121
122         //compute layout
123         float panel_ar = panel_size.x/panel_size.y;
124         vector speed_offset = '0 0 0', acceleration_offset = '0 0 0';
125         if (panel_ar >= 5 && !acceleration_progressbar_scale)
126         {
127                 panel_size.x *= 0.5;
128                 if (autocvar_hud_panel_physics_flip)
129                         speed_offset.x = panel_size.x;
130                 else
131                         acceleration_offset.x = panel_size.x;
132         }
133         else
134         {
135                 panel_size.y *= 0.5;
136                 if (autocvar_hud_panel_physics_flip)
137                         speed_offset.y = panel_size.y;
138                 else
139                         acceleration_offset.y = panel_size.y;
140         }
141         int speed_baralign, acceleration_baralign;
142         if (autocvar_hud_panel_physics_baralign == 1)
143                 acceleration_baralign = speed_baralign = 1;
144     else if(autocvar_hud_panel_physics_baralign == 4)
145                 acceleration_baralign = speed_baralign = 2;
146         else if (autocvar_hud_panel_physics_flip)
147         {
148                 acceleration_baralign = (autocvar_hud_panel_physics_baralign == 2);
149                 speed_baralign = (autocvar_hud_panel_physics_baralign == 3);
150         }
151         else
152         {
153                 speed_baralign = (autocvar_hud_panel_physics_baralign == 2);
154                 acceleration_baralign = (autocvar_hud_panel_physics_baralign == 3);
155         }
156         if (autocvar_hud_panel_physics_acceleration_progressbar_mode == 0)
157                 acceleration_baralign = 3; //override hud_panel_physics_baralign value for acceleration
158
159         //draw speed
160         if(speed)
161         if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
162                 HUD_Panel_DrawProgressBar(panel_pos + speed_offset, panel_size, "progressbar", speed/max_speed, 0, speed_baralign, autocvar_hud_progressbar_speed_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
163         vector tmp_offset = '0 0 0', tmp_size = '0 0 0';
164         if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
165         {
166                 tmp_size.x = panel_size.x * 0.75;
167                 tmp_size.y = panel_size.y * text_scale;
168                 if (speed_baralign)
169                         tmp_offset.x = panel_size.x - tmp_size.x;
170                 //else
171                         //tmp_offset_x = 0;
172                 tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
173                 drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(discrete_speed), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
174
175                 //draw speed unit
176                 if (speed_baralign)
177                         tmp_offset.x = 0;
178                 else
179                         tmp_offset.x = tmp_size.x;
180                 if (autocvar_hud_panel_physics_speed_unit_show)
181                 {
182                         //tmp_offset_y = 0;
183                         tmp_size.x = panel_size.x * (1 - 0.75);
184                         tmp_size.y = panel_size.y * 0.4 * text_scale;
185                         tmp_offset.y = (panel_size.y * 0.4 - tmp_size.y) / 2;
186                         drawstring_aspect(panel_pos + speed_offset + tmp_offset, unit, tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
187                 }
188         }
189
190         //compute and draw top speed
191         if (autocvar_hud_panel_physics_topspeed)
192         if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
193         {
194                 if (autocvar__hud_configure)
195                 {
196                         top_speed = floor( max_speed * 0.75 + 0.5 );
197                         f = 1;
198                 }
199                 else
200                 {
201                         if (speed >= top_speed)
202                         {
203                                 top_speed = speed;
204                                 top_speed_time = time;
205                         }
206                         if (top_speed != 0)
207                         {
208                                 f = max(1, autocvar_hud_panel_physics_topspeed_time);
209                                 // divide by f to make it start from 1
210                                 f = cos( ((time - top_speed_time) / f) * PI/2 );
211                         }
212             else //hide top speed 0, it would be stupid
213                                 f = 0;
214                 }
215                 if (f > 0)
216                 {
217                         //top speed progressbar peak
218                         if(speed < top_speed)
219                         if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
220                         {
221                                 float peak_offsetX;
222                                 vector peak_size = '0 0 0';
223                                 if (speed_baralign == 0)
224                                         peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x;
225                 else if (speed_baralign == 1)
226                                         peak_offsetX = (1 - min(top_speed, max_speed)/max_speed) * panel_size.x;
227                 else // if (speed_baralign == 2)
228                     peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x * 0.5;
229                                 peak_size.x = floor(panel_size.x * 0.01 + 1.5);
230                 peak_size.y = panel_size.y;
231                 if (speed_baralign == 2) // draw two peaks, on both sides
232                 {
233                     drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x + peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
234                     drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x - peak_offsetX + peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
235                 }
236                 else
237                     drawfill(panel_pos + speed_offset + eX * (peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
238                         }
239
240                         //top speed
241                         tmp_offset.y = panel_size.y * 0.4;
242                         tmp_size.x = panel_size.x * (1 - 0.75);
243                         tmp_size.y = (panel_size.y - tmp_offset.y) * text_scale;
244                         tmp_offset.y += (panel_size.y - tmp_offset.y - tmp_size.y) / 2;
245                         drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(top_speed), tmp_size, '1 0 0', f * panel_fg_alpha, DRAWFLAG_NORMAL);
246                 }
247                 else
248                         top_speed = 0;
249         }
250
251         //draw acceleration
252         if(acceleration)
253         if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 3)
254         {
255                 vector progressbar_color;
256                 if(acceleration < 0)
257                         progressbar_color = autocvar_hud_progressbar_acceleration_neg_color;
258                 else
259                         progressbar_color = autocvar_hud_progressbar_acceleration_color;
260
261                 f = acceleration/autocvar_hud_panel_physics_acceleration_max;
262                 if (autocvar_hud_panel_physics_acceleration_progressbar_nonlinear)
263                         f = (f >= 0 ? sqrt(f) : -sqrt(-f));
264
265                 if (acceleration_progressbar_scale) // allow progressbar to go out of panel bounds
266                 {
267                         tmp_size = acceleration_progressbar_scale * panel_size.x * eX + panel_size.y * eY;
268
269                         if (acceleration_baralign == 1)
270                                 tmp_offset.x = panel_size.x - tmp_size.x;
271                         else if (acceleration_baralign == 2 || acceleration_baralign == 3)
272                                 tmp_offset.x = (panel_size.x - tmp_size.x) / 2;
273                         else
274                                 tmp_offset.x = 0;
275                         tmp_offset.y = 0;
276                 }
277                 else
278                 {
279                         tmp_size = panel_size;
280                         tmp_offset = '0 0 0';
281                 }
282
283                 HUD_Panel_DrawProgressBar(panel_pos + acceleration_offset + tmp_offset, tmp_size, "accelbar", f, 0, acceleration_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
284         }
285
286         if(autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 3)
287         {
288                 tmp_size.x = panel_size.x;
289                 tmp_size.y = panel_size.y * text_scale;
290                 tmp_offset.x = 0;
291                 tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
292
293                 drawstring_aspect(panel_pos + acceleration_offset + tmp_offset, strcat(ftos_decimals(discrete_acceleration, acc_decimals), "g"), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
294         }
295
296         draw_endBoldFont();
297 }