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