Added in_mouse_x and in_mouse_y, which contain the rel. coords of the mouse.
[divverent/darkplaces.git] / cl_screen.c
1
2 #include "quakedef.h"
3 #include "cl_video.h"
4 #include "jpeg.h"
5 #include "cl_collision.h"
6
7 cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100"};
8 cvar_t scr_fov = {CVAR_SAVE, "fov","90"};       // 10 - 170
9 cvar_t scr_conspeed = {CVAR_SAVE, "scr_conspeed","900"}; // LordHavoc: quake used 300
10 cvar_t scr_conalpha = {CVAR_SAVE, "scr_conalpha", "1"};
11 cvar_t scr_conbrightness = {CVAR_SAVE, "scr_conbrightness", "0.2"};
12 cvar_t scr_centertime = {0, "scr_centertime","2"};
13 cvar_t scr_showram = {CVAR_SAVE, "showram","1"};
14 cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0"};
15 cvar_t scr_showpause = {CVAR_SAVE, "showpause","1"};
16 cvar_t scr_printspeed = {0, "scr_printspeed","8"};
17 cvar_t vid_conwidth = {CVAR_SAVE, "vid_conwidth", "640"};
18 cvar_t vid_conheight = {CVAR_SAVE, "vid_conheight", "480"};
19 cvar_t scr_screenshot_jpeg = {CVAR_SAVE, "scr_screenshot_jpeg","0"};
20 cvar_t cl_avidemo = {0, "cl_avidemo", "0"};
21
22 qboolean        scr_initialized;                // ready to draw
23
24 float           scr_con_current;
25 float           scr_conlines;           // lines of console to display
26
27 int                     clearconsole;
28 int                     clearnotify;
29
30 qboolean        scr_drawloading = false;
31
32 static qbyte menuplyr_pixels[4096];
33
34 void DrawCrosshair(int num);
35 void V_CalcRefdef (void);
36 static void SCR_ScreenShot_f (void);
37 static void R_Envmap_f (void);
38
39 // backend
40 void R_ClearScreen(void);
41
42 /*
43 ===============================================================================
44
45 CENTER PRINTING
46
47 ===============================================================================
48 */
49
50 char            scr_centerstring[1024];
51 float           scr_centertime_start;   // for slow victory printing
52 float           scr_centertime_off;
53 int                     scr_center_lines;
54 int                     scr_erase_lines;
55 int                     scr_erase_center;
56
57 /*
58 ==============
59 SCR_CenterPrint
60
61 Called for important messages that should stay in the center of the screen
62 for a few moments
63 ==============
64 */
65 void SCR_CenterPrint (char *str)
66 {
67         strlcpy (scr_centerstring, str, sizeof (scr_centerstring));
68         scr_centertime_off = scr_centertime.value;
69         scr_centertime_start = cl.time;
70
71 // count the number of lines for centering
72         scr_center_lines = 1;
73         while (*str)
74         {
75                 if (*str == '\n')
76                         scr_center_lines++;
77                 str++;
78         }
79 }
80
81
82 void SCR_DrawCenterString (void)
83 {
84         char    *start;
85         int             l;
86         int             x, y;
87         int             remaining;
88
89 // the finale prints the characters one at a time
90         if (cl.intermission)
91                 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
92         else
93                 remaining = 9999;
94
95         scr_erase_center = 0;
96         start = scr_centerstring;
97
98         if (scr_center_lines <= 4)
99                 y = vid.conheight*0.35;
100         else
101                 y = 48;
102
103         do
104         {
105         // scan the width of the line
106                 for (l=0 ; l<40 ; l++)
107                         if (start[l] == '\n' || !start[l])
108                                 break;
109                 x = (vid.conwidth - l*8)/2;
110                 if (l > 0)
111                 {
112                         if (remaining < l)
113                                 l = remaining;
114                         DrawQ_String(x, y, start, l, 8, 8, 1, 1, 1, 1, 0);
115                         remaining -= l;
116                         if (remaining <= 0)
117                                 return;
118                 }
119
120                 y += 8;
121
122                 while (*start && *start != '\n')
123                         start++;
124
125                 if (!*start)
126                         break;
127                 start++;                // skip the \n
128         } while (1);
129 }
130
131 void SCR_CheckDrawCenterString (void)
132 {
133         if (scr_center_lines > scr_erase_lines)
134                 scr_erase_lines = scr_center_lines;
135
136         scr_centertime_off -= host_frametime;
137
138         // don't draw if this is a normal stats-screen intermission,
139         // only if it is not an intermission, or a finale intermission
140         if (cl.intermission == 1)
141                 return;
142         if (scr_centertime_off <= 0 && !cl.intermission)
143                 return;
144         if (key_dest != key_game)
145                 return;
146
147         SCR_DrawCenterString ();
148 }
149
150 /*
151 ==============
152 SCR_DrawTurtle
153 ==============
154 */
155 void SCR_DrawTurtle (void)
156 {
157         static int      count;
158
159         if (cls.state != ca_connected)
160                 return;
161
162         if (!scr_showturtle.integer)
163                 return;
164
165         if (host_frametime < 0.1)
166         {
167                 count = 0;
168                 return;
169         }
170
171         count++;
172         if (count < 3)
173                 return;
174
175         DrawQ_Pic (0, 0, "gfx/turtle.lmp", 0, 0, 1, 1, 1, 1, 0);
176 }
177
178 /*
179 ==============
180 SCR_DrawNet
181 ==============
182 */
183 void SCR_DrawNet (void)
184 {
185         if (cls.state != ca_connected)
186                 return;
187         if (realtime - cl.last_received_message < 0.3)
188                 return;
189         if (cls.demoplayback)
190                 return;
191
192         DrawQ_Pic (64, 0, "gfx/net.lmp", 0, 0, 1, 1, 1, 1, 0);
193 }
194
195 /*
196 ==============
197 DrawPause
198 ==============
199 */
200 void SCR_DrawPause (void)
201 {
202         cachepic_t      *pic;
203
204         if (cls.state != ca_connected)
205                 return;
206
207         if (!scr_showpause.integer)             // turn off for screenshots
208                 return;
209
210         if (!cl.paused)
211                 return;
212
213         pic = Draw_CachePic ("gfx/pause.lmp");
214         DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/pause.lmp", 0, 0, 1, 1, 1, 1, 0);
215 }
216
217
218
219 /*
220 ==============
221 SCR_DrawLoading
222 ==============
223 */
224 void SCR_DrawLoading (void)
225 {
226         cachepic_t      *pic;
227
228         pic = Draw_CachePic ("gfx/loading.lmp");
229         DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/loading.lmp", 0, 0, 1, 1, 1, 1, 0);
230 }
231
232
233
234 //=============================================================================
235
236
237 /*
238 ==================
239 SCR_SetUpToDrawConsole
240 ==================
241 */
242 void SCR_SetUpToDrawConsole (void)
243 {
244         Con_CheckResize ();
245
246         if (key_dest == key_game && cls.signon != SIGNONS)
247                 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
248         else
249                 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
250
251 // decide on the height of the console
252         if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
253                 scr_conlines = vid.conheight; // full screen
254         else if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
255                 scr_conlines = vid.conheight/2; // half screen
256         else
257                 scr_conlines = 0;                               // none visible
258
259         if (scr_conspeed.value)
260         {
261                 if (scr_conlines < scr_con_current)
262                 {
263                         scr_con_current -= scr_conspeed.value*host_realframetime;
264                         if (scr_conlines > scr_con_current)
265                                 scr_con_current = scr_conlines;
266
267                 }
268                 else if (scr_conlines > scr_con_current)
269                 {
270                         scr_con_current += scr_conspeed.value*host_realframetime;
271                         if (scr_conlines < scr_con_current)
272                                 scr_con_current = scr_conlines;
273                 }
274         }
275         else
276                 scr_con_current = scr_conlines;
277 }
278
279 /*
280 ==================
281 SCR_DrawConsole
282 ==================
283 */
284 void SCR_DrawConsole (void)
285 {
286         if (scr_con_current)
287         {
288                 Con_DrawConsole (scr_con_current);
289                 clearconsole = 0;
290         }
291         else
292         {
293                 if (key_dest == key_game || key_dest == key_message)
294                         Con_DrawNotify ();      // only draw notify in game
295         }
296 }
297
298 /*
299 ===============
300 SCR_BeginLoadingPlaque
301
302 ================
303 */
304 void SCR_BeginLoadingPlaque (void)
305 {
306         if (scr_drawloading)
307                 return;
308
309         S_StopAllSounds (true);
310
311         scr_drawloading = true;
312         CL_UpdateScreen ();
313         scr_drawloading = true;
314         CL_UpdateScreen ();
315 }
316
317 //=============================================================================
318
319 char r_speeds_string[1024];
320 int speedstringcount, r_timereport_active;
321 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
322
323 void R_TimeReport(char *desc)
324 {
325         char tempbuf[256];
326         int length;
327         int t;
328
329         if (!r_timereport_active)
330                 return;
331
332         r_timereport_temp = r_timereport_current;
333         r_timereport_current = Sys_DoubleTime();
334         t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
335
336         sprintf(tempbuf, "%8i %s", t, desc);
337         length = strlen(tempbuf);
338         while (length < 20)
339                 tempbuf[length++] = ' ';
340         tempbuf[length] = 0;
341         if (speedstringcount + length > (vid.conwidth / 8))
342         {
343                 strcat(r_speeds_string, "\n");
344                 speedstringcount = 0;
345         }
346         // skip the space at the beginning if it's the first on the line
347         if (speedstringcount == 0)
348         {
349                 strcat(r_speeds_string, tempbuf + 1);
350                 speedstringcount = length - 1;
351         }
352         else
353         {
354                 strcat(r_speeds_string, tempbuf);
355                 speedstringcount += length;
356         }
357 }
358
359 extern int c_rt_lights, c_rt_clears, c_rt_scissored;
360 extern int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
361 extern int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
362 void R_TimeReport_Start(void)
363 {
364         r_timereport_active = r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected;
365         r_speeds_string[0] = 0;
366         if (r_timereport_active)
367         {
368                 speedstringcount = 0;
369                 AngleVectors (r_refdef.viewangles, vpn, NULL, NULL);
370                 sprintf(r_speeds_string,
371                         "org:'%+8.2f %+8.2f %+8.2f' ang:'%+4.0f %+4.0f %+4.0f' dir:'%+2.3f %+2.3f %+2.3f'\n"
372                         "world:%6i faces%6i nodes%6i leafs%6i dlitwalls\n"
373                         "%5i models%5i bmodels%5i sprites%6i particles%4i dlights\n"
374                         "%6i modeltris%6i meshs%6i meshtris\n",
375                         r_refdef.vieworg[0], r_refdef.vieworg[1], r_refdef.vieworg[2], r_refdef.viewangles[0], r_refdef.viewangles[1], r_refdef.viewangles[2], vpn[0], vpn[1], vpn[2],
376                         c_faces, c_nodes, c_leafs, c_light_polys,
377                         c_models, c_bmodels, c_sprites, c_particles, c_dlights,
378                         c_alias_polys, c_meshs, c_meshelements / 3);
379
380                 sprintf(r_speeds_string + strlen(r_speeds_string),
381                         "realtime lighting:%4i lights%4i clears%4i scissored\n"
382                         "dynamic: %6i shadowmeshes%6i shadowtris%6i lightmeshes%6i lighttris\n"
383                         "precomputed: %6i shadowmeshes%6i shadowtris\n",
384                         c_rt_lights, c_rt_clears, c_rt_scissored,
385                         c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris,
386                         c_rtcached_shadowmeshes, c_rtcached_shadowtris);
387
388                 c_alias_polys = 0;
389                 c_light_polys = 0;
390                 c_faces = 0;
391                 c_nodes = 0;
392                 c_leafs = 0;
393                 c_models = 0;
394                 c_bmodels = 0;
395                 c_sprites = 0;
396                 c_particles = 0;
397                 c_meshs = 0;
398                 c_meshelements = 0;
399
400                 r_timereport_start = Sys_DoubleTime();
401         }
402 }
403
404 void R_TimeReport_End(void)
405 {
406         r_timereport_current = r_timereport_start;
407         R_TimeReport("total");
408
409         if (r_timereport_active)
410         {
411                 int i, j, lines, y;
412                 lines = 1;
413                 for (i = 0;r_speeds_string[i];i++)
414                         if (r_speeds_string[i] == '\n')
415                                 lines++;
416                 y = vid.conheight - sb_lines - lines * 8;
417                 i = j = 0;
418                 DrawQ_Fill(0, y, vid.conwidth, lines * 8, 0, 0, 0, 0.5, 0);
419                 while (r_speeds_string[i])
420                 {
421                         j = i;
422                         while (r_speeds_string[i] && r_speeds_string[i] != '\n')
423                                 i++;
424                         if (i - j > 0)
425                                 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
426                         if (r_speeds_string[i] == '\n')
427                                 i++;
428                         y += 8;
429                 }
430         }
431 }
432
433 /*
434 =================
435 SCR_SizeUp_f
436
437 Keybinding command
438 =================
439 */
440 void SCR_SizeUp_f (void)
441 {
442         Cvar_SetValue ("viewsize",scr_viewsize.value+10);
443 }
444
445
446 /*
447 =================
448 SCR_SizeDown_f
449
450 Keybinding command
451 =================
452 */
453 void SCR_SizeDown_f (void)
454 {
455         Cvar_SetValue ("viewsize",scr_viewsize.value-10);
456 }
457
458 void CL_Screen_Init(void)
459 {
460         qpic_t *dat;
461
462         Cvar_RegisterVariable (&scr_fov);
463         Cvar_RegisterVariable (&scr_viewsize);
464         Cvar_RegisterVariable (&scr_conspeed);
465         Cvar_RegisterVariable (&scr_conalpha);
466         Cvar_RegisterVariable (&scr_conbrightness);
467         Cvar_RegisterVariable (&scr_showram);
468         Cvar_RegisterVariable (&scr_showturtle);
469         Cvar_RegisterVariable (&scr_showpause);
470         Cvar_RegisterVariable (&scr_centertime);
471         Cvar_RegisterVariable (&scr_printspeed);
472         Cvar_RegisterVariable (&vid_conwidth);
473         Cvar_RegisterVariable (&vid_conheight);
474         Cvar_RegisterVariable (&scr_screenshot_jpeg);
475         Cvar_RegisterVariable (&cl_avidemo);
476
477         Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
478         Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
479         Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
480         Cmd_AddCommand ("envmap", R_Envmap_f);
481
482         scr_initialized = true;
483
484         // HACK HACK HACK
485         // load the image data for the player image in the config menu
486         dat = (qpic_t *)FS_LoadFile ("gfx/menuplyr.lmp", false);
487         if (!dat)
488                 Sys_Error("unable to load gfx/menuplyr.lmp");
489         SwapPic (dat);
490
491         if (dat->width*dat->height <= 4096)
492                 memcpy (menuplyr_pixels, dat->data, dat->width * dat->height);
493         else
494                 Con_Printf("gfx/menuplyr.lmp larger than 4k buffer");
495         Mem_Free(dat);
496 }
497
498 void DrawQ_Clear(void)
499 {
500         r_refdef.drawqueuesize = 0;
501 }
502
503 static int picelements[6] = {0, 1, 2, 0, 2, 3};
504 void DrawQ_Pic(float x, float y, char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
505 {
506         DrawQ_SuperPic(x,y,picname,width,height,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags);
507 }
508
509 void DrawQ_String(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
510 {
511         int size, len;
512         drawqueue_t *dq;
513         char *out;
514         if (alpha < (1.0f / 255.0f))
515                 return;
516         if (maxlen < 1)
517                 len = strlen(string);
518         else
519                 for (len = 0;len < maxlen && string[len];len++);
520         for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
521         for (;len > 0 && string[len - 1] == ' ';len--);
522         if (len < 1)
523                 return;
524         if (x >= vid.conwidth || y >= vid.conheight || x < (-scalex * maxlen) || y < (-scaley))
525                 return;
526         size = sizeof(*dq) + ((len + 1 + 3) & ~3);
527         if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
528                 return;
529         red = bound(0, red, 1);
530         green = bound(0, green, 1);
531         blue = bound(0, blue, 1);
532         alpha = bound(0, alpha, 1);
533         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
534         dq->size = size;
535         dq->command = DRAWQUEUE_STRING;
536         dq->flags = flags;
537         dq->color = ((unsigned int) (red * 255.0f) << 24) | ((unsigned int) (green * 255.0f) << 16) | ((unsigned int) (blue * 255.0f) << 8) | ((unsigned int) (alpha * 255.0f));
538         dq->x = x;
539         dq->y = y;
540         dq->scalex = scalex;
541         dq->scaley = scaley;
542         out = (char *)(dq + 1);
543         memcpy(out, string, len);
544         out[len] = 0;
545         r_refdef.drawqueuesize += dq->size;
546 }
547
548 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
549 {
550         DrawQ_SuperPic(x,y,NULL,w,h,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags);
551 }
552
553 void DrawQ_SuperPic(float x, float y, char *picname, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags)
554 {
555         float floats[36];
556         cachepic_t *pic;
557         drawqueuemesh_t mesh;
558         memset(&mesh, 0, sizeof(mesh));
559         if (picname && picname[0])
560         {
561                 pic = Draw_CachePic(picname);
562                 if (width == 0)
563                         width = pic->width;
564                 if (height == 0)
565                         height = pic->height;
566                 mesh.texture = pic->tex;
567         }
568         mesh.num_triangles = 2;
569         mesh.num_vertices = 4;
570         mesh.data_element3i = picelements;
571         mesh.data_vertex3f = floats;
572         mesh.data_texcoord2f = floats + 12;
573         mesh.data_color4f = floats + 20;
574         memset(floats, 0, sizeof(floats));
575         mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
576         mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
577         mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
578         mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
579         mesh.data_texcoord2f[0] = s1;mesh.data_texcoord2f[1] = t1;mesh.data_color4f[ 0] = r1;mesh.data_color4f[ 1] = g1;mesh.data_color4f[ 2] = b1;mesh.data_color4f[ 3] = a1;
580         mesh.data_texcoord2f[2] = s2;mesh.data_texcoord2f[3] = t2;mesh.data_color4f[ 4] = r2;mesh.data_color4f[ 5] = g2;mesh.data_color4f[ 6] = b2;mesh.data_color4f[ 7] = a2;
581         mesh.data_texcoord2f[4] = s4;mesh.data_texcoord2f[5] = t4;mesh.data_color4f[ 8] = r4;mesh.data_color4f[ 9] = g4;mesh.data_color4f[10] = b4;mesh.data_color4f[11] = a4;
582         mesh.data_texcoord2f[6] = s3;mesh.data_texcoord2f[7] = t3;mesh.data_color4f[12] = r3;mesh.data_color4f[13] = g3;mesh.data_color4f[14] = b3;mesh.data_color4f[15] = a3;
583         DrawQ_Mesh (&mesh, flags);
584 }
585
586 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
587 {
588         int size;
589         void *p;
590         drawqueue_t *dq;
591         drawqueuemesh_t *m;
592         size = sizeof(*dq);
593         size += sizeof(drawqueuemesh_t);
594         size += sizeof(int[3]) * mesh->num_triangles;
595         size += sizeof(float[3]) * mesh->num_vertices;
596         size += sizeof(float[2]) * mesh->num_vertices;
597         size += sizeof(float[4]) * mesh->num_vertices;
598         if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
599                 return;
600         dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
601         dq->size = size;
602         dq->command = DRAWQUEUE_MESH;
603         dq->flags = flags;
604         dq->color = 0;
605         dq->x = 0;
606         dq->y = 0;
607         dq->scalex = 0;
608         dq->scaley = 0;
609         p = (void *)(dq + 1);
610         m = p;(qbyte *)p += sizeof(drawqueuemesh_t);
611         m->num_triangles = mesh->num_triangles;
612         m->num_vertices = mesh->num_vertices;
613         m->texture = mesh->texture;
614         m->data_element3i  = p;memcpy(m->data_element3i , mesh->data_element3i , m->num_triangles * sizeof(int[3]));(qbyte *)p += m->num_triangles * sizeof(int[3]);
615         m->data_vertex3f   = p;memcpy(m->data_vertex3f  , mesh->data_vertex3f  , m->num_vertices * sizeof(float[3]));(qbyte *)p += m->num_vertices * sizeof(float[3]);
616         m->data_texcoord2f = p;memcpy(m->data_texcoord2f, mesh->data_texcoord2f, m->num_vertices * sizeof(float[2]));(qbyte *)p += m->num_vertices * sizeof(float[2]);
617         m->data_color4f    = p;memcpy(m->data_color4f   , mesh->data_color4f   , m->num_vertices * sizeof(float[4]));(qbyte *)p += m->num_vertices * sizeof(float[4]);
618         r_refdef.drawqueuesize += dq->size;
619 }
620
621 void DrawQ_SetClipArea(float x, float y, float width, float height)
622 {
623         drawqueue_t * dq;
624         if(r_refdef.drawqueuesize + sizeof(*dq) > r_refdef.maxdrawqueuesize)
625         {
626                 Con_DPrintf("DrawQueue full !\n");
627                 return;
628         }
629         dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
630         dq->size = sizeof(*dq);
631         dq->command = DRAWQUEUE_SETCLIP;
632         dq->x = x;
633         dq->y = y;
634         dq->scalex = width;
635         dq->scaley = height;
636         dq->flags = 0;
637         dq->color = 0;
638         
639         r_refdef.drawqueuesize += dq->size;
640 }
641
642 void DrawQ_ResetClipArea(void)
643 {
644         drawqueue_t *dq;
645         if(r_refdef.drawqueuesize + sizeof(*dq) > r_refdef.maxdrawqueuesize)
646         {
647                 Con_DPrintf("DrawQueue full !\n");
648                 return;
649         }
650         dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
651         dq->size = sizeof(*dq);
652         dq->command = DRAWQUEUE_RESETCLIP;
653         dq->x = 0;
654         dq->y = 0;
655         dq->scalex = 0;
656         dq->scaley = 0;
657         dq->flags = 0;
658         dq->color = 0;
659         
660         r_refdef.drawqueuesize += dq->size;
661 }
662
663 /*
664 ====================
665 CalcFov
666 ====================
667 */
668 float CalcFov (float fov_x, float width, float height)
669 {
670         // calculate vision size and alter by aspect, then convert back to angle
671         return atan (height / (width / tan(fov_x/360*M_PI))) * 360 / M_PI;
672 }
673
674 /*
675 =================
676 SCR_CalcRefdef
677
678 Must be called whenever vid changes
679 Internal use only
680 =================
681 */
682 static void SCR_CalcRefdef (void)
683 {
684         float size;
685         int contents;
686
687 //========================================
688
689 // bound viewsize
690         if (scr_viewsize.value < 30)
691                 Cvar_Set ("viewsize","30");
692         if (scr_viewsize.value > 120)
693                 Cvar_Set ("viewsize","120");
694
695 // bound field of view
696         if (scr_fov.value < 10)
697                 Cvar_Set ("fov","10");
698         if (scr_fov.value > 170)
699                 Cvar_Set ("fov","170");
700
701 // intermission is always full screen
702         if (cl.intermission)
703         {
704                 size = 1;
705                 sb_lines = 0;
706         }
707         else
708         {
709                 if (scr_viewsize.value >= 120)
710                         sb_lines = 0;           // no status bar at all
711                 else if (scr_viewsize.value >= 110)
712                         sb_lines = 24;          // no inventory
713                 else
714                         sb_lines = 24+16+8;
715                 size = scr_viewsize.value * (1.0 / 100.0);
716         }
717
718         if (size >= 1)
719         {
720                 r_refdef.width = vid.realwidth;
721                 r_refdef.height = vid.realheight;
722                 r_refdef.x = 0;
723                 r_refdef.y = 0;
724         }
725         else
726         {
727                 r_refdef.width = vid.realwidth * size;
728                 r_refdef.height = vid.realheight * size;
729                 r_refdef.x = (vid.realwidth - r_refdef.width)/2;
730                 r_refdef.y = (vid.realheight - r_refdef.height)/2;
731         }
732
733         r_refdef.width = bound(0, r_refdef.width, vid.realwidth);
734         r_refdef.height = bound(0, r_refdef.height, vid.realheight);
735         r_refdef.x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width) + vid.realx;
736         r_refdef.y = bound(0, r_refdef.y, vid.realheight - r_refdef.height) + vid.realy;
737
738         // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
739         r_refdef.fov_x = scr_fov.value * cl.viewzoom;
740         r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.width, r_refdef.height);
741
742         if (cl.worldmodel)
743         {
744                 Mod_CheckLoaded(cl.worldmodel);
745                 contents = CL_PointSuperContents(r_refdef.vieworg);
746                 if (contents & SUPERCONTENTS_LIQUIDSMASK)
747                 {
748                         r_refdef.fov_x *= (sin(cl.time * 4.7) * 0.015 + 0.985);
749                         r_refdef.fov_y *= (sin(cl.time * 3.0) * 0.015 + 0.985);
750                 }
751         }
752 }
753
754 /*
755 ==================
756 SCR_ScreenShot_f
757 ==================
758 */
759 void SCR_ScreenShot_f (void)
760 {
761         static int i = 0;
762         char filename[16];
763         char checkname[MAX_OSPATH];
764         const char* extens;
765         qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
766
767         if (jpeg)
768                 extens = "jpg";
769         else
770                 extens = "tga";
771
772         // find a file name to save it to
773         for (; i<=9999 ; i++)
774         {
775                 sprintf (filename, "dp%04i.%s", i, extens);
776                 sprintf (checkname, "%s/%s", fs_gamedir, filename);
777                 if (!FS_SysFileExists(checkname))
778                         break;
779         }
780         if (i==10000)
781         {
782                 Con_Printf ("SCR_ScreenShot_f: Couldn't create the image file\n");
783                 return;
784         }
785
786         if (SCR_ScreenShot (filename, vid.realx, vid.realy, vid.realwidth, vid.realheight, jpeg))
787                 Con_Printf ("Wrote %s\n", filename);
788         else
789                 Con_Printf ("unable to write %s\n", filename);
790 }
791
792 static int cl_avidemo_frame = 0;
793
794 void SCR_CaptureAVIDemo(void)
795 {
796         char filename[32];
797         qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
798
799         if (jpeg)
800                 sprintf(filename, "dpavi%06d.jpg", cl_avidemo_frame);
801         else
802                 sprintf(filename, "dpavi%06d.tga", cl_avidemo_frame);
803
804         if (SCR_ScreenShot(filename, vid.realx, vid.realy, vid.realwidth, vid.realheight, jpeg))
805                 cl_avidemo_frame++;
806         else
807         {
808                 Cvar_SetValueQuick(&cl_avidemo, 0);
809                 Con_Printf("avi saving failed on frame %i, out of disk space?  stopping avi demo catpure.\n", cl_avidemo_frame);
810                 cl_avidemo_frame = 0;
811         }
812 }
813
814 /*
815 ===============
816 R_Envmap_f
817
818 Grab six views for environment mapping tests
819 ===============
820 */
821 struct
822 {
823         float angles[3];
824         char *name;
825 }
826 envmapinfo[6] =
827 {
828         {{  0,   0, 0}, "ft"},
829         {{  0,  90, 0}, "rt"},
830         {{  0, 180, 0}, "bk"},
831         {{  0, 270, 0}, "lf"},
832         {{-90,  90, 0}, "up"},
833         {{ 90,  90, 0}, "dn"}
834 };
835
836 static void R_Envmap_f (void)
837 {
838         int j, size;
839         char filename[256], basename[256];
840
841         if (Cmd_Argc() != 3)
842         {
843                 Con_Printf ("envmap <basename> <size>: save out 6 cubic environment map images, usable with loadsky, note that size must one of 128, 256, 512, or 1024 and can't be bigger than your current resolution\n");
844                 return;
845         }
846
847         strlcpy (basename, Cmd_Argv(1), sizeof (basename));
848         size = atoi(Cmd_Argv(2));
849         if (size != 128 && size != 256 && size != 512 && size != 1024)
850         {
851                 Con_Printf("envmap: size must be one of 128, 256, 512, or 1024\n");
852                 return;
853         }
854         if (size > vid.realwidth || size > vid.realheight)
855         {
856                 Con_Printf("envmap: your resolution is not big enough to render that size\n");
857                 return;
858         }
859
860         envmap = true;
861
862         r_refdef.x = 0;
863         r_refdef.y = 0;
864         r_refdef.width = size;
865         r_refdef.height = size;
866
867         r_refdef.fov_x = 90;
868         r_refdef.fov_y = 90;
869
870         for (j = 0;j < 6;j++)
871         {
872                 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
873                 VectorCopy(envmapinfo[j].angles, r_refdef.viewangles);
874                 R_ClearScreen();
875                 R_RenderView ();
876                 SCR_ScreenShot(filename, vid.realx, vid.realy, size, size, false);
877         }
878
879         envmap = false;
880 }
881
882 //=============================================================================
883
884 // LordHavoc: SHOWLMP stuff
885 #define SHOWLMP_MAXLABELS 256
886 typedef struct showlmp_s
887 {
888         qboolean        isactive;
889         float           x;
890         float           y;
891         char            label[32];
892         char            pic[128];
893 }
894 showlmp_t;
895
896 showlmp_t showlmp[SHOWLMP_MAXLABELS];
897
898 void SHOWLMP_decodehide(void)
899 {
900         int i;
901         qbyte *lmplabel;
902         lmplabel = MSG_ReadString();
903         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
904                 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
905                 {
906                         showlmp[i].isactive = false;
907                         return;
908                 }
909 }
910
911 void SHOWLMP_decodeshow(void)
912 {
913         int i, k;
914         qbyte lmplabel[256], picname[256];
915         float x, y;
916         strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
917         strlcpy (picname, MSG_ReadString(), sizeof (picname));
918         if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
919         {
920                 x = MSG_ReadByte();
921                 y = MSG_ReadByte();
922         }
923         else
924         {
925                 x = MSG_ReadShort();
926                 y = MSG_ReadShort();
927         }
928         k = -1;
929         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
930                 if (showlmp[i].isactive)
931                 {
932                         if (strcmp(showlmp[i].label, lmplabel) == 0)
933                         {
934                                 k = i;
935                                 break; // drop out to replace it
936                         }
937                 }
938                 else if (k < 0) // find first empty one to replace
939                         k = i;
940         if (k < 0)
941                 return; // none found to replace
942         // change existing one
943         showlmp[k].isactive = true;
944         strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
945         strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
946         showlmp[k].x = x;
947         showlmp[k].y = y;
948 }
949
950 void SHOWLMP_drawall(void)
951 {
952         int i;
953         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
954                 if (showlmp[i].isactive)
955                         DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
956 }
957
958 void SHOWLMP_clear(void)
959 {
960         int i;
961         for (i = 0;i < SHOWLMP_MAXLABELS;i++)
962                 showlmp[i].isactive = false;
963 }
964
965 void CL_SetupScreenSize(void)
966 {
967         float conwidth, conheight;
968
969         VID_GetWindowSize (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
970
971         VID_UpdateGamma(false);
972
973         conwidth = bound(320, vid_conwidth.value, 2048);
974         conheight = bound(200, vid_conheight.value, 1536);
975         if (vid_conwidth.value != conwidth)
976                 Cvar_SetValue("vid_conwidth", conwidth);
977         if (vid_conheight.value != conheight)
978                 Cvar_SetValue("vid_conheight", conheight);
979
980         vid.conwidth = vid_conwidth.integer;
981         vid.conheight = vid_conheight.integer;
982
983 /*      if (vid.realheight > 240)
984         {
985                 vid.conheight = (vid.realheight - 240) * scr_2dresolution.value + 240;
986                 vid.conheight = bound(240, vid.conheight, vid.realheight);
987         }
988         else
989                 vid.conheight = 240;*/
990
991         SCR_SetUpToDrawConsole();
992
993         // determine size of refresh window
994         SCR_CalcRefdef();
995 }
996
997 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
998 void CL_UpdateScreen(void)
999 {
1000         if (!scr_initialized || !con_initialized || vid_hidden)
1001                 return;                         // not initialized yet
1002
1003         if (cl_avidemo.integer)
1004                 SCR_CaptureAVIDemo();
1005         else
1006                 cl_avidemo_frame = 0;
1007
1008         if (cls.signon == SIGNONS)
1009                 R_TimeReport("other");
1010
1011         CL_SetupScreenSize();
1012
1013         DrawQ_Clear();
1014
1015         if (cls.signon == SIGNONS)
1016                 R_TimeReport("setup");
1017
1018         //FIXME: force menu if nothing else to look at?
1019         //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1020
1021         if (scr_drawloading)
1022         {
1023                 scr_drawloading = false;
1024                 SCR_DrawLoading();
1025         }
1026         else
1027         {
1028                 if (cls.signon == SIGNONS)
1029                 {
1030                         SCR_DrawNet ();
1031                         SCR_DrawTurtle ();
1032                         SCR_DrawPause ();
1033                         Sbar_Draw();
1034                         SHOWLMP_drawall();
1035                         SCR_CheckDrawCenterString();
1036                 }
1037                 MR_Draw();
1038                 CL_DrawVideo();
1039                 ui_draw();
1040                 if (cls.signon == SIGNONS)
1041                 {
1042                         R_TimeReport("2d");
1043                         R_TimeReport_End();
1044                         R_TimeReport_Start();
1045                 }
1046                 R_Shadow_EditLights_DrawSelectedLightProperties();
1047         }
1048         SCR_DrawConsole();
1049
1050         SCR_UpdateScreen();
1051 }
1052
1053 void CL_Screen_NewMap(void)
1054 {
1055         SHOWLMP_clear();
1056 }
1057