]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_screen.c
cleaned up a lot of particle rendering properties (mainly related to rain code),...
[xonotic/darkplaces.git] / gl_screen.c
index 2a0bfa531316d6aae5022557505ba967586e8472..dc542a1c23859592c466f8bf2a74535d195f24a7 100644 (file)
@@ -55,64 +55,50 @@ SlowPrint ()
 Screen_Update ();
 Con_Printf ();
 
 Screen_Update ();
 Con_Printf ();
 
-net 
+net
 turn off messages option
 
 turn off messages option
 
-the refresh is allways rendered, unless the console is full screen
+the refresh is always rendered, unless the console is full screen
 
 
 console is:
        notify lines
        half
        full
 
 
 console is:
        notify lines
        half
        full
-       
-
-*/
-
 
 
-int                    glx, gly, glwidth, glheight;
 
 
-// only the refresh window will be updated unless these variables are flagged 
-int                    scr_copytop;
-int                    scr_copyeverything;
-
-float          scr_con_current;
-float          scr_conlines;           // lines of console to display
+*/
 
 
-float          oldscreensize, oldfov;
-cvar_t         scr_viewsize = {"viewsize","100", true};
-cvar_t         scr_fov = {"fov","90"}; // 10 - 170
-cvar_t         scr_conspeed = {"scr_conspeed","300"};
-cvar_t         scr_centertime = {"scr_centertime","2"};
-cvar_t         scr_showram = {"showram","1"};
-cvar_t         scr_showturtle = {"showturtle","0"};
-cvar_t         scr_showpause = {"showpause","1"};
-cvar_t         scr_printspeed = {"scr_printspeed","8"};
-cvar_t         gl_triplebuffer = {"gl_triplebuffer", "1", true };
-cvar_t         showfps = {"showfps", "0", true};
 
 
-extern cvar_t  crosshair;
+float  scr_con_current;
+float  scr_conlines;           // lines of console to display
+
+float  oldscreensize, oldfov;
+cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100"};
+cvar_t scr_fov = {CVAR_SAVE, "fov","90"};      // 10 - 170
+cvar_t scr_conspeed = {CVAR_SAVE, "scr_conspeed","900"}; // LordHavoc: quake used 300
+cvar_t scr_centertime = {0, "scr_centertime","2"};
+cvar_t scr_showram = {CVAR_SAVE, "showram","1"};
+cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0"};
+cvar_t scr_showpause = {CVAR_SAVE, "showpause","1"};
+cvar_t scr_printspeed = {0, "scr_printspeed","8"};
+cvar_t showfps = {CVAR_SAVE, "showfps", "0"};
+cvar_t r_render = {0, "r_render", "1"};
+cvar_t r_brightness = {CVAR_SAVE, "r_brightness", "1"}; // LordHavoc: a method of operating system independent color correction
+cvar_t r_contrast = {CVAR_SAVE, "r_contrast", "1"}; // LordHavoc: a method of operating system independent color correction
+cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1"}; // whether or not to use dithering
 
 qboolean       scr_initialized;                // ready to draw
 
 
 qboolean       scr_initialized;                // ready to draw
 
-qpic_t         *scr_ram;
-qpic_t         *scr_net;
-qpic_t         *scr_turtle;
-
-int                    scr_fullupdate;
-
 int                    clearconsole;
 int                    clearnotify;
 
 int                    clearconsole;
 int                    clearnotify;
 
-extern int                     sb_lines;
-
-extern viddef_t        vid;                            // global video state
-
-vrect_t                scr_vrect;
+int                    lightscalebit;
+float          lightscale;
 
 qboolean       scr_disabled_for_loading;
 
 qboolean       scr_disabled_for_loading;
-qboolean       scr_drawloading;
-float          scr_disabled_time;
+//qboolean     scr_drawloading;
+//float                scr_disabled_time;
 
 void SCR_ScreenShot_f (void);
 
 
 void SCR_ScreenShot_f (void);
 
@@ -173,7 +159,7 @@ void SCR_DrawCenterString (void)
        start = scr_centerstring;
 
        if (scr_center_lines <= 4)
        start = scr_centerstring;
 
        if (scr_center_lines <= 4)
-               y = vid.height*0.35;
+               y = vid.conheight*0.35;
        else
                y = 48;
 
        else
                y = 48;
 
@@ -183,7 +169,7 @@ void SCR_DrawCenterString (void)
                for (l=0 ; l<40 ; l++)
                        if (start[l] == '\n' || !start[l])
                                break;
                for (l=0 ; l<40 ; l++)
                        if (start[l] == '\n' || !start[l])
                                break;
