]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/client/waypointsprites.qc
work around engine crash by drawing 2D polygons after R_RenderView() (i.e. forcing...
[divverent/nexuiz.git] / data / qcsrc / client / waypointsprites.qc
1 vector project_3d_to_2d(vector vec)
2
3         vec = cs_project(vec);
4         if(cs_project_is_b0rked)
5         {
6                 vec_x += vid_width / 2;
7                 vec_y += vid_height / 2;
8         }
9         vec_x *= vid_conwidth / vid_width;
10         vec_y *= vid_conheight / vid_height;
11         return vec;
12 }
13
14 float waypointsprite_fadedistance;
15 float waypointsprite_normdistance;
16 float waypointsprite_minscale;
17 float waypointsprite_minalpha;
18 float waypointsprite_distancealphaexponent;
19 float waypointsprite_timealphaexponent;
20 float waypointsprite_scale;
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
32 vector SPRITE_SIZE = '128 32 0';
33 vector SPRITE_HOTSPOT = '64 32 0';
34
35 void drawrotpic(vector org, float rot, string pic, vector sz, vector hotspot, vector rgb, float a, float f)
36 {
37         vector v1, v2, v3, v4;
38
39         hotspot = -1 * hotspot;
40
41         // hotspot-relative coordinates of the corners
42         v1 = hotspot;
43         v2 = hotspot + '1 0 0' * sz_x;
44         v3 = hotspot + '1 0 0' * sz_x + '0 1 0' * sz_y;
45         v4 = hotspot                  + '0 1 0' * sz_y;
46
47         // rotate them, and make them absolute
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 Draw_WaypointSprite()
63 {
64         string spriteimage;
65         float t;
66
67         if(self.lifetime)
68                 self.alpha = pow(bound(0, (self.fadetime - time) / self.lifetime, 1), waypointsprite_timealphaexponent);
69         else
70                 self.alpha = 1;
71
72         if(self.hideflags & 2)
73                 return; // radar only
74
75         if(cvar("cl_hidewaypoints") >= 2)
76                 return;
77
78         if(self.hideflags & 1)
79                 if(cvar("cl_hidewaypoints"))
80                         return; // fixed waypoint
81
82         InterpolateOrigin_Do();
83
84         t = GetPlayerColor(player_localentnum - 1) + 1;
85
86         spriteimage = "";
87
88         // choose the sprite
89         switch(self.rule)
90         {
91                 case SPRITERULE_DEFAULT:
92                         spriteimage = self.netname;
93                         break;
94                 case SPRITERULE_TEAMPLAY:
95                         if(self.team == t)
96                                 spriteimage = self.netname2;
97                         else
98                                 spriteimage = self.netname;
99                         break;
100                 default:
101                         error("Invalid waypointsprite rule!");
102                         break;
103         }
104
105         if(spriteimage == "")
106                 return;
107         
108         float dist;
109         dist = vlen(self.origin - view_origin);
110         
111         float a;
112         a = self.alpha;
113
114         if(self.maxdistance > waypointsprite_normdistance)
115                 a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
116         else if(self.maxdistance > 0)
117                 a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
118
119         if(a <= 0)
120                 return;
121         
122         // draw the sprite image
123         vector o;
124         float rot;
125         o = project_3d_to_2d(self.origin);
126         rot = 0;
127
128         if(o_z < 0 || o_x < 0 || o_y < 0 || o_x > vid_conwidth || o_y > vid_conheight)
129         {
130                 // scale it to be just in view
131                 vector d;
132                 float f1, f2;
133                 d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
134
135                 f1 = d_x / vid_conwidth;
136                 f2 = d_y / vid_conheight;
137
138                 if(max(f1, -f1) > max(f2, -f2))
139                 {
140                         if(f1 > 0)
141                         {
142                                 // RIGHT edge
143                                 d = d * (0.5 / f1);
144                                 rot = 1;
145                         }
146                         else
147                         {
148                                 // LEFT edge
149                                 d = d * (-0.5 / f1);
150                                 rot = 3;
151                         }
152                 }
153                 else
154                 {
155                         if(f2 > 0)
156                         {
157                                 // BOTTOM edge
158                                 d = d * (0.5 / f2);
159                                 rot = 0;
160                         }
161                         else
162                         {
163                                 // TOP edge
164                                 d = d * (-0.5 / f2);
165                                 rot = 2;
166                         }
167                 }
168
169                 o = d + '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
170         }
171         o_z = 0;
172
173         drawrotpic(o, rot * 90 * DEG2RAD, strcat("models/sprites/", spriteimage), SPRITE_SIZE * waypointsprite_scale, SPRITE_HOTSPOT * waypointsprite_scale, '1 1 1', a, 0);
174 }
175
176 void Ent_WaypointSprite()
177 {
178         float sendflags, f;
179         sendflags = ReadByte();
180
181         self.draw2d = Draw_WaypointSprite;
182
183         InterpolateOrigin_Undo();
184
185         // unfortunately, this needs to be exact (for the 3D display)
186         self.origin_x = ReadCoord();
187         self.origin_y = ReadCoord();
188         self.origin_z = ReadCoord();
189
190         if(sendflags & 1)
191         {
192                 self.team = ReadByte();
193                 self.rule = ReadByte();
194         }
195
196         if(sendflags & 2)
197         {
198                 if(self.netname)
199                         strunzone(self.netname);
200                 self.netname = strzone(ReadString());
201         }
202
203         if(sendflags & 4)
204         {
205                 if(self.netname2)
206                         strunzone(self.netname2);
207                 self.netname2 = strzone(ReadString());
208         }
209
210         if(sendflags & 8)
211         {
212                 if(self.netname3)
213                         strunzone(self.netname3);
214                 self.netname3 = strzone(ReadString());
215         }
216
217         if(sendflags & 16)
218         {
219                 self.lifetime = ReadCoord();
220                 self.fadetime = ReadCoord();
221                 self.maxdistance = ReadShort();
222                 self.hideflags = ReadByte();
223         }
224
225         if(sendflags & 32)
226         {
227                 f = ReadByte();
228                 self.teamradar_icon = (f & 0x7F);
229                 if(f & 0x80)
230                         self.teamradar_time = time;
231                 self.teamradar_color_x = ReadByte() / 255.0;
232                 self.teamradar_color_y = ReadByte() / 255.0;
233                 self.teamradar_color_z = ReadByte() / 255.0;
234         }
235
236         InterpolateOrigin_Note();
237 }
238
239 void Ent_RemoveWaypointSprite()
240 {
241         if(self.netname)
242                 strunzone(self.netname);
243         if(self.netname2)
244                 strunzone(self.netname2);
245         if(self.netname3)
246                 strunzone(self.netname3);
247 }
248
249 void WaypointSprite_Load()
250 {
251         waypointsprite_fadedistance = vlen(world.maxs - world.mins);
252         waypointsprite_normdistance = cvar("g_waypointsprite_normdistance");
253         waypointsprite_minscale = cvar("g_waypointsprite_minscale");
254         waypointsprite_minalpha = cvar("g_waypointsprite_minalpha");
255         waypointsprite_distancealphaexponent = cvar("g_waypointsprite_distancealphaexponent");
256         waypointsprite_timealphaexponent = cvar("g_waypointsprite_timealphaexponent");
257         waypointsprite_scale = cvar("g_waypointsprite_scale");
258         if(!waypointsprite_scale)
259                 waypointsprite_scale = 1.0;
260 }