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