-               x = (vid.width - l*8)/2;
+               x = (vid.conwidth - l*8)/2;
                // LordHavoc: speedup
                if (l > 0)
                {
                // LordHavoc: speedup
                if (l > 0)
                {
@@ -216,12 +202,11 @@ void SCR_DrawCenterString (void)
 
 void SCR_CheckDrawCenterString (void)
 {
 
 void SCR_CheckDrawCenterString (void)
 {
-       scr_copytop = 1;
        if (scr_center_lines > scr_erase_lines)
                scr_erase_lines = scr_center_lines;
 
        scr_centertime_off -= host_frametime;
        if (scr_center_lines > scr_erase_lines)
                scr_erase_lines = scr_center_lines;
 
        scr_centertime_off -= host_frametime;
-       
+
        if (scr_centertime_off <= 0 && !cl.intermission)
                return;
        if (key_dest != key_game)
        if (scr_centertime_off <= 0 && !cl.intermission)
                return;
        if (key_dest != key_game)
@@ -239,19 +224,8 @@ CalcFov
 */
 float CalcFov (float fov_x, float width, float height)
 {
 */
 float CalcFov (float fov_x, float width, float height)
 {
-        float   a;
-        float   x;
-
-        if (fov_x < 1 || fov_x > 179)
-                Sys_Error ("Bad fov: %f", fov_x);
-
-        x = width/tan(fov_x/360*M_PI);
-
-        a = atan (height/x);
-
-        a = a*360/M_PI;
-
-        return a;
+       // calculate vision size and alter by aspect, then convert back to angle
+       return atan (height / (width / tan(fov_x/360*M_PI))) * 360 / M_PI;
 }
 
 /*
 }
 
 /*
@@ -264,19 +238,12 @@ Internal use only
 */
 static void SCR_CalcRefdef (void)
 {
 */
 static void SCR_CalcRefdef (void)
 {
-       float           size;
-       int             h;
-       qboolean                full = false;
-
+       float size;
 
 
-       scr_fullupdate = 0;             // force a background redraw
-       vid.recalc_refdef = 0;
-
-// force the status bar to redraw
-//     Sbar_Changed ();
+//     vid.recalc_refdef = 0;
 
 //========================================
 
 //========================================
-       
+
 // bound viewsize
        if (scr_viewsize.value < 30)
                Cvar_Set ("viewsize","30");
 // bound viewsize
        if (scr_viewsize.value < 30)
                Cvar_Set ("viewsize","30");
@@ -289,59 +256,45 @@ static void SCR_CalcRefdef (void)
        if (scr_fov.value > 170)
                Cvar_Set ("fov","170");
 
        if (scr_fov.value > 170)
                Cvar_Set ("fov","170");
 
-// intermission is always full screen  
+// intermission is always full screen
        if (cl.intermission)
        if (cl.intermission)
-               size = 120;
-       else
-               size = scr_viewsize.value;
-
-       if (size >= 120)
-               sb_lines = 0;           // no status bar at all
-       else if (size >= 110)
-               sb_lines = 24;          // no inventory
-       else
-               sb_lines = 24+16+8;
-
-       if (scr_viewsize.value >= 100.0)
        {
        {
-               full = true;
-               size = 100.0;
+               size = 1;
+               sb_lines = 0;
        }
        else
        }
        else
-               size = scr_viewsize.value;
-       if (cl.intermission)
        {
        {
-               full = true;
-               size = 100;
-               sb_lines = 0;
+               if (scr_viewsize.value >= 120)
+                       sb_lines = 0;           // no status bar at all
+               else if (scr_viewsize.value >= 110)
+                       sb_lines = 24;          // no inventory
+               else
+                       sb_lines = 24+16+8;
+               size = scr_viewsize.value * (1.0 / 100.0);
        }
        }
-       size /= 100.0;
-
-       // LordHavoc: always fullyscreen rendering
-       h = vid.height/* - sb_lines*/;
 
 
-       r_refdef.vrect.width = vid.width * size;
-       if (r_refdef.vrect.width < 96)
+       if (size >= 1)
        {
        {
-               size = 96.0 / r_refdef.vrect.width;
-               r_refdef.vrect.width = 96;      // min for icons
+               r_refdef.width = vid.realwidth;
+               r_refdef.height = vid.realheight;
+               r_refdef.x = 0;
+               r_refdef.y = 0;
+       }
+       else
+       {
+               r_refdef.width = vid.realwidth * size;
+               r_refdef.height = vid.realheight * size;
+               r_refdef.x = (vid.realwidth - r_refdef.width)/2;
+               r_refdef.y = (vid.realheight - r_refdef.height)/2;
        }
        }
-
-       r_refdef.vrect.height = vid.height * size;
-       //if (r_refdef.vrect.height > vid.height - sb_lines)
-       //      r_refdef.vrect.height = vid.height - sb_lines;
-       if (r_refdef.vrect.height > (int) vid.height)
-                       r_refdef.vrect.height = vid.height;
-       r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
-       if (full)
-               r_refdef.vrect.y = 0;
-       else 
-               r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
 
        r_refdef.fov_x = scr_fov.value;
 
        r_refdef.fov_x = scr_fov.value;
-       r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
+       r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.width, r_refdef.height);
 
 
-       scr_vrect = r_refdef.vrect;
+       r_refdef.width = bound(0, r_refdef.width, vid.realwidth);
+       r_refdef.height = bound(0, r_refdef.height, vid.realheight);
+       r_refdef.x = bound(0, r_refdef.x, vid.realwidth) + vid.realx;
+       r_refdef.y = bound(0, r_refdef.y, vid.realheight) + vid.realy;
 }
 
 
 }
 
 
@@ -355,7 +308,7 @@ Keybinding command
 void SCR_SizeUp_f (void)
 {
        Cvar_SetValue ("viewsize",scr_viewsize.value+10);
 void SCR_SizeUp_f (void)
 {
        Cvar_SetValue ("viewsize",scr_viewsize.value+10);
-       vid.recalc_refdef = 1;
+//     vid.recalc_refdef = 1;
 }
 
 
 }
 
 
@@ -369,19 +322,31 @@ Keybinding command
 void SCR_SizeDown_f (void)
 {
        Cvar_SetValue ("viewsize",scr_viewsize.value-10);
 void SCR_SizeDown_f (void)
 {
        Cvar_SetValue ("viewsize",scr_viewsize.value-10);
-       vid.recalc_refdef = 1;
+//     vid.recalc_refdef = 1;
 }
 
 //============================================================================
 
 }
 
 //============================================================================
 
+void gl_screen_start(void)
+{
+}
+
+void gl_screen_shutdown(void)
+{
+}
+
+void gl_screen_newmap(void)
+{
+}
+
 /*
 ==================
 SCR_Init
 ==================
 */
 /*
 ==================
 SCR_Init
 ==================
 */
-void SCR_Init (void)
+static void R_Envmap_f (void);
+void GL_Screen_Init (void)
 {
 {
-
        Cvar_RegisterVariable (&scr_fov);
        Cvar_RegisterVariable (&scr_viewsize);
        Cvar_RegisterVariable (&scr_conspeed);
        Cvar_RegisterVariable (&scr_fov);
        Cvar_RegisterVariable (&scr_viewsize);
        Cvar_RegisterVariable (&scr_conspeed);
@@ -390,21 +355,26 @@ void SCR_Init (void)
        Cvar_RegisterVariable (&scr_showpause);
        Cvar_RegisterVariable (&scr_centertime);
        Cvar_RegisterVariable (&scr_printspeed);
        Cvar_RegisterVariable (&scr_showpause);
        Cvar_RegisterVariable (&scr_centertime);
        Cvar_RegisterVariable (&scr_printspeed);
-       Cvar_RegisterVariable (&gl_triplebuffer);
        Cvar_RegisterVariable (&showfps);
        Cvar_RegisterVariable (&showfps);
+       Cvar_RegisterVariable (&r_render);
+       Cvar_RegisterVariable (&r_brightness);
+       Cvar_RegisterVariable (&r_contrast);
+       Cvar_RegisterVariable (&gl_dither);
+#ifdef NORENDER
+       Cvar_SetValue("r_render", 0);
+#endif
 
 //
 // register our commands
 //
        Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
 
 //
 // register our commands
 //
        Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
+       Cmd_AddCommand ("envmap", R_Envmap_f);
        Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
        Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
 
        Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
        Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
 
-       scr_ram = Draw_PicFromWad ("ram");
-       scr_net = Draw_PicFromWad ("net");
-       scr_turtle = Draw_PicFromWad ("turtle");
-
        scr_initialized = true;
        scr_initialized = true;
+
+       R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown, gl_screen_newmap);
 }
 
 
 }
 
 
@@ -416,13 +386,9 @@ SCR_DrawRam
 */
 void SCR_DrawRam (void)
 {
 */
 void SCR_DrawRam (void)
 {
-       if (!scr_showram.value)
-               return;
-
-       if (!r_cache_thrash)
-               return;
-
-       Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);
+//     if (!scr_showram.integer)
+//             return;
+//     Draw_Pic (32, 0, Draw_CachePic("ram"));
 }
 
 /*
 }
 
 /*
@@ -433,8 +399,8 @@ SCR_DrawTurtle
 void SCR_DrawTurtle (void)
 {
        static int      count;
 void SCR_DrawTurtle (void)
 {
        static int      count;
-       
-       if (!scr_showturtle.value)
+
+       if (!scr_showturtle.integer)
                return;
 
        if (host_frametime < 0.1)
                return;
 
        if (host_frametime < 0.1)
@@ -447,7 +413,7 @@ void SCR_DrawTurtle (void)
        if (count < 3)
                return;
 
        if (count < 3)
                return;
 
-       Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);
+       Draw_Pic (0, 0, Draw_CachePic("turtle"));
 }
 
 /*
 }
 
 /*
@@ -462,7 +428,7 @@ void SCR_DrawNet (void)
        if (cls.demoplayback)
                return;
 
        if (cls.demoplayback)
                return;
 
-       Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);
+       Draw_Pic (64, 0, Draw_CachePic("net"));
 }
 
 /*
 }
 
 /*
@@ -474,15 +440,14 @@ void SCR_DrawPause (void)
 {
        qpic_t  *pic;
 
 {
        qpic_t  *pic;
 
-       if (!scr_showpause.value)               // turn off for screenshots
+       if (!scr_showpause.integer)             // turn off for screenshots
                return;
 
        if (!cl.paused)
                return;
 
        pic = Draw_CachePic ("gfx/pause.lmp");
                return;
 
        if (!cl.paused)
                return;
 
        pic = Draw_CachePic ("gfx/pause.lmp");
-       Draw_Pic ( (vid.width - pic->width)/2, 
-               (vid.height - 48 - pic->height)/2, pic);
+       Draw_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, pic);
 }
 
 
 }
 
 
@@ -492,6 +457,7 @@ void SCR_DrawPause (void)
 SCR_DrawLoading
 ==============
 */
 SCR_DrawLoading
 ==============
 */
+/*
 void SCR_DrawLoading (void)
 {
        qpic_t  *pic;
 void SCR_DrawLoading (void)
 {
        qpic_t  *pic;
@@ -500,9 +466,9 @@ void SCR_DrawLoading (void)
                return;
                
        pic = Draw_CachePic ("gfx/loading.lmp");
                return;
                
        pic = Draw_CachePic ("gfx/loading.lmp");
-       Draw_Pic ( (vid.width - pic->width)/2, 
-               (vid.height - 48 - pic->height)/2, pic);
+       Draw_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, pic);
 }
 }
+*/
 
 
 
 
 
 
@@ -526,41 +492,29 @@ void SCR_SetUpToDrawConsole (void)
 
        if (con_forcedup)
        {
 
        if (con_forcedup)
        {
-               scr_conlines = vid.height;              // full screen
+               scr_conlines = vid.conheight;           // full screen
                scr_con_current = scr_conlines;
        }
        else if (key_dest == key_console)
                scr_con_current = scr_conlines;
        }
        else if (key_dest == key_console)
-               scr_conlines = vid.height/2;    // half screen
+               scr_conlines = vid.conheight/2; // half screen
        else
                scr_conlines = 0;                               // none visible
        else
                scr_conlines = 0;                               // none visible
-       
+
        if (scr_conlines < scr_con_current)
        {
        if (scr_conlines < scr_con_current)
        {
-               scr_con_current -= scr_conspeed.value*host_frametime;
+               scr_con_current -= scr_conspeed.value*host_realframetime;
                if (scr_conlines > scr_con_current)
                        scr_con_current = scr_conlines;
 
        }
        else if (scr_conlines > scr_con_current)
        {
                if (scr_conlines > scr_con_current)
                        scr_con_current = scr_conlines;
 
        }
        else if (scr_conlines > scr_con_current)
        {
-               scr_con_current += scr_conspeed.value*host_frametime;
+               scr_con_current += scr_conspeed.value*host_realframetime;
                if (scr_conlines < scr_con_current)
                        scr_con_current = scr_conlines;
        }
                if (scr_conlines < scr_con_current)
                        scr_con_current = scr_conlines;
        }
-
-       /*
-       if (clearconsole++ < vid.numpages)
-       {
-               Sbar_Changed ();
-       }
-       else if (clearnotify++ < vid.numpages)
-       {
-       }
-       else
-               con_notifylines = 0;
-       */
 }
 }
-       
+
 /*
 ==================
 SCR_DrawConsole
 /*
 ==================
 SCR_DrawConsole
@@ -570,7 +524,6 @@ void SCR_DrawConsole (void)
 {
        if (scr_con_current)
        {
 {
        if (scr_con_current)
        {
-               scr_copyeverything = 1;
                Con_DrawConsole (scr_con_current, true);
                clearconsole = 0;
        }
                Con_DrawConsole (scr_con_current, true);
                clearconsole = 0;
        }
@@ -582,81 +535,155 @@ void SCR_DrawConsole (void)
 }
 
 
 }
 
 
-/* 
+/*
 ============================================================================== 
 ============================================================================== 
+
                                                SCREEN SHOTS 
                                                SCREEN SHOTS 
+
 ============================================================================== 
 */ 
 
 ============================================================================== 
 */ 
 
-typedef struct _TargaHeader {
-       unsigned char   id_length, colormap_type, image_type;
-       unsigned short  colormap_index, colormap_length;
-       unsigned char   colormap_size;
-       unsigned short  x_origin, y_origin, width, height;
-       unsigned char   pixel_size, attributes;
-} TargaHeader;
-
-
-/* 
-================== 
+/*
+==================
 SCR_ScreenShot_f
 SCR_ScreenShot_f
-================== 
-*/  
-void SCR_ScreenShot_f (void) 
+==================
+*/
+void SCR_ScreenShot_f (void)
 {
 {
-       byte            *buffer;
-       char            pcxname[80]; 
+       byte            *buffer, gamma[256];
+       char            filename[80];
        char            checkname[MAX_OSPATH];
        char            checkname[MAX_OSPATH];
-       int                     i, c, temp;
-// 
-// find a file name to save it to 
-// 
-       strcpy(pcxname,"dp0000.tga");
-               
-       for (i=0 ; i<=9999 ; i++) 
-       { 
-               pcxname[2] = (i/1000)%10 + '0'; 
-               pcxname[3] = (i/ 100)%10 + '0'; 
-               pcxname[4] = (i/  10)%10 + '0'; 
-               pcxname[5] = (i/   1)%10 + '0'; 
-               sprintf (checkname, "%s/%s", com_gamedir, pcxname);
+       int                     i;
+//
+// find a file name to save it to
+//
+       strcpy(filename,"dp0000.tga");
+
+       for (i=0 ; i<=9999 ; i++)
+       {
+               filename[2] = (i/1000)%10 + '0';
+               filename[3] = (i/ 100)%10 + '0';
+               filename[4] = (i/  10)%10 + '0';
+               filename[5] = (i/   1)%10 + '0';
+               sprintf (checkname, "%s/%s", com_gamedir, filename);
                if (Sys_FileTime(checkname) == -1)
                        break;  // file doesn't exist
                if (Sys_FileTime(checkname) == -1)
                        break;  // file doesn't exist
-       } 
+       }
        if (i==10000)
        {
        if (i==10000)
        {
-               Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n"); 
+               Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
                return;
        }
 
                return;
        }
 
+       buffer = Mem_Alloc(tempmempool, vid.realwidth*vid.realheight*3);
+       glReadPixels (vid.realx, vid.realy, vid.realwidth, vid.realheight, GL_RGB, GL_UNSIGNED_BYTE, buffer);
+       CHECKGLERROR
+
+       // apply hardware gamma to the image
+       BuildGammaTable8((lighthalf && hardwaregammasupported) ? 2.0f : 1.0f, 1, 1, 0, gamma);
+       Image_GammaRemapRGB(buffer, buffer, vid.realwidth*vid.realheight, gamma, gamma, gamma);
+
+       Image_WriteTGARGB_preflipped(filename, vid.realwidth, vid.realheight, buffer);
+
+       Mem_Free(buffer);
+       Con_Printf ("Wrote %s\n", filename);
+}
+
+/*
+===============
+R_Envmap_f
+
+Grab six views for environment mapping tests
+===============
+*/
+float CalcFov (float fov_x, float width, float height);
+struct
+{
+       float angles[3];
+       char *name;
+}
+envmapinfo[6] =
+{
+       {{  0,   0, 0}, "ft"},
+       {{  0,  90, 0}, "rt"},
+       {{  0, 180, 0}, "bk"},
+       {{  0, 270, 0}, "lf"},
+       {{-90,  90, 0}, "up"},
+       {{ 90,  90, 0}, "dn"}
+};
+static void R_Envmap_f (void)
+{
+       int             i, size;
+       char    filename[256];
+       char    basename[256];
+       byte    *buffer, gamma[256];
+
+       if (Cmd_Argc() != 3)
+       {
+               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");
+               return;
+       }
+
+       if (!r_render.integer)
+               return;
+
+       strcpy(basename, Cmd_Argv(1));
+       size = atoi(Cmd_Argv(2));
+       if (size != 128 && size != 256 && size != 512 && size != 1024)
+       {
+               Con_Printf("envmap: size must be one of 128, 256, 512, or 1024\n");
+               return;
+       }
+       if (size > vid.realwidth || size > vid.realheight)
+       {
+               Con_Printf("envmap: your resolution is not big enough to render that size\n");
+               return;
+       }
+
+       buffer = Mem_Alloc(tempmempool, size*size*3);
+       if (buffer == NULL)
+       {
+               Con_Printf("envmap: unable to allocate memory for image\n");
+               return;
+       }
+
+       BuildGammaTable8((lighthalf && hardwaregammasupported) ? 2.0f : 1.0f, 1, 1, 0, gamma);
+
+//     glDrawBuffer  (GL_FRONT);
+//     glReadBuffer  (GL_FRONT);
+       glDrawBuffer  (GL_BACK);
+       glReadBuffer  (GL_BACK);
+       envmap = true;
 
 
-       buffer = malloc(glwidth*glheight*3 + 18);
-       memset (buffer, 0, 18);
-       buffer[2] = 2;          // uncompressed type
-       buffer[12] = glwidth&255;
-       buffer[13] = glwidth>>8;
-       buffer[14] = glheight&255;
-       buffer[15] = glheight>>8;
-       buffer[16] = 24;        // pixel size
+       r_refdef.x = 0;
+       r_refdef.y = 0;
+       r_refdef.width = size;
+       r_refdef.height = size;
 
 
-       glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); 
+       r_refdef.fov_x = 90;
+       r_refdef.fov_y = 90;
 
 
-       // swap rgb to bgr
-       c = 18+glwidth*glheight*3;
-       for (i=18 ; i<c ; i+=3)
+       for (i = 0;i < 6;i++)
        {
        {
-               temp = buffer[i];
-               buffer[i] = buffer[i+2];
-               buffer[i+2] = temp;
+               VectorCopy(envmapinfo[i].angles, r_refdef.viewangles);
+               glClearColor(0,0,0,0);
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
+               R_RenderView ();
+               glReadPixels (0, 0, size, size, GL_RGB, GL_UNSIGNED_BYTE, buffer);
+               sprintf(filename, "env/%s%s.tga", basename, envmapinfo[i].name);
+               Image_GammaRemapRGB(buffer, buffer, size * size, gamma, gamma, gamma);
+               Image_WriteTGARGB_preflipped(filename, size, size, buffer);
        }
        }
-       COM_WriteFile (pcxname, buffer, glwidth*glheight*3 + 18 );
 
 
-       free (buffer);
-       Con_Printf ("Wrote %s\n", pcxname);
-} 
+       envmap = false;
+       glDrawBuffer  (GL_BACK);
+       glReadBuffer  (GL_BACK);
 
 
+       Mem_Free(buffer);
+
+       // cause refdef to be fixed
+//     vid.recalc_refdef = 1;
+}
 
 //=============================================================================
 
 
 //=============================================================================
 
