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