]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/waypointsprites.qc
Some ground work for screen offsets for waypointsprites -- doesn't work right now...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / waypointsprites.qc
1 float waypointsprite_initialized;
2 float waypointsprite_fadedistance;
3 float waypointsprite_normdistance;
4 float waypointsprite_minscale;
5 float waypointsprite_minalpha;
6 float waypointsprite_distancealphaexponent;
7 float waypointsprite_timealphaexponent;
8 float waypointsprite_scale;
9 float waypointsprite_edgefadealpha;
10 float waypointsprite_edgefadescale;
11 float waypointsprite_edgefadedistance;
12 float waypointsprite_edgeoffset_x;
13 float waypointsprite_edgeoffset_y;
14 float waypointsprite_crosshairfadealpha;
15 float waypointsprite_crosshairfadescale;
16 float waypointsprite_crosshairfadedistance;
17 float waypointsprite_distancefadealpha;
18 float waypointsprite_distancefadescale;
19 float waypointsprite_distancefadedistance;
20 float waypointsprite_alpha;
21
22 .float rule;
23 .string netname; // primary picture
24 .string netname2; // secondary picture
25 .string netname3; // tertiary picture
26 .float team; // team that gets netname2
27 .float lifetime;
28 .float fadetime;
29 .float maxdistance;
30 .float hideflags;
31 .float spawntime;
32 .float health;
33 .float build_started;
34 .float build_starthealth;
35 .float build_finished;
36
37 vector SPRITE_SIZE = '288 36 0';
38 vector SPRITE_HOTSPOT = '144 36 0';
39 float SPRITE_HEALTHBAR_WIDTH = 144;
40 float SPRITE_HEALTHBAR_HEIGHT = 9;
41 float SPRITE_HEALTHBAR_MARGIN = 6;
42 float SPRITE_HEALTHBAR_BORDER = 2;
43 float SPRITE_HEALTHBAR_BORDERALPHA = 1;
44 float SPRITE_HEALTHBAR_HEALTHALPHA = 0.5;
45
46 void drawrotpic(vector org, float rot, string pic, vector sz, vector hotspot, vector rgb, float a, float f)
47 {
48         vector v1, v2, v3, v4;
49
50         hotspot = -1 * hotspot;
51
52         // hotspot-relative coordinates of the corners
53         v1 = hotspot;
54         v2 = hotspot + '1 0 0' * sz_x;
55         v3 = hotspot + '1 0 0' * sz_x + '0 1 0' * sz_y;
56         v4 = hotspot                  + '0 1 0' * sz_y;
57
58         // rotate them, and make them absolute
59         rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
60         v1 = rotate(v1, rot) + org;
61         v2 = rotate(v2, rot) + org;
62         v3 = rotate(v3, rot) + org;
63         v4 = rotate(v4, rot) + org;
64
65         // draw them
66         R_BeginPolygon(pic, f);
67         R_PolygonVertex(v1, '0 0 0', rgb, a);
68         R_PolygonVertex(v2, '1 0 0', rgb, a);
69         R_PolygonVertex(v3, '1 1 0', rgb, a);
70         R_PolygonVertex(v4, '0 1 0', rgb, a);
71         R_EndPolygon();
72 }
73
74 void drawquad(vector o, vector ri, vector up, string pic, vector rgb, float a, float f)
75 {
76         R_BeginPolygon(pic, f);
77         R_PolygonVertex(o, '0 0 0', rgb, a);
78         R_PolygonVertex(o + ri, '1 0 0', rgb, a);
79         R_PolygonVertex(o + up + ri, '1 1 0', rgb, a);
80         R_PolygonVertex(o + up, '0 1 0', rgb, a);
81         R_EndPolygon();
82 }
83
84 void drawhealthbar(vector org, float rot, float h, vector sz, vector hotspot, float width, float height, float margin, float border, float align, vector rgb, float a, vector hrgb, float ha, float f)
85 {
86         vector o, ri, up;
87         float owidth; // outer width
88
89         hotspot = -1 * hotspot;
90
91         // hotspot-relative coordinates of the healthbar corners
92         o = hotspot;
93         ri = '1 0 0';
94         up = '0 1 0';
95         
96         rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
97         o = rotate(o, rot) + org;
98         ri = rotate(ri, rot);
99         up = rotate(up, rot);
100
101         owidth = width + 2 * border;
102         o = o - up * (margin + border + height) + ri * (sz_x - owidth) * 0.5;
103
104         drawquad(o - up * border,                               ri * owidth,    up * border, "", rgb,  a,  f);
105         drawquad(o + up * height,                               ri * owidth,    up * border, "", rgb,  a,  f);
106         drawquad(o,                                             ri * border,    up * height, "", rgb,  a,  f);
107         drawquad(o + ri * (owidth - border),                    ri * border,    up * height, "", rgb,  a,  f);
108         drawquad(o + ri * (border + align * ((1 - h) * width)), ri * width * h, up * height, "", hrgb, ha, f);
109 }
110
111 void Draw_WaypointSprite()
112 {
113         string spriteimage;
114         float t;
115
116         if(self.lifetime)
117                 self.alpha = pow(bound(0, (self.fadetime - time) / self.lifetime, 1), waypointsprite_timealphaexponent);
118         else
119                 self.alpha = 1;
120
121         if(self.hideflags & 2)
122                 return; // radar only
123
124         if(autocvar_cl_hidewaypoints >= 2)
125                 return;
126
127         if(self.hideflags & 1)
128                 if(autocvar_cl_hidewaypoints)
129                         return; // fixed waypoint
130
131         InterpolateOrigin_Do();
132
133         t = GetPlayerColor(player_localentnum - 1) + 1;
134
135         spriteimage = "";
136
137         // choose the sprite
138         switch(self.rule)
139         {
140                 case SPRITERULE_DEFAULT:
141                         if(self.team)
142                         {
143                                 if(self.team == t)
144                                         spriteimage = self.netname;
145                                 else
146                                         spriteimage = "";
147                         }
148                         else
149                                 spriteimage = self.netname;
150                         break;
151                 case SPRITERULE_TEAMPLAY:
152                         if(t == COLOR_SPECTATOR + 1)
153                                 spriteimage = self.netname3;
154                         else if(self.team == t)
155                                 spriteimage = self.netname2;
156                         else
157                                 spriteimage = self.netname;
158                         break;
159                 default:
160                         error("Invalid waypointsprite rule!");
161                         break;
162         }
163
164         if(spriteimage == "")
165                 return;
166         
167         float dist;
168         dist = vlen(self.origin - view_origin);
169         
170         float a;
171         a = self.alpha * autocvar_hud_panel_fg_alpha;
172
173         if(self.maxdistance > waypointsprite_normdistance)
174                 a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
175         else if(self.maxdistance > 0)
176                 a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
177
178         if(a <= 0)
179                 return;
180         
181         // draw the sprite image
182         vector o;
183         float rot;
184         o = project_3d_to_2d(self.origin);
185         rot = 0;
186
187         print("origin: ", vtos(o), ", edgeoffsets: ", ftos(waypointsprite_edgeoffset_x), " - ", ftos(autocvar_g_waypointsprite_edgeoffset_x), ". \n");
188
189         if(o_z < 0 
190         || o_x < (vid_conwidth * waypointsprite_edgeoffset_x) 
191         || o_y < (vid_conheight * waypointsprite_edgeoffset_y) 
192         || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_x))  
193         || o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_y)))
194         {
195                 // scale it to be just in view
196                 vector d;
197                 float f1, f2;
198
199                 // get the waypoint angle vector
200                 /*
201                 d_x = view_right * (self.origin - view_origin) * vid_conwidth / vid_width;
202                 d_y = -view_up * (self.origin - view_origin) * vid_conheight / (vid_height * vid_pixelheight);
203                 d_z = 0;
204                 */
205                 
206                 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
207
208                 /*
209                 if(autocvar_v_flipped)
210                         d_x = -d_x;
211                 */
212
213                 f1 = d_x / vid_conwidth;
214                 f2 = d_y / vid_conheight;
215
216                 if(max(f1, -f1) > max(f2, -f2))
217                 {
218                         if(d_z * f1 > 0)
219                         {
220                                 // RIGHT edge
221                                 d = d * ((0.5 - waypointsprite_edgeoffset_x) / f1);
222                                 rot = 3;
223                         }
224                         else
225                         {
226                                 // LEFT edge
227                                 d = d * (-(0.5 - waypointsprite_edgeoffset_x) / f1);
228                                 rot = 1;
229                         }
230                 }
231                 else
232                 {
233                         if(d_z * f2 > 0)
234                         {
235                                 // BOTTOM edge
236                                 d = d * ((0.5 - waypointsprite_edgeoffset_y) / f2);
237                                 rot = 0;
238                         }
239                         else
240                         {
241                                 // TOP edge
242                                 d = d * (-(0.5 - waypointsprite_edgeoffset_y) / f2);
243                                 rot = 2;
244                         }
245                 }
246
247                 o = d + '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
248         }
249         o_z = 0;
250
251         float vidscale;
252         vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
253
254         t = stof(db_get(tempdb, strcat("/spriteframes/", spriteimage)));
255         if(t == 0)
256                 spriteimage = strcat("models/sprites/", spriteimage);
257         else
258                 spriteimage = strcat("models/sprites/", spriteimage, "_frame", ftos(mod(floor((max(0, time - self.spawntime)) * 2), t)));
259
260         float edgedistance_min, crosshairdistance;
261         edgedistance_min = min4(o_y, o_x,vid_conwidth - o_x, vid_conheight - o_y);
262
263         crosshairdistance = sqrt( pow(o_x - vid_conwidth/2, 2) + pow(o_y - vid_conheight/2, 2) );
264
265         t = waypointsprite_scale * vidscale;
266         a *= waypointsprite_alpha;
267
268         {
269                 a = a * (1 - (1 - waypointsprite_distancefadealpha) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
270                 t = t * (1 - (1 - waypointsprite_distancefadescale) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
271         }
272         if (edgedistance_min < waypointsprite_edgefadedistance) {
273                 a = a * (1 - (1 - waypointsprite_edgefadealpha) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
274                 t = t * (1 - (1 - waypointsprite_edgefadescale) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
275         }
276         if(crosshairdistance < waypointsprite_crosshairfadedistance) {
277                 a = a * (1 - (1 - waypointsprite_crosshairfadealpha) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
278                 t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
279         }
280         drawrotpic(o, rot * 90 * DEG2RAD, spriteimage, SPRITE_SIZE * t, SPRITE_HOTSPOT * t, '1 1 1', a, DRAWFLAG_MIPMAP);
281
282         if(self.build_finished)
283         {
284                 if(time < self.build_finished + 0.25)
285                 {
286                         if(time < self.build_started)
287                                 self.health = self.build_starthealth;
288                         else if(time < self.build_finished)
289                                 self.health = (time - self.build_started) / (self.build_finished - self.build_started) * (1 - self.build_starthealth) + self.build_starthealth;
290                         else
291                                 self.health = 1;
292                 }
293                 else
294                         self.health = -1;
295         }
296
297         if(self.health >= 0)
298         {
299                 float align;
300                 if(self.build_finished)
301                         align = 0.5;
302                 else
303                         align = 0;
304                 drawhealthbar(o, rot * 90 * DEG2RAD, self.health, SPRITE_SIZE * t, SPRITE_HOTSPOT * t, SPRITE_HEALTHBAR_WIDTH * t, SPRITE_HEALTHBAR_HEIGHT * t, SPRITE_HEALTHBAR_MARGIN * t, SPRITE_HEALTHBAR_BORDER * t, align, self.teamradar_color, a * SPRITE_HEALTHBAR_BORDERALPHA, self.teamradar_color, a * SPRITE_HEALTHBAR_HEALTHALPHA, DRAWFLAG_NORMAL);
305         }
306 }
307
308 void Ent_RemoveWaypointSprite()
309 {
310         if(self.netname)
311                 strunzone(self.netname);
312         if(self.netname2)
313                 strunzone(self.netname2);
314         if(self.netname3)
315                 strunzone(self.netname3);
316 }
317
318 void Ent_WaypointSprite()
319 {
320         float sendflags, f, t;
321         sendflags = ReadByte();
322
323         if(!self.spawntime)
324                 self.spawntime = time;
325
326         self.draw2d = Draw_WaypointSprite;
327
328         InterpolateOrigin_Undo();
329
330         if(sendflags & 0x80)
331         {
332                 t = ReadByte();
333                 if(t < 192)
334                 {
335                         self.health = t / 191.0;
336                         self.build_finished = 0;
337                 }
338                 else
339                 {
340                         t = (t - 192) * 256 + ReadByte();
341                         self.build_started = servertime;
342                         if(self.build_finished)
343                                 self.build_starthealth = bound(0, self.health, 1);
344                         else
345                                 self.build_starthealth = 0;
346                         self.build_finished = servertime + t / 32;
347                 }
348         }
349         else
350         {
351                 self.health = -1;
352                 self.build_finished = 0;
353         }
354
355         if(sendflags & 64)
356         {
357                 // unfortunately, this needs to be exact (for the 3D display)
358                 self.origin_x = ReadCoord();
359                 self.origin_y = ReadCoord();
360                 self.origin_z = ReadCoord();
361         }
362
363         if(sendflags & 1)
364         {
365                 self.team = ReadByte();
366                 self.rule = ReadByte();
367         }
368
369         if(sendflags & 2)
370         {
371                 if(self.netname)
372                         strunzone(self.netname);
373                 self.netname = strzone(ReadString());
374         }
375
376         if(sendflags & 4)
377         {
378                 if(self.netname2)
379                         strunzone(self.netname2);
380                 self.netname2 = strzone(ReadString());
381         }
382
383         if(sendflags & 8)
384         {
385                 if(self.netname3)
386                         strunzone(self.netname3);
387                 self.netname3 = strzone(ReadString());
388         }
389
390         if(sendflags & 16)
391         {
392                 self.lifetime = ReadCoord();
393                 self.fadetime = ReadCoord();
394                 self.maxdistance = ReadShort();
395                 self.hideflags = ReadByte();
396         }
397
398         if(sendflags & 32)
399         {
400                 f = ReadByte();
401                 self.teamradar_icon = (f & 0x7F);
402                 if(f & 0x80)
403                 {
404                         self.(teamradar_times[self.teamradar_time_index]) = time;
405                         self.teamradar_time_index = mod(self.teamradar_time_index + 1, MAX_TEAMRADAR_TIMES);
406                 }
407                 self.teamradar_color_x = ReadByte() / 255.0;
408                 self.teamradar_color_y = ReadByte() / 255.0;
409                 self.teamradar_color_z = ReadByte() / 255.0;
410         }
411
412         InterpolateOrigin_Note();
413
414         self.entremove = Ent_RemoveWaypointSprite;
415 }
416
417 void WaypointSprite_Load()
418 {
419         waypointsprite_fadedistance = vlen(mi_scale);
420         waypointsprite_normdistance = autocvar_g_waypointsprite_normdistance;
421         waypointsprite_minscale = autocvar_g_waypointsprite_minscale;
422         waypointsprite_minalpha = autocvar_g_waypointsprite_minalpha;
423         waypointsprite_distancealphaexponent = autocvar_g_waypointsprite_distancealphaexponent;
424         waypointsprite_timealphaexponent = autocvar_g_waypointsprite_timealphaexponent;
425         waypointsprite_scale = autocvar_g_waypointsprite_scale;
426         waypointsprite_edgefadealpha = autocvar_g_waypointsprite_edgefadealpha;
427         waypointsprite_edgefadescale = autocvar_g_waypointsprite_edgefadescale;
428         waypointsprite_edgefadedistance = autocvar_g_waypointsprite_edgefadedistance;
429         waypointsprite_edgeoffset_x = autocvar_g_waypointsprite_edgeoffset_x;
430         waypointsprite_edgeoffset_y = autocvar_g_waypointsprite_edgeoffset_y;
431         waypointsprite_crosshairfadealpha = autocvar_g_waypointsprite_crosshairfadealpha;
432         waypointsprite_crosshairfadescale = autocvar_g_waypointsprite_crosshairfadescale;
433         waypointsprite_crosshairfadedistance = autocvar_g_waypointsprite_crosshairfadedistance;
434         waypointsprite_distancefadealpha = autocvar_g_waypointsprite_distancefadealpha;
435         waypointsprite_distancefadescale = autocvar_g_waypointsprite_distancefadescale;
436         waypointsprite_distancefadedistance = waypointsprite_fadedistance * autocvar_g_waypointsprite_distancefadedistancemultiplier;
437         waypointsprite_alpha = autocvar_g_waypointsprite_alpha * (1 - autocvar__menu_alpha);
438
439         if(!waypointsprite_initialized)
440         {
441                 float dh, n, i, o, f;
442                 string s, sname, sframes;
443
444                 dh = search_begin("models/sprites/*_frame*.tga", FALSE, FALSE);
445                 n = search_getsize(dh);
446                 for(i = 0; i < n; ++i)
447                 {
448                         s = search_getfilename(dh, i);
449                         s = substring(s, 15, strlen(s) - 15 - 4); // strip models/sprites/ and .tga
450
451                         o = strstrofs(s, "_frame", 0);
452                         sname = strcat("/spriteframes/", substring(s, 0, o));
453                         sframes = substring(s, o + 6, strlen(s) - o - 6);
454                         f = stof(sframes) + 1;
455                         db_put(tempdb, sname, ftos(max(f, stof(db_get(tempdb, sname)))));
456                 }
457                 search_end(dh);
458
459                 dh = search_begin("models/sprites/*_frame*.jpg", FALSE, FALSE);
460                 n = search_getsize(dh);
461                 for(i = 0; i < n; ++i)
462                 {
463                         s = search_getfilename(dh, i);
464                         s = substring(s, 15, strlen(s) - 15 - 4); // strip models/sprites/ and .jpg
465
466                         o = strstrofs(s, "_frame", 0);
467                         sname = strcat("/spriteframes/", substring(s, 0, o));
468                         sframes = substring(s, o + 6, strlen(s) - o - 6);
469                         f = stof(sframes) + 1;
470                         db_put(tempdb, sname, ftos(max(f, stof(db_get(tempdb, sname)))));
471                 }
472                 search_end(dh);
473                 waypointsprite_initialized = true;
474         }
475 }