@@ -667,30 +694,28 @@ SCR_BeginLoadingPlaque
 
 ================
 */
 
 ================
 */
+/*
 void SCR_BeginLoadingPlaque (void)
 {
        S_StopAllSounds (true);
 
 void SCR_BeginLoadingPlaque (void)
 {
        S_StopAllSounds (true);
 
-       if (cls.state != ca_connected)
-               return;
-       if (cls.signon != SIGNONS)
-               return;
-       
+//     if (cls.state != ca_connected)
+//             return;
+//     if (cls.signon != SIGNONS)
+//             return;
+
 // redraw with no console and the loading plaque
 // redraw with no console and the loading plaque
-       Con_ClearNotify ();
-       scr_centertime_off = 0;
-       scr_con_current = 0;
+//     Con_ClearNotify ();
+//     scr_centertime_off = 0;
+//     scr_con_current = 0;
 
        scr_drawloading = true;
 
        scr_drawloading = true;
-       scr_fullupdate = 0;
-//     Sbar_Changed ();
        SCR_UpdateScreen ();
        SCR_UpdateScreen ();
-       scr_drawloading = false;
 
 
-       scr_disabled_for_loading = true;
-       scr_disabled_time = realtime;
-       scr_fullupdate = 0;
+//     scr_disabled_for_loading = true;
+//     scr_disabled_time = realtime;
 }
 }
+*/
 
 /*
 ===============
 
 /*
 ===============
@@ -698,17 +723,18 @@ SCR_EndLoadingPlaque
 
 ================
 */
 
 ================
 */
