waypointsprites: support v_flipped correctly
[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
20 vector SPRITE_SIZE = '128 32 0';
21 vector SPRITE_HOTSPOT = '64 32 0';
22
23 void drawrotpic(vector org, float rot, string pic, vector sz, vector hotspot, vector rgb, float a, float f)
24 {
25         vector v1, v2, v3, v4;
26
27         hotspot = -1 * hotspot;
28
29         // hotspot-relative coordinates of the corners
30         v1 = hotspot;
31         v2 = hotspot + '1 0 0' * sz_x;
32         v3 = hotspot + '1 0 0' * sz_x + '0 1 0' * sz_y;
33         v4 = hotspot                  + '0 1 0' * sz_y;
34
35         // rotate them, and make them absolute
36         rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
37         v1 = rotate(v1, rot) + org;
38         v2 = rotate(v2, rot) + org;
39         v3 = rotate(v3, rot) + org;
40         v4 = rotate(v4, rot) + org;
41
42         // draw them
43         R_BeginPolygon(pic, f);
44         R_PolygonVertex(v1, '0 0 0', rgb, a);
45         R_PolygonVertex(v2, '1 0 0', rgb, a);
46         R_PolygonVertex(v3, '1 1 0', rgb, a);
47         R_PolygonVertex(v4, '0 1 0', rgb, a);
48         R_EndPolygon();
49 }
50
51 void Draw_WaypointSprite()
52 {
53         string spriteimage;
54         float t;
55
56         if(self.lifetime)
57                 self.alpha = pow(bound(0, (self.fadetime - time) / self.lifetime, 1), waypointsprite_timealphaexponent);
58         else
59                 self.alpha = 1;
60
61         if(self.hideflags & 2)
62                 return; // radar only
63
64         if(cvar("cl_hidewaypoints") >= 2)
65                 return;
66
67         if(self.hideflags & 1)
68                 if(cvar("cl_hidewaypoints"))
69                         return; // fixed waypoint
70
71         InterpolateOrigin_Do();
72
73         t = GetPlayerColor(player_localentnum - 1) + 1;
74
75         spriteimage = "";
76
77         // choose the sprite
78         switch(self.rule)
79         {
80                 case SPRITERULE_DEFAULT:
81                         if(self.team)
82                         {
83                                 if(self.team == t)
84                                         spriteimage = self.netname;
85                                 else
86                                         spriteimage = "";
87                         }
88                         else
89                                 spriteimage = self.netname;
90                         break;
91                 case SPRITERULE_TEAMPLAY:
92                         if(t == COLOR_SPECTATOR + 1)
93                                 spriteimage = self.netname3;
94                         else if(self.team == t)
95                                 spriteimage = self.netname2;
96                         else
97                                 spriteimage = self.netname;
98                         break;
99                 default:
100                         error("Invalid waypointsprite rule!");
101                         break;
102         }
103
104         if(spriteimage == "")
105                 return;
106         
107         float dist;
108         dist = vlen(self.origin - view_origin);
109         
110         float a;
111         a = self.alpha;
112
113         if(self.maxdistance > waypointsprite_normdistance)
114                 a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
115         else if(self.maxdistance > 0)
116                 a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
117
118         if(a <= 0)
119                 return;
120         
121         // draw the sprite image
122         vector o;
123         float rot;
124         o = project_3d_to_2d(self.origin);
125         rot = 0;
126
127         if(o_z < 0 || o_x < 0 || o_y < 0 || o_x > vid_conwidth || o_y > vid_conheight)
128         {
129                 // scale it to be just in view
130                 vector d;
131                 float f1, f2;
132
133                 // get the waypoint angle vector
134                 d_x = view_right * (self.origin - view_origin) * vid_conwidth / vid_width;
135                 d_y = -view_up * (self.origin - view_origin) * vid_conheight / (vid_height * vid_pixelheight);
136                 d_z = 0;
137                 
138                 //d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
139
140                 if(cvar("v_flipped"))
141                         d_x = -d_x;
142
143                 f1 = d_x / vid_conwidth;
144                 f2 = d_y / vid_conheight;
145
146                 if(max(f1, -f1) > max(f2, -f2))
147                 {
148                         if(f1 > 0)
149                         {
150                                 // RIGHT edge
151                                 d = d * (0.5 / f1);
152                                 rot = 3;
153                         }
154                         else
155                         {
156                                 // LEFT edge
157                                 d = d * (-0.5 / f1);
158                                 rot = 1;
159                         }
160                 }
161                 else
162                 {
163                         if(f2 > 0)
164                         {
165                                 // BOTTOM edge
166                                 d = d * (0.5 / f2);
167                                 rot = 0;
168                         }
169                         else
170                         {
171                                 // TOP edge
172                                 d = d * (-0.5 / f2);
173                                 rot = 2;
174                         }
175                 }
176
177                 o = d + '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
178         }
179         o_z = 0;
180
181         float vidscale;
182         vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
183
184         t = stof(db_get(tempdb, strcat("/spriteframes/", spriteimage)));
185         if(t == 0)
186                 spriteimage = strcat("models/sprites/", spriteimage);
187         else
188                 spriteimage = strcat("models/sprites/", spriteimage, "_frame", ftos(mod(floor(time * 2), t)));
189
190         drawrotpic(o, rot * 90 * DEG2RAD, spriteimage, SPRITE_SIZE * waypointsprite_scale * vidscale, SPRITE_HOTSPOT * waypointsprite_scale * vidscale, '1 1 1', a, DRAWFLAG_MIPMAP);
191 }
192
193 void Ent_RemoveWaypointSprite()
194 {
195         if(self.netname)
196                 strunzone(self.netname);
197         if(self.netname2)
198                 strunzone(self.netname2);
199         if(self.netname3)
200                 strunzone(self.netname3);
201 }
202
203 void Ent_WaypointSprite()
204 {
205         float sendflags, f;
206         sendflags = ReadByte();
207
208         self.draw2d = Draw_WaypointSprite;
209
210         InterpolateOrigin_Undo();
211
212         if(sendflags & 64)
213         {
214                 // unfortunately, this needs to be exact (for the 3D display)
215                 self.origin_x = ReadCoord();
216                 self.origin_y = ReadCoord();
217                 self.origin_z = ReadCoord();
218         }
219
220         if(sendflags & 1)
221         {
222                 self.team = ReadByte();
223                 self.rule = ReadByte();
224         }
225
226         if(sendflags & 2)
227         {
228                 if(self.netname)
229                         strunzone(self.netname);
230                 self.netname = strzone(ReadString());
231         }
232
233         if(sendflags & 4)
234         {
235                 if(self.netname2)
236                         strunzone(self.netname2);
237                 self.netname2 = strzone(ReadString());
238         }
239
240         if(sendflags & 8)
241         {
242                 if(self.netname3)
243                         strunzone(self.netname3);
244                 self.netname3 = strzone(ReadString());
245         }
246
247         if(sendflags & 16)
248         {
249                 self.lifetime = ReadCoord();
250                 self.fadetime = ReadCoord();
251                 self.maxdistance = ReadShort();
252                 self.hideflags = ReadByte();
253         }
254
255         if(sendflags & 32)
256         {
257                 f = ReadByte();
258                 self.teamradar_icon = (f & 0x7F);
259                 if(f & 0x80)
260                 {
261                         self.(teamradar_times[self.teamradar_time_index]) = time;
262                         self.teamradar_time_index = mod(self.teamradar_time_index + 1, MAX_TEAMRADAR_TIMES);
263                 }
264                 self.teamradar_color_x = ReadByte() / 255.0;
265                 self.teamradar_color_y = ReadByte() / 255.0;
266                 self.teamradar_color_z = ReadByte() / 255.0;
267         }
268
269         InterpolateOrigin_Note();
270
271         self.entremove = Ent_RemoveWaypointSprite;
272 }
273
274 void WaypointSprite_Load()
275 {
276         waypointsprite_fadedistance = vlen(world.maxs - world.mins);
277         waypointsprite_normdistance = cvar("g_waypointsprite_normdistance");
278         waypointsprite_minscale = cvar("g_waypointsprite_minscale");
279         waypointsprite_minalpha = cvar("g_waypointsprite_minalpha");
280         waypointsprite_distancealphaexponent = cvar("g_waypointsprite_distancealphaexponent");
281         waypointsprite_timealphaexponent = cvar("g_waypointsprite_timealphaexponent");
282         waypointsprite_scale = cvar("g_waypointsprite_scale");
283         if(!waypointsprite_scale)
284                 waypointsprite_scale = 1.0;
285
286         if(!waypointsprite_initialized)
287         {
288                 float dh, n, i, o, f;
289                 string s, sname, sframes;
290                 dh = search_begin("models/sprites/*_frame*.tga", FALSE, FALSE);
291                 n = search_getsize(dh);
292                 for(i = 0; i < n; ++i)
293                 {
294                         s = search_getfilename(dh, i);
295                         if(substring(s, 0, 15) != "models/sprites/")
296                                 continue;
297                         if(substring(s, strlen(s) - 4, 4) != ".tga")
298                                 continue;
299                         s = substring(s, 15, strlen(s) - 19);
300
301                         o = strstrofs(s, "_frame", 0);
302                         sname = strcat("/spriteframes/", substring(s, 0, o));
303                         sframes = substring(s, o + 6, strlen(s) - o - 6);
304                         f = stof(sframes) + 1;
305                         db_put(tempdb, sname, ftos(max(f, stof(db_get(tempdb, sname)))));
306                 }
307                 search_end(dh);
308         }
309         waypointsprite_initialized = 1;
310 }