+/*
 void SCR_EndLoadingPlaque (void)
 {
 void SCR_EndLoadingPlaque (void)
 {
-       scr_disabled_for_loading = false;
-       scr_fullupdate = 0;
+//     scr_disabled_for_loading = false;
+       scr_drawloading = false;
        Con_ClearNotify ();
 }
        Con_ClearNotify ();
 }
+*/
 
 //=============================================================================
 
 char   *scr_notifystring;
 
 //=============================================================================
 
 char   *scr_notifystring;
-qboolean       scr_drawdialog;
 
 void SCR_DrawNotifyString (void)
 {
 
 void SCR_DrawNotifyString (void)
 {
@@ -718,7 +744,7 @@ void SCR_DrawNotifyString (void)
 
        start = scr_notifystring;
 
 
        start = scr_notifystring;
 
-       y = vid.height*0.35;
+       y = vid.conheight*0.35;
 
        do      
        {
 
        do      
        {
@@ -726,12 +752,12 @@ void SCR_DrawNotifyString (void)
                for (l=0 ; l<40 ; l++)
                        if (start[l] == '\n' || !start[l])
                                break;
                for (l=0 ; l<40 ; l++)
                        if (start[l] == '\n' || !start[l])
                                break;
-               x = (vid.width - l*8)/2;
+               x = (vid.conwidth - l*8)/2;
                // LordHavoc: speedup
 //             for (j=0 ; j<l ; j++, x+=8)
                // LordHavoc: speedup
 //             for (j=0 ; j<l ; j++, x+=8)
-//                     Draw_Character (x, y, start[j]);        
+//                     Draw_Character (x, y, start[j]);
                Draw_String (x, y, start, l);
                Draw_String (x, y, start, l);
-                       
+
                y += 8;
 
                while (*start && *start != '\n')
                y += 8;
 
                while (*start && *start != '\n')
@@ -743,82 +769,45 @@ void SCR_DrawNotifyString (void)
        } while (1);
 }
 
        } while (1);
 }
 
-/*
-==================
-SCR_ModalMessage
-
-Displays a text string in the center of the screen and waits for a Y or N
-keypress.  
-==================
-*/
-int SCR_ModalMessage (char *text)
-{
-       if (cls.state == ca_dedicated)
-               return true;
-
-       scr_notifystring = text;
-// draw a fresh screen
-       scr_fullupdate = 0;
-       scr_drawdialog = true;
-       SCR_UpdateScreen ();
-       scr_drawdialog = false;
-       
-       S_ClearBuffer ();               // so dma doesn't loop current sound
-
-       do
-       {
-               key_count = -1;         // wait for a key down and up
-               Sys_SendKeyEvents ();
-       } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
-
-       scr_fullupdate = 0;
-       SCR_UpdateScreen ();
-
-       return key_lastpress == 'y';
-}
-
-
 //=============================================================================
 
 //=============================================================================
 
-/*
-===============
-SCR_BringDownConsole
+void DrawCrosshair(int num);
+void GL_Set2D (void);
 
 
-Brings the console down and fades the palettes back to normal
-================
-*/
-void SCR_BringDownConsole (void)
+void GL_BrightenScreen(void)
 {
 {
-       int             i;
-       
-       scr_centertime_off = 0;
-       
-       for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
-               SCR_UpdateScreen ();
+       float f;
 
 
-       cl.cshifts[0].percent = 0;              // no area contents palette on next frame
-       VID_SetPalette (host_basepal);
-}
+       if (r_brightness.value < 0.1f)
+               Cvar_SetValue("r_brightness", 0.1f);
+       if (r_brightness.value > 5.0f)
+               Cvar_SetValue("r_brightness", 5.0f);
 
 
-void GL_Set2D (void);
+       if (r_contrast.value < 0.2f)
+               Cvar_SetValue("r_contrast", 0.2f);
+       if (r_contrast.value > 1.0f)
+               Cvar_SetValue("r_contrast", 1.0f);
 
 
-extern void SHOWLMP_drawall();
-extern cvar_t contrast;
-extern cvar_t brightness;
-extern cvar_t gl_lightmode;
+       if (!(lighthalf && !hardwaregammasupported) && r_brightness.value < 1.01f && r_contrast.value > 0.99f)
+               return;
+
+       if (!r_render.integer)
+               return;
 
 
-void GL_BrightenScreen()
-{
-       float f;
        glDisable(GL_TEXTURE_2D);
        glDisable(GL_TEXTURE_2D);
+       CHECKGLERROR
        glEnable(GL_BLEND);
        glEnable(GL_BLEND);
-       f = brightness.value = bound(1.0f, brightness.value, 5.0f);
-       if (f > 1)
+       CHECKGLERROR
+       f = r_brightness.value;
+       // only apply lighthalf using software color correction if hardware is not available (speed reasons)
+       if (lighthalf && !hardwaregammasupported)
+               f *= 2;
+       if (f >= 1.01f)
        {
                glBlendFunc (GL_DST_COLOR, GL_ONE);
        {
                glBlendFunc (GL_DST_COLOR, GL_ONE);
+               CHECKGLERROR
                glBegin (GL_TRIANGLES);
                glBegin (GL_TRIANGLES);
-               while (f > 1)
+               while (f >= 1.01f)
                {
                        if (f >= 2)
                                glColor3f (1, 1, 1);
                {
                        if (f >= 2)
                                glColor3f (1, 1, 1);
@@ -830,23 +819,88 @@ void GL_BrightenScreen()
                        f *= 0.5;
                }
                glEnd ();
                        f *= 0.5;
                }
                glEnd ();
+               CHECKGLERROR
        }
        }
-       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-       contrast.value = bound(0.2, contrast.value, 1.0);
-       if (contrast.value < 1.0f)
+       if (r_contrast.value <= 0.99f)
        {
        {
+               glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               CHECKGLERROR
+               if (lighthalf && hardwaregammasupported)
+                       glColor4f (0.5, 0.5, 0.5, 1 - r_contrast.value);
+               else
+                       glColor4f (1, 1, 1, 1 - r_contrast.value);
+               CHECKGLERROR
                glBegin (GL_TRIANGLES);
                glBegin (GL_TRIANGLES);
-               glColor4f (1, 1, 1, 1-contrast.value);
                glVertex2f (-5000, -5000);
                glVertex2f (10000, -5000);
                glVertex2f (-5000, 10000);
                glEnd ();
                glVertex2f (-5000, -5000);
                glVertex2f (10000, -5000);
                glVertex2f (-5000, 10000);
                glEnd ();
+               CHECKGLERROR
        }
        }
+       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       CHECKGLERROR
 
        glEnable (GL_CULL_FACE);
 
        glEnable (GL_CULL_FACE);
+       CHECKGLERROR
        glEnable (GL_DEPTH_TEST);
        glEnable (GL_DEPTH_TEST);
+       CHECKGLERROR
        glDisable(GL_BLEND);
        glDisable(GL_BLEND);
+       CHECKGLERROR
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_TEXTURE_2D);
+       CHECKGLERROR
+}
+
+char r_speeds2_string[1024];
+int speedstringcount, r_timereport_active;
+double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
+
+void R_TimeReport(char *desc)
+{
+       char tempbuf[256];
+       int length;
+       int t;
+
+       if (!r_timereport_active)
+               return;
+
+       r_timereport_temp = r_timereport_current;
+       r_timereport_current = Sys_DoubleTime();
+       t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
+
+       sprintf(tempbuf, "%8i %s", t, desc);
+       length = strlen(tempbuf);
+       while (length < 20)
+               tempbuf[length++] = ' ';
+       tempbuf[length] = 0;
+       if (speedstringcount + length > (vid.conwidth / 8))
+       {
+               strcat(r_speeds2_string, "\n");
+               speedstringcount = 0;
+       }
+       // skip the space at the beginning if it's the first on the line
+       if (speedstringcount == 0)
+       {
+               strcat(r_speeds2_string, tempbuf + 1);
+               speedstringcount = length - 1;
+       }
+       else
+       {
+               strcat(r_speeds2_string, tempbuf);
+               speedstringcount += length;
+       }
+}
+
+void R_TimeReport_Start(void)
+{
+       r_timereport_active = r_speeds2.integer && cl.worldmodel && cls.state == ca_connected;
+       if (r_timereport_active)
+               r_timereport_start = Sys_DoubleTime();
+}
+
+void R_TimeReport_End(void)
+{
+       r_timereport_current = r_timereport_start;
+       R_TimeReport("total");
 }
 
 /*
 }
 
 /*
@@ -856,148 +910,221 @@ SCR_UpdateScreen
 This is called every frame, and can also be called explicitly to flush
 text to the screen.
 
 This is called every frame, and can also be called explicitly to flush
 text to the screen.
 
-WARNING: be very careful calling this from elsewhere, because the refresh
-needs almost the entire 256k of stack space!
+LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
 ==================
 */
 ==================
 */
-extern cvar_t gl_vertexarrays;
-extern qboolean gl_arrays;
-void GL_Finish();
-int c_nodes;
+void GL_Finish(void);
+void R_Clip_DisplayBuffer(void);
 void SCR_UpdateScreen (void)
 {
        double  time1 = 0, time2;
 
 void SCR_UpdateScreen (void)
 {
        double  time1 = 0, time2;
 
-       if (r_speeds.value)
-       {
-               time1 = Sys_FloatTime ();
-               c_brush_polys = 0;
-               c_alias_polys = 0;
-               c_nodes = 0;
-       }
-
-       if (!gl_arrays)
-               gl_vertexarrays.value = 0;
+       if (r_speeds.integer)
+               time1 = Sys_DoubleTime ();
 
 
-       vid.numpages = 2 + gl_triplebuffer.value;
-
-       scr_copytop = 0;
-       scr_copyeverything = 0;
+       VID_UpdateGamma(false);
 
        if (scr_disabled_for_loading)
        {
 
        if (scr_disabled_for_loading)
        {
+               /*
                if (realtime - scr_disabled_time > 60)
                {
                        scr_disabled_for_loading = false;
                        Con_Printf ("load failed.\n");
                }
                else
                if (realtime - scr_disabled_time > 60)
                {
                        scr_disabled_for_loading = false;
                        Con_Printf ("load failed.\n");
                }
                else
+               */
                        return;
        }
 
        if (!scr_initialized || !con_initialized)
                return;                         // not initialized yet
 
                        return;
        }
 
        if (!scr_initialized || !con_initialized)
                return;                         // not initialized yet
 
+       r_speeds2_string[0] = 0;
+       if (r_speeds2.integer)
+       {
+               speedstringcount = 0;
+               sprintf(r_speeds2_string, "org:'%c%6.2f %c%6.2f %c%6.2f' ang:'%c%3.0f %c%3.0f %c%3.0f' dir:'%c%2.3f %c%2.3f %c%2.3f'\n%6i walls %6i dlitwalls %7i modeltris %7i meshtris\nBSP: %6i faces %6i nodes %6i leafs\n%4i models %4i bmodels %4i sprites %5i particles %3i dlights\n",
+                       r_origin[0] < 0 ? '-' : ' ', fabs(r_origin[0]), r_origin[1] < 0 ? '-' : ' ', fabs(r_origin[1]), r_origin[2] < 0 ? '-' : ' ', fabs(r_origin[2]), r_refdef.viewangles[0] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[0]), r_refdef.viewangles[1] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[1]), r_refdef.viewangles[2] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[2]), vpn[0] < 0 ? '-' : ' ', fabs(vpn[0]), vpn[1] < 0 ? '-' : ' ', fabs(vpn[1]), vpn[2] < 0 ? '-' : ' ', fabs(vpn[2]),
+                       c_brush_polys, c_light_polys, c_alias_polys, c_meshtris,
+                       c_faces, c_nodes, c_leafs,
+                       c_models, c_bmodels, c_sprites, c_particles, c_dlights);
+               R_TimeReport_Start();
+       }
+
+       Mem_CheckSentinelsGlobal();
+       R_TimeReport("memtest");
+
+       GL_Finish();
+       GL_EndRendering ();
+
+       R_TimeReport("finish");
+
+       GL_BeginRendering (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
+
+       if (gl_combine.integer && !gl_combine_extension)
+               Cvar_SetValue("gl_combine", 0);
+
+       lighthalf = gl_lightmode.integer;
+
+       lightscalebit = 0;
+       if (lighthalf)
+               lightscalebit += 1;
+
+       if (gl_combine.integer && r_multitexture.integer)
+               lightscalebit += 2;
+
+       lightscale = 1.0f / (float) (1 << lightscalebit);
 
 
-       GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
-       
        //
        // determine size of refresh window
        //
        if (oldfov != scr_fov.value)
        {
                oldfov = scr_fov.value;
        //
        // determine size of refresh window
        //
        if (oldfov != scr_fov.value)
        {
                oldfov = scr_fov.value;
-               vid.recalc_refdef = true;
+//             vid.recalc_refdef = true;
        }
 
        if (oldscreensize != scr_viewsize.value)
        {
                oldscreensize = scr_viewsize.value;
        }
 
        if (oldscreensize != scr_viewsize.value)
        {
                oldscreensize = scr_viewsize.value;
-               vid.recalc_refdef = true;
+//             vid.recalc_refdef = true;
        }
 
        }
 
-       if (vid.recalc_refdef)
-               SCR_CalcRefdef ();
+//     if (vid.recalc_refdef)
+               SCR_CalcRefdef();
 
 
-       glClearColor(0,0,0,0);
-       glClear (GL_COLOR_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
+       R_TimeReport("calcrefdef");
+
+       if (r_render.integer)
+       {
+               glClearColor(0,0,0,0);
+               CHECKGLERROR
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
+               CHECKGLERROR
+       }
+
+       R_TimeReport("clear");
+
+       if (gl_dither.integer)
+               glEnable(GL_DITHER);
+       else
+               glDisable(GL_DITHER);
+       CHECKGLERROR
 
 //
 // do 3D refresh drawing, and then update the screen
 //
 
 //
 // do 3D refresh drawing, and then update the screen
 //
-       SCR_SetUpToDrawConsole ();
+       SCR_SetUpToDrawConsole();
 
 
-       V_RenderView ();
+       R_TimeReport("setupconsole");
 
 
-       GL_Set2D ();
+       V_RenderView();
 
 
-       if (scr_drawdialog)
-       {
-               Sbar_Draw ();
-//             Draw_FadeScreen ();
-               SCR_DrawNotifyString ();
-               scr_copyeverything = true;
-       }
-       else if (scr_drawloading)
-       {
-               SCR_DrawLoading ();
-               Sbar_Draw ();
-       }
-       else if (cl.intermission == 1 && key_dest == key_game)
-       {
-               Sbar_IntermissionOverlay ();
-       }
-       else if (cl.intermission == 2 && key_dest == key_game)
-       {
-               Sbar_FinaleOverlay ();
-               SCR_CheckDrawCenterString ();
-       }
-       else
-       {
-               if (crosshair.value)
-                       Draw_Character (scr_vrect.x + scr_vrect.width/2, scr_vrect.y + scr_vrect.height/2, '+');
-               
-               SCR_DrawRam ();
-               SCR_DrawNet ();
-               SCR_DrawTurtle ();
-               SCR_DrawPause ();
-               SCR_CheckDrawCenterString ();
-               Sbar_Draw ();
-               SHOWLMP_drawall();
-               SCR_DrawConsole ();     
-               M_Draw ();
-       }
+       V_UpdateBlends();
+
+       GL_Set2D();
+
+       R_Clip_DisplayBuffer();
+
+       SCR_DrawRam();
+       SCR_DrawNet();
+       SCR_DrawTurtle();
+       SCR_DrawPause();
+       SCR_CheckDrawCenterString();
+       Sbar_Draw();
+       SHOWLMP_drawall();
+
+       if (crosshair.integer)
+               DrawCrosshair(crosshair.integer - 1);
+
+       if (cl.intermission == 1)
+               Sbar_IntermissionOverlay();
+       else if (cl.intermission == 2)
+               Sbar_FinaleOverlay();
+
+       SCR_DrawConsole();
+       M_Draw();
 
 
-       if (showfps.value)
+       ui_draw();
+
+//     if (scr_drawloading)
+//             SCR_DrawLoading();
+
+       if (showfps.integer)
        {
        {
-               static double currtime;
-               double newtime;
+               static double currtime, frametimes[32];
+               double newtime, total;
                char temp[32];
                char temp[32];
-               int calc;
-               newtime = Sys_FloatTime();
-               calc = (int) (100.0 / (newtime - currtime));
-               sprintf(temp, "% 4i.%02i fps", calc / 100, calc % 100);
+               int calc, count, i;
+               static int framecycle = 0;
+               newtime = Sys_DoubleTime();
+               frametimes[framecycle] = newtime - currtime;
+               framecycle++;
+               framecycle &= 31;
+               total = 0;
+               count = 0;
+               for (i = 0;i < 32;i++)
+               {
+                       if (frametimes[i])
+                       {
+                               total += frametimes[i];
+                               count++;
+                               // limit how far back we look
+                               if (total >= 0.25)
+                                       break;
+                       }
+               }
+               if (showfps.integer == 1)
+                       calc = (int) ((count / total) + 0.5);
+               else // showfps 2, rapid update
+                       calc = (int) ((1.0 / (newtime - currtime)) + 0.5);
+               sprintf(temp, "%4i fps", calc);
                currtime = newtime;
                currtime = newtime;
-               Draw_String(vid.width - (12*8), 0, temp, 9999);
+               Draw_String(vid.conwidth - (8*8), vid.conheight - sb_lines - 8, temp, 9999);
        }
 
        }
 
-       V_UpdatePalette ();
+       R_TimeReport("2d");
 
 
-       GL_BrightenScreen();
+       R_TimeReport_End();
 
 
-       GL_Finish();
+       if (r_speeds2_string[0] && cls.state == ca_connected && cl.worldmodel)
+       {
+               int i, j, lines, y;
+               lines = 1;
+               for (i = 0;r_speeds2_string[i];i++)
+                       if (r_speeds2_string[i] == '\n')
+                               lines++;
+               y = vid.conheight - sb_lines - lines * 8 - 8;
+               i = j = 0;
+               while (r_speeds2_string[i])
+               {
+                       j = i;
+                       while (r_speeds2_string[i] && r_speeds2_string[i] != '\n')
+                               i++;
+                       if (i - j > 0)
+                               Draw_String(0, y, r_speeds2_string + j, i - j);
+                       if (r_speeds2_string[i] == '\n')
+                               i++;
+                       y += 8;
+               }
+       }
 
 
-       if (r_speeds.value)
+       GL_BrightenScreen();
+
+       if (r_speeds.integer)
        {
        {
-               time2 = Sys_FloatTime ();
-               Con_Printf ("%3i ms  %4i wpoly %4i epoly %4i transpoly %4i BSPnodes\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys, currenttranspoly, c_nodes); 
+               time2 = Sys_DoubleTime ();
+               Con_Printf ("%3i ms  %4i wpoly %4i epoly %6i meshtris %4i lightpoly %4i BSPnodes %4i BSPleafs %4i BSPfaces %4i models %4i bmodels %4i sprites %4i particles %3i dlights\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys, c_meshtris, c_light_polys, c_nodes, c_leafs, c_faces, c_models, c_bmodels, c_sprites, c_particles, c_dlights);
        }
        }
-       GL_EndRendering ();
 }
 
 }
 
-// for profiling, this is seperated
-void GL_Finish()
+// for profiling, this is separated
+void GL_Finish(void)
 {
 {
+       if (!r_render.integer)
+               return;
        glFinish ();
        glFinish ();
+       CHECKGLERROR
 }
 
 }