Red and blue quake2
Chris Venter
chris at dsp.sun.ac.za
Wed Jan 30 09:41:20 EST 2002
Hi all,
I saw this link <http://www.jfedor.org/red-blue-quake2/>
on www.linuxgames.com on Friday. It creates a stereo software renderer for
those funky red and blue glasses.
jfedor modified the original id source, which I just manually
applied to the r0.0.8 release, and created a patch (attached).
I have tested this patch on a clean r0.0.8 source tree and it compiles
for me. If it doesn't want to patch/compile properly, please tell me.
Thanks for all the cool work guys, I have rediscovered quake2!
PS jfedor mentions he may still do an OpenGL renderer, which may speed
things up. Any takers?
--
Chris Venter :: http://www.dsp.sun.ac.za/~chris
Two fish are in a tank. One says to the other, "I'll drive. You man the guns."
-------------- next part --------------
diff -ur quake2-r0.0.8/Makefile quake2-devel-r0.0.8/Makefile
--- quake2-r0.0.8/Makefile Wed Jan 9 13:26:31 2002
+++ quake2-devel-r0.0.8/Makefile Wed Jan 30 15:04:13 2002
@@ -14,7 +14,7 @@
# game{i386,axp,ppc}.so is automatically built.
BUILD_SDLQUAKE2=YES # sdlquake2 executable (uses SDL for cdrom and sound)
BUILD_SVGA=NO # SVGAlib driver. Seems to work fine.
-BUILD_X11=NO # X11 software driver. Works somewhat ok.
+BUILD_X11=YES # X11 software driver. Works somewhat ok.
BUILD_GLX=YES # X11 GLX driver. Works somewhat ok.
BUILD_FXGL=NO # FXMesa driver. Not tested. (used only for V1 and V2).
BUILD_SDL=YES # SDL software driver. Works fine for some people.
Only in quake2-r0.0.8: Makefile~
Only in quake2-r0.0.8: README.r~
diff -ur quake2-r0.0.8/src/client/cl_scrn.c quake2-devel-r0.0.8/src/client/cl_scrn.c
--- quake2-r0.0.8/src/client/cl_scrn.c Thu Jan 3 07:10:13 2002
+++ quake2-devel-r0.0.8/src/client/cl_scrn.c Wed Jan 30 15:18:24 2002
@@ -1,1411 +1,1410 @@
-/*
-Copyright (C) 1997-2001 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
-
-/*
-
- full screen console
- put up loading plaque
- blanked background with loading plaque
- blanked background with menu
- cinematics
- full screen image for quit and victory
-
- end of unit intermissions
-
- */
-
-#include "client.h"
-
-float scr_con_current; // aproaches scr_conlines at scr_conspeed
-float scr_conlines; // 0.0 to 1.0 lines of console to display
-
-qboolean scr_initialized; // ready to draw
-
-int scr_draw_loading;
-
-vrect_t scr_vrect; // position of render window on screen
-
-
-cvar_t *scr_viewsize;
-cvar_t *scr_conspeed;
-cvar_t *scr_centertime;
-cvar_t *scr_showturtle;
-cvar_t *scr_showpause;
-cvar_t *scr_printspeed;
-
-cvar_t *scr_netgraph;
-cvar_t *scr_timegraph;
-cvar_t *scr_debuggraph;
-cvar_t *scr_graphheight;
-cvar_t *scr_graphscale;
-cvar_t *scr_graphshift;
-cvar_t *scr_drawall;
-
-typedef struct
-{
- int x1, y1, x2, y2;
-} dirty_t;
-
-dirty_t scr_dirty, scr_old_dirty[2];
-
-char crosshair_pic[MAX_QPATH];
-int crosshair_width, crosshair_height;
-
-extern cvar_t *cl_drawfps; // FPS hack
-
-void SCR_TimeRefresh_f (void);
-void SCR_Loading_f (void);
-
-
-/*
-===============================================================================
-
-BAR GRAPHS
-
-===============================================================================
-*/
-
-/*
-==============
-CL_AddNetgraph
-
-A new packet was just parsed
-==============
-*/
-void CL_AddNetgraph (void)
-{
- int i;
- int in;
- int ping;
-
- // if using the debuggraph for something else, don't
- // add the net lines
- if (scr_debuggraph->value || scr_timegraph->value)
- return;
-
- for (i=0 ; i<cls.netchan.dropped ; i++)
- SCR_DebugGraph (30, 0x40);
-
- for (i=0 ; i<cl.surpressCount ; i++)
- SCR_DebugGraph (30, 0xdf);
-
- // see what the latency was on this packet
- in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
- ping = cls.realtime - cl.cmd_time[in];
- ping /= 30;
- if (ping > 30)
- ping = 30;
- SCR_DebugGraph (ping, 0xd0);
-}
-
-
-typedef struct
-{
- float value;
- int color;
-} graphsamp_t;
-
-static int current;
-static graphsamp_t values[1024];
-
-/*
-==============
-SCR_DebugGraph
-==============
-*/
-void SCR_DebugGraph (float value, int color)
-{
- values[current&1023].value = value;
- values[current&1023].color = color;
- current++;
-}
-
-/*
-==============
-SCR_DrawDebugGraph
-==============
-*/
-void SCR_DrawDebugGraph (void)
-{
- int a, x, y, w, i, h;
- float v;
- int color;
-
- //
- // draw the graph
- //
- w = scr_vrect.width;
-
- x = scr_vrect.x;
- y = scr_vrect.y+scr_vrect.height;
- re.DrawFill (x, y-scr_graphheight->value,
- w, scr_graphheight->value, 8);
-
- for (a=0 ; a<w ; a++)
- {
- i = (current-1-a+1024) & 1023;
- v = values[i].value;
- color = values[i].color;
- v = v*scr_graphscale->value + scr_graphshift->value;
-
- if (v < 0)
- v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
- h = (int)v % (int)scr_graphheight->value;
- re.DrawFill (x+w-1-a, y - h, 1, h, color);
- }
-}
-
-/*
-===============================================================================
-
-CENTER PRINTING
-
-===============================================================================
-*/
-
-char scr_centerstring[1024];
-float scr_centertime_start; // for slow victory printing
-float scr_centertime_off;
-int scr_center_lines;
-int scr_erase_center;
-
-/*
-==============
-SCR_CenterPrint
-
-Called for important messages that should stay in the center of the screen
-for a few moments
-==============
-*/
-void SCR_CenterPrint (char *str)
-{
- char *s;
- char line[64];
- int i, j, l;
-
- strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
- scr_centertime_off = scr_centertime->value;
- scr_centertime_start = cl.time;
-
- // count the number of lines for centering
- scr_center_lines = 1;
- s = str;
- while (*s)
- {
- if (*s == '\n')
- scr_center_lines++;
- s++;
- }
-
- // echo it to the console
- Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
-
- s = str;
- do
- {
- // scan the width of the line
- for (l=0 ; l<40 ; l++)
- if (s[l] == '\n' || !s[l])
- break;
- for (i=0 ; i<(40-l)/2 ; i++)
- line[i] = ' ';
-
- for (j=0 ; j<l ; j++)
- {
- line[i++] = s[j];
- }
-
- line[i] = '\n';
- line[i+1] = 0;
-
- Com_Printf ("%s", line);
-
- while (*s && *s != '\n')
- s++;
-
- if (!*s)
- break;
- s++; // skip the \n
- } while (1);
- Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
- Con_ClearNotify ();
-}
-
-
-void SCR_DrawCenterString (void)
-{
- char *start;
- int l;
- int j;
- int x, y;
- int remaining;
-
-// the finale prints the characters one at a time
- remaining = 9999;
-
- scr_erase_center = 0;
- start = scr_centerstring;
-
- if (scr_center_lines <= 4)
- y = viddef.height*0.35;
- else
- y = 48;
-
- do
- {
- // scan the width of the line
- for (l=0 ; l<40 ; l++)
- if (start[l] == '\n' || !start[l])
- break;
- x = (viddef.width - l*8)/2;
- SCR_AddDirtyPoint (x, y);
- for (j=0 ; j<l ; j++, x+=8)
- {
- re.DrawChar (x, y, start[j]);
- if (!remaining--)
- return;
- }
- SCR_AddDirtyPoint (x, y+8);
-
- y += 8;
-
- while (*start && *start != '\n')
- start++;
-
- if (!*start)
- break;
- start++; // skip the \n
- } while (1);
-}
-
-void SCR_CheckDrawCenterString (void)
-{
- scr_centertime_off -= cls.frametime;
-
- if (scr_centertime_off <= 0)
- return;
-
- SCR_DrawCenterString ();
-}
-
-//=============================================================================
-
-/*
-=================
-SCR_CalcVrect
-
-Sets scr_vrect, the coordinates of the rendered window
-=================
-*/
-static void SCR_CalcVrect (void)
-{
- int size;
-
- // bound viewsize
- if (scr_viewsize->value < 40)
- Cvar_Set ("viewsize","40");
- if (scr_viewsize->value > 100)
- Cvar_Set ("viewsize","100");
-
- size = scr_viewsize->value;
-
- scr_vrect.width = viddef.width*size/100;
- scr_vrect.width &= ~7;
-
- scr_vrect.height = viddef.height*size/100;
- scr_vrect.height &= ~1;
-
- scr_vrect.x = (viddef.width - scr_vrect.width)/2;
- scr_vrect.y = (viddef.height - scr_vrect.height)/2;
-}
-
-
-/*
-=================
-SCR_SizeUp_f
-
-Keybinding command
-=================
-*/
-void SCR_SizeUp_f (void)
-{
- Cvar_SetValue ("viewsize",scr_viewsize->value+10);
-}
-
-
-/*
-=================
-SCR_SizeDown_f
-
-Keybinding command
-=================
-*/
-void SCR_SizeDown_f (void)
-{
- Cvar_SetValue ("viewsize",scr_viewsize->value-10);
-}
-
-/*
-=================
-SCR_Sky_f
-
-Set a specific sky and rotation speed
-=================
-*/
-void SCR_Sky_f (void)
-{
- float rotate;
- vec3_t axis;
-
- if (Cmd_Argc() < 2)
- {
- Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
- return;
- }
- if (Cmd_Argc() > 2)
- rotate = atof(Cmd_Argv(2));
- else
- rotate = 0;
- if (Cmd_Argc() == 6)
- {
- axis[0] = atof(Cmd_Argv(3));
- axis[1] = atof(Cmd_Argv(4));
- axis[2] = atof(Cmd_Argv(5));
- }
- else
- {
- axis[0] = 0;
- axis[1] = 0;
- axis[2] = 1;
- }
-
- re.SetSky (Cmd_Argv(1), rotate, axis);
-}
-
-//============================================================================
-
-/*
-==================
-SCR_Init
-==================
-*/
-void SCR_Init (void)
-{
- scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
- scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
- scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
- scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
- scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
- scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
- scr_netgraph = Cvar_Get ("netgraph", "0", 0);
- scr_timegraph = Cvar_Get ("timegraph", "0", 0);
- scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
- scr_graphheight = Cvar_Get ("graphheight", "32", 0);
- scr_graphscale = Cvar_Get ("graphscale", "1", 0);
- scr_graphshift = Cvar_Get ("graphshift", "0", 0);
- scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
-
-//
-// register our commands
-//
- Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
- Cmd_AddCommand ("loading",SCR_Loading_f);
- Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
- Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
- Cmd_AddCommand ("sky",SCR_Sky_f);
-
- scr_initialized = true;
-}
-
-
-/*
-==============
-SCR_DrawNet
-==============
-*/
-void SCR_DrawNet (void)
-{
- if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged
- < CMD_BACKUP-1)
- return;
-
- re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
-}
-
-/*
-==============
-SCR_DrawPause
-==============
-*/
-void SCR_DrawPause (void)
-{
- int w, h;
-
- if (!scr_showpause->value) // turn off for screenshots
- return;
-
- if (!cl_paused->value)
- return;
-
- re.DrawGetPicSize (&w, &h, "pause");
- re.DrawPic ((viddef.width-w)/2, viddef.height/2 + 8, "pause");
-}
-
-/*
-==============
-SCR_DrawLoading
-==============
-*/
-void SCR_DrawLoading (void)
-{
- int w, h;
-
- if (!scr_draw_loading)
- return;
-
- scr_draw_loading = false;
- re.DrawGetPicSize (&w, &h, "loading");
- re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
-}
-
-//=============================================================================
-
-/*
-==================
-SCR_RunConsole
-
-Scroll it up or down
-==================
-*/
-void SCR_RunConsole (void)
-{
-// decide on the height of the console
- if (cls.key_dest == key_console)
- scr_conlines = 0.5; // half screen
- else
- scr_conlines = 0; // none visible
-
- if (scr_conlines < scr_con_current)
- {
- scr_con_current -= scr_conspeed->value*cls.frametime;
- if (scr_conlines > scr_con_current)
- scr_con_current = scr_conlines;
-
- }
- else if (scr_conlines > scr_con_current)
- {
- scr_con_current += scr_conspeed->value*cls.frametime;
- if (scr_conlines < scr_con_current)
- scr_con_current = scr_conlines;
- }
-
-}
-
-/*
-==================
-SCR_DrawConsole
-==================
-*/
-void SCR_DrawConsole (void)
-{
- Con_CheckResize ();
-
- if (cls.state == ca_disconnected || cls.state == ca_connecting)
- { // forced full screen console
- Con_DrawConsole (1.0);
- return;
- }
-
- if (cls.state != ca_active || !cl.refresh_prepped)
- { // connected, but can't render
- Con_DrawConsole (0.5);
- re.DrawFill (0, viddef.height/2, viddef.width, viddef.height/2, 0);
- return;
- }
-
- if (scr_con_current)
- {
- Con_DrawConsole (scr_con_current);
- }
- else
- {
- if (cls.key_dest == key_game || cls.key_dest == key_message)
- Con_DrawNotify (); // only draw notify in game
- }
-}
-
-//=============================================================================
-
-/*
-================
-SCR_BeginLoadingPlaque
-================
-*/
-void SCR_BeginLoadingPlaque (void)
-{
- S_StopAllSounds ();
- cl.sound_prepped = false; // don't play ambients
- CDAudio_Stop ();
- if (cls.disable_screen)
- return;
- if (developer->value)
- return;
- if (cls.state == ca_disconnected)
- return; // if at console, don't bring up the plaque
- if (cls.key_dest == key_console)
- return;
- if (cl.cinematictime > 0)
- scr_draw_loading = 2; // clear to balack first
- else
- scr_draw_loading = 1;
- SCR_UpdateScreen ();
- cls.disable_screen = Sys_Milliseconds ();
- cls.disable_servercount = cl.servercount;
-}
-
-/*
-================
-SCR_EndLoadingPlaque
-================
-*/
-void SCR_EndLoadingPlaque (void)
-{
- cls.disable_screen = 0;
- Con_ClearNotify ();
-}
-
-/*
-================
-SCR_Loading_f
-================
-*/
-void SCR_Loading_f (void)
-{
- SCR_BeginLoadingPlaque ();
-}
-
-/*
-================
-SCR_TimeRefresh_f
-================
-*/
-int entitycmpfnc( const entity_t *a, const entity_t *b )
-{
- /*
- ** all other models are sorted by model then skin
- */
- if ( a->model == b->model )
- {
- return ( ( int ) a->skin - ( int ) b->skin );
- }
- else
- {
- return ( ( int ) a->model - ( int ) b->model );
- }
-}
-
-void SCR_TimeRefresh_f (void)
-{
- int i;
- int start, stop;
- float time;
-
- if ( cls.state != ca_active )
- return;
-
- start = Sys_Milliseconds ();
-
- if (Cmd_Argc() == 2)
- { // run without page flipping
- re.BeginFrame( 0 );
- for (i=0 ; i<128 ; i++)
- {
- cl.refdef.viewangles[1] = i/128.0*360.0;
- re.RenderFrame (&cl.refdef);
- }
- re.EndFrame();
- }
- else
- {
- for (i=0 ; i<128 ; i++)
- {
- cl.refdef.viewangles[1] = i/128.0*360.0;
-
- re.BeginFrame( 0 );
- re.RenderFrame (&cl.refdef);
- re.EndFrame();
- }
- }
-
- stop = Sys_Milliseconds ();
- time = (stop-start)/1000.0;
- Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
-}
-
-/*
-=================
-SCR_AddDirtyPoint
-=================
-*/
-void SCR_AddDirtyPoint (int x, int y)
-{
- if (x < scr_dirty.x1)
- scr_dirty.x1 = x;
- if (x > scr_dirty.x2)
- scr_dirty.x2 = x;
- if (y < scr_dirty.y1)
- scr_dirty.y1 = y;
- if (y > scr_dirty.y2)
- scr_dirty.y2 = y;
-}
-
-void SCR_DirtyScreen (void)
-{
- SCR_AddDirtyPoint (0, 0);
- SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
-}
-
-/*
-==============
-SCR_TileClear
-
-Clear any parts of the tiled background that were drawn on last frame
-==============
-*/
-void SCR_TileClear (void)
-{
- int i;
- int top, bottom, left, right;
- dirty_t clear;
-
- if (scr_drawall->value)
- SCR_DirtyScreen (); // for power vr or broken page flippers...
-
- if (scr_con_current == 1.0)
- return; // full screen console
- if (scr_viewsize->value == 100)
- return; // full screen rendering
- if (cl.cinematictime > 0)
- return; // full screen cinematic
-
- // erase rect will be the union of the past three frames
- // so tripple buffering works properly
- clear = scr_dirty;
- for (i=0 ; i<2 ; i++)
- {
- if (scr_old_dirty[i].x1 < clear.x1)
- clear.x1 = scr_old_dirty[i].x1;
- if (scr_old_dirty[i].x2 > clear.x2)
- clear.x2 = scr_old_dirty[i].x2;
- if (scr_old_dirty[i].y1 < clear.y1)
- clear.y1 = scr_old_dirty[i].y1;
- if (scr_old_dirty[i].y2 > clear.y2)
- clear.y2 = scr_old_dirty[i].y2;
- }
-
- scr_old_dirty[1] = scr_old_dirty[0];
- scr_old_dirty[0] = scr_dirty;
-
- scr_dirty.x1 = 9999;
- scr_dirty.x2 = -9999;
- scr_dirty.y1 = 9999;
- scr_dirty.y2 = -9999;
-
- // don't bother with anything convered by the console)
- top = scr_con_current*viddef.height;
- if (top >= clear.y1)
- clear.y1 = top;
-
- if (clear.y2 <= clear.y1)
- return; // nothing disturbed
-
- top = scr_vrect.y;
- bottom = top + scr_vrect.height-1;
- left = scr_vrect.x;
- right = left + scr_vrect.width-1;
-
- if (clear.y1 < top)
- { // clear above view screen
- i = clear.y2 < top-1 ? clear.y2 : top-1;
- re.DrawTileClear (clear.x1 , clear.y1,
- clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
- clear.y1 = top;
- }
- if (clear.y2 > bottom)
- { // clear below view screen
- i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
- re.DrawTileClear (clear.x1, i,
- clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
- clear.y2 = bottom;
- }
- if (clear.x1 < left)
- { // clear left of view screen
- i = clear.x2 < left-1 ? clear.x2 : left-1;
- re.DrawTileClear (clear.x1, clear.y1,
- i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
- clear.x1 = left;
- }
- if (clear.x2 > right)
- { // clear left of view screen
- i = clear.x1 > right+1 ? clear.x1 : right+1;
- re.DrawTileClear (i, clear.y1,
- clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
- clear.x2 = right;
- }
-
-}
-
-
-//===============================================================
-
-
-#define STAT_MINUS 10 // num frame for '-' stats digit
-char *sb_nums[2][11] =
-{
- {"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
- "num_6", "num_7", "num_8", "num_9", "num_minus"},
- {"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
- "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
-};
-
-#define ICON_WIDTH 24
-#define ICON_HEIGHT 24
-#define CHAR_WIDTH 16
-#define ICON_SPACE 8
-
-
-
-/*
-================
-SizeHUDString
-
-Allow embedded \n in the string
-================
-*/
-void SizeHUDString (char *string, int *w, int *h)
-{
- int lines, width, current;
-
- lines = 1;
- width = 0;
-
- current = 0;
- while (*string)
- {
- if (*string == '\n')
- {
- lines++;
- current = 0;
- }
- else
- {
- current++;
- if (current > width)
- width = current;
- }
- string++;
- }
-
- *w = width * 8;
- *h = lines * 8;
-}
-
-void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
-{
- int margin;
- char line[1024];
- int width;
- int i;
-
- margin = x;
-
- while (*string)
- {
- // scan out one line of text from the string
- width = 0;
- while (*string && *string != '\n')
- line[width++] = *string++;
- line[width] = 0;
-
- if (centerwidth)
- x = margin + (centerwidth - width*8)/2;
- else
- x = margin;
- for (i=0 ; i<width ; i++)
- {
- re.DrawChar (x, y, line[i]^xor);
- x += 8;
- }
- if (*string)
- {
- string++; // skip the \n
- x = margin;
- y += 8;
- }
- }
-}
-
-
-/*
-==============
-SCR_DrawField
-==============
-*/
-void SCR_DrawField (int x, int y, int color, int width, int value)
-{
- char num[16], *ptr;
- int l;
- int frame;
-
- if (width < 1)
- return;
-
- // draw number string
- if (width > 5)
- width = 5;
-
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
-
- Com_sprintf (num, sizeof(num), "%i", value);
- l = strlen(num);
- if (l > width)
- l = width;
- x += 2 + CHAR_WIDTH*(width - l);
-
- ptr = num;
- while (*ptr && l)
- {
- if (*ptr == '-')
- frame = STAT_MINUS;
- else
- frame = *ptr -'0';
-
- re.DrawPic (x,y,sb_nums[color][frame]);
- x += CHAR_WIDTH;
- ptr++;
- l--;
- }
-}
-
-
-/*
-===============
-SCR_TouchPics
-
-Allows rendering code to cache all needed sbar graphics
-===============
-*/
-void SCR_TouchPics (void)
-{
- int i, j;
-
- for (i=0 ; i<2 ; i++)
- for (j=0 ; j<11 ; j++)
- re.RegisterPic (sb_nums[i][j]);
-
- if (crosshair->value)
- {
- if (crosshair->value > 3 || crosshair->value < 0)
- crosshair->value = 3;
-
- Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
- re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
- if (!crosshair_width)
- crosshair_pic[0] = 0;
- }
-}
-
-/*
-================
-SCR_ExecuteLayoutString
-
-================
-*/
-void SCR_ExecuteLayoutString (char *s)
-{
- int x, y;
- int value;
- char *token;
- int width;
- int index;
- clientinfo_t *ci;
-
- if (cls.state != ca_active || !cl.refresh_prepped)
- return;
-
- if (!s[0])
- return;
-
- x = 0;
- y = 0;
- width = 3;
-
- while (s)
- {
- token = COM_Parse (&s);
- if (!strcmp(token, "xl"))
- {
- token = COM_Parse (&s);
- x = atoi(token);
- continue;
- }
- if (!strcmp(token, "xr"))
- {
- token = COM_Parse (&s);
- x = viddef.width + atoi(token);
- continue;
- }
- if (!strcmp(token, "xv"))
- {
- token = COM_Parse (&s);
- x = viddef.width/2 - 160 + atoi(token);
- continue;
- }
-
- if (!strcmp(token, "yt"))
- {
- token = COM_Parse (&s);
- y = atoi(token);
- continue;
- }
- if (!strcmp(token, "yb"))
- {
- token = COM_Parse (&s);
- y = viddef.height + atoi(token);
- continue;
- }
- if (!strcmp(token, "yv"))
- {
- token = COM_Parse (&s);
- y = viddef.height/2 - 120 + atoi(token);
- continue;
- }
-
- if (!strcmp(token, "pic"))
- { // draw a pic from a stat number
- token = COM_Parse (&s);
- value = cl.frame.playerstate.stats[atoi(token)];
- if (value >= MAX_IMAGES)
- Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
- if (cl.configstrings[CS_IMAGES+value])
- {
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+23, y+23);
- re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
- }
- continue;
- }
-
- if (!strcmp(token, "client"))
- { // draw a deathmatch client block
- int score, ping, time;
-
- token = COM_Parse (&s);
- x = viddef.width/2 - 160 + atoi(token);
- token = COM_Parse (&s);
- y = viddef.height/2 - 120 + atoi(token);
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+159, y+31);
-
- token = COM_Parse (&s);
- value = atoi(token);
- if (value >= MAX_CLIENTS || value < 0)
- Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
- ci = &cl.clientinfo[value];
-
- token = COM_Parse (&s);
- score = atoi(token);
-
- token = COM_Parse (&s);
- ping = atoi(token);
-
- token = COM_Parse (&s);
- time = atoi(token);
-
- DrawAltString (x+32, y, ci->name);
- DrawString (x+32, y+8, "Score: ");
- DrawAltString (x+32+7*8, y+8, va("%i", score));
- DrawString (x+32, y+16, va("Ping: %i", ping));
- DrawString (x+32, y+24, va("Time: %i", time));
-
- if (!ci->icon)
- ci = &cl.baseclientinfo;
- re.DrawPic (x, y, ci->iconname);
- continue;
- }
-
- if (!strcmp(token, "ctf"))
- { // draw a ctf client block
- int score, ping;
- char block[80];
-
- token = COM_Parse (&s);
- x = viddef.width/2 - 160 + atoi(token);
- token = COM_Parse (&s);
- y = viddef.height/2 - 120 + atoi(token);
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+159, y+31);
-
- token = COM_Parse (&s);
- value = atoi(token);
- if (value >= MAX_CLIENTS || value < 0)
- Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
- ci = &cl.clientinfo[value];
-
- token = COM_Parse (&s);
- score = atoi(token);
-
- token = COM_Parse (&s);
- ping = atoi(token);
- if (ping > 999)
- ping = 999;
-
- sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
-
- if (value == cl.playernum)
- DrawAltString (x, y, block);
- else
- DrawString (x, y, block);
- continue;
- }
-
- if (!strcmp(token, "picn"))
- { // draw a pic from a name
- token = COM_Parse (&s);
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+23, y+23);
- re.DrawPic (x, y, token);
- continue;
- }
-
- if (!strcmp(token, "num"))
- { // draw a number
- token = COM_Parse (&s);
- width = atoi(token);
- token = COM_Parse (&s);
- value = cl.frame.playerstate.stats[atoi(token)];
- SCR_DrawField (x, y, 0, width, value);
- continue;
- }
-
- if (!strcmp(token, "hnum"))
- { // health number
- int color;
-
- width = 3;
- value = cl.frame.playerstate.stats[STAT_HEALTH];
- if (value > 25)
- color = 0; // green
- else if (value > 0)
- color = (cl.frame.serverframe>>2) & 1; // flash
- else
- color = 1;
-
- if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
- re.DrawPic (x, y, "field_3");
-
- SCR_DrawField (x, y, color, width, value);
- continue;
- }
-
- if (!strcmp(token, "anum"))
- { // ammo number
- int color;
-
- width = 3;
- value = cl.frame.playerstate.stats[STAT_AMMO];
- if (value > 5)
- color = 0; // green
- else if (value >= 0)
- color = (cl.frame.serverframe>>2) & 1; // flash
- else
- continue; // negative number = don't show
-
- if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
- re.DrawPic (x, y, "field_3");
-
- SCR_DrawField (x, y, color, width, value);
- continue;
- }
-
- if (!strcmp(token, "rnum"))
- { // armor number
- int color;
-
- width = 3;
- value = cl.frame.playerstate.stats[STAT_ARMOR];
- if (value < 1)
- continue;
-
- color = 0; // green
-
- if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
- re.DrawPic (x, y, "field_3");
-
- SCR_DrawField (x, y, color, width, value);
- continue;
- }
-
-
- if (!strcmp(token, "stat_string"))
- {
- token = COM_Parse (&s);
- index = atoi(token);
- if (index < 0 || index >= MAX_CONFIGSTRINGS)
- Com_Error (ERR_DROP, "Bad stat_string index");
- index = cl.frame.playerstate.stats[index];
- if (index < 0 || index >= MAX_CONFIGSTRINGS)
- Com_Error (ERR_DROP, "Bad stat_string index");
- DrawString (x, y, cl.configstrings[index]);
- continue;
- }
-
- if (!strcmp(token, "cstring"))
- {
- token = COM_Parse (&s);
- DrawHUDString (token, x, y, 320, 0);
- continue;
- }
-
- if (!strcmp(token, "string"))
- {
- token = COM_Parse (&s);
- DrawString (x, y, token);
- continue;
- }
-
- if (!strcmp(token, "cstring2"))
- {
- token = COM_Parse (&s);
- DrawHUDString (token, x, y, 320,0x80);
- continue;
- }
-
- if (!strcmp(token, "string2"))
- {
- token = COM_Parse (&s);
- DrawAltString (x, y, token);
- continue;
- }
-
- if (!strcmp(token, "if"))
- { // draw a number
- token = COM_Parse (&s);
- value = cl.frame.playerstate.stats[atoi(token)];
- if (!value)
- { // skip to endif
- while (s && strcmp(token, "endif") )
- {
- token = COM_Parse (&s);
- }
- }
-
- continue;
- }
-
-
- }
-}
-
-
-/*
-================
-SCR_DrawStats
-
-The status bar is a small layout program that
-is based on the stats array
-================
-*/
-void SCR_DrawStats (void)
-{
- SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
-}
-
-
-/*
-================
-SCR_DrawLayout
-
-================
-*/
-#define STAT_LAYOUTS 13
-
-void SCR_DrawLayout (void)
-{
- if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
- return;
- SCR_ExecuteLayoutString (cl.layout);
-}
-
-//=======================================================
-
-/*
-==================
-SCR_UpdateScreen
-
-This is called every frame, and can also be called explicitly to flush
-text to the screen.
-==================
-*/
-void SCR_UpdateScreen (void)
-{
- int numframes;
- int i;
- float separation[2] = { 0, 0 };
-
- // if the screen is disabled (loading plaque is up, or vid mode changing)
- // do nothing at all
- if (cls.disable_screen)
- {
- if (Sys_Milliseconds() - cls.disable_screen > 120000)
- {
- cls.disable_screen = 0;
- Com_Printf ("Loading plaque timed out.\n");
- }
- return;
- }
-
- if (!scr_initialized || !con.initialized)
- return; // not initialized yet
-
- /*
- ** range check cl_camera_separation so we don't inadvertently fry someone's
- ** brain
- */
- if ( cl_stereo_separation->value > 1.0 )
- Cvar_SetValue( "cl_stereo_separation", 1.0 );
- else if ( cl_stereo_separation->value < 0 )
- Cvar_SetValue( "cl_stereo_separation", 0.0 );
-
- if ( cl_stereo->value )
- {
- numframes = 2;
- separation[0] = -cl_stereo_separation->value / 2;
- separation[1] = cl_stereo_separation->value / 2;
- }
- else
- {
- separation[0] = 0;
- separation[1] = 0;
- numframes = 1;
- }
-
- for ( i = 0; i < numframes; i++ )
- {
- re.BeginFrame( separation[i] );
-
- if (scr_draw_loading == 2)
- { // loading plaque over black screen
- int w, h;
-
- re.CinematicSetPalette(NULL);
- scr_draw_loading = false;
- re.DrawGetPicSize (&w, &h, "loading");
- re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
-// re.EndFrame();
-// return;
- }
- // if a cinematic is supposed to be running, handle menus
- // and console specially
- else if (cl.cinematictime > 0)
- {
- if (cls.key_dest == key_menu)
- {
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
- M_Draw ();
-// re.EndFrame();
-// return;
- }
- else if (cls.key_dest == key_console)
- {
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
- SCR_DrawConsole ();
-// re.EndFrame();
-// return;
- }
- else
- {
- SCR_DrawCinematic();
-// re.EndFrame();
-// return;
- }
- }
- else
- {
-
- // make sure the game palette is active
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
-
- // do 3D refresh drawing, and then update the screen
- SCR_CalcVrect ();
-
- // clear any dirty part of the background
- SCR_TileClear ();
-
- V_RenderView ( separation[i] );
-
- SCR_DrawStats ();
- if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
- SCR_DrawLayout ();
- if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
- CL_DrawInventory ();
-
- SCR_DrawNet ();
- SCR_CheckDrawCenterString ();
-
- // FPS counter hack
- // http://www.quakesrc.org/?Page=tutorials&What=./tutorials/Quake2/misc/fps.txt
- if (cl_drawfps->value) {
- char s[8];
- sprintf(s,"%3.0ffps", 1/cls.frametime);
- DrawString(viddef.width-64,0,s);
- }
-
- if (scr_timegraph->value)
- SCR_DebugGraph (cls.frametime*300, 0);
-
- if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
- SCR_DrawDebugGraph ();
-
- SCR_DrawPause ();
-
- SCR_DrawConsole ();
-
- M_Draw ();
-
- SCR_DrawLoading ();
- }
- }
- re.EndFrame();
-}
+/*
+Copyright (C) 1997-2001 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
+
+/*
+
+ full screen console
+ put up loading plaque
+ blanked background with loading plaque
+ blanked background with menu
+ cinematics
+ full screen image for quit and victory
+
+ end of unit intermissions
+
+ */
+
+#include "client.h"
+
+float scr_con_current; // aproaches scr_conlines at scr_conspeed
+float scr_conlines; // 0.0 to 1.0 lines of console to display
+
+qboolean scr_initialized; // ready to draw
+
+int scr_draw_loading;
+
+vrect_t scr_vrect; // position of render window on screen
+
+
+cvar_t *scr_viewsize;
+cvar_t *scr_conspeed;
+cvar_t *scr_centertime;
+cvar_t *scr_showturtle;
+cvar_t *scr_showpause;
+cvar_t *scr_printspeed;
+
+cvar_t *scr_netgraph;
+cvar_t *scr_timegraph;
+cvar_t *scr_debuggraph;
+cvar_t *scr_graphheight;
+cvar_t *scr_graphscale;
+cvar_t *scr_graphshift;
+cvar_t *scr_drawall;
+
+typedef struct
+{
+ int x1, y1, x2, y2;
+} dirty_t;
+
+dirty_t scr_dirty, scr_old_dirty[2];
+
+char crosshair_pic[MAX_QPATH];
+int crosshair_width, crosshair_height;
+
+void SCR_TimeRefresh_f (void);
+void SCR_Loading_f (void);
+
+
+/*
+===============================================================================
+
+BAR GRAPHS
+
+===============================================================================
+*/
+
+/*
+==============
+CL_AddNetgraph
+
+A new packet was just parsed
+==============
+*/
+void CL_AddNetgraph (void)
+{
+ int i;
+ int in;
+ int ping;
+
+ // if using the debuggraph for something else, don't
+ // add the net lines
+ if (scr_debuggraph->value || scr_timegraph->value)
+ return;
+
+ for (i=0 ; i<cls.netchan.dropped ; i++)
+ SCR_DebugGraph (30, 0x40);
+
+ for (i=0 ; i<cl.surpressCount ; i++)
+ SCR_DebugGraph (30, 0xdf);
+
+ // see what the latency was on this packet
+ in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
+ ping = cls.realtime - cl.cmd_time[in];
+ ping /= 30;
+ if (ping > 30)
+ ping = 30;
+ SCR_DebugGraph (ping, 0xd0);
+}
+
+
+typedef struct
+{
+ float value;
+ int color;
+} graphsamp_t;
+
+static int current;
+static graphsamp_t values[1024];
+
+/*
+==============
+SCR_DebugGraph
+==============
+*/
+void SCR_DebugGraph (float value, int color)
+{
+ values[current&1023].value = value;
+ values[current&1023].color = color;
+ current++;
+}
+
+/*
+==============
+SCR_DrawDebugGraph
+==============
+*/
+void SCR_DrawDebugGraph (void)
+{
+ int a, x, y, w, i, h;
+ float v;
+ int color;
+
+ //
+ // draw the graph
+ //
+ w = scr_vrect.width;
+
+ x = scr_vrect.x;
+ y = scr_vrect.y+scr_vrect.height;
+ re.DrawFill (x, y-scr_graphheight->value,
+ w, scr_graphheight->value, 8);
+
+ for (a=0 ; a<w ; a++)
+ {
+ i = (current-1-a+1024) & 1023;
+ v = values[i].value;
+ color = values[i].color;
+ v = v*scr_graphscale->value + scr_graphshift->value;
+
+ if (v < 0)
+ v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
+ h = (int)v % (int)scr_graphheight->value;
+ re.DrawFill (x+w-1-a, y - h, 1, h, color);
+ }
+}
+
+/*
+===============================================================================
+
+CENTER PRINTING
+
+===============================================================================
+*/
+
+char scr_centerstring[1024];
+float scr_centertime_start; // for slow victory printing
+float scr_centertime_off;
+int scr_center_lines;
+int scr_erase_center;
+
+/*
+==============
+SCR_CenterPrint
+
+Called for important messages that should stay in the center of the screen
+for a few moments
+==============
+*/
+void SCR_CenterPrint (char *str)
+{
+ char *s;
+ char line[64];
+ int i, j, l;
+
+ strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
+ scr_centertime_off = scr_centertime->value;
+ scr_centertime_start = cl.time;
+
+ // count the number of lines for centering
+ scr_center_lines = 1;
+ s = str;
+ while (*s)
+ {
+ if (*s == '\n')
+ scr_center_lines++;
+ s++;
+ }
+
+ // echo it to the console
+ Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+
+ s = str;
+ do
+ {
+ // scan the width of the line
+ for (l=0 ; l<40 ; l++)
+ if (s[l] == '\n' || !s[l])
+ break;
+ for (i=0 ; i<(40-l)/2 ; i++)
+ line[i] = ' ';
+
+ for (j=0 ; j<l ; j++)
+ {
+ line[i++] = s[j];
+ }
+
+ line[i] = '\n';
+ line[i+1] = 0;
+
+ Com_Printf ("%s", line);
+
+ while (*s && *s != '\n')
+ s++;
+
+ if (!*s)
+ break;
+ s++; // skip the \n
+ } while (1);
+ Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+ Con_ClearNotify ();
+}
+
+
+void SCR_DrawCenterString (void)
+{
+ char *start;
+ int l;
+ int j;
+ int x, y;
+ int remaining;
+
+// the finale prints the characters one at a time
+ remaining = 9999;
+
+ scr_erase_center = 0;
+ start = scr_centerstring;
+
+ if (scr_center_lines <= 4)
+ y = viddef.height*0.35;
+ else
+ y = 48;
+
+ do
+ {
+ // scan the width of the line
+ for (l=0 ; l<40 ; l++)
+ if (start[l] == '\n' || !start[l])
+ break;
+ x = (viddef.width - l*8)/2;
+ SCR_AddDirtyPoint (x, y);
+ for (j=0 ; j<l ; j++, x+=8)
+ {
+ re.DrawChar (x, y, start[j]);
+ if (!remaining--)
+ return;
+ }
+ SCR_AddDirtyPoint (x, y+8);
+
+ y += 8;
+
+ while (*start && *start != '\n')
+ start++;
+
+ if (!*start)
+ break;
+ start++; // skip the \n
+ } while (1);
+}
+
+void SCR_CheckDrawCenterString (void)
+{
+ scr_centertime_off -= cls.frametime;
+
+ if (scr_centertime_off <= 0)
+ return;
+
+ SCR_DrawCenterString ();
+}
+
+//=============================================================================
+
+/*
+=================
+SCR_CalcVrect
+
+Sets scr_vrect, the coordinates of the rendered window
+=================
+*/
+static void SCR_CalcVrect (void)
+{
+ int size;
+
+ // bound viewsize
+ if (scr_viewsize->value < 40)
+ Cvar_Set ("viewsize","40");
+ if (scr_viewsize->value > 100)
+ Cvar_Set ("viewsize","100");
+
+ size = scr_viewsize->value;
+
+ scr_vrect.width = viddef.width*size/100;
+ scr_vrect.width &= ~7;
+
+ scr_vrect.height = viddef.height*size/100;
+ scr_vrect.height &= ~1;
+
+ scr_vrect.x = (viddef.width - scr_vrect.width)/2;
+ scr_vrect.y = (viddef.height - scr_vrect.height)/2;
+}
+
+
+/*
+=================
+SCR_SizeUp_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeUp_f (void)
+{
+ Cvar_SetValue ("viewsize",scr_viewsize->value+10);
+}
+
+
+/*
+=================
+SCR_SizeDown_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeDown_f (void)
+{
+ Cvar_SetValue ("viewsize",scr_viewsize->value-10);
+}
+
+/*
+=================
+SCR_Sky_f
+
+Set a specific sky and rotation speed
+=================
+*/
+void SCR_Sky_f (void)
+{
+ float rotate;
+ vec3_t axis;
+
+ if (Cmd_Argc() < 2)
+ {
+ Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
+ return;
+ }
+ if (Cmd_Argc() > 2)
+ rotate = atof(Cmd_Argv(2));
+ else
+ rotate = 0;
+ if (Cmd_Argc() == 6)
+ {
+ axis[0] = atof(Cmd_Argv(3));
+ axis[1] = atof(Cmd_Argv(4));
+ axis[2] = atof(Cmd_Argv(5));
+ }
+ else
+ {
+ axis[0] = 0;
+ axis[1] = 0;
+ axis[2] = 1;
+ }
+
+ re.SetSky (Cmd_Argv(1), rotate, axis);
+}
+
+//============================================================================
+
+/*
+==================
+SCR_Init
+==================
+*/
+void SCR_Init (void)
+{
+ scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
+ scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
+ scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
+ scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
+ scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
+ scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
+ scr_netgraph = Cvar_Get ("netgraph", "0", 0);
+ scr_timegraph = Cvar_Get ("timegraph", "0", 0);
+ scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
+ scr_graphheight = Cvar_Get ("graphheight", "32", 0);
+ scr_graphscale = Cvar_Get ("graphscale", "1", 0);
+ scr_graphshift = Cvar_Get ("graphshift", "0", 0);
+ scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
+
+//
+// register our commands
+//
+ Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
+ Cmd_AddCommand ("loading",SCR_Loading_f);
+ Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
+ Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
+ Cmd_AddCommand ("sky",SCR_Sky_f);
+
+ scr_initialized = true;
+}
+
+
+/*
+==============
+SCR_DrawNet
+==============
+*/
+void SCR_DrawNet (void)
+{
+ if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged
+ < CMD_BACKUP-1)
+ return;
+
+ re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
+}
+
+/*
+==============
+SCR_DrawPause
+==============
+*/
+void SCR_DrawPause (void)
+{
+ int w, h;
+
+ if (!scr_showpause->value) // turn off for screenshots
+ return;
+
+ if (!cl_paused->value)
+ return;
+
+ re.DrawGetPicSize (&w, &h, "pause");
+ re.DrawPic ((viddef.width-w)/2, viddef.height/2 + 8, "pause");
+}
+
+/*
+==============
+SCR_DrawLoading
+==============
+*/
+void SCR_DrawLoading (void)
+{
+ int w, h;
+
+ if (!scr_draw_loading)
+ return;
+
+ scr_draw_loading = false;
+ re.DrawGetPicSize (&w, &h, "loading");
+ re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
+}
+
+//=============================================================================
+
+/*
+==================
+SCR_RunConsole
+
+Scroll it up or down
+==================
+*/
+void SCR_RunConsole (void)
+{
+// decide on the height of the console
+ if (cls.key_dest == key_console)
+ scr_conlines = 0.5; // half screen
+ else
+ scr_conlines = 0; // none visible
+
+ if (scr_conlines < scr_con_current)
+ {
+ scr_con_current -= scr_conspeed->value*cls.frametime;
+ if (scr_conlines > scr_con_current)
+ scr_con_current = scr_conlines;
+
+ }
+ else if (scr_conlines > scr_con_current)
+ {
+ scr_con_current += scr_conspeed->value*cls.frametime;
+ if (scr_conlines < scr_con_current)
+ scr_con_current = scr_conlines;
+ }
+
+}
+
+/*
+==================
+SCR_DrawConsole
+==================
+*/
+void SCR_DrawConsole (void)
+{
+ Con_CheckResize ();
+
+ if (cls.state == ca_disconnected || cls.state == ca_connecting)
+ { // forced full screen console
+ Con_DrawConsole (1.0);
+ return;
+ }
+
+ if (cls.state != ca_active || !cl.refresh_prepped)
+ { // connected, but can't render
+ Con_DrawConsole (0.5);
+ re.DrawFill (0, viddef.height/2, viddef.width, viddef.height/2, 0);
+ return;
+ }
+
+ if (scr_con_current)
+ {
+ Con_DrawConsole (scr_con_current);
+ }
+ else
+ {
+ if (cls.key_dest == key_game || cls.key_dest == key_message)
+ Con_DrawNotify (); // only draw notify in game
+ }
+}
+
+//=============================================================================
+
+/*
+================
+SCR_BeginLoadingPlaque
+================
+*/
+void SCR_BeginLoadingPlaque (void)
+{
+ S_StopAllSounds ();
+ cl.sound_prepped = false; // don't play ambients
+ CDAudio_Stop ();
+ if (cls.disable_screen)
+ return;
+ if (developer->value)
+ return;
+ if (cls.state == ca_disconnected)
+ return; // if at console, don't bring up the plaque
+ if (cls.key_dest == key_console)
+ return;
+ if (cl.cinematictime > 0)
+ scr_draw_loading = 2; // clear to balack first
+ else
+ scr_draw_loading = 1;
+ SCR_UpdateScreen ();
+ cls.disable_screen = Sys_Milliseconds ();
+ cls.disable_servercount = cl.servercount;
+}
+
+/*
+================
+SCR_EndLoadingPlaque
+================
+*/
+void SCR_EndLoadingPlaque (void)
+{
+ cls.disable_screen = 0;
+ Con_ClearNotify ();
+}
+
+/*
+================
+SCR_Loading_f
+================
+*/
+void SCR_Loading_f (void)
+{
+ SCR_BeginLoadingPlaque ();
+}
+
+/*
+================
+SCR_TimeRefresh_f
+================
+*/
+int entitycmpfnc( const entity_t *a, const entity_t *b )
+{
+ /*
+ ** all other models are sorted by model then skin
+ */
+ if ( a->model == b->model )
+ {
+ return ( ( int ) a->skin - ( int ) b->skin );
+ }
+ else
+ {
+ return ( ( int ) a->model - ( int ) b->model );
+ }
+}
+
+void SCR_TimeRefresh_f (void)
+{
+ int i;
+ int start, stop;
+ float time;
+
+ if ( cls.state != ca_active )
+ return;
+
+ start = Sys_Milliseconds ();
+
+ if (Cmd_Argc() == 2)
+ { // run without page flipping
+ re.BeginFrame( 0 );
+ for (i=0 ; i<128 ; i++)
+ {
+ cl.refdef.viewangles[1] = i/128.0*360.0;
+ re.RenderFrame (&cl.refdef);
+ }
+ re.EndFrame();
+ }
+ else
+ {
+ for (i=0 ; i<128 ; i++)
+ {
+ cl.refdef.viewangles[1] = i/128.0*360.0;
+
+ re.BeginFrame( 0 );
+ re.RenderFrame (&cl.refdef);
+ re.EndFrame();
+ }
+ }
+
+ stop = Sys_Milliseconds ();
+ time = (stop-start)/1000.0;
+ Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
+}
+
+/*
+=================
+SCR_AddDirtyPoint
+=================
+*/
+void SCR_AddDirtyPoint (int x, int y)
+{
+ if (x < scr_dirty.x1)
+ scr_dirty.x1 = x;
+ if (x > scr_dirty.x2)
+ scr_dirty.x2 = x;
+ if (y < scr_dirty.y1)
+ scr_dirty.y1 = y;
+ if (y > scr_dirty.y2)
+ scr_dirty.y2 = y;
+}
+
+void SCR_DirtyScreen (void)
+{
+ SCR_AddDirtyPoint (0, 0);
+ SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
+}
+
+/*
+==============
+SCR_TileClear
+
+Clear any parts of the tiled background that were drawn on last frame
+==============
+*/
+void SCR_TileClear (void)
+{
+ int i;
+ int top, bottom, left, right;
+ dirty_t clear;
+
+ if (scr_drawall->value)
+ SCR_DirtyScreen (); // for power vr or broken page flippers...
+
+ if (scr_con_current == 1.0)
+ return; // full screen console
+ if (scr_viewsize->value == 100)
+ return; // full screen rendering
+ if (cl.cinematictime > 0)
+ return; // full screen cinematic
+
+ // erase rect will be the union of the past three frames
+ // so tripple buffering works properly
+ clear = scr_dirty;
+ for (i=0 ; i<2 ; i++)
+ {
+ if (scr_old_dirty[i].x1 < clear.x1)
+ clear.x1 = scr_old_dirty[i].x1;
+ if (scr_old_dirty[i].x2 > clear.x2)
+ clear.x2 = scr_old_dirty[i].x2;
+ if (scr_old_dirty[i].y1 < clear.y1)
+ clear.y1 = scr_old_dirty[i].y1;
+ if (scr_old_dirty[i].y2 > clear.y2)
+ clear.y2 = scr_old_dirty[i].y2;
+ }
+
+ scr_old_dirty[1] = scr_old_dirty[0];
+ scr_old_dirty[0] = scr_dirty;
+
+ scr_dirty.x1 = 9999;
+ scr_dirty.x2 = -9999;
+ scr_dirty.y1 = 9999;
+ scr_dirty.y2 = -9999;
+
+ // don't bother with anything convered by the console)
+ top = scr_con_current*viddef.height;
+ if (top >= clear.y1)
+ clear.y1 = top;
+
+ if (clear.y2 <= clear.y1)
+ return; // nothing disturbed
+
+ top = scr_vrect.y;
+ bottom = top + scr_vrect.height-1;
+ left = scr_vrect.x;
+ right = left + scr_vrect.width-1;
+
+ if (clear.y1 < top)
+ { // clear above view screen
+ i = clear.y2 < top-1 ? clear.y2 : top-1;
+ re.DrawTileClear (clear.x1 , clear.y1,
+ clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
+ clear.y1 = top;
+ }
+ if (clear.y2 > bottom)
+ { // clear below view screen
+ i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
+ re.DrawTileClear (clear.x1, i,
+ clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
+ clear.y2 = bottom;
+ }
+ if (clear.x1 < left)
+ { // clear left of view screen
+ i = clear.x2 < left-1 ? clear.x2 : left-1;
+ re.DrawTileClear (clear.x1, clear.y1,
+ i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
+ clear.x1 = left;
+ }
+ if (clear.x2 > right)
+ { // clear left of view screen
+ i = clear.x1 > right+1 ? clear.x1 : right+1;
+ re.DrawTileClear (i, clear.y1,
+ clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
+ clear.x2 = right;
+ }
+
+}
+
+
+//===============================================================
+
+
+#define STAT_MINUS 10 // num frame for '-' stats digit
+char *sb_nums[2][11] =
+{
+ {"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
+ "num_6", "num_7", "num_8", "num_9", "num_minus"},
+ {"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
+ "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
+};
+
+#define ICON_WIDTH 24
+#define ICON_HEIGHT 24
+#define CHAR_WIDTH 16
+#define ICON_SPACE 8
+
+
+
+/*
+================
+SizeHUDString
+
+Allow embedded \n in the string
+================
+*/
+void SizeHUDString (char *string, int *w, int *h)
+{
+ int lines, width, current;
+
+ lines = 1;
+ width = 0;
+
+ current = 0;
+ while (*string)
+ {
+ if (*string == '\n')
+ {
+ lines++;
+ current = 0;
+ }
+ else
+ {
+ current++;
+ if (current > width)
+ width = current;
+ }
+ string++;
+ }
+
+ *w = width * 8;
+ *h = lines * 8;
+}
+
+void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
+{
+ int margin;
+ char line[1024];
+ int width;
+ int i;
+
+ margin = x;
+
+ while (*string)
+ {
+ // scan out one line of text from the string
+ width = 0;
+ while (*string && *string != '\n')
+ line[width++] = *string++;
+ line[width] = 0;
+
+ if (centerwidth)
+ x = margin + (centerwidth - width*8)/2;
+ else
+ x = margin;
+ for (i=0 ; i<width ; i++)
+ {
+ re.DrawChar (x, y, line[i]^xor);
+ x += 8;
+ }
+ if (*string)
+ {
+ string++; // skip the \n
+ x = margin;
+ y += 8;
+ }
+ }
+}
+
+
+/*
+==============
+SCR_DrawField
+==============
+*/
+void SCR_DrawField (int x, int y, int color, int width, int value)
+{
+ char num[16], *ptr;
+ int l;
+ int frame;
+
+ if (width < 1)
+ return;
+
+ // draw number string
+ if (width > 5)
+ width = 5;
+
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
+
+ Com_sprintf (num, sizeof(num), "%i", value);
+ l = strlen(num);
+ if (l > width)
+ l = width;
+ x += 2 + CHAR_WIDTH*(width - l);
+
+ ptr = num;
+ while (*ptr && l)
+ {
+ if (*ptr == '-')
+ frame = STAT_MINUS;
+ else
+ frame = *ptr -'0';
+
+ re.DrawPic (x,y,sb_nums[color][frame]);
+ x += CHAR_WIDTH;
+ ptr++;
+ l--;
+ }
+}
+
+
+/*
+===============
+SCR_TouchPics
+
+Allows rendering code to cache all needed sbar graphics
+===============
+*/
+void SCR_TouchPics (void)
+{
+ int i, j;
+
+ for (i=0 ; i<2 ; i++)
+ for (j=0 ; j<11 ; j++)
+ re.RegisterPic (sb_nums[i][j]);
+
+ if (crosshair->value)
+ {
+ if (crosshair->value > 3 || crosshair->value < 0)
+ crosshair->value = 3;
+
+ Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
+ re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
+ if (!crosshair_width)
+ crosshair_pic[0] = 0;
+ }
+}
+
+/*
+================
+SCR_ExecuteLayoutString
+
+================
+*/
+void SCR_ExecuteLayoutString (char *s)
+{
+ int x, y;
+ int value;
+ char *token;
+ int width;
+ int index;
+ clientinfo_t *ci;
+
+ if (cls.state != ca_active || !cl.refresh_prepped)
+ return;
+
+ if (!s[0])
+ return;
+
+ x = 0;
+ y = 0;
+ width = 3;
+
+ while (s)
+ {
+ token = COM_Parse (&s);
+ if (!strcmp(token, "xl"))
+ {
+ token = COM_Parse (&s);
+ x = atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "xr"))
+ {
+ token = COM_Parse (&s);
+ x = viddef.width + atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "xv"))
+ {
+ token = COM_Parse (&s);
+ x = viddef.width/2 - 160 + atoi(token);
+ continue;
+ }
+
+ if (!strcmp(token, "yt"))
+ {
+ token = COM_Parse (&s);
+ y = atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "yb"))
+ {
+ token = COM_Parse (&s);
+ y = viddef.height + atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "yv"))
+ {
+ token = COM_Parse (&s);
+ y = viddef.height/2 - 120 + atoi(token);
+ continue;
+ }
+
+ if (!strcmp(token, "pic"))
+ { // draw a pic from a stat number
+ token = COM_Parse (&s);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ if (value >= MAX_IMAGES)
+ Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
+ if (cl.configstrings[CS_IMAGES+value])
+ {
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+23, y+23);
+ re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
+ }
+ continue;
+ }
+
+ if (!strcmp(token, "client"))
+ { // draw a deathmatch client block
+ int score, ping, time;
+
+ token = COM_Parse (&s);
+ x = viddef.width/2 - 160 + atoi(token);
+ token = COM_Parse (&s);
+ y = viddef.height/2 - 120 + atoi(token);
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+159, y+31);
+
+ token = COM_Parse (&s);
+ value = atoi(token);
+ if (value >= MAX_CLIENTS || value < 0)
+ Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
+ ci = &cl.clientinfo[value];
+
+ token = COM_Parse (&s);
+ score = atoi(token);
+
+ token = COM_Parse (&s);
+ ping = atoi(token);
+
+ token = COM_Parse (&s);
+ time = atoi(token);
+
+ DrawAltString (x+32, y, ci->name);
+ DrawString (x+32, y+8, "Score: ");
+ DrawAltString (x+32+7*8, y+8, va("%i", score));
+ DrawString (x+32, y+16, va("Ping: %i", ping));
+ DrawString (x+32, y+24, va("Time: %i", time));
+
+ if (!ci->icon)
+ ci = &cl.baseclientinfo;
+ re.DrawPic (x, y, ci->iconname);
+ continue;
+ }
+
+ if (!strcmp(token, "ctf"))
+ { // draw a ctf client block
+ int score, ping;
+ char block[80];
+
+ token = COM_Parse (&s);
+ x = viddef.width/2 - 160 + atoi(token);
+ token = COM_Parse (&s);
+ y = viddef.height/2 - 120 + atoi(token);
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+159, y+31);
+
+ token = COM_Parse (&s);
+ value = atoi(token);
+ if (value >= MAX_CLIENTS || value < 0)
+ Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
+ ci = &cl.clientinfo[value];
+
+ token = COM_Parse (&s);
+ score = atoi(token);
+
+ token = COM_Parse (&s);
+ ping = atoi(token);
+ if (ping > 999)
+ ping = 999;
+
+ sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
+
+ if (value == cl.playernum)
+ DrawAltString (x, y, block);
+ else
+ DrawString (x, y, block);
+ continue;
+ }
+
+ if (!strcmp(token, "picn"))
+ { // draw a pic from a name
+ token = COM_Parse (&s);
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+23, y+23);
+ re.DrawPic (x, y, token);
+ continue;
+ }
+
+ if (!strcmp(token, "num"))
+ { // draw a number
+ token = COM_Parse (&s);
+ width = atoi(token);
+ token = COM_Parse (&s);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ SCR_DrawField (x, y, 0, width, value);
+ continue;
+ }
+
+ if (!strcmp(token, "hnum"))
+ { // health number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_HEALTH];
+ if (value > 25)
+ color = 0; // green
+ else if (value > 0)
+ color = (cl.frame.serverframe>>2) & 1; // flash
+ else
+ color = 1;
+
+ if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
+ re.DrawPic (x, y, "field_3");
+
+ SCR_DrawField (x, y, color, width, value);
+ continue;
+ }
+
+ if (!strcmp(token, "anum"))
+ { // ammo number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_AMMO];
+ if (value > 5)
+ color = 0; // green
+ else if (value >= 0)
+ color = (cl.frame.serverframe>>2) & 1; // flash
+ else
+ continue; // negative number = don't show
+
+ if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
+ re.DrawPic (x, y, "field_3");
+
+ SCR_DrawField (x, y, color, width, value);
+ continue;
+ }
+
+ if (!strcmp(token, "rnum"))
+ { // armor number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_ARMOR];
+ if (value < 1)
+ continue;
+
+ color = 0; // green
+
+ if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
+ re.DrawPic (x, y, "field_3");
+
+ SCR_DrawField (x, y, color, width, value);
+ continue;
+ }
+
+
+ if (!strcmp(token, "stat_string"))
+ {
+ token = COM_Parse (&s);
+ index = atoi(token);
+ if (index < 0 || index >= MAX_CONFIGSTRINGS)
+ Com_Error (ERR_DROP, "Bad stat_string index");
+ index = cl.frame.playerstate.stats[index];
+ if (index < 0 || index >= MAX_CONFIGSTRINGS)
+ Com_Error (ERR_DROP, "Bad stat_string index");
+ DrawString (x, y, cl.configstrings[index]);
+ continue;
+ }
+
+ if (!strcmp(token, "cstring"))
+ {
+ token = COM_Parse (&s);
+ DrawHUDString (token, x, y, 320, 0);
+ continue;
+ }
+
+ if (!strcmp(token, "string"))
+ {
+ token = COM_Parse (&s);
+ DrawString (x, y, token);
+ continue;
+ }
+
+ if (!strcmp(token, "cstring2"))
+ {
+ token = COM_Parse (&s);
+ DrawHUDString (token, x, y, 320,0x80);
+ continue;
+ }
+
+ if (!strcmp(token, "string2"))
+ {
+ token = COM_Parse (&s);
+ DrawAltString (x, y, token);
+ continue;
+ }
+
+ if (!strcmp(token, "if"))
+ { // draw a number
+ token = COM_Parse (&s);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ if (!value)
+ { // skip to endif
+ while (s && strcmp(token, "endif") )
+ {
+ token = COM_Parse (&s);
+ }
+ }
+
+ continue;
+ }
+
+
+ }
+}
+
+
+/*
+================
+SCR_DrawStats
+
+The status bar is a small layout program that
+is based on the stats array
+================
+*/
+void SCR_DrawStats (void)
+{
+ SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
+}
+
+
+/*
+================
+SCR_DrawLayout
+
+================
+*/
+#define STAT_LAYOUTS 13
+
+void SCR_DrawLayout (void)
+{
+ if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
+ return;
+ SCR_ExecuteLayoutString (cl.layout);
+}
+
+//=======================================================
+
+/*
+==================
+SCR_UpdateScreen
+
+This is called every frame, and can also be called explicitly to flush
+text to the screen.
+==================
+*/
+void SCR_UpdateScreen (void)
+{
+ int numframes;
+ int i;
+ float separation[2] = { 0, 0 };
+
+ // if the screen is disabled (loading plaque is up, or vid mode changing)
+ // do nothing at all
+ if (cls.disable_screen)
+ {
+ if (Sys_Milliseconds() - cls.disable_screen > 120000)
+ {
+ cls.disable_screen = 0;
+ Com_Printf ("Loading plaque timed out.\n");
+ }
+ return;
+ }
+
+ if (!scr_initialized || !con.initialized)
+ return; // not initialized yet
+
+ /*
+ ** range check cl_camera_separation so we don't inadvertently fry someone's
+ ** brain
+ */
+ if ( cl_stereo_separation->value > 10.0 )
+ Cvar_SetValue( "cl_stereo_separation", 10.0 );
+ else if ( cl_stereo_separation->value < 0 )
+ Cvar_SetValue( "cl_stereo_separation", 0.0 );
+
+ if ( !cl_stereo->value )
+ Cvar_SetValue( "cl_stereo", 1 );
+
+ numframes = 2;
+ separation[0] = -cl_stereo_separation->value / 2.0;
+ separation[1] = cl_stereo_separation->value / 2.0;
+
+/*
+ if ( cl_stereo->value )
+ {
+ numframes = 2;
+ separation[0] = -cl_stereo_separation->value / 2.0;
+ separation[1] = cl_stereo_separation->value / 2.0;
+ }
+ else
+ {
+ separation[0] = 0;
+ separation[1] = 0;
+ numframes = 1;
+ }
+*/
+
+ for ( i = 0; i < numframes; i++ )
+ {
+ re.BeginFrame( separation[i] );
+
+ if (scr_draw_loading == 2)
+ { // loading plaque over black screen
+ int w, h;
+
+ re.CinematicSetPalette(NULL);
+ scr_draw_loading = false;
+ re.DrawGetPicSize (&w, &h, "loading");
+ re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
+// re.EndFrame();
+// return;
+ }
+ // if a cinematic is supposed to be running, handle menus
+ // and console specially
+ else if (cl.cinematictime > 0)
+ {
+ if (cls.key_dest == key_menu)
+ {
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ }
+ M_Draw ();
+// re.EndFrame();
+// return;
+ }
+ else if (cls.key_dest == key_console)
+ {
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ }
+ SCR_DrawConsole ();
+// re.EndFrame();
+// return;
+ }
+ else
+ {
+ SCR_DrawCinematic();
+// re.EndFrame();
+// return;
+ }
+ }
+ else
+ {
+
+ // make sure the game palette is active
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ }
+
+ // do 3D refresh drawing, and then update the screen
+ SCR_CalcVrect ();
+
+ // clear any dirty part of the background
+ SCR_TileClear ();
+
+ V_RenderView ( separation[i] );
+
+ SCR_DrawStats ();
+ if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
+ SCR_DrawLayout ();
+ if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
+ CL_DrawInventory ();
+
+ SCR_DrawNet ();
+ SCR_CheckDrawCenterString ();
+
+ if (scr_timegraph->value)
+ SCR_DebugGraph (cls.frametime*300, 0);
+
+ if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
+ SCR_DrawDebugGraph ();
+
+ SCR_DrawPause ();
+
+ SCR_DrawConsole ();
+
+ M_Draw ();
+
+ SCR_DrawLoading ();
+ }
+ }
+ re.EndFrame();
+}
diff -ur quake2-r0.0.8/src/linux/rw_x11.c quake2-devel-r0.0.8/src/linux/rw_x11.c
--- quake2-r0.0.8/src/linux/rw_x11.c Sat Jan 5 02:35:22 2002
+++ quake2-devel-r0.0.8/src/linux/rw_x11.c Wed Jan 30 15:03:18 2002
@@ -1,1339 +1,1445 @@
-/*
-Copyright (C) 1997-2001 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-/*
-** RW_X11.C
-**
-** This file contains ALL Linux specific stuff having to do with the
-** software refresh. When a port is being made the following functions
-** must be implemented by the port:
-**
-** SWimp_EndFrame
-** SWimp_Init
-** SWimp_InitGraphics
-** SWimp_SetPalette
-** SWimp_Shutdown
-** SWimp_SwitchFullscreen
-*/
-
-#include <ctype.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/mman.h>
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xatom.h>
-#include <X11/keysym.h>
-#include <X11/extensions/XShm.h>
-#include <X11/extensions/xf86dga.h>
-
-#include "../ref_soft/r_local.h"
-#include "../client/keys.h"
-#include "../linux/rw_linux.h"
-
-/*****************************************************************************/
-
-static qboolean doShm;
-static Display *dpy;
-static Colormap x_cmap;
-static Window win;
-static GC x_gc;
-static Visual *x_vis;
-static XVisualInfo *x_visinfo;
-static int win_x, win_y;
-static Atom wmDeleteWindow;
-
-#define KEY_MASK (KeyPressMask | KeyReleaseMask)
-#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
- PointerMotionMask | ButtonMotionMask )
-#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask | ExposureMask )
-
-static int x_shmeventtype;
-//static XShmSegmentInfo x_shminfo;
-
-static qboolean oktodraw = false;
-static qboolean ignorefirst = false;
-static qboolean exposureflag = false;
-static qboolean X11_active = false;
-
-int XShmQueryExtension(Display *);
-int XShmGetEventBase(Display *);
-
-int current_framebuffer;
-static XImage *x_framebuffer[2] = { 0, 0 };
-static XShmSegmentInfo x_shminfo[2];
-
-int config_notify=0;
-int config_notify_width;
-int config_notify_height;
-
-typedef unsigned short PIXEL16;
-typedef unsigned long PIXEL24;
-static PIXEL16 st2d_8to16table[256];
-static PIXEL24 st2d_8to24table[256];
-static int shiftmask_fl=0;
-static long r_shift,g_shift,b_shift;
-static unsigned long r_mask,g_mask,b_mask;
-
-void shiftmask_init(void)
-{
- unsigned int x;
- r_mask=x_vis->red_mask;
- g_mask=x_vis->green_mask;
- b_mask=x_vis->blue_mask;
- for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;
- for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;
- for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;
- shiftmask_fl=1;
-}
-
-PIXEL16 xlib_rgb16(int r,int g,int b)
-{
- PIXEL16 p;
- if(shiftmask_fl==0) shiftmask_init();
- p=0;
-
- if(r_shift>0) {
- p=(r<<(r_shift))&r_mask;
- } else if(r_shift<0) {
- p=(r>>(-r_shift))&r_mask;
- } else p|=(r&r_mask);
-
- if(g_shift>0) {
- p|=(g<<(g_shift))&g_mask;
- } else if(g_shift<0) {
- p|=(g>>(-g_shift))&g_mask;
- } else p|=(g&g_mask);
-
- if(b_shift>0) {
- p|=(b<<(b_shift))&b_mask;
- } else if(b_shift<0) {
- p|=(b>>(-b_shift))&b_mask;
- } else p|=(b&b_mask);
-
- return p;
-}
-
-PIXEL24 xlib_rgb24(int r,int g,int b)
-{
- PIXEL24 p;
- if(shiftmask_fl==0) shiftmask_init();
- p=0;
-
- if(r_shift>0) {
- p=(r<<(r_shift))&r_mask;
- } else if(r_shift<0) {
- p=(r>>(-r_shift))&r_mask;
- } else p|=(r&r_mask);
-
- if(g_shift>0) {
- p|=(g<<(g_shift))&g_mask;
- } else if(g_shift<0) {
- p|=(g>>(-g_shift))&g_mask;
- } else p|=(g&g_mask);
-
- if(b_shift>0) {
- p|=(b<<(b_shift))&b_mask;
- } else if(b_shift<0) {
- p|=(b>>(-b_shift))&b_mask;
- } else p|=(b&b_mask);
-
- return p;
-}
-
-
-void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
-{
- int yi;
- byte *src;
- PIXEL16 *dest;
- register int count, n;
-
- if( (x<0)||(y<0) )return;
-
- for (yi = y; yi < (y+height); yi++) {
- src = (byte *)&framebuf->data [yi * framebuf->bytes_per_line];
-
- // Duff's Device
- count = width;
- n = (count + 7) / 8;
- dest = ((PIXEL16 *)src) + x+width - 1;
- src += x+width - 1;
-
- switch (count % 8) {
- case 0: do { *dest-- = st2d_8to16table[*src--];
- case 7: *dest-- = st2d_8to16table[*src--];
- case 6: *dest-- = st2d_8to16table[*src--];
- case 5: *dest-- = st2d_8to16table[*src--];
- case 4: *dest-- = st2d_8to16table[*src--];
- case 3: *dest-- = st2d_8to16table[*src--];
- case 2: *dest-- = st2d_8to16table[*src--];
- case 1: *dest-- = st2d_8to16table[*src--];
- } while (--n > 0);
- }
-
-// for(xi = (x+width-1); xi >= x; xi--) {
-// dest[xi] = st2d_8to16table[src[xi]];
-// }
- }
-}
-
-void st3_fixup( XImage *framebuf, int x, int y, int width, int height)
-{
- int yi;
- byte *src;
- PIXEL24 *dest;
- register int count, n;
-
- if( (x<0)||(y<0) )return;
-
- for (yi = y; yi < (y+height); yi++) {
- src = (byte *)&framebuf->data [yi * framebuf->bytes_per_line];
-
- // Duff's Device
- count = width;
- n = (count + 7) / 8;
- dest = ((PIXEL24 *)src) + x+width - 1;
- src += x+width - 1;
-
- switch (count % 8) {
- case 0: do { *dest-- = st2d_8to24table[*src--];
- case 7: *dest-- = st2d_8to24table[*src--];
- case 6: *dest-- = st2d_8to24table[*src--];
- case 5: *dest-- = st2d_8to24table[*src--];
- case 4: *dest-- = st2d_8to24table[*src--];
- case 3: *dest-- = st2d_8to24table[*src--];
- case 2: *dest-- = st2d_8to24table[*src--];
- case 1: *dest-- = st2d_8to24table[*src--];
- } while (--n > 0);
- }
-
-// for(xi = (x+width-1); xi >= x; xi--) {
-// dest[xi] = st2d_8to16table[src[xi]];
-// }
- }
-}
-
-
-
-// Console variables that we need to access from this module
-
-/*****************************************************************************/
-/* MOUSE */
-/*****************************************************************************/
-
-// this is inside the renderer shared lib, so these are called from vid_so
-
-static qboolean mouse_avail;
-static int mouse_buttonstate;
-static int mouse_oldbuttonstate;
-static int old_mouse_x, old_mouse_y;
-static int mx, my;
-
-static qboolean mouse_active = false;
-static qboolean dgamouse = false;
-
-static cvar_t *m_filter;
-static cvar_t *in_mouse;
-static cvar_t *in_dgamouse;
-
-static cvar_t *vid_xpos; // X coordinate of window position
-static cvar_t *vid_ypos; // Y coordinate of window position
-
-static qboolean mlooking;
-
-// state struct passed in Init
-static in_state_t *in_state;
-
-static cvar_t *sensitivity;
-static cvar_t *lookstrafe;
-static cvar_t *m_side;
-static cvar_t *m_yaw;
-static cvar_t *m_pitch;
-static cvar_t *m_forward;
-static cvar_t *freelook;
-
-static void Force_CenterView_f (void)
-{
- in_state->viewangles[PITCH] = 0;
-}
-
-static void RW_IN_MLookDown (void)
-{
- mlooking = true;
-}
-
-static void RW_IN_MLookUp (void)
-{
- mlooking = false;
- in_state->IN_CenterView_fp ();
-}
-
-void RW_IN_Init(in_state_t *in_state_p)
-{
- in_state = in_state_p;
-
- // mouse variables
- m_filter = ri.Cvar_Get ("m_filter", "0", 0);
- in_mouse = ri.Cvar_Get ("in_mouse", "0", CVAR_ARCHIVE);
- in_dgamouse = ri.Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE);
- freelook = ri.Cvar_Get( "freelook", "0", 0 );
- lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);
- sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);
- m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);
- m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);
- m_forward = ri.Cvar_Get ("m_forward", "1", 0);
- m_side = ri.Cvar_Get ("m_side", "0.8", 0);
-
- ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);
- ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);
-
- ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);
-
- mouse_avail = true;
-}
-
-
-/*
-===========
-IN_Commands
-===========
-*/
-void RW_IN_Commands (void)
-{
- int i;
-
- if (!mouse_avail)
- return;
-
- for (i=0 ; i<3 ; i++) {
- if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
- in_state->Key_Event_fp (K_MOUSE1 + i, true);
-
- if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
- in_state->Key_Event_fp (K_MOUSE1 + i, false);
- }
- mouse_oldbuttonstate = mouse_buttonstate;
-}
-
-/*
-===========
-IN_Move
-===========
-*/
-void RW_IN_Move (usercmd_t *cmd)
-{
- if (!mouse_avail)
- return;
-
- if (m_filter->value)
- {
- mx = (mx + old_mouse_x) * 0.5;
- my = (my + old_mouse_y) * 0.5;
- }
-
- old_mouse_x = mx;
- old_mouse_y = my;
-
- mx *= sensitivity->value;
- my *= sensitivity->value;
-
-// add mouse X/Y movement to cmd
- if ( (*in_state->in_strafe_state & 1) ||
- (lookstrafe->value && mlooking ))
- cmd->sidemove += m_side->value * mx;
- else
- in_state->viewangles[YAW] -= m_yaw->value * mx;
-
- if ( (mlooking || freelook->value) &&
- !(*in_state->in_strafe_state & 1))
- {
- in_state->viewangles[PITCH] += m_pitch->value * my;
- }
- else
- {
- cmd->forwardmove -= m_forward->value * my;
- }
- mx = my = 0;
-}
-
-// ========================================================================
-// makes a null cursor
-// ========================================================================
-
-static Cursor CreateNullCursor(Display *display, Window root)
-{
- Pixmap cursormask;
- XGCValues xgc;
- GC gc;
- XColor dummycolour;
- Cursor cursor;
-
- cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
- xgc.function = GXclear;
- gc = XCreateGC(display, cursormask, GCFunction, &xgc);
- XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
- dummycolour.pixel = 0;
- dummycolour.red = 0;
- dummycolour.flags = 04;
- cursor = XCreatePixmapCursor(display, cursormask, cursormask,
- &dummycolour,&dummycolour, 0,0);
- XFreePixmap(display,cursormask);
- XFreeGC(display,gc);
- return cursor;
-}
-
-static void install_grabs(void)
-{
-
-// inviso cursor
- XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
-
- XGrabPointer(dpy, win,
- True,
- 0,
- GrabModeAsync, GrabModeAsync,
- win,
- None,
- CurrentTime);
-
- if (in_dgamouse->value) {
- int MajorVersion, MinorVersion;
-
- if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
- // unable to query, probalby not supported
- ri.Con_Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
- ri.Cvar_Set( "in_dgamouse", "0" );
- } else {
- dgamouse = true;
- XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
- XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
- }
- } else
- XWarpPointer(dpy, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2);
-
- XGrabKeyboard(dpy, win,
- False,
- GrabModeAsync, GrabModeAsync,
- CurrentTime);
-
- mouse_active = true;
-
- ignorefirst = true;
-
-// XSync(dpy, True);
-}
-
-static void uninstall_grabs(void)
-{
- if (!dpy || !win)
- return;
-
- if (dgamouse) {
- dgamouse = false;
- XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
- }
-
- XUngrabPointer(dpy, CurrentTime);
- XUngrabKeyboard(dpy, CurrentTime);
-
-// inviso cursor
- XUndefineCursor(dpy, win);
-
- mouse_active = false;
-}
-
-static void IN_DeactivateMouse( void )
-{
- if (!mouse_avail || !dpy || !win)
- return;
-
- if (mouse_active) {
- uninstall_grabs();
- mouse_active = false;
- }
-}
-
-static void IN_ActivateMouse( void )
-{
- if (!mouse_avail || !dpy || !win)
- return;
-
- if (!mouse_active) {
- mx = my = 0; // don't spazz
- install_grabs();
- mouse_active = true;
- }
-}
-
-void RW_IN_Frame (void)
-{
-}
-
-void RW_IN_Activate(qboolean active)
-{
- if (active)
- IN_ActivateMouse();
- else
- IN_DeactivateMouse();
-}
-
-void RW_IN_Shutdown(void)
-{
- if (mouse_avail) {
- RW_IN_Activate (false);
-
- mouse_avail = false;
-
- ri.Cmd_RemoveCommand ("+mlook");
- ri.Cmd_RemoveCommand ("-mlook");
- ri.Cmd_RemoveCommand ("force_centerview");
- }
-}
-
-/*****************************************************************************/
-
-void ResetFrameBuffer(void)
-{
- int mem;
- int pwidth;
-
- if (x_framebuffer[0])
- {
- free(x_framebuffer[0]->data);
- free(x_framebuffer[0]);
- }
-
-// alloc an extra line in case we want to wrap, and allocate the z-buffer
- pwidth = x_visinfo->depth / 8;
- if (pwidth == 3) pwidth = 4;
- mem = ((vid.width*pwidth+7)&~7) * vid.height;
-
- x_framebuffer[0] = XCreateImage(dpy,
- x_vis,
- x_visinfo->depth,
- ZPixmap,
- 0,
- malloc(mem),
- vid.width, vid.height,
- 32,
- 0);
-
- if (!x_framebuffer[0])
- Sys_Error("VID: XCreateImage failed\n");
-
- vid.buffer = (byte*) (x_framebuffer[0]);
-}
-
-void ResetSharedFrameBuffers(void)
-{
- int size;
- int key;
- int minsize = getpagesize();
- int frm;
-
- for (frm=0 ; frm<2 ; frm++)
- {
- // free up old frame buffer memory
- if (x_framebuffer[frm])
- {
- XShmDetach(dpy, &x_shminfo[frm]);
- free(x_framebuffer[frm]);
- shmdt(x_shminfo[frm].shmaddr);
- }
-
- // create the image
- x_framebuffer[frm] = XShmCreateImage( dpy,
- x_vis,
- x_visinfo->depth,
- ZPixmap,
- 0,
- &x_shminfo[frm],
- vid.width,
- vid.height );
-
- // grab shared memory
-
- size = x_framebuffer[frm]->bytes_per_line
- * x_framebuffer[frm]->height;
- if (size < minsize)
- Sys_Error("VID: Window must use at least %d bytes\n", minsize);
-
- key = random();
- x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
- if (x_shminfo[frm].shmid==-1)
- Sys_Error("VID: Could not get any shared memory\n");
-
- // attach to the shared memory segment
- x_shminfo[frm].shmaddr =
- (void *) shmat(x_shminfo[frm].shmid, 0, 0);
-
- ri.Con_Printf(PRINT_DEVELOPER, "MITSHM shared memory (id=%d, addr=0x%lx)\n",
- x_shminfo[frm].shmid, (long) x_shminfo[frm].shmaddr);
-
- x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
-
- // get the X server to attach to it
-
- if (!XShmAttach(dpy, &x_shminfo[frm]))
- Sys_Error("VID: XShmAttach() failed\n");
- XSync(dpy, 0);
- shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
- }
-
-}
-
-// ========================================================================
-// Tragic death handler
-// ========================================================================
-
-void TragicDeath(int signal_num)
-{
-// XAutoRepeatOn(dpy);
- XCloseDisplay(dpy);
- Sys_Error("This death brought to you by the number %d\n", signal_num);
-}
-
-int XLateKey(XKeyEvent *ev)
-{
-
- int key;
- char buf[64];
- KeySym keysym;
-
- key = 0;
-
- XLookupString(ev, buf, sizeof buf, &keysym, 0);
-
- switch(keysym)
- {
- case XK_KP_Page_Up: key = K_KP_PGUP; break;
- case XK_Page_Up: key = K_PGUP; break;
-
- case XK_KP_Page_Down: key = K_KP_PGDN; break;
- case XK_Page_Down: key = K_PGDN; break;
-
- case XK_KP_Home: key = K_KP_HOME; break;
- case XK_Home: key = K_HOME; break;
-
- case XK_KP_End: key = K_KP_END; break;
- case XK_End: key = K_END; break;
-
- case XK_KP_Left: key = K_KP_LEFTARROW; break;
- case XK_Left: key = K_LEFTARROW; break;
-
- case XK_KP_Right: key = K_KP_RIGHTARROW; break;
- case XK_Right: key = K_RIGHTARROW; break;
-
- case XK_KP_Down: key = K_KP_DOWNARROW; break;
- case XK_Down: key = K_DOWNARROW; break;
-
- case XK_KP_Up: key = K_KP_UPARROW; break;
- case XK_Up: key = K_UPARROW; break;
-
- case XK_Escape: key = K_ESCAPE; break;
-
- case XK_KP_Enter: key = K_KP_ENTER; break;
- case XK_Return: key = K_ENTER; break;
-
- case XK_Tab: key = K_TAB; break;
-
- case XK_F1: key = K_F1; break;
-
- case XK_F2: key = K_F2; break;
-
- case XK_F3: key = K_F3; break;
-
- case XK_F4: key = K_F4; break;
-
- case XK_F5: key = K_F5; break;
-
- case XK_F6: key = K_F6; break;
-
- case XK_F7: key = K_F7; break;
-
- case XK_F8: key = K_F8; break;
-
- case XK_F9: key = K_F9; break;
-
- case XK_F10: key = K_F10; break;
-
- case XK_F11: key = K_F11; break;
-
- case XK_F12: key = K_F12; break;
-
- case XK_BackSpace: key = K_BACKSPACE; break;
-
- case XK_KP_Delete: key = K_KP_DEL; break;
- case XK_Delete: key = K_DEL; break;
-
- case XK_Pause: key = K_PAUSE; break;
-
- case XK_Shift_L:
- case XK_Shift_R: key = K_SHIFT; break;
-
- case XK_Execute:
- case XK_Control_L:
- case XK_Control_R: key = K_CTRL; break;
-
- case XK_Alt_L:
- case XK_Meta_L:
- case XK_Alt_R:
- case XK_Meta_R: key = K_ALT; break;
-
- case XK_KP_Begin: key = K_KP_5; break;
-
- case XK_Insert:key = K_INS; break;
- case XK_KP_Insert: key = K_KP_INS; break;
-
- case XK_KP_Multiply: key = '*'; break;
- case XK_KP_Add: key = K_KP_PLUS; break;
- case XK_KP_Subtract: key = K_KP_MINUS; break;
- case XK_KP_Divide: key = K_KP_SLASH; break;
-
-#if 0
- case 0x021: key = '1';break;/* [!] */
- case 0x040: key = '2';break;/* [@] */
- case 0x023: key = '3';break;/* [#] */
- case 0x024: key = '4';break;/* [$] */
- case 0x025: key = '5';break;/* [%] */
- case 0x05e: key = '6';break;/* [^] */
- case 0x026: key = '7';break;/* [&] */
- case 0x02a: key = '8';break;/* [*] */
- case 0x028: key = '9';;break;/* [(] */
- case 0x029: key = '0';break;/* [)] */
- case 0x05f: key = '-';break;/* [_] */
- case 0x02b: key = '=';break;/* [+] */
- case 0x07c: key = '\'';break;/* [|] */
- case 0x07d: key = '[';break;/* [}] */
- case 0x07b: key = ']';break;/* [{] */
- case 0x022: key = '\'';break;/* ["] */
- case 0x03a: key = ';';break;/* [:] */
- case 0x03f: key = '/';break;/* [?] */
- case 0x03e: key = '.';break;/* [>] */
- case 0x03c: key = ',';break;/* [<] */
-#endif
-
- default:
- key = *(unsigned char*)buf;
- if (key >= 'A' && key <= 'Z')
- key = key - 'A' + 'a';
- if (key >= 1 && key <= 26) /* ctrl+alpha */
- key = key + 'a' - 1;
- break;
- }
-
- return key;
-}
-
-void HandleEvents(void)
-{
- XEvent event;
- int b;
- qboolean dowarp = false;
- int mwx = vid.width/2;
- int mwy = vid.height/2;
-
- while (XPending(dpy)) {
-
- XNextEvent(dpy, &event);
-
- switch(event.type) {
- case KeyPress:
- case KeyRelease:
- if (in_state && in_state->Key_Event_fp)
- in_state->Key_Event_fp (XLateKey(&event.xkey), event.type == KeyPress);
- break;
-
- case MotionNotify:
- if (ignorefirst) {
- ignorefirst = false;
- break;
- }
-
- if (mouse_active) {
- if (dgamouse) {
- mx += (event.xmotion.x + win_x) * 2;
- my += (event.xmotion.y + win_y) * 2;
- }
- else
- {
- mx += ((int)event.xmotion.x - mwx) * 2;
- my += ((int)event.xmotion.y - mwy) * 2;
- mwx = event.xmotion.x;
- mwy = event.xmotion.y;
-
- if (mx || my)
- dowarp = true;
- }
- }
- break;
-
-
- break;
-
- case ButtonPress:
- b=-1;
- if (event.xbutton.button == 1)
- b = 0;
- else if (event.xbutton.button == 2)
- b = 2;
- else if (event.xbutton.button == 3)
- b = 1;
- if (b>=0)
- mouse_buttonstate |= 1<<b;
- break;
-
- case ButtonRelease:
- b=-1;
- if (event.xbutton.button == 1)
- b = 0;
- else if (event.xbutton.button == 2)
- b = 2;
- else if (event.xbutton.button == 3)
- b = 1;
- if (b>=0)
- mouse_buttonstate &= ~(1<<b);
- break;
-
- case CreateNotify :
- ri.Cvar_Set( "vid_xpos", va("%d", event.xcreatewindow.x));
- ri.Cvar_Set( "vid_ypos", va("%d", event.xcreatewindow.y));
- vid_xpos->modified = false;
- vid_ypos->modified = false;
- win_x = event.xcreatewindow.x;
- win_y = event.xcreatewindow.y;
- break;
-
- case ConfigureNotify :
- ri.Cvar_Set( "vid_xpos", va("%d", event.xcreatewindow.x));
- ri.Cvar_Set( "vid_ypos", va("%d", event.xcreatewindow.y));
- vid_xpos->modified = false;
- vid_ypos->modified = false;
- win_x = event.xconfigure.x;
- win_y = event.xconfigure.y;
- config_notify_width = event.xconfigure.width;
- config_notify_height = event.xconfigure.height;
- if (config_notify_width != vid.width ||
- config_notify_height != vid.height)
- XMoveResizeWindow(dpy, win, win_x, win_y, vid.width, vid.height);
- config_notify = 1;
- break;
-
- case ClientMessage:
- if (event.xclient.data.l[0] == wmDeleteWindow)
- ri.Cmd_ExecuteText(EXEC_NOW, "quit");
- break;
- default:
- if (doShm && event.type == x_shmeventtype)
- oktodraw = true;
- if (event.type == Expose && !event.xexpose.count)
- exposureflag = true;
- }
- }
-
- if (dowarp) {
- /* move the mouse to the window center again */
- XWarpPointer(dpy,None,win,0,0,0,0, vid.width/2,vid.height/2);
- }
-}
-
-/*****************************************************************************/
-
-/*
-** SWimp_Init
-**
-** This routine is responsible for initializing the implementation
-** specific stuff in a software rendering subsystem.
-*/
-int SWimp_Init( void *hInstance, void *wndProc )
-{
-
- vid_xpos = ri.Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
- vid_ypos = ri.Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
-
-// open the display
- dpy = XOpenDisplay(NULL);
- if (!dpy)
- {
- if (getenv("DISPLAY"))
- Sys_Error("VID: Could not open display [%s]\n",
- getenv("DISPLAY"));
- else
- Sys_Error("VID: Could not open local display\n");
- }
-
-// catch signals so i can turn on auto-repeat
-
- {
- struct sigaction sa;
- sigaction(SIGINT, 0, &sa);
- sa.sa_handler = TragicDeath;
- sigaction(SIGINT, &sa, 0);
- sigaction(SIGTERM, &sa, 0);
- }
-
- return true;
-}
-
-/*
-** SWimp_InitGraphics
-**
-** This initializes the software refresh's implementation specific
-** graphics subsystem. In the case of Windows it creates DIB or
-** DDRAW surfaces.
-**
-** The necessary width and height parameters are grabbed from
-** vid.width and vid.height.
-*/
-static qboolean SWimp_InitGraphics( qboolean fullscreen )
-{
- int i;
- XVisualInfo template;
- int num_visuals;
- int template_mask;
- Window root;
- //int pnum;
-
- srandom(getpid());
-
- // free resources in use
- SWimp_Shutdown ();
-
- // let the sound and input subsystems know about the new window
- ri.Vid_NewWindow (vid.width, vid.height);
-
-// XAutoRepeatOff(dpy);
-
-// for debugging only
- XSynchronize(dpy, True);
-
-// check for command-line window size
- template_mask = 0;
-
-#if 0
-// specify a visual id
- if ((pnum=COM_CheckParm("-visualid")))
- {
- if (pnum >= com_argc-1)
- Sys_Error("VID: -visualid <id#>\n");
- template.visualid = Q_atoi(com_argv[pnum+1]);
- template_mask = VisualIDMask;
- }
-
-// If not specified, use default visual
- else
-#endif
- {
- int screen;
- screen = XDefaultScreen(dpy);
- template.visualid =
- XVisualIDFromVisual(XDefaultVisual(dpy, screen));
- template_mask = VisualIDMask;
- }
-
-// pick a visual- warn if more than one was available
- x_visinfo = XGetVisualInfo(dpy, template_mask, &template, &num_visuals);
- if (num_visuals > 1)
- {
- printf("Found more than one visual id at depth %d:\n", template.depth);
- for (i=0 ; i<num_visuals ; i++)
- printf(" -visualid %d\n", (int)(x_visinfo[i].visualid));
- }
- else if (num_visuals == 0)
- {
- if (template_mask == VisualIDMask)
- Sys_Error("VID: Bad visual id %d\n", template.visualid);
- else
- Sys_Error("VID: No visuals at depth %d\n", template.depth);
- }
-
-#if 0
- printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
- printf(" screen %d\n", x_visinfo->screen);
- printf(" red_mask 0x%x\n", (int)(x_visinfo->red_mask));
- printf(" green_mask 0x%x\n", (int)(x_visinfo->green_mask));
- printf(" blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
- printf(" colormap_size %d\n", x_visinfo->colormap_size);
- printf(" bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
-#endif
-
- x_vis = x_visinfo->visual;
- root = XRootWindow(dpy, x_visinfo->screen);
-
-// setup attributes for main window
- {
- int attribmask = CWEventMask | CWColormap | CWBorderPixel;
- XSetWindowAttributes attribs;
- XSizeHints *sizehints;
- XWMHints *wmhints;
- Colormap tmpcmap;
-
- tmpcmap = XCreateColormap(dpy, root, x_vis, AllocNone);
-
- attribs.event_mask = X_MASK;
- attribs.border_pixel = 0;
- attribs.colormap = tmpcmap;
-
-// create the main window
- win = XCreateWindow(dpy, root, (int)vid_xpos->value, (int)vid_ypos->value,
- vid.width, vid.height, 0, x_visinfo->depth, InputOutput, x_vis,
- attribmask, &attribs );
-
- sizehints = XAllocSizeHints();
- if (sizehints) {
- sizehints->min_width = vid.width;
- sizehints->min_height = vid.height;
- sizehints->max_width = vid.width;
- sizehints->max_height = vid.height;
- sizehints->base_width = vid.width;
- sizehints->base_height = vid.height;
-
- sizehints->flags = PMinSize | PMaxSize | PBaseSize;
- }
-
- wmhints = XAllocWMHints();
- if (wmhints) {
- #include "q2icon.xbm"
-
- Pixmap icon_pixmap, icon_mask;
- unsigned long fg, bg;
- int i;
-
- fg = BlackPixel(dpy, x_visinfo->screen);
- bg = WhitePixel(dpy, x_visinfo->screen);
- icon_pixmap = XCreatePixmapFromBitmapData(dpy, win, (char *)q2icon_bits, q2icon_width, q2icon_height, fg, bg, x_visinfo->depth);
- for (i = 0; i < sizeof(q2icon_bits); i++)
- q2icon_bits[i] = ~q2icon_bits[i];
- icon_mask = XCreatePixmapFromBitmapData(dpy, win, (char *)q2icon_bits, q2icon_width, q2icon_height, bg, fg, x_visinfo->depth);
-
- wmhints->flags = IconPixmapHint|IconMaskHint;
- wmhints->icon_pixmap = icon_pixmap;
- wmhints->icon_mask = icon_mask;
- }
-
- XSetWMProperties(dpy, win, NULL, NULL, NULL, 0,
- sizehints, wmhints, None);
- if (sizehints)
- XFree(sizehints);
- if (wmhints)
- XFree(wmhints);
-
- XStoreName(dpy, win, "Quake II");
-
- wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
- XSetWMProtocols(dpy, win, &wmDeleteWindow, 1);
-
- if (x_visinfo->class != TrueColor)
- XFreeColormap(dpy, tmpcmap);
- }
-
- if (x_visinfo->depth == 8)
- {
- // create and upload the palette
- if (x_visinfo->class == PseudoColor)
- {
- x_cmap = XCreateColormap(dpy, win, x_vis, AllocAll);
- XSetWindowColormap(dpy, win, x_cmap);
- }
-
- }
-
-// create the GC
- {
- XGCValues xgcvalues;
- int valuemask = GCGraphicsExposures;
- xgcvalues.graphics_exposures = False;
- x_gc = XCreateGC(dpy, win, valuemask, &xgcvalues );
- }
-
- XMapWindow(dpy, win);
- XMoveWindow(dpy, win, (int)vid_xpos->value, (int)vid_ypos->value);
-
-// wait for first exposure event
- {
- exposureflag = false;
- do
- {
- HandleEvents();
- } while (!exposureflag);
- }
-// now safe to draw
-
-// even if MITSHM is available, make sure it's a local connection
- if (XShmQueryExtension(dpy))
- {
- char *displayname;
- doShm = true;
- displayname = (char *) getenv("DISPLAY");
- if (displayname)
- {
- char *dptr = strdup(displayname);
- char *d;
-
- d = dptr;
- while (*d && (*d != ':')) d++;
- if (*d) *d = 0;
- if (!(!strcasecmp(displayname, "unix") || !*displayname))
- doShm = false;
-
- free(dptr);
- }
- }
-
- if (doShm)
- {
- x_shmeventtype = XShmGetEventBase(dpy) + ShmCompletion;
- ResetSharedFrameBuffers();
- }
- else
- ResetFrameBuffer();
-
- current_framebuffer = 0;
- vid.rowbytes = x_framebuffer[0]->bytes_per_line;
- vid.buffer = (byte *)x_framebuffer[0]->data;
-
-// XSynchronize(dpy, False);
-
- X11_active = true;
-
- return true;
-}
-
-/*
-** SWimp_EndFrame
-**
-** This does an implementation specific copy from the backbuffer to the
-** front buffer. In the Win32 case it uses BitBlt or BltFast depending
-** on whether we're using DIB sections/GDI or DDRAW.
-*/
-void SWimp_EndFrame (void)
-{
-// if the window changes dimension, skip this frame
-#if 0
- if (config_notify)
- {
- fprintf(stderr, "config notify\n");
- config_notify = 0;
- vid.width = config_notify_width & ~7;
- vid.height = config_notify_height;
- if (doShm)
- ResetSharedFrameBuffers();
- else
- ResetFrameBuffer();
- vid.rowbytes = x_framebuffer[0]->bytes_per_line;
- vid.buffer = x_framebuffer[current_framebuffer]->data;
- vid.recalc_refdef = 1; // force a surface cache flush
- Con_CheckResize();
- Con_Clear_f();
- return;
- }
-#endif
-
- if (doShm)
- {
- if (x_visinfo->depth == 16)
- st2_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
- else if (x_visinfo->depth == 24)
- st3_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
- if (!XShmPutImage(dpy, win, x_gc,
- x_framebuffer[current_framebuffer], 0, 0, 0, 0, vid.width, vid.height, True))
- Sys_Error("VID_Update: XShmPutImage failed\n");
- oktodraw = false;
- while (!oktodraw)
- HandleEvents();
- current_framebuffer = !current_framebuffer;
- vid.buffer = (byte *)x_framebuffer[current_framebuffer]->data;
- XSync(dpy, False);
- }
- else
- {
- if (x_visinfo->depth == 16)
- st2_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
- else if (x_visinfo->depth == 24)
- st3_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
- XPutImage(dpy, win, x_gc, x_framebuffer[0], 0, 0, 0, 0, vid.width, vid.height);
- XSync(dpy, False);
- }
-}
-
-/*
-** SWimp_SetMode
-*/
-rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
-{
- rserr_t retval = rserr_ok;
-
- ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
-
- if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
- {
- ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
- return rserr_invalid_mode;
- }
-
- ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight);
-
- if ( !SWimp_InitGraphics( false ) ) {
- // failed to set a valid mode in windowed mode
- return rserr_invalid_mode;
- }
-
- R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
-
- return retval;
-}
-
-/*
-** SWimp_SetPalette
-**
-** System specific palette setting routine. A NULL palette means
-** to use the existing palette. The palette is expected to be in
-** a padded 4-byte xRGB format.
-*/
-void SWimp_SetPalette( const unsigned char *palette )
-{
- int i;
- XColor colors[256];
-
- if (!X11_active)
- return;
-
- if ( !palette )
- palette = ( const unsigned char * ) sw_state.currentpalette;
-
- for(i=0;i<256;i++) {
- st2d_8to16table[i]= xlib_rgb16(palette[i*4], palette[i*4+1],palette[i*4+2]);
- st2d_8to24table[i]= xlib_rgb24(palette[i*4], palette[i*4+1],palette[i*4+2]);
- }
-
- if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
- {
- for (i=0 ; i<256 ; i++)
- {
- colors[i].pixel = i;
- colors[i].flags = DoRed|DoGreen|DoBlue;
- colors[i].red = palette[i*4] * 257;
- colors[i].green = palette[i*4+1] * 257;
- colors[i].blue = palette[i*4+2] * 257;
- }
- XStoreColors(dpy, x_cmap, colors, 256);
- }
-}
-
-/*
-** SWimp_Shutdown
-**
-** System specific graphics subsystem shutdown routine. Destroys
-** DIBs or DDRAW surfaces as appropriate.
-*/
-void SWimp_Shutdown( void )
-{
- int i;
-
- if (!X11_active)
- return;
-
- if (doShm) {
- for (i = 0; i < 2; i++)
- if (x_framebuffer[i]) {
- XShmDetach(dpy, &x_shminfo[i]);
- free(x_framebuffer[i]);
- shmdt(x_shminfo[i].shmaddr);
- x_framebuffer[i] = NULL;
- }
- } else if (x_framebuffer[0]) {
- free(x_framebuffer[0]->data);
- free(x_framebuffer[0]);
- x_framebuffer[0] = NULL;
- }
-
- XDestroyWindow( dpy, win );
-
- win = 0;
-
-// XAutoRepeatOn(dpy);
-// XCloseDisplay(dpy);
-
- X11_active = false;
-}
-
-/*
-** SWimp_AppActivate
-*/
-void SWimp_AppActivate( qboolean active )
-{
-}
-
-//===============================================================================
-
-/*
-================
-Sys_MakeCodeWriteable
-================
-*/
-void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
-{
-
- int r;
- unsigned long addr;
- int psize = getpagesize();
-
- addr = (startaddr & ~(psize-1)) - psize;
-
-// fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
-// addr, startaddr+length, length);
-
- r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
-
- if (r < 0)
- Sys_Error("Protection change failed\n");
-
-}
-
-/*****************************************************************************/
-/* KEYBOARD */
-/*****************************************************************************/
-
-Key_Event_fp_t Key_Event_fp;
-
-void KBD_Init(Key_Event_fp_t fp)
-{
- Key_Event_fp = fp;
-}
-
-void KBD_Update(void)
-{
-// get events from x server
- HandleEvents();
-}
-
-void KBD_Close(void)
-{
-}
-
-
+/*
+Copyright (C) 1997-2001 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+/*
+** RW_X11.C
+**
+** This file contains ALL Linux specific stuff having to do with the
+** software refresh. When a port is being made the following functions
+** must be implemented by the port:
+**
+** SWimp_EndFrame
+** SWimp_Init
+** SWimp_InitGraphics
+** SWimp_SetPalette
+** SWimp_Shutdown
+** SWimp_SwitchFullscreen
+*/
+
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/xf86dga.h>
+
+#include "../ref_soft/r_local.h"
+#include "../client/keys.h"
+#include "../linux/rw_linux.h"
+
+/*****************************************************************************/
+
+static qboolean doShm;
+static Display *dpy;
+static Colormap x_cmap;
+static Window win;
+static GC x_gc;
+static Visual *x_vis;
+static XVisualInfo *x_visinfo;
+static int win_x, win_y;
+
+#define KEY_MASK (KeyPressMask | KeyReleaseMask)
+#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
+ PointerMotionMask | ButtonMotionMask )
+#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask | ExposureMask )
+
+static int x_shmeventtype;
+//static XShmSegmentInfo x_shminfo;
+
+static qboolean oktodraw = false;
+static qboolean ignorefirst = false;
+static qboolean exposureflag = false;
+static qboolean X11_active = false;
+
+int XShmQueryExtension(Display *);
+int XShmGetEventBase(Display *);
+
+int current_framebuffer;
+static XImage *x_framebuffer[2] = { 0, 0 };
+static XShmSegmentInfo x_shminfo[2];
+
+int config_notify=0;
+int config_notify_width;
+int config_notify_height;
+
+typedef unsigned short PIXEL16;
+typedef unsigned long PIXEL24;
+static PIXEL16 st2d_8to16table[256];
+static PIXEL16 st2d_8to16table_s[2][256];
+static PIXEL24 st2d_8to24table[256];
+static PIXEL24 st2d_8to24table_s[2][256];
+static int shiftmask_fl=0;
+static long r_shift,g_shift,b_shift;
+static unsigned long r_mask,g_mask,b_mask;
+
+void shiftmask_init(void)
+{
+ unsigned int x;
+ r_mask=x_vis->red_mask;
+ g_mask=x_vis->green_mask;
+ b_mask=x_vis->blue_mask;
+ for(r_shift=-8,x=1;x<r_mask;x=x<<1)r_shift++;
+ for(g_shift=-8,x=1;x<g_mask;x=x<<1)g_shift++;
+ for(b_shift=-8,x=1;x<b_mask;x=x<<1)b_shift++;
+ shiftmask_fl=1;
+}
+
+PIXEL16 xlib_rgb16(int r,int g,int b)
+{
+ PIXEL16 p;
+ if(shiftmask_fl==0) shiftmask_init();
+ p=0;
+
+ if(r_shift>0) {
+ p=(r<<(r_shift))&r_mask;
+ } else if(r_shift<0) {
+ p=(r>>(-r_shift))&r_mask;
+ } else p|=(r&r_mask);
+
+ if(g_shift>0) {
+ p|=(g<<(g_shift))&g_mask;
+ } else if(g_shift<0) {
+ p|=(g>>(-g_shift))&g_mask;
+ } else p|=(g&g_mask);
+
+ if(b_shift>0) {
+ p|=(b<<(b_shift))&b_mask;
+ } else if(b_shift<0) {
+ p|=(b>>(-b_shift))&b_mask;
+ } else p|=(b&b_mask);
+
+ return p;
+}
+
+PIXEL24 xlib_rgb24(int r,int g,int b)
+{
+ PIXEL24 p;
+ if(shiftmask_fl==0) shiftmask_init();
+ p=0;
+
+ if(r_shift>0) {
+ p=(r<<(r_shift))&r_mask;
+ } else if(r_shift<0) {
+ p=(r>>(-r_shift))&r_mask;
+ } else p|=(r&r_mask);
+
+ if(g_shift>0) {
+ p|=(g<<(g_shift))&g_mask;
+ } else if(g_shift<0) {
+ p|=(g>>(-g_shift))&g_mask;
+ } else p|=(g&g_mask);
+
+ if(b_shift>0) {
+ p|=(b<<(b_shift))&b_mask;
+ } else if(b_shift<0) {
+ p|=(b>>(-b_shift))&b_mask;
+ } else p|=(b&b_mask);
+
+ return p;
+}
+
+
+void st2_fixup( XImage *framebuf, int x, int y, int width, int height)
+{
+ int xi,yi;
+ unsigned char *src;
+ PIXEL16 *dest;
+ register int count, n;
+
+ if( (x<0)||(y<0) )return;
+
+ for (yi = y; yi < (y+height); yi++) {
+ src = &framebuf->data [yi * framebuf->bytes_per_line];
+
+ // Duff's Device
+ count = width;
+ n = (count + 7) / 8;
+ dest = ((PIXEL16 *)src) + x+width - 1;
+ src += x+width - 1;
+
+ switch (count % 8) {
+ case 0: do { *dest-- = st2d_8to16table[*src--];
+ case 7: *dest-- = st2d_8to16table[*src--];
+ case 6: *dest-- = st2d_8to16table[*src--];
+ case 5: *dest-- = st2d_8to16table[*src--];
+ case 4: *dest-- = st2d_8to16table[*src--];
+ case 3: *dest-- = st2d_8to16table[*src--];
+ case 2: *dest-- = st2d_8to16table[*src--];
+ case 1: *dest-- = st2d_8to16table[*src--];
+ } while (--n > 0);
+ }
+
+// for(xi = (x+width-1); xi >= x; xi--) {
+// dest[xi] = st2d_8to16table[src[xi]];
+// }
+ }
+}
+
+void st2_fixup_stereo( XImage *framebuf1, XImage *framebuf2, int x, int y, int width, int height)
+{
+ int xi,yi;
+ unsigned char *src;
+ PIXEL16 *dest;
+ register int count, n;
+
+ if( (x<0)||(y<0) )return;
+
+ for (yi = y; yi < (y+height); yi++) {
+ src = &framebuf1->data [yi * framebuf1->bytes_per_line];
+
+ // Duff's Device
+ count = width;
+ n = (count + 7) / 8;
+ dest = ((PIXEL16 *)src) + x+width - 1;
+ src += x+width - 1;
+
+ switch (count % 8) {
+ case 0: do { *dest-- = st2d_8to16table_s[0][*src--];
+ case 7: *dest-- = st2d_8to16table_s[0][*src--];
+ case 6: *dest-- = st2d_8to16table_s[0][*src--];
+ case 5: *dest-- = st2d_8to16table_s[0][*src--];
+ case 4: *dest-- = st2d_8to16table_s[0][*src--];
+ case 3: *dest-- = st2d_8to16table_s[0][*src--];
+ case 2: *dest-- = st2d_8to16table_s[0][*src--];
+ case 1: *dest-- = st2d_8to16table_s[0][*src--];
+ } while (--n > 0);
+ }
+
+// for(xi = (x+width-1); xi >= x; xi--) {
+// dest[xi] = st2d_8to16table[src[xi]];
+// }
+ }
+
+ for (yi = y; yi < (y+height); yi++) {
+ src = &framebuf1->data [yi * framebuf1->bytes_per_line];
+
+ // Duff's Device
+ count = width;
+ n = (count + 7) / 8;
+ dest = ((PIXEL16 *)src) + x+width - 1;
+ src = &framebuf2->data [yi * framebuf2->bytes_per_line];
+ src += x+width - 1;
+
+ switch (count % 8) {
+ case 0: do { *dest-- += st2d_8to16table_s[1][*src--];
+ case 7: *dest-- += st2d_8to16table_s[1][*src--];
+ case 6: *dest-- += st2d_8to16table_s[1][*src--];
+ case 5: *dest-- += st2d_8to16table_s[1][*src--];
+ case 4: *dest-- += st2d_8to16table_s[1][*src--];
+ case 3: *dest-- += st2d_8to16table_s[1][*src--];
+ case 2: *dest-- += st2d_8to16table_s[1][*src--];
+ case 1: *dest-- += st2d_8to16table_s[1][*src--];
+ } while (--n > 0);
+ }
+
+// for(xi = (x+width-1); xi >= x; xi--) {
+// dest[xi] = st2d_8to16table[src[xi]];
+// }
+ }
+}
+
+void st3_fixup( XImage *framebuf, int x, int y, int width, int height)
+{
+ int xi,yi;
+ unsigned char *src;
+ PIXEL24 *dest;
+ register int count, n;
+
+ if( (x<0)||(y<0) )return;
+
+ for (yi = y; yi < (y+height); yi++) {
+ src = &framebuf->data [yi * framebuf->bytes_per_line];
+
+ // Duff's Device
+ count = width;
+ n = (count + 7) / 8;
+ dest = ((PIXEL24 *)src) + x+width - 1;
+ src += x+width - 1;
+
+ switch (count % 8) {
+ case 0: do { *dest-- = st2d_8to24table[*src--];
+ case 7: *dest-- = st2d_8to24table[*src--];
+ case 6: *dest-- = st2d_8to24table[*src--];
+ case 5: *dest-- = st2d_8to24table[*src--];
+ case 4: *dest-- = st2d_8to24table[*src--];
+ case 3: *dest-- = st2d_8to24table[*src--];
+ case 2: *dest-- = st2d_8to24table[*src--];
+ case 1: *dest-- = st2d_8to24table[*src--];
+ } while (--n > 0);
+ }
+
+// for(xi = (x+width-1); xi >= x; xi--) {
+// dest[xi] = st2d_8to16table[src[xi]];
+// }
+ }
+}
+
+void st3_fixup_stereo( XImage *framebuf1, XImage *framebuf2, int x, int y, int width, int height)
+{
+ int xi,yi;
+ unsigned char *src;
+ PIXEL24 *dest;
+ register int count, n;
+
+ if( (x<0)||(y<0) )return;
+
+ for (yi = y; yi < (y+height); yi++) {
+ src = &framebuf1->data [yi * framebuf1->bytes_per_line];
+
+ // Duff's Device
+ count = width;
+ n = (count + 7) / 8;
+ dest = ((PIXEL24 *)src) + x+width - 1;
+ src += x+width - 1;
+
+ switch (count % 8) {
+ case 0: do { *dest-- = st2d_8to24table_s[0][*src--];
+ case 7: *dest-- = st2d_8to24table_s[0][*src--];
+ case 6: *dest-- = st2d_8to24table_s[0][*src--];
+ case 5: *dest-- = st2d_8to24table_s[0][*src--];
+ case 4: *dest-- = st2d_8to24table_s[0][*src--];
+ case 3: *dest-- = st2d_8to24table_s[0][*src--];
+ case 2: *dest-- = st2d_8to24table_s[0][*src--];
+ case 1: *dest-- = st2d_8to24table_s[0][*src--];
+ } while (--n > 0);
+ }
+
+// for(xi = (x+width-1); xi >= x; xi--) {
+// dest[xi] = st2d_8to16table[src[xi]];
+// }
+ }
+
+ for (yi = y; yi < (y+height); yi++) {
+ src = &framebuf1->data [yi * framebuf1->bytes_per_line];
+
+ // Duff's Device
+ count = width;
+ n = (count + 7) / 8;
+ dest = ((PIXEL24 *)src) + x+width - 1;
+ src = &framebuf2->data [yi * framebuf2->bytes_per_line];
+ src += x+width - 1;
+
+ switch (count % 8) {
+ case 0: do { *dest-- += st2d_8to24table_s[1][*src--];
+ case 7: *dest-- += st2d_8to24table_s[1][*src--];
+ case 6: *dest-- += st2d_8to24table_s[1][*src--];
+ case 5: *dest-- += st2d_8to24table_s[1][*src--];
+ case 4: *dest-- += st2d_8to24table_s[1][*src--];
+ case 3: *dest-- += st2d_8to24table_s[1][*src--];
+ case 2: *dest-- += st2d_8to24table_s[1][*src--];
+ case 1: *dest-- += st2d_8to24table_s[1][*src--];
+ } while (--n > 0);
+ }
+
+// for(xi = (x+width-1); xi >= x; xi--) {
+// dest[xi] = st2d_8to16table[src[xi]];
+// }
+ }
+}
+
+
+
+// Console variables that we need to access from this module
+
+/*****************************************************************************/
+/* MOUSE */
+/*****************************************************************************/
+
+// this is inside the renderer shared lib, so these are called from vid_so
+
+static qboolean mouse_avail;
+static int mouse_buttonstate;
+static int mouse_oldbuttonstate;
+static int old_mouse_x, old_mouse_y;
+static int mx, my;
+
+static qboolean mouse_active = false;
+static qboolean dgamouse = false;
+
+static cvar_t *m_filter;
+static cvar_t *in_mouse;
+static cvar_t *in_dgamouse;
+
+static cvar_t *vid_xpos; // X coordinate of window position
+static cvar_t *vid_ypos; // Y coordinate of window position
+
+static qboolean mlooking;
+
+// state struct passed in Init
+static in_state_t *in_state;
+
+static cvar_t *sensitivity;
+static cvar_t *lookstrafe;
+static cvar_t *m_side;
+static cvar_t *m_yaw;
+static cvar_t *m_pitch;
+static cvar_t *m_forward;
+static cvar_t *freelook;
+
+static void Force_CenterView_f (void)
+{
+ in_state->viewangles[PITCH] = 0;
+}
+
+static void RW_IN_MLookDown (void)
+{
+ mlooking = true;
+}
+
+static void RW_IN_MLookUp (void)
+{
+ mlooking = false;
+ in_state->IN_CenterView_fp ();
+}
+
+void RW_IN_Init(in_state_t *in_state_p)
+{
+ int mtype;
+ int i;
+
+ in_state = in_state_p;
+
+ // mouse variables
+ m_filter = ri.Cvar_Get ("m_filter", "0", 0);
+ in_mouse = ri.Cvar_Get ("in_mouse", "0", CVAR_ARCHIVE);
+ in_dgamouse = ri.Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE);
+ freelook = ri.Cvar_Get( "freelook", "0", 0 );
+ lookstrafe = ri.Cvar_Get ("lookstrafe", "0", 0);
+ sensitivity = ri.Cvar_Get ("sensitivity", "3", 0);
+ m_pitch = ri.Cvar_Get ("m_pitch", "0.022", 0);
+ m_yaw = ri.Cvar_Get ("m_yaw", "0.022", 0);
+ m_forward = ri.Cvar_Get ("m_forward", "1", 0);
+ m_side = ri.Cvar_Get ("m_side", "0.8", 0);
+
+ ri.Cmd_AddCommand ("+mlook", RW_IN_MLookDown);
+ ri.Cmd_AddCommand ("-mlook", RW_IN_MLookUp);
+
+ ri.Cmd_AddCommand ("force_centerview", Force_CenterView_f);
+
+ mouse_avail = true;
+}
+
+void RW_IN_Shutdown(void)
+{
+ mouse_avail = false;
+}
+
+/*
+===========
+IN_Commands
+===========
+*/
+void RW_IN_Commands (void)
+{
+ int i;
+
+ if (!mouse_avail)
+ return;
+
+ for (i=0 ; i<3 ; i++) {
+ if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
+ in_state->Key_Event_fp (K_MOUSE1 + i, true);
+
+ if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
+ in_state->Key_Event_fp (K_MOUSE1 + i, false);
+ }
+ mouse_oldbuttonstate = mouse_buttonstate;
+}
+
+/*
+===========
+IN_Move
+===========
+*/
+void RW_IN_Move (usercmd_t *cmd)
+{
+ if (!mouse_avail)
+ return;
+
+ if (m_filter->value)
+ {
+ mx = (mx + old_mouse_x) * 0.5;
+ my = (my + old_mouse_y) * 0.5;
+ }
+
+ old_mouse_x = mx;
+ old_mouse_y = my;
+
+ mx *= sensitivity->value;
+ my *= sensitivity->value;
+
+// add mouse X/Y movement to cmd
+ if ( (*in_state->in_strafe_state & 1) ||
+ (lookstrafe->value && mlooking ))
+ cmd->sidemove += m_side->value * mx;
+ else
+ in_state->viewangles[YAW] -= m_yaw->value * mx;
+
+ if ( (mlooking || freelook->value) &&
+ !(*in_state->in_strafe_state & 1))
+ {
+ in_state->viewangles[PITCH] += m_pitch->value * my;
+ }
+ else
+ {
+ cmd->forwardmove -= m_forward->value * my;
+ }
+ mx = my = 0;
+}
+
+// ========================================================================
+// makes a null cursor
+// ========================================================================
+
+static Cursor CreateNullCursor(Display *display, Window root)
+{
+ Pixmap cursormask;
+ XGCValues xgc;
+ GC gc;
+ XColor dummycolour;
+ Cursor cursor;
+
+ cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
+ xgc.function = GXclear;
+ gc = XCreateGC(display, cursormask, GCFunction, &xgc);
+ XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
+ dummycolour.pixel = 0;
+ dummycolour.red = 0;
+ dummycolour.flags = 04;
+ cursor = XCreatePixmapCursor(display, cursormask, cursormask,
+ &dummycolour,&dummycolour, 0,0);
+ XFreePixmap(display,cursormask);
+ XFreeGC(display,gc);
+ return cursor;
+}
+
+static void install_grabs(void)
+{
+
+// inviso cursor
+ XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
+
+ XGrabPointer(dpy, win,
+ True,
+ 0,
+ GrabModeAsync, GrabModeAsync,
+ win,
+ None,
+ CurrentTime);
+
+ if (in_dgamouse->value) {
+ int MajorVersion, MinorVersion;
+
+ if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
+ // unable to query, probalby not supported
+ ri.Con_Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" );
+ ri.Cvar_Set( "in_dgamouse", "0" );
+ } else {
+ dgamouse = true;
+ XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
+ XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
+ }
+ } else
+ XWarpPointer(dpy, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2);
+
+ XGrabKeyboard(dpy, win,
+ False,
+ GrabModeAsync, GrabModeAsync,
+ CurrentTime);
+
+ mouse_active = true;
+
+ ignorefirst = true;
+
+// XSync(dpy, True);
+}
+
+static void uninstall_grabs(void)
+{
+ if (!dpy || !win)
+ return;
+
+ if (dgamouse) {
+ dgamouse = false;
+ XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
+ }
+
+ XUngrabPointer(dpy, CurrentTime);
+ XUngrabKeyboard(dpy, CurrentTime);
+
+// inviso cursor
+ XUndefineCursor(dpy, win);
+
+ mouse_active = false;
+}
+
+static void IN_DeactivateMouse( void )
+{
+ if (!mouse_avail || !dpy || !win)
+ return;
+
+ if (mouse_active) {
+ uninstall_grabs();
+ mouse_active = false;
+ }
+}
+
+static void IN_ActivateMouse( void )
+{
+ if (!mouse_avail || !dpy || !win)
+ return;
+
+ if (!mouse_active) {
+ mx = my = 0; // don't spazz
+ install_grabs();
+ mouse_active = true;
+ }
+}
+
+void RW_IN_Frame (void)
+{
+}
+
+void RW_IN_Activate(qboolean active)
+{
+ if (active)
+ IN_ActivateMouse();
+ else
+ IN_DeactivateMouse ();
+}
+
+/*****************************************************************************/
+
+void ResetFrameBuffer(void)
+{
+ int mem;
+ int pwidth;
+
+ if (x_framebuffer[0])
+ {
+ free(x_framebuffer[0]->data);
+ free(x_framebuffer[0]);
+ }
+
+ if (x_framebuffer[1])
+ {
+ free(x_framebuffer[1]->data);
+ free(x_framebuffer[1]);
+ }
+
+// alloc an extra line in case we want to wrap, and allocate the z-buffer
+ pwidth = x_visinfo->depth / 8;
+ if (pwidth == 3) pwidth = 4;
+ mem = ((vid.width*pwidth+7)&~7) * vid.height;
+
+ x_framebuffer[0] = XCreateImage(dpy,
+ x_vis,
+ x_visinfo->depth,
+ ZPixmap,
+ 0,
+ malloc(mem),
+ vid.width, vid.height,
+ 32,
+ 0);
+
+ if (!x_framebuffer[0])
+ Sys_Error("VID: XCreateImage failed\n");
+
+ x_framebuffer[1] = XCreateImage(dpy,
+ x_vis,
+ x_visinfo->depth,
+ ZPixmap,
+ 0,
+ malloc(mem),
+ vid.width, vid.height,
+ 32,
+ 0);
+
+ if (!x_framebuffer[1])
+ Sys_Error("VID: XCreateImage failed\n");
+
+ vid.buffer = (byte*) (x_framebuffer[0]->data);
+}
+
+void ResetSharedFrameBuffers(void)
+{
+ int size;
+ int key;
+ int minsize = getpagesize();
+ int frm;
+
+ for (frm=0 ; frm<2 ; frm++)
+ {
+ // free up old frame buffer memory
+ if (x_framebuffer[frm])
+ {
+ XShmDetach(dpy, &x_shminfo[frm]);
+ free(x_framebuffer[frm]);
+ shmdt(x_shminfo[frm].shmaddr);
+ }
+
+ // create the image
+ x_framebuffer[frm] = XShmCreateImage( dpy,
+ x_vis,
+ x_visinfo->depth,
+ ZPixmap,
+ 0,
+ &x_shminfo[frm],
+ vid.width,
+ vid.height );
+
+ // grab shared memory
+
+ size = x_framebuffer[frm]->bytes_per_line
+ * x_framebuffer[frm]->height;
+ if (size < minsize)
+ Sys_Error("VID: Window must use at least %d bytes\n", minsize);
+
+ key = random();
+ x_shminfo[frm].shmid = shmget((key_t)key, size, IPC_CREAT|0777);
+ if (x_shminfo[frm].shmid==-1)
+ Sys_Error("VID: Could not get any shared memory\n");
+
+ // attach to the shared memory segment
+ x_shminfo[frm].shmaddr =
+ (void *) shmat(x_shminfo[frm].shmid, 0, 0);
+
+ ri.Con_Printf(PRINT_DEVELOPER, "MITSHM shared memory (id=%d, addr=0x%lx)\n",
+ x_shminfo[frm].shmid, (long) x_shminfo[frm].shmaddr);
+
+ x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
+
+ // get the X server to attach to it
+
+ if (!XShmAttach(dpy, &x_shminfo[frm]))
+ Sys_Error("VID: XShmAttach() failed\n");
+ XSync(dpy, 0);
+ shmctl(x_shminfo[frm].shmid, IPC_RMID, 0);
+ }
+
+}
+
+// ========================================================================
+// Tragic death handler
+// ========================================================================
+
+void TragicDeath(int signal_num)
+{
+// XAutoRepeatOn(dpy);
+ XCloseDisplay(dpy);
+ Sys_Error("This death brought to you by the number %d\n", signal_num);
+}
+
+int XLateKey(XKeyEvent *ev)
+{
+
+ int key;
+ char buf[64];
+ KeySym keysym;
+
+ key = 0;
+
+ XLookupString(ev, buf, sizeof buf, &keysym, 0);
+
+ switch(keysym)
+ {
+ case XK_KP_Page_Up: key = K_KP_PGUP; break;
+ case XK_Page_Up: key = K_PGUP; break;
+
+ case XK_KP_Page_Down: key = K_KP_PGDN; break;
+ case XK_Page_Down: key = K_PGDN; break;
+
+ case XK_KP_Home: key = K_KP_HOME; break;
+ case XK_Home: key = K_HOME; break;
+
+ case XK_KP_End: key = K_KP_END; break;
+ case XK_End: key = K_END; break;
+
+ case XK_KP_Left: key = K_KP_LEFTARROW; break;
+ case XK_Left: key = K_LEFTARROW; break;
+
+ case XK_KP_Right: key = K_KP_RIGHTARROW; break;
+ case XK_Right: key = K_RIGHTARROW; break;
+
+ case XK_KP_Down: key = K_KP_DOWNARROW; break;
+ case XK_Down: key = K_DOWNARROW; break;
+
+ case XK_KP_Up: key = K_KP_UPARROW; break;
+ case XK_Up: key = K_UPARROW; break;
+
+ case XK_Escape: key = K_ESCAPE; break;
+
+ case XK_KP_Enter: key = K_KP_ENTER; break;
+ case XK_Return: key = K_ENTER; break;
+
+ case XK_Tab: key = K_TAB; break;
+
+ case XK_F1: key = K_F1; break;
+
+ case XK_F2: key = K_F2; break;
+
+ case XK_F3: key = K_F3; break;
+
+ case XK_F4: key = K_F4; break;
+
+ case XK_F5: key = K_F5; break;
+
+ case XK_F6: key = K_F6; break;
+
+ case XK_F7: key = K_F7; break;
+
+ case XK_F8: key = K_F8; break;
+
+ case XK_F9: key = K_F9; break;
+
+ case XK_F10: key = K_F10; break;
+
+ case XK_F11: key = K_F11; break;
+
+ case XK_F12: key = K_F12; break;
+
+ case XK_BackSpace: key = K_BACKSPACE; break;
+
+ case XK_KP_Delete: key = K_KP_DEL; break;
+ case XK_Delete: key = K_DEL; break;
+
+ case XK_Pause: key = K_PAUSE; break;
+
+ case XK_Shift_L:
+ case XK_Shift_R: key = K_SHIFT; break;
+
+ case XK_Execute:
+ case XK_Control_L:
+ case XK_Control_R: key = K_CTRL; break;
+
+ case XK_Alt_L:
+ case XK_Meta_L:
+ case XK_Alt_R:
+ case XK_Meta_R: key = K_ALT; break;
+
+ case XK_KP_Begin: key = K_KP_5; break;
+
+ case XK_Insert:key = K_INS; break;
+ case XK_KP_Insert: key = K_KP_INS; break;
+
+ case XK_KP_Multiply: key = '*'; break;
+ case XK_KP_Add: key = K_KP_PLUS; break;
+ case XK_KP_Subtract: key = K_KP_MINUS; break;
+ case XK_KP_Divide: key = K_KP_SLASH; break;
+
+#if 0
+ case 0x021: key = '1';break;/* [!] */
+ case 0x040: key = '2';break;/* [@] */
+ case 0x023: key = '3';break;/* [#] */
+ case 0x024: key = '4';break;/* [$] */
+ case 0x025: key = '5';break;/* [%] */
+ case 0x05e: key = '6';break;/* [^] */
+ case 0x026: key = '7';break;/* [&] */
+ case 0x02a: key = '8';break;/* [*] */
+ case 0x028: key = '9';;break;/* [(] */
+ case 0x029: key = '0';break;/* [)] */
+ case 0x05f: key = '-';break;/* [_] */
+ case 0x02b: key = '=';break;/* [+] */
+ case 0x07c: key = '\'';break;/* [|] */
+ case 0x07d: key = '[';break;/* [}] */
+ case 0x07b: key = ']';break;/* [{] */
+ case 0x022: key = '\'';break;/* ["] */
+ case 0x03a: key = ';';break;/* [:] */
+ case 0x03f: key = '/';break;/* [?] */
+ case 0x03e: key = '.';break;/* [>] */
+ case 0x03c: key = ',';break;/* [<] */
+#endif
+
+ default:
+ key = *(unsigned char*)buf;
+ if (key >= 'A' && key <= 'Z')
+ key = key - 'A' + 'a';
+ break;
+ }
+
+ return key;
+}
+
+void HandleEvents(void)
+{
+ XEvent event;
+ int b;
+ qboolean dowarp = false;
+ int mwx = vid.width/2;
+ int mwy = vid.height/2;
+
+ while (XPending(dpy)) {
+
+ XNextEvent(dpy, &event);
+
+ switch(event.type) {
+ case KeyPress:
+ case KeyRelease:
+ if (in_state && in_state->Key_Event_fp)
+ in_state->Key_Event_fp (XLateKey(&event.xkey), event.type == KeyPress);
+ break;
+
+ case MotionNotify:
+ if (ignorefirst) {
+ ignorefirst = false;
+ break;
+ }
+
+ if (mouse_active) {
+ if (dgamouse) {
+ mx += (event.xmotion.x + win_x) * 2;
+ my += (event.xmotion.y + win_y) * 2;
+ }
+ else
+ {
+ mx += ((int)event.xmotion.x - mwx) * 2;
+ my += ((int)event.xmotion.y - mwy) * 2;
+ mwx = event.xmotion.x;
+ mwy = event.xmotion.y;
+
+ if (mx || my)
+ dowarp = true;
+ }
+ }
+ break;
+
+
+ break;
+
+ case ButtonPress:
+ b=-1;
+ if (event.xbutton.button == 1)
+ b = 0;
+ else if (event.xbutton.button == 2)
+ b = 2;
+ else if (event.xbutton.button == 3)
+ b = 1;
+ if (b>=0)
+ mouse_buttonstate |= 1<<b;
+ break;
+
+ case ButtonRelease:
+ b=-1;
+ if (event.xbutton.button == 1)
+ b = 0;
+ else if (event.xbutton.button == 2)
+ b = 2;
+ else if (event.xbutton.button == 3)
+ b = 1;
+ if (b>=0)
+ mouse_buttonstate &= ~(1<<b);
+ break;
+
+ case CreateNotify :
+ ri.Cvar_Set( "vid_xpos", va("%d", event.xcreatewindow.x));
+ ri.Cvar_Set( "vid_ypos", va("%d", event.xcreatewindow.y));
+ vid_xpos->modified = false;
+ vid_ypos->modified = false;
+ win_x = event.xcreatewindow.x;
+ win_y = event.xcreatewindow.y;
+ break;
+
+ case ConfigureNotify :
+ ri.Cvar_Set( "vid_xpos", va("%d", event.xcreatewindow.x));
+ ri.Cvar_Set( "vid_ypos", va("%d", event.xcreatewindow.y));
+ vid_xpos->modified = false;
+ vid_ypos->modified = false;
+ win_x = event.xconfigure.x;
+ win_y = event.xconfigure.y;
+ config_notify_width = event.xconfigure.width;
+ config_notify_height = event.xconfigure.height;
+ if (config_notify_width != vid.width ||
+ config_notify_height != vid.height)
+ XMoveResizeWindow(dpy, win, win_x, win_y, vid.width, vid.height);
+ config_notify = 1;
+ break;
+
+ default:
+ if (doShm && event.type == x_shmeventtype)
+ oktodraw = true;
+ if (event.type == Expose && !event.xexpose.count)
+ exposureflag = true;
+ }
+ }
+
+ if (dowarp) {
+ /* move the mouse to the window center again */
+ XWarpPointer(dpy,None,win,0,0,0,0, vid.width/2,vid.height/2);
+ }
+}
+
+/*****************************************************************************/
+
+/*
+** SWimp_Init
+**
+** This routine is responsible for initializing the implementation
+** specific stuff in a software rendering subsystem.
+*/
+int SWimp_Init( void *hInstance, void *wndProc )
+{
+
+ vid_xpos = ri.Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
+ vid_ypos = ri.Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
+
+// open the display
+ dpy = XOpenDisplay(0);
+ if (!dpy)
+ {
+ if (getenv("DISPLAY"))
+ Sys_Error("VID: Could not open display [%s]\n",
+ getenv("DISPLAY"));
+ else
+ Sys_Error("VID: Could not open local display\n");
+ }
+
+// catch signals so i can turn on auto-repeat
+
+ {
+ struct sigaction sa;
+ sigaction(SIGINT, 0, &sa);
+ sa.sa_handler = TragicDeath;
+ sigaction(SIGINT, &sa, 0);
+ sigaction(SIGTERM, &sa, 0);
+ }
+
+ return true;
+}
+
+/*
+** SWimp_InitGraphics
+**
+** This initializes the software refresh's implementation specific
+** graphics subsystem. In the case of Windows it creates DIB or
+** DDRAW surfaces.
+**
+** The necessary width and height parameters are grabbed from
+** vid.width and vid.height.
+*/
+static qboolean SWimp_InitGraphics( qboolean fullscreen )
+{
+ int pnum, i;
+ XVisualInfo template;
+ int num_visuals;
+ int template_mask;
+ Window root;
+
+ srandom(getpid());
+
+ // free resources in use
+ SWimp_Shutdown ();
+
+ // let the sound and input subsystems know about the new window
+ ri.Vid_NewWindow (vid.width, vid.height);
+
+// XAutoRepeatOff(dpy);
+
+// for debugging only
+ XSynchronize(dpy, True);
+
+// check for command-line window size
+ template_mask = 0;
+
+#if 0
+// specify a visual id
+ if ((pnum=COM_CheckParm("-visualid")))
+ {
+ if (pnum >= com_argc-1)
+ Sys_Error("VID: -visualid <id#>\n");
+ template.visualid = Q_atoi(com_argv[pnum+1]);
+ template_mask = VisualIDMask;
+ }
+
+// If not specified, use default visual
+ else
+#endif
+ {
+ int screen;
+ screen = XDefaultScreen(dpy);
+ template.visualid =
+ XVisualIDFromVisual(XDefaultVisual(dpy, screen));
+ template_mask = VisualIDMask;
+ }
+
+// pick a visual- warn if more than one was available
+ x_visinfo = XGetVisualInfo(dpy, template_mask, &template, &num_visuals);
+ if (num_visuals > 1)
+ {
+ printf("Found more than one visual id at depth %d:\n", template.depth);
+ for (i=0 ; i<num_visuals ; i++)
+ printf(" -visualid %d\n", (int)(x_visinfo[i].visualid));
+ }
+ else if (num_visuals == 0)
+ {
+ if (template_mask == VisualIDMask)
+ Sys_Error("VID: Bad visual id %d\n", template.visualid);
+ else
+ Sys_Error("VID: No visuals at depth %d\n", template.depth);
+ }
+
+#if 0
+ printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
+ printf(" screen %d\n", x_visinfo->screen);
+ printf(" red_mask 0x%x\n", (int)(x_visinfo->red_mask));
+ printf(" green_mask 0x%x\n", (int)(x_visinfo->green_mask));
+ printf(" blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
+ printf(" colormap_size %d\n", x_visinfo->colormap_size);
+ printf(" bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
+#endif
+
+ x_vis = x_visinfo->visual;
+ root = XRootWindow(dpy, x_visinfo->screen);
+
+// setup attributes for main window
+ {
+ int attribmask = CWEventMask | CWColormap | CWBorderPixel;
+ XSetWindowAttributes attribs;
+ Colormap tmpcmap;
+
+ tmpcmap = XCreateColormap(dpy, root, x_vis, AllocNone);
+
+ attribs.event_mask = X_MASK;
+ attribs.border_pixel = 0;
+ attribs.colormap = tmpcmap;
+
+// create the main window
+ win = XCreateWindow(dpy, root, (int)vid_xpos->value, (int)vid_ypos->value,
+ vid.width, vid.height, 0, x_visinfo->depth, InputOutput, x_vis,
+ attribmask, &attribs );
+ XStoreName(dpy, win, "Quake II");
+
+ if (x_visinfo->class != TrueColor)
+ XFreeColormap(dpy, tmpcmap);
+ }
+
+ if (x_visinfo->depth == 8)
+ {
+ // create and upload the palette
+ if (x_visinfo->class == PseudoColor)
+ {
+ x_cmap = XCreateColormap(dpy, win, x_vis, AllocAll);
+ XSetWindowColormap(dpy, win, x_cmap);
+ }
+
+ }
+
+// create the GC
+ {
+ XGCValues xgcvalues;
+ int valuemask = GCGraphicsExposures;
+ xgcvalues.graphics_exposures = False;
+ x_gc = XCreateGC(dpy, win, valuemask, &xgcvalues );
+ }
+
+ XMapWindow(dpy, win);
+ XMoveWindow(dpy, win, (int)vid_xpos->value, (int)vid_ypos->value);
+
+// wait for first exposure event
+ {
+ XEvent event;
+ exposureflag = false;
+ do
+ {
+ HandleEvents();
+ } while (!exposureflag);
+ }
+// now safe to draw
+
+// even if MITSHM is available, make sure it's a local connection
+ doShm = false;
+/*
+ if (XShmQueryExtension(dpy))
+ {
+ char *displayname;
+ doShm = true;
+ displayname = (char *) getenv("DISPLAY");
+ if (displayname)
+ {
+ char *d = displayname;
+ while (*d && (*d != ':')) d++;
+ if (*d) *d = 0;
+ if (!(!strcasecmp(displayname, "unix") || !*displayname))
+ doShm = false;
+ }
+ }
+*/
+
+ if (doShm)
+ {
+ x_shmeventtype = XShmGetEventBase(dpy) + ShmCompletion;
+ ResetSharedFrameBuffers();
+ }
+ else
+ ResetFrameBuffer();
+
+ current_framebuffer = 0;
+ vid.rowbytes = x_framebuffer[0]->bytes_per_line;
+ vid.buffer = x_framebuffer[0]->data;
+
+// XSynchronize(dpy, False);
+
+ X11_active = true;
+
+ return true;
+}
+
+/*
+** SWimp_EndFrame
+**
+** This does an implementation specific copy from the backbuffer to the
+** front buffer. In the Win32 case it uses BitBlt or BltFast depending
+** on whether we're using DIB sections/GDI or DDRAW.
+*/
+void SWimp_EndFrame (void)
+{
+// if the window changes dimension, skip this frame
+#if 0
+ if (config_notify)
+ {
+ fprintf(stderr, "config notify\n");
+ config_notify = 0;
+ vid.width = config_notify_width & ~7;
+ vid.height = config_notify_height;
+ if (doShm)
+ ResetSharedFrameBuffers();
+ else
+ ResetFrameBuffer();
+ vid.rowbytes = x_framebuffer[0]->bytes_per_line;
+ vid.buffer = x_framebuffer[current_framebuffer]->data;
+ vid.recalc_refdef = 1; // force a surface cache flush
+ Con_CheckResize();
+ Con_Clear_f();
+ return;
+ }
+#endif
+
+ if (doShm)
+ {
+ if (x_visinfo->depth == 16)
+ st2_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
+ else if (x_visinfo->depth == 24)
+ st3_fixup( x_framebuffer[current_framebuffer], 0, 0, vid.width, vid.height);
+ if (!XShmPutImage(dpy, win, x_gc,
+ x_framebuffer[current_framebuffer], 0, 0, 0, 0, vid.width, vid.height, True))
+ Sys_Error("VID_Update: XShmPutImage failed\n");
+ oktodraw = false;
+ while (!oktodraw)
+ HandleEvents();
+ current_framebuffer = !current_framebuffer;
+ vid.buffer = x_framebuffer[current_framebuffer]->data;
+ XSync(dpy, False);
+ }
+ else
+ {
+ if (x_visinfo->depth == 16)
+ st2_fixup_stereo( x_framebuffer[0], x_framebuffer[1], 0, 0, vid.width, vid.height);
+ else if (x_visinfo->depth == 24)
+ st3_fixup_stereo( x_framebuffer[0], x_framebuffer[1], 0, 0, vid.width, vid.height);
+ XPutImage(dpy, win, x_gc, x_framebuffer[0], 0, 0, 0, 0, vid.width, vid.height);
+ XSync(dpy, False);
+ }
+}
+
+/*
+** SWimp_SetMode
+*/
+rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
+{
+ rserr_t retval = rserr_ok;
+
+ ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
+
+ if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
+ {
+ ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
+ return rserr_invalid_mode;
+ }
+
+ ri.Con_Printf( PRINT_ALL, " %d %d\n", *pwidth, *pheight);
+
+ if ( !SWimp_InitGraphics( false ) ) {
+ // failed to set a valid mode in windowed mode
+ return rserr_invalid_mode;
+ }
+
+ R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+
+ return retval;
+}
+
+/*
+** SWimp_SetPalette
+**
+** System specific palette setting routine. A NULL palette means
+** to use the existing palette. The palette is expected to be in
+** a padded 4-byte xRGB format.
+*/
+void SWimp_SetPalette( const unsigned char *palette )
+{
+ int i;
+ XColor colors[256];
+ int tmp;
+
+ if (!X11_active)
+ return;
+
+ if ( !palette )
+ palette = ( const unsigned char * ) sw_state.currentpalette;
+
+ for(i=0;i<256;i++) {
+ st2d_8to16table[i]= xlib_rgb16(palette[i*4], palette[i*4+1],palette[i*4+2]);
+ st2d_8to24table[i]= xlib_rgb24(palette[i*4], palette[i*4+1],palette[i*4+2]);
+
+ tmp = (30*palette[i*4] + 59*palette[i*4+1] + 11*palette[i*4+2]) / 100;
+ st2d_8to16table_s[0][i] = xlib_rgb16(tmp, 0, 0);
+ st2d_8to16table_s[1][i] = xlib_rgb16(0, 0, tmp);
+ st2d_8to24table_s[0][i] = xlib_rgb24(tmp, 0, 0);
+ st2d_8to24table_s[1][i] = xlib_rgb24(0, 0, tmp);
+ }
+
+ if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
+ {
+ for (i=0 ; i<256 ; i++)
+ {
+ colors[i].pixel = i;
+ colors[i].flags = DoRed|DoGreen|DoBlue;
+ colors[i].red = palette[i*4] * 257;
+ colors[i].green = palette[i*4+1] * 257;
+ colors[i].blue = palette[i*4+2] * 257;
+ }
+ XStoreColors(dpy, x_cmap, colors, 256);
+ }
+}
+
+/*
+** SWimp_Shutdown
+**
+** System specific graphics subsystem shutdown routine. Destroys
+** DIBs or DDRAW surfaces as appropriate.
+*/
+void SWimp_Shutdown( void )
+{
+ int i;
+
+ if (!X11_active)
+ return;
+
+ if (doShm) {
+ for (i = 0; i < 2; i++)
+ if (x_framebuffer[i]) {
+ XShmDetach(dpy, &x_shminfo[i]);
+ free(x_framebuffer[i]);
+ shmdt(x_shminfo[i].shmaddr);
+ x_framebuffer[i] = NULL;
+ }
+ } else {
+ if (x_framebuffer[0]) {
+ free(x_framebuffer[0]->data);
+ free(x_framebuffer[0]);
+ x_framebuffer[0] = NULL;
+ }
+ if (x_framebuffer[1]) {
+ free(x_framebuffer[1]->data);
+ free(x_framebuffer[1]);
+ x_framebuffer[1] = NULL;
+ }
+ }
+
+ XDestroyWindow( dpy, win );
+
+// XAutoRepeatOn(dpy);
+// XCloseDisplay(dpy);
+
+ X11_active = false;
+}
+
+/*
+** SWimp_AppActivate
+*/
+void SWimp_AppActivate( qboolean active )
+{
+}
+
+void SetStereoBuffer(int buf)
+{
+ if (x_framebuffer[buf])
+ vid.buffer = (byte*) (x_framebuffer[buf]->data);
+ else
+ printf("SetStereoBuffer: x_framebuffer[%d] is NULL\n", buf);
+}
+
+//===============================================================================
+
+/*
+================
+Sys_MakeCodeWriteable
+================
+*/
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
+{
+
+ int r;
+ unsigned long addr;
+ int psize = getpagesize();
+
+ addr = (startaddr & ~(psize-1)) - psize;
+
+// fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
+// addr, startaddr+length, length);
+
+ r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
+
+ if (r < 0)
+ Sys_Error("Protection change failed\n");
+
+}
+
+/*****************************************************************************/
+/* KEYBOARD */
+/*****************************************************************************/
+
+Key_Event_fp_t Key_Event_fp;
+
+void KBD_Init(Key_Event_fp_t fp)
+{
+ Key_Event_fp = fp;
+}
+
+void KBD_Update(void)
+{
+// get events from x server
+ HandleEvents();
+}
+
+void KBD_Close(void)
+{
+}
+
+
diff -ur quake2-r0.0.8/src/ref_soft/r_main.c quake2-devel-r0.0.8/src/ref_soft/r_main.c
--- quake2-r0.0.8/src/ref_soft/r_main.c Thu Jan 3 07:10:14 2002
+++ quake2-devel-r0.0.8/src/ref_soft/r_main.c Wed Jan 30 15:03:01 2002
@@ -1,1423 +1,1426 @@
-/*
-Copyright (C) 1997-2001 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-// r_main.c
-
-#include "r_local.h"
-
-viddef_t vid;
-refimport_t ri;
-
-unsigned d_8to24table[256];
-
-entity_t r_worldentity;
-
-char skyname[MAX_QPATH];
-float skyrotate;
-vec3_t skyaxis;
-image_t *sky_images[6];
-
-refdef_t r_newrefdef;
-model_t *currentmodel;
-
-model_t *r_worldmodel;
-
-byte r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
-
-swstate_t sw_state;
-
-void *colormap;
-vec3_t viewlightvec;
-alight_t r_viewlighting = {128, 192, viewlightvec};
-float r_time1;
-int r_numallocatededges;
-float r_aliasuvscale = 1.0;
-int r_outofsurfaces;
-int r_outofedges;
-
-qboolean r_dowarp;
-
-mvertex_t *r_pcurrentvertbase;
-
-int c_surf;
-int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
-qboolean r_surfsonstack;
-int r_clipflags;
-
-//
-// view origin
-//
-vec3_t vup, base_vup;
-vec3_t vpn, base_vpn;
-vec3_t vright, base_vright;
-vec3_t r_origin;
-
-//
-// screen size info
-//
-oldrefdef_t r_refdef;
-float xcenter, ycenter;
-float xscale, yscale;
-float xscaleinv, yscaleinv;
-float xscaleshrink, yscaleshrink;
-float aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
-
-int r_screenwidth;
-
-float verticalFieldOfView;
-float xOrigin, yOrigin;
-
-mplane_t screenedge[4];
-
-//
-// refresh flags
-//
-int r_framecount = 1; // so frame counts initialized to 0 don't match
-int r_visframecount;
-int d_spanpixcount;
-int r_polycount;
-int r_drawnpolycount;
-int r_wholepolycount;
-
-int *pfrustum_indexes[4];
-int r_frustum_indexes[4*6];
-
-mleaf_t *r_viewleaf;
-int r_viewcluster, r_oldviewcluster;
-
-image_t *r_notexture_mip;
-
-float da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
-float se_time1, se_time2, de_time1, de_time2;
-
-void R_MarkLeaves (void);
-
-cvar_t *r_lefthand;
-cvar_t *sw_aliasstats;
-cvar_t *sw_allow_modex;
-cvar_t *sw_clearcolor;
-cvar_t *sw_drawflat;
-cvar_t *sw_draworder;
-cvar_t *sw_maxedges;
-cvar_t *sw_maxsurfs;
-cvar_t *sw_mode;
-cvar_t *sw_reportedgeout;
-cvar_t *sw_reportsurfout;
-cvar_t *sw_stipplealpha;
-cvar_t *sw_surfcacheoverride;
-cvar_t *sw_waterwarp;
-
-cvar_t *r_drawworld;
-cvar_t *r_drawentities;
-cvar_t *r_dspeeds;
-cvar_t *r_fullbright;
-cvar_t *r_lerpmodels;
-cvar_t *r_novis;
-
-cvar_t *r_speeds;
-cvar_t *r_lightlevel; //FIXME HACK
-
-cvar_t *vid_fullscreen;
-cvar_t *vid_gamma;
-
-//PGM
-cvar_t *sw_lockpvs;
-//PGM
-
-#define STRINGER(x) "x"
-
-
-#if !id386
-
-// r_vars.c
-
-// all global and static refresh variables are collected in a contiguous block
-// to avoid cache conflicts.
-
-//-------------------------------------------------------
-// global refresh variables
-//-------------------------------------------------------
-
-// FIXME: make into one big structure, like cl or sv
-// FIXME: do separately for refresh engine and driver
-
-
-// d_vars.c
-
-// all global and static refresh variables are collected in a contiguous block
-// to avoid cache conflicts.
-
-//-------------------------------------------------------
-// global refresh variables
-//-------------------------------------------------------
-
-// FIXME: make into one big structure, like cl or sv
-// FIXME: do separately for refresh engine and driver
-
-float d_sdivzstepu, d_tdivzstepu, d_zistepu;
-float d_sdivzstepv, d_tdivzstepv, d_zistepv;
-float d_sdivzorigin, d_tdivzorigin, d_ziorigin;
-
-fixed16_t sadjust, tadjust, bbextents, bbextentt;
-
-pixel_t *cacheblock;
-int cachewidth;
-pixel_t *d_viewbuffer;
-short *d_pzbuffer;
-unsigned int d_zrowbytes;
-unsigned int d_zwidth;
-
-
-#endif // !id386
-
-byte r_notexture_buffer[1024];
-
-/*
-==================
-R_InitTextures
-==================
-*/
-void R_InitTextures (void)
-{
- int x,y, m;
- byte *dest;
-
-// create a simple checkerboard texture for the default
- r_notexture_mip = (image_t *)&r_notexture_buffer;
-
- r_notexture_mip->width = r_notexture_mip->height = 16;
- r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)];
- r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16;
- r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8;
- r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4;
-
- for (m=0 ; m<4 ; m++)
- {
- dest = r_notexture_mip->pixels[m];
- for (y=0 ; y< (16>>m) ; y++)
- for (x=0 ; x< (16>>m) ; x++)
- {
- if ( (y< (8>>m) ) ^ (x< (8>>m) ) )
-
- *dest++ = 0;
- else
- *dest++ = 0xff;
- }
- }
-}
-
-
-/*
-================
-R_InitTurb
-================
-*/
-void R_InitTurb (void)
-{
- int i;
-
- for (i=0 ; i<1280 ; i++)
- {
- sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
- intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2; // AMP2, not 20
- blanktable[i] = 0; //PGM
- }
-}
-
-void R_ImageList_f( void );
-
-void R_Register (void)
-{
- sw_aliasstats = ri.Cvar_Get ("sw_polymodelstats", "0", 0);
- sw_allow_modex = ri.Cvar_Get( "sw_allow_modex", "1", CVAR_ARCHIVE );
- sw_clearcolor = ri.Cvar_Get ("sw_clearcolor", "2", 0);
- sw_drawflat = ri.Cvar_Get ("sw_drawflat", "0", 0);
- sw_draworder = ri.Cvar_Get ("sw_draworder", "0", 0);
- sw_maxedges = ri.Cvar_Get ("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0);
- sw_maxsurfs = ri.Cvar_Get ("sw_maxsurfs", "0", 0);
- sw_mipcap = ri.Cvar_Get ("sw_mipcap", "0", 0);
- sw_mipscale = ri.Cvar_Get ("sw_mipscale", "1", 0);
- sw_reportedgeout = ri.Cvar_Get ("sw_reportedgeout", "0", 0);
- sw_reportsurfout = ri.Cvar_Get ("sw_reportsurfout", "0", 0);
- sw_stipplealpha = ri.Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
- sw_surfcacheoverride = ri.Cvar_Get ("sw_surfcacheoverride", "0", 0);
- sw_waterwarp = ri.Cvar_Get ("sw_waterwarp", "1", 0);
- sw_mode = ri.Cvar_Get( "sw_mode", "0", CVAR_ARCHIVE );
-
- r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
- r_speeds = ri.Cvar_Get ("r_speeds", "0", 0);
- r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0);
- r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0);
- r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0);
- r_dspeeds = ri.Cvar_Get ("r_dspeeds", "0", 0);
- r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0);
- r_lerpmodels = ri.Cvar_Get( "r_lerpmodels", "1", 0 );
- r_novis = ri.Cvar_Get( "r_novis", "0", 0 );
-
- vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE );
- vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE );
-
- ri.Cmd_AddCommand ("modellist", Mod_Modellist_f);
- ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
- ri.Cmd_AddCommand( "imagelist", R_ImageList_f );
-
- sw_mode->modified = true; // force us to do mode specific stuff later
- vid_gamma->modified = true; // force us to rebuild the gamma table later
-
-//PGM
- sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0);
-//PGM
-}
-
-void R_UnRegister (void)
-{
- ri.Cmd_RemoveCommand( "screenshot" );
- ri.Cmd_RemoveCommand ("modellist");
- ri.Cmd_RemoveCommand( "imagelist" );
-}
-
-/*
-===============
-R_Init
-===============
-*/
-int R_Init( void *hInstance, void *wndProc )
-{
- R_InitImages ();
- Mod_Init ();
- Draw_InitLocal ();
- R_InitTextures ();
-
- R_InitTurb ();
-
- view_clipplanes[0].leftedge = true;
- view_clipplanes[1].rightedge = true;
- view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
- view_clipplanes[3].leftedge = false;
- view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
- view_clipplanes[3].rightedge = false;
-
- r_refdef.xOrigin = XCENTERING;
- r_refdef.yOrigin = YCENTERING;
-
-// TODO: collect 386-specific code in one place
-#if id386
- Sys_MakeCodeWriteable ((long)R_EdgeCodeStart,
- (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart);
- Sys_SetFPCW (); // get bit masks for FPCW (FIXME: is this id386?)
-#endif // id386
-
- r_aliasuvscale = 1.0;
-
- R_Register ();
- Draw_GetPalette ();
- if (SWimp_Init( hInstance, wndProc ) == false)
- return -1;
-
- // create the window
- R_BeginFrame( 0 );
-
- ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");
-
- return true;
-}
-
-/*
-===============
-R_Shutdown
-===============
-*/
-void R_Shutdown (void)
-{
- // free z buffer
- if (d_pzbuffer)
- {
- free (d_pzbuffer);
- d_pzbuffer = NULL;
- }
- // free surface cache
- if (sc_base)
- {
- D_FlushCaches ();
- free (sc_base);
- sc_base = NULL;
- }
-
- // free colormap
- if (vid.colormap)
- {
- free (vid.colormap);
- vid.colormap = NULL;
- }
- R_UnRegister ();
- Mod_FreeAll ();
- R_ShutdownImages ();
-
- SWimp_Shutdown();
-}
-
-/*
-===============
-R_NewMap
-===============
-*/
-void R_NewMap (void)
-{
- r_viewcluster = -1;
-
- r_cnumsurfs = sw_maxsurfs->value;
-
- if (r_cnumsurfs <= MINSURFACES)
- r_cnumsurfs = MINSURFACES;
-
- if (r_cnumsurfs > NUMSTACKSURFACES)
- {
- surfaces = malloc (r_cnumsurfs * sizeof(surf_t));
- surface_p = surfaces;
- surf_max = &surfaces[r_cnumsurfs];
- r_surfsonstack = false;
- // surface 0 doesn't really exist; it's just a dummy because index 0
- // is used to indicate no edge attached to surface
- surfaces--;
- R_SurfacePatch ();
- }
- else
- {
- r_surfsonstack = true;
- }
-
- r_maxedgesseen = 0;
- r_maxsurfsseen = 0;
-
- r_numallocatededges = sw_maxedges->value;
-
- if (r_numallocatededges < MINEDGES)
- r_numallocatededges = MINEDGES;
-
- if (r_numallocatededges <= NUMSTACKEDGES)
- {
- auxedges = NULL;
- }
- else
- {
- auxedges = malloc (r_numallocatededges * sizeof(edge_t));
- }
-}
-
-
-/*
-===============
-R_MarkLeaves
-
-Mark the leaves and nodes that are in the PVS for the current
-cluster
-===============
-*/
-void R_MarkLeaves (void)
-{
- byte *vis;
- mnode_t *node;
- int i;
- mleaf_t *leaf;
- int cluster;
-
- if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
- return;
-
- // development aid to let you run around and see exactly where
- // the pvs ends
- if (sw_lockpvs->value)
- return;
-
- r_visframecount++;
- r_oldviewcluster = r_viewcluster;
-
- if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
- {
- // mark everything
- for (i=0 ; i<r_worldmodel->numleafs ; i++)
- r_worldmodel->leafs[i].visframe = r_visframecount;
- for (i=0 ; i<r_worldmodel->numnodes ; i++)
- r_worldmodel->nodes[i].visframe = r_visframecount;
- return;
- }
-
- vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
-
- for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
- {
- cluster = leaf->cluster;
- if (cluster == -1)
- continue;
- if (vis[cluster>>3] & (1<<(cluster&7)))
- {
- node = (mnode_t *)leaf;
- do
- {
- if (node->visframe == r_visframecount)
- break;
- node->visframe = r_visframecount;
- node = node->parent;
- } while (node);
- }
- }
-
-#if 0
- for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
- {
- if (vis[i>>3] & (1<<(i&7)))
- {
- node = (mnode_t *)&r_worldmodel->leafs[i]; // FIXME: cluster
- do
- {
- if (node->visframe == r_visframecount)
- break;
- node->visframe = r_visframecount;
- node = node->parent;
- } while (node);
- }
- }
-#endif
-}
-
-/*
-** R_DrawNullModel
-**
-** IMPLEMENT THIS!
-*/
-void R_DrawNullModel( void )
-{
-}
-
-/*
-=============
-R_DrawEntitiesOnList
-=============
-*/
-void R_DrawEntitiesOnList (void)
-{
- int i;
- qboolean translucent_entities = false;
-
- if (!r_drawentities->value)
- return;
-
- // all bmodels have already been drawn by the edge list
- for (i=0 ; i<r_newrefdef.num_entities ; i++)
- {
- currententity = &r_newrefdef.entities[i];
-
- if ( currententity->flags & RF_TRANSLUCENT )
- {
- translucent_entities = true;
- continue;
- }
-
- if ( currententity->flags & RF_BEAM )
- {
- modelorg[0] = -r_origin[0];
- modelorg[1] = -r_origin[1];
- modelorg[2] = -r_origin[2];
- VectorCopy( vec3_origin, r_entorigin );
- R_DrawBeam( currententity );
- }
- else
- {
- currentmodel = currententity->model;
- if (!currentmodel)
- {
- R_DrawNullModel();
- continue;
- }
- VectorCopy (currententity->origin, r_entorigin);
- VectorSubtract (r_origin, r_entorigin, modelorg);
-
- switch (currentmodel->type)
- {
- case mod_sprite:
- R_DrawSprite ();
- break;
-
- case mod_alias:
- R_AliasDrawModel ();
- break;
-
- default:
- break;
- }
- }
- }
-
- if ( !translucent_entities )
- return;
-
- for (i=0 ; i<r_newrefdef.num_entities ; i++)
- {
- currententity = &r_newrefdef.entities[i];
-
- if ( !( currententity->flags & RF_TRANSLUCENT ) )
- continue;
-
- if ( currententity->flags & RF_BEAM )
- {
- modelorg[0] = -r_origin[0];
- modelorg[1] = -r_origin[1];
- modelorg[2] = -r_origin[2];
- VectorCopy( vec3_origin, r_entorigin );
- R_DrawBeam( currententity );
- }
- else
- {
- currentmodel = currententity->model;
- if (!currentmodel)
- {
- R_DrawNullModel();
- continue;
- }
- VectorCopy (currententity->origin, r_entorigin);
- VectorSubtract (r_origin, r_entorigin, modelorg);
-
- switch (currentmodel->type)
- {
- case mod_sprite:
- R_DrawSprite ();
- break;
-
- case mod_alias:
- R_AliasDrawModel ();
- break;
-
- default:
- break;
- }
- }
- }
-}
-
-
-/*
-=============
-R_BmodelCheckBBox
-=============
-*/
-int R_BmodelCheckBBox (float *minmaxs)
-{
- int i, *pindex, clipflags;
- vec3_t acceptpt, rejectpt;
- float d;
-
- clipflags = 0;
-
- for (i=0 ; i<4 ; i++)
- {
- // generate accept and reject points
- // FIXME: do with fast look-ups or integer tests based on the sign bit
- // of the floating point values
-
- pindex = pfrustum_indexes[i];
-
- rejectpt[0] = minmaxs[pindex[0]];
- rejectpt[1] = minmaxs[pindex[1]];
- rejectpt[2] = minmaxs[pindex[2]];
-
- d = DotProduct (rejectpt, view_clipplanes[i].normal);
- d -= view_clipplanes[i].dist;
-
- if (d <= 0)
- return BMODEL_FULLY_CLIPPED;
-
- acceptpt[0] = minmaxs[pindex[3+0]];
- acceptpt[1] = minmaxs[pindex[3+1]];
- acceptpt[2] = minmaxs[pindex[3+2]];
-
- d = DotProduct (acceptpt, view_clipplanes[i].normal);
- d -= view_clipplanes[i].dist;
-
- if (d <= 0)
- clipflags |= (1<<i);
- }
-
- return clipflags;
-}
-
-
-/*
-===================
-R_FindTopnode
-
-Find the first node that splits the given box
-===================
-*/
-mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
-{
- mplane_t *splitplane;
- int sides;
- mnode_t *node;
-
- node = r_worldmodel->nodes;
-
- while (1)
- {
- if (node->visframe != r_visframecount)
- return NULL; // not visible at all
-
- if (node->contents != CONTENTS_NODE)
- {
- if (node->contents != CONTENTS_SOLID)
- return node; // we've reached a non-solid leaf, so it's
- // visible and not BSP clipped
- return NULL; // in solid, so not visible
- }
-
- splitplane = node->plane;
- sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);
-
- if (sides == 3)
- return node; // this is the splitter
-
- // not split yet; recurse down the contacted side
- if (sides & 1)
- node = node->children[0];
- else
- node = node->children[1];
- }
-}
-
-
-/*
-=============
-RotatedBBox
-
-Returns an axially aligned box that contains the input box at the given rotation
-=============
-*/
-void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)
-{
- vec3_t tmp, v;
- int i, j;
- vec3_t forward, right, up;
-
- if (!angles[0] && !angles[1] && !angles[2])
- {
- VectorCopy (mins, tmins);
- VectorCopy (maxs, tmaxs);
- return;
- }
-
- for (i=0 ; i<3 ; i++)
- {
- tmins[i] = 99999;
- tmaxs[i] = -99999;
- }
-
- AngleVectors (angles, forward, right, up);
-
- for ( i = 0; i < 8; i++ )
- {
- if ( i & 1 )
- tmp[0] = mins[0];
- else
- tmp[0] = maxs[0];
-
- if ( i & 2 )
- tmp[1] = mins[1];
- else
- tmp[1] = maxs[1];
-
- if ( i & 4 )
- tmp[2] = mins[2];
- else
- tmp[2] = maxs[2];
-
-
- VectorScale (forward, tmp[0], v);
- VectorMA (v, -tmp[1], right, v);
- VectorMA (v, tmp[2], up, v);
-
- for (j=0 ; j<3 ; j++)
- {
- if (v[j] < tmins[j])
- tmins[j] = v[j];
- if (v[j] > tmaxs[j])
- tmaxs[j] = v[j];
- }
- }
-}
-
-/*
-=============
-R_DrawBEntitiesOnList
-=============
-*/
-void R_DrawBEntitiesOnList (void)
-{
- int i, clipflags;
- vec3_t oldorigin;
- vec3_t mins, maxs;
- float minmaxs[6];
- mnode_t *topnode;
-
- if (!r_drawentities->value)
- return;
-
- VectorCopy (modelorg, oldorigin);
- insubmodel = true;
- r_dlightframecount = r_framecount;
-
- for (i=0 ; i<r_newrefdef.num_entities ; i++)
- {
- currententity = &r_newrefdef.entities[i];
- currentmodel = currententity->model;
- if (!currentmodel)
- continue;
- if (currentmodel->nummodelsurfaces == 0)
- continue; // clip brush only
- if ( currententity->flags & RF_BEAM )
- continue;
- if (currentmodel->type != mod_brush)
- continue;
- // see if the bounding box lets us trivially reject, also sets
- // trivial accept status
- RotatedBBox (currentmodel->mins, currentmodel->maxs,
- currententity->angles, mins, maxs);
- VectorAdd (mins, currententity->origin, minmaxs);
- VectorAdd (maxs, currententity->origin, (minmaxs+3));
-
- clipflags = R_BmodelCheckBBox (minmaxs);
- if (clipflags == BMODEL_FULLY_CLIPPED)
- continue; // off the edge of the screen
-
- topnode = R_FindTopnode (minmaxs, minmaxs+3);
- if (!topnode)
- continue; // no part in a visible leaf
-
- VectorCopy (currententity->origin, r_entorigin);
- VectorSubtract (r_origin, r_entorigin, modelorg);
-
- r_pcurrentvertbase = currentmodel->vertexes;
-
- // FIXME: stop transforming twice
- R_RotateBmodel ();
-
- // calculate dynamic lighting for bmodel
- R_PushDlights (currentmodel);
-
- if (topnode->contents == CONTENTS_NODE)
- {
- // not a leaf; has to be clipped to the world BSP
- r_clipflags = clipflags;
- R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);
- }
- else
- {
- // falls entirely in one leaf, so we just put all the
- // edges in the edge list and let 1/z sorting handle
- // drawing order
- R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);
- }
-
- // put back world rotation and frustum clipping
- // FIXME: R_RotateBmodel should just work off base_vxx
- VectorCopy (base_vpn, vpn);
- VectorCopy (base_vup, vup);
- VectorCopy (base_vright, vright);
- VectorCopy (oldorigin, modelorg);
- R_TransformFrustum ();
- }
-
- insubmodel = false;
-}
-
-
-/*
-================
-R_EdgeDrawing
-================
-*/
-void R_EdgeDrawing (void)
-{
- edge_t ledges[NUMSTACKEDGES +
- ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
- surf_t lsurfs[NUMSTACKSURFACES +
- ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
-
- if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
- return;
-
- if (auxedges)
- {
- r_edges = auxedges;
- }
- else
- {
- r_edges = (edge_t *)
- (((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
- }
-
- if (r_surfsonstack)
- {
- surfaces = (surf_t *)
- (((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
- surf_max = &surfaces[r_cnumsurfs];
- // surface 0 doesn't really exist; it's just a dummy because index 0
- // is used to indicate no edge attached to surface
- surfaces--;
- R_SurfacePatch ();
- }
-
- R_BeginEdgeFrame ();
-
- if (r_dspeeds->value)
- {
- rw_time1 = Sys_Milliseconds ();
- }
-
- R_RenderWorld ();
-
- if (r_dspeeds->value)
- {
- rw_time2 = Sys_Milliseconds ();
- db_time1 = rw_time2;
- }
-
- R_DrawBEntitiesOnList ();
-
- if (r_dspeeds->value)
- {
- db_time2 = Sys_Milliseconds ();
- se_time1 = db_time2;
- }
-
- R_ScanEdges ();
-}
-
-//=======================================================================
-
-
-/*
-=============
-R_CalcPalette
-
-=============
-*/
-void R_CalcPalette (void)
-{
- static qboolean modified;
- byte palette[256][4], *in, *out;
- int i, j;
- float alpha, one_minus_alpha;
- vec3_t premult;
- int v;
-
- alpha = r_newrefdef.blend[3];
- if (alpha <= 0)
- {
- if (modified)
- { // set back to default
- modified = false;
- R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
- return;
- }
- return;
- }
-
- modified = true;
- if (alpha > 1)
- alpha = 1;
-
- premult[0] = r_newrefdef.blend[0]*alpha*255;
- premult[1] = r_newrefdef.blend[1]*alpha*255;
- premult[2] = r_newrefdef.blend[2]*alpha*255;
-
- one_minus_alpha = (1.0 - alpha);
-
- in = (byte *)d_8to24table;
- out = palette[0];
- for (i=0 ; i<256 ; i++, in+=4, out+=4)
- {
- for (j=0 ; j<3 ; j++)
- {
- v = premult[j] + one_minus_alpha * in[j];
- if (v > 255)
- v = 255;
- out[j] = v;
- }
- out[3] = 255;
- }
-
- R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] );
-// SWimp_SetPalette( palette[0] );
-}
-
-//=======================================================================
-
-void R_SetLightLevel (void)
-{
- vec3_t light;
-
- if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))
- {
- r_lightlevel->value = 150.0;
- return;
- }
-
- // save off light value for server to look at (BIG HACK!)
- R_LightPoint (r_newrefdef.vieworg, light);
- r_lightlevel->value = 150.0 * light[0];
-}
-
-
-/*
-@@@@@@@@@@@@@@@@
-R_RenderFrame
-
-@@@@@@@@@@@@@@@@
-*/
-void R_RenderFrame (refdef_t *fd)
-{
- r_newrefdef = *fd;
-
- if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
- ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");
-
- VectorCopy (fd->vieworg, r_refdef.vieworg);
- VectorCopy (fd->viewangles, r_refdef.viewangles);
-
- if (r_speeds->value || r_dspeeds->value)
- r_time1 = Sys_Milliseconds ();
-
- R_SetupFrame ();
-
- R_MarkLeaves (); // done here so we know if we're in water
-
- R_PushDlights (r_worldmodel);
-
- R_EdgeDrawing ();
-
- if (r_dspeeds->value)
- {
- se_time2 = Sys_Milliseconds ();
- de_time1 = se_time2;
- }
-
- R_DrawEntitiesOnList ();
-
- if (r_dspeeds->value)
- {
- de_time2 = Sys_Milliseconds ();
- dp_time1 = Sys_Milliseconds ();
- }
-
- R_DrawParticles ();
-
- if (r_dspeeds->value)
- dp_time2 = Sys_Milliseconds ();
-
- R_DrawAlphaSurfaces();
-
- R_SetLightLevel ();
-
- if (r_dowarp)
- D_WarpScreen ();
-
- if (r_dspeeds->value)
- da_time1 = Sys_Milliseconds ();
-
- if (r_dspeeds->value)
- da_time2 = Sys_Milliseconds ();
-
- R_CalcPalette ();
-
- if (sw_aliasstats->value)
- R_PrintAliasStats ();
-
- if (r_speeds->value)
- R_PrintTimes ();
-
- if (r_dspeeds->value)
- R_PrintDSpeeds ();
-
- if (sw_reportsurfout->value && r_outofsurfaces)
- ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);
-
- if (sw_reportedgeout->value && r_outofedges)
- ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);
-}
-
-/*
-** R_InitGraphics
-*/
-void R_InitGraphics( int width, int height )
-{
- vid.width = width;
- vid.height = height;
-
- // free z buffer
- if ( d_pzbuffer )
- {
- free( d_pzbuffer );
- d_pzbuffer = NULL;
- }
-
- // free surface cache
- if ( sc_base )
- {
- D_FlushCaches ();
- free( sc_base );
- sc_base = NULL;
- }
-
- d_pzbuffer = malloc(vid.width*vid.height*2);
-
- R_InitCaches ();
-
- R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table );
-}
-
-/*
-** R_BeginFrame
-*/
-void R_BeginFrame( float camera_separation )
-{
- extern void Draw_BuildGammaTable( void );
-
- /*
- ** rebuild the gamma correction palette if necessary
- */
- if ( vid_gamma->modified )
- {
- Draw_BuildGammaTable();
- R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
-
- vid_gamma->modified = false;
- }
-
- while ( sw_mode->modified || vid_fullscreen->modified )
- {
- rserr_t err;
-
- /*
- ** if this returns rserr_invalid_fullscreen then it set the mode but not as a
- ** fullscreen mode, e.g. 320x200 on a system that doesn't support that res
- */
- if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )
- {
- R_InitGraphics( vid.width, vid.height );
-
- sw_state.prev_mode = sw_mode->value;
- vid_fullscreen->modified = false;
- sw_mode->modified = false;
- }
- else
- {
- if ( err == rserr_invalid_mode )
- {
- ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );
- ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );
- }
- else if ( err == rserr_invalid_fullscreen )
- {
- R_InitGraphics( vid.width, vid.height );
-
- ri.Cvar_SetValue( "vid_fullscreen", 0);
- ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );
- sw_state.prev_mode = sw_mode->value;
-// vid_fullscreen->modified = false;
-// sw_mode->modified = false;
- }
- else
- {
- ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );
- }
- }
- }
-}
-
-/*
-** R_GammaCorrectAndSetPalette
-*/
-void R_GammaCorrectAndSetPalette( const unsigned char *palette )
-{
- int i;
-
- for ( i = 0; i < 256; i++ )
- {
- sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];
- sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];
- sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];
- }
-
- SWimp_SetPalette( sw_state.currentpalette );
-}
-
-/*
-** R_CinematicSetPalette
-*/
-void R_CinematicSetPalette( const unsigned char *palette )
-{
- byte palette32[1024];
- int i, j, w;
- int *d;
-
- // clear screen to black to avoid any palette flash
- w = abs(vid.rowbytes)>>2; // stupid negative pitch win32 stuff...
- for (i=0 ; i<vid.height ; i++, d+=w)
- {
- d = (int *)(vid.buffer + i*vid.rowbytes);
- for (j=0 ; j<w ; j++)
- d[j] = 0;
- }
- // flush it to the screen
- SWimp_EndFrame ();
-
- if ( palette )
- {
- for ( i = 0; i < 256; i++ )
- {
- palette32[i*4+0] = palette[i*3+0];
- palette32[i*4+1] = palette[i*3+1];
- palette32[i*4+2] = palette[i*3+2];
- palette32[i*4+3] = 0xFF;
- }
-
- R_GammaCorrectAndSetPalette( palette32 );
- }
- else
- {
- R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
- }
-}
-
-/*
-================
-Draw_BuildGammaTable
-================
-*/
-void Draw_BuildGammaTable (void)
-{
- int i, inf;
- float g;
-
- g = vid_gamma->value;
-
- if (g == 1.0)
- {
- for (i=0 ; i<256 ; i++)
- sw_state.gammatable[i] = i;
- return;
- }
-
- for (i=0 ; i<256 ; i++)
- {
- inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
- if (inf < 0)
- inf = 0;
- if (inf > 255)
- inf = 255;
- sw_state.gammatable[i] = inf;
- }
-}
-
-/*
-** R_DrawBeam
-*/
-void R_DrawBeam( entity_t *e )
-{
-#define NUM_BEAM_SEGS 6
-
- int i;
-
- vec3_t perpvec;
- vec3_t direction, normalized_direction;
- vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
- vec3_t oldorigin, origin;
-
- oldorigin[0] = e->oldorigin[0];
- oldorigin[1] = e->oldorigin[1];
- oldorigin[2] = e->oldorigin[2];
-
- origin[0] = e->origin[0];
- origin[1] = e->origin[1];
- origin[2] = e->origin[2];
-
- normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
- normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
- normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
-
- if ( VectorNormalize( normalized_direction ) == 0 )
- return;
-
- PerpendicularVector( perpvec, normalized_direction );
- VectorScale( perpvec, e->frame / 2, perpvec );
-
- for ( i = 0; i < NUM_BEAM_SEGS; i++ )
- {
- RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
- VectorAdd( start_points[i], origin, start_points[i] );
- VectorAdd( start_points[i], direction, end_points[i] );
- }
-
- for ( i = 0; i < NUM_BEAM_SEGS; i++ )
- {
- R_IMFlatShadedQuad( start_points[i],
- end_points[i],
- end_points[(i+1)%NUM_BEAM_SEGS],
- start_points[(i+1)%NUM_BEAM_SEGS],
- e->skinnum & 0xFF,
- e->alpha );
- }
-}
-
-
-//===================================================================
-
-/*
-============
-R_SetSky
-============
-*/
-// 3dstudio environment map names
-char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
-int r_skysideimage[6] = {5, 2, 4, 1, 0, 3};
-extern mtexinfo_t r_skytexinfo[6];
-void R_SetSky (char *name, float rotate, vec3_t axis)
-{
- int i;
- char pathname[MAX_QPATH];
-
- strncpy (skyname, name, sizeof(skyname)-1);
- skyrotate = rotate;
- VectorCopy (axis, skyaxis);
-
- for (i=0 ; i<6 ; i++)
- {
- Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);
- r_skytexinfo[i].image = R_FindImage (pathname, it_sky);
- }
-}
-
-
-/*
-===============
-Draw_GetPalette
-===============
-*/
-void Draw_GetPalette (void)
-{
- byte *pal, *out;
- int i;
- int r, g, b;
-
- // get the palette and colormap
- LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);
- if (!vid.colormap)
- ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
- vid.alphamap = vid.colormap + 64*256;
-
- out = (byte *)d_8to24table;
- for (i=0 ; i<256 ; i++, out+=4)
- {
- r = pal[i*3+0];
- g = pal[i*3+1];
- b = pal[i*3+2];
-
- out[0] = r;
- out[1] = g;
- out[2] = b;
- }
-
- free (pal);
-}
-
-struct image_s *R_RegisterSkin (char *name);
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-GetRefAPI
-
-@@@@@@@@@@@@@@@@@@@@@
-*/
-refexport_t GetRefAPI (refimport_t rimp)
-{
- refexport_t re;
-
- ri = rimp;
-
- re.api_version = API_VERSION;
-
- re.BeginRegistration = R_BeginRegistration;
- re.RegisterModel = R_RegisterModel;
- re.RegisterSkin = R_RegisterSkin;
- re.RegisterPic = Draw_FindPic;
- re.SetSky = R_SetSky;
- re.EndRegistration = R_EndRegistration;
-
- re.RenderFrame = R_RenderFrame;
-
- re.DrawGetPicSize = Draw_GetPicSize;
- re.DrawPic = Draw_Pic;
- re.DrawStretchPic = Draw_StretchPic;
- re.DrawChar = Draw_Char;
- re.DrawTileClear = Draw_TileClear;
- re.DrawFill = Draw_Fill;
- re.DrawFadeScreen= Draw_FadeScreen;
-
- re.DrawStretchRaw = Draw_StretchRaw;
-
- re.Init = R_Init;
- re.Shutdown = R_Shutdown;
-
- re.CinematicSetPalette = R_CinematicSetPalette;
- re.BeginFrame = R_BeginFrame;
- re.EndFrame = SWimp_EndFrame;
-
- re.AppActivate = SWimp_AppActivate;
-
- Swap_Init ();
-
- return re;
-}
-
-#ifndef REF_HARD_LINKED
-// this is only here so the functions in q_shared.c and q_shwin.c can link
-void Sys_Error (char *error, ...)
-{
- va_list argptr;
- char text[1024];
-
- va_start (argptr, error);
- vsprintf (text, error, argptr);
- va_end (argptr);
-
- ri.Sys_Error (ERR_FATAL, "%s", text);
-}
-
-void Com_Printf (char *fmt, ...)
-{
- va_list argptr;
- char text[1024];
-
- va_start (argptr, fmt);
- vsprintf (text, fmt, argptr);
- va_end (argptr);
-
- ri.Con_Printf (PRINT_ALL, "%s", text);
-}
-
-#endif
+/*
+Copyright (C) 1997-2001 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+// r_main.c
+
+#include "r_local.h"
+
+viddef_t vid;
+refimport_t ri;
+
+unsigned d_8to24table[256];
+
+entity_t r_worldentity;
+
+char skyname[MAX_QPATH];
+float skyrotate;
+vec3_t skyaxis;
+image_t *sky_images[6];
+
+refdef_t r_newrefdef;
+model_t *currentmodel;
+
+model_t *r_worldmodel;
+
+byte r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
+
+swstate_t sw_state;
+
+void *colormap;
+vec3_t viewlightvec;
+alight_t r_viewlighting = {128, 192, viewlightvec};
+float r_time1;
+int r_numallocatededges;
+float r_aliasuvscale = 1.0;
+int r_outofsurfaces;
+int r_outofedges;
+
+qboolean r_dowarp;
+
+mvertex_t *r_pcurrentvertbase;
+
+int c_surf;
+int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
+qboolean r_surfsonstack;
+int r_clipflags;
+
+//
+// view origin
+//
+vec3_t vup, base_vup;
+vec3_t vpn, base_vpn;
+vec3_t vright, base_vright;
+vec3_t r_origin;
+
+//
+// screen size info
+//
+oldrefdef_t r_refdef;
+float xcenter, ycenter;
+float xscale, yscale;
+float xscaleinv, yscaleinv;
+float xscaleshrink, yscaleshrink;
+float aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
+
+int r_screenwidth;
+
+float verticalFieldOfView;
+float xOrigin, yOrigin;
+
+mplane_t screenedge[4];
+
+//
+// refresh flags
+//
+int r_framecount = 1; // so frame counts initialized to 0 don't match
+int r_visframecount;
+int d_spanpixcount;
+int r_polycount;
+int r_drawnpolycount;
+int r_wholepolycount;
+
+int *pfrustum_indexes[4];
+int r_frustum_indexes[4*6];
+
+mleaf_t *r_viewleaf;
+int r_viewcluster, r_oldviewcluster;
+
+image_t *r_notexture_mip;
+
+float da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
+float se_time1, se_time2, de_time1, de_time2;
+
+void R_MarkLeaves (void);
+
+cvar_t *r_lefthand;
+cvar_t *sw_aliasstats;
+cvar_t *sw_allow_modex;
+cvar_t *sw_clearcolor;
+cvar_t *sw_drawflat;
+cvar_t *sw_draworder;
+cvar_t *sw_maxedges;
+cvar_t *sw_maxsurfs;
+cvar_t *sw_mode;
+cvar_t *sw_reportedgeout;
+cvar_t *sw_reportsurfout;
+cvar_t *sw_stipplealpha;
+cvar_t *sw_surfcacheoverride;
+cvar_t *sw_waterwarp;
+
+cvar_t *r_drawworld;
+cvar_t *r_drawentities;
+cvar_t *r_dspeeds;
+cvar_t *r_fullbright;
+cvar_t *r_lerpmodels;
+cvar_t *r_novis;
+
+cvar_t *r_speeds;
+cvar_t *r_lightlevel; //FIXME HACK
+
+cvar_t *vid_fullscreen;
+cvar_t *vid_gamma;
+
+//PGM
+cvar_t *sw_lockpvs;
+//PGM
+
+#define STRINGER(x) "x"
+
+
+#if !id386
+
+// r_vars.c
+
+// all global and static refresh variables are collected in a contiguous block
+// to avoid cache conflicts.
+
+//-------------------------------------------------------
+// global refresh variables
+//-------------------------------------------------------
+
+// FIXME: make into one big structure, like cl or sv
+// FIXME: do separately for refresh engine and driver
+
+
+// d_vars.c
+
+// all global and static refresh variables are collected in a contiguous block
+// to avoid cache conflicts.
+
+//-------------------------------------------------------
+// global refresh variables
+//-------------------------------------------------------
+
+// FIXME: make into one big structure, like cl or sv
+// FIXME: do separately for refresh engine and driver
+
+float d_sdivzstepu, d_tdivzstepu, d_zistepu;
+float d_sdivzstepv, d_tdivzstepv, d_zistepv;
+float d_sdivzorigin, d_tdivzorigin, d_ziorigin;
+
+fixed16_t sadjust, tadjust, bbextents, bbextentt;
+
+pixel_t *cacheblock;
+int cachewidth;
+pixel_t *d_viewbuffer;
+short *d_pzbuffer;
+unsigned int d_zrowbytes;
+unsigned int d_zwidth;
+
+
+#endif // !id386
+
+byte r_notexture_buffer[1024];
+
+/*
+==================
+R_InitTextures
+==================
+*/
+void R_InitTextures (void)
+{
+ int x,y, m;
+ byte *dest;
+
+// create a simple checkerboard texture for the default
+ r_notexture_mip = (image_t *)&r_notexture_buffer;
+
+ r_notexture_mip->width = r_notexture_mip->height = 16;
+ r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)];
+ r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16;
+ r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8;
+ r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4;
+
+ for (m=0 ; m<4 ; m++)
+ {
+ dest = r_notexture_mip->pixels[m];
+ for (y=0 ; y< (16>>m) ; y++)
+ for (x=0 ; x< (16>>m) ; x++)
+ {
+ if ( (y< (8>>m) ) ^ (x< (8>>m) ) )
+
+ *dest++ = 0;
+ else
+ *dest++ = 0xff;
+ }
+ }
+}
+
+
+/*
+================
+R_InitTurb
+================
+*/
+void R_InitTurb (void)
+{
+ int i;
+
+ for (i=0 ; i<1280 ; i++)
+ {
+ sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
+ intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2; // AMP2, not 20
+ blanktable[i] = 0; //PGM
+ }
+}
+
+void R_ImageList_f( void );
+
+void R_Register (void)
+{
+ sw_aliasstats = ri.Cvar_Get ("sw_polymodelstats", "0", 0);
+ sw_allow_modex = ri.Cvar_Get( "sw_allow_modex", "1", CVAR_ARCHIVE );
+ sw_clearcolor = ri.Cvar_Get ("sw_clearcolor", "2", 0);
+ sw_drawflat = ri.Cvar_Get ("sw_drawflat", "0", 0);
+ sw_draworder = ri.Cvar_Get ("sw_draworder", "0", 0);
+ sw_maxedges = ri.Cvar_Get ("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0);
+ sw_maxsurfs = ri.Cvar_Get ("sw_maxsurfs", "0", 0);
+ sw_mipcap = ri.Cvar_Get ("sw_mipcap", "0", 0);
+ sw_mipscale = ri.Cvar_Get ("sw_mipscale", "1", 0);
+ sw_reportedgeout = ri.Cvar_Get ("sw_reportedgeout", "0", 0);
+ sw_reportsurfout = ri.Cvar_Get ("sw_reportsurfout", "0", 0);
+ sw_stipplealpha = ri.Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
+ sw_surfcacheoverride = ri.Cvar_Get ("sw_surfcacheoverride", "0", 0);
+ sw_waterwarp = ri.Cvar_Get ("sw_waterwarp", "1", 0);
+ sw_mode = ri.Cvar_Get( "sw_mode", "0", CVAR_ARCHIVE );
+
+ r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
+ r_speeds = ri.Cvar_Get ("r_speeds", "0", 0);
+ r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0);
+ r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0);
+ r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0);
+ r_dspeeds = ri.Cvar_Get ("r_dspeeds", "0", 0);
+ r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0);
+ r_lerpmodels = ri.Cvar_Get( "r_lerpmodels", "1", 0 );
+ r_novis = ri.Cvar_Get( "r_novis", "0", 0 );
+
+ vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE );
+ vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE );
+
+ ri.Cmd_AddCommand ("modellist", Mod_Modellist_f);
+ ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
+ ri.Cmd_AddCommand( "imagelist", R_ImageList_f );
+
+ sw_mode->modified = true; // force us to do mode specific stuff later
+ vid_gamma->modified = true; // force us to rebuild the gamma table later
+
+//PGM
+ sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0);
+//PGM
+}
+
+void R_UnRegister (void)
+{
+ ri.Cmd_RemoveCommand( "screenshot" );
+ ri.Cmd_RemoveCommand ("modellist");
+ ri.Cmd_RemoveCommand( "imagelist" );
+}
+
+/*
+===============
+R_Init
+===============
+*/
+int R_Init( void *hInstance, void *wndProc )
+{
+ R_InitImages ();
+ Mod_Init ();
+ Draw_InitLocal ();
+ R_InitTextures ();
+
+ R_InitTurb ();
+
+ view_clipplanes[0].leftedge = true;
+ view_clipplanes[1].rightedge = true;
+ view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
+ view_clipplanes[3].leftedge = false;
+ view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
+ view_clipplanes[3].rightedge = false;
+
+ r_refdef.xOrigin = XCENTERING;
+ r_refdef.yOrigin = YCENTERING;
+
+// TODO: collect 386-specific code in one place
+#if id386
+ Sys_MakeCodeWriteable ((long)R_EdgeCodeStart,
+ (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart);
+ Sys_SetFPCW (); // get bit masks for FPCW (FIXME: is this id386?)
+#endif // id386
+
+ r_aliasuvscale = 1.0;
+
+ R_Register ();
+ Draw_GetPalette ();
+ SWimp_Init( hInstance, wndProc );
+
+ // create the window
+ R_BeginFrame( 0 );
+
+ ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");
+
+ return true;
+}
+
+/*
+===============
+R_Shutdown
+===============
+*/
+void R_Shutdown (void)
+{
+ // free z buffer
+ if (d_pzbuffer)
+ {
+ free (d_pzbuffer);
+ d_pzbuffer = NULL;
+ }
+ // free surface cache
+ if (sc_base)
+ {
+ D_FlushCaches ();
+ free (sc_base);
+ sc_base = NULL;
+ }
+
+ // free colormap
+ if (vid.colormap)
+ {
+ free (vid.colormap);
+ vid.colormap = NULL;
+ }
+ R_UnRegister ();
+ Mod_FreeAll ();
+ R_ShutdownImages ();
+
+ SWimp_Shutdown();
+}
+
+/*
+===============
+R_NewMap
+===============
+*/
+void R_NewMap (void)
+{
+ r_viewcluster = -1;
+
+ r_cnumsurfs = sw_maxsurfs->value;
+
+ if (r_cnumsurfs <= MINSURFACES)
+ r_cnumsurfs = MINSURFACES;
+
+ if (r_cnumsurfs > NUMSTACKSURFACES)
+ {
+ surfaces = malloc (r_cnumsurfs * sizeof(surf_t));
+ surface_p = surfaces;
+ surf_max = &surfaces[r_cnumsurfs];
+ r_surfsonstack = false;
+ // surface 0 doesn't really exist; it's just a dummy because index 0
+ // is used to indicate no edge attached to surface
+ surfaces--;
+ R_SurfacePatch ();
+ }
+ else
+ {
+ r_surfsonstack = true;
+ }
+
+ r_maxedgesseen = 0;
+ r_maxsurfsseen = 0;
+
+ r_numallocatededges = sw_maxedges->value;
+
+ if (r_numallocatededges < MINEDGES)
+ r_numallocatededges = MINEDGES;
+
+ if (r_numallocatededges <= NUMSTACKEDGES)
+ {
+ auxedges = NULL;
+ }
+ else
+ {
+ auxedges = malloc (r_numallocatededges * sizeof(edge_t));
+ }
+}
+
+
+/*
+===============
+R_MarkLeaves
+
+Mark the leaves and nodes that are in the PVS for the current
+cluster
+===============
+*/
+void R_MarkLeaves (void)
+{
+ byte *vis;
+ mnode_t *node;
+ int i;
+ mleaf_t *leaf;
+ int cluster;
+
+ if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
+ return;
+
+ // development aid to let you run around and see exactly where
+ // the pvs ends
+ if (sw_lockpvs->value)
+ return;
+
+ r_visframecount++;
+ r_oldviewcluster = r_viewcluster;
+
+ if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
+ {
+ // mark everything
+ for (i=0 ; i<r_worldmodel->numleafs ; i++)
+ r_worldmodel->leafs[i].visframe = r_visframecount;
+ for (i=0 ; i<r_worldmodel->numnodes ; i++)
+ r_worldmodel->nodes[i].visframe = r_visframecount;
+ return;
+ }
+
+ vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
+
+ for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
+ {
+ cluster = leaf->cluster;
+ if (cluster == -1)
+ continue;
+ if (vis[cluster>>3] & (1<<(cluster&7)))
+ {
+ node = (mnode_t *)leaf;
+ do
+ {
+ if (node->visframe == r_visframecount)
+ break;
+ node->visframe = r_visframecount;
+ node = node->parent;
+ } while (node);
+ }
+ }
+
+#if 0
+ for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
+ {
+ if (vis[i>>3] & (1<<(i&7)))
+ {
+ node = (mnode_t *)&r_worldmodel->leafs[i]; // FIXME: cluster
+ do
+ {
+ if (node->visframe == r_visframecount)
+ break;
+ node->visframe = r_visframecount;
+ node = node->parent;
+ } while (node);
+ }
+ }
+#endif
+}
+
+/*
+** R_DrawNullModel
+**
+** IMPLEMENT THIS!
+*/
+void R_DrawNullModel( void )
+{
+}
+
+/*
+=============
+R_DrawEntitiesOnList
+=============
+*/
+void R_DrawEntitiesOnList (void)
+{
+ int i;
+ qboolean translucent_entities = false;
+
+ if (!r_drawentities->value)
+ return;
+
+ // all bmodels have already been drawn by the edge list
+ for (i=0 ; i<r_newrefdef.num_entities ; i++)
+ {
+ currententity = &r_newrefdef.entities[i];
+
+ if ( currententity->flags & RF_TRANSLUCENT )
+ {
+ translucent_entities = true;
+ continue;
+ }
+
+ if ( currententity->flags & RF_BEAM )
+ {
+ modelorg[0] = -r_origin[0];
+ modelorg[1] = -r_origin[1];
+ modelorg[2] = -r_origin[2];
+ VectorCopy( vec3_origin, r_entorigin );
+ R_DrawBeam( currententity );
+ }
+ else
+ {
+ currentmodel = currententity->model;
+ if (!currentmodel)
+ {
+ R_DrawNullModel();
+ continue;
+ }
+ VectorCopy (currententity->origin, r_entorigin);
+ VectorSubtract (r_origin, r_entorigin, modelorg);
+
+ switch (currentmodel->type)
+ {
+ case mod_sprite:
+ R_DrawSprite ();
+ break;
+
+ case mod_alias:
+ R_AliasDrawModel ();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if ( !translucent_entities )
+ return;
+
+ for (i=0 ; i<r_newrefdef.num_entities ; i++)
+ {
+ currententity = &r_newrefdef.entities[i];
+
+ if ( !( currententity->flags & RF_TRANSLUCENT ) )
+ continue;
+
+ if ( currententity->flags & RF_BEAM )
+ {
+ modelorg[0] = -r_origin[0];
+ modelorg[1] = -r_origin[1];
+ modelorg[2] = -r_origin[2];
+ VectorCopy( vec3_origin, r_entorigin );
+ R_DrawBeam( currententity );
+ }
+ else
+ {
+ currentmodel = currententity->model;
+ if (!currentmodel)
+ {
+ R_DrawNullModel();
+ continue;
+ }
+ VectorCopy (currententity->origin, r_entorigin);
+ VectorSubtract (r_origin, r_entorigin, modelorg);
+
+ switch (currentmodel->type)
+ {
+ case mod_sprite:
+ R_DrawSprite ();
+ break;
+
+ case mod_alias:
+ R_AliasDrawModel ();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+
+/*
+=============
+R_BmodelCheckBBox
+=============
+*/
+int R_BmodelCheckBBox (float *minmaxs)
+{
+ int i, *pindex, clipflags;
+ vec3_t acceptpt, rejectpt;
+ float d;
+
+ clipflags = 0;
+
+ for (i=0 ; i<4 ; i++)
+ {
+ // generate accept and reject points
+ // FIXME: do with fast look-ups or integer tests based on the sign bit
+ // of the floating point values
+
+ pindex = pfrustum_indexes[i];
+
+ rejectpt[0] = minmaxs[pindex[0]];
+ rejectpt[1] = minmaxs[pindex[1]];
+ rejectpt[2] = minmaxs[pindex[2]];
+
+ d = DotProduct (rejectpt, view_clipplanes[i].normal);
+ d -= view_clipplanes[i].dist;
+
+ if (d <= 0)
+ return BMODEL_FULLY_CLIPPED;
+
+ acceptpt[0] = minmaxs[pindex[3+0]];
+ acceptpt[1] = minmaxs[pindex[3+1]];
+ acceptpt[2] = minmaxs[pindex[3+2]];
+
+ d = DotProduct (acceptpt, view_clipplanes[i].normal);
+ d -= view_clipplanes[i].dist;
+
+ if (d <= 0)
+ clipflags |= (1<<i);
+ }
+
+ return clipflags;
+}
+
+
+/*
+===================
+R_FindTopnode
+
+Find the first node that splits the given box
+===================
+*/
+mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
+{
+ mplane_t *splitplane;
+ int sides;
+ mnode_t *node;
+
+ node = r_worldmodel->nodes;
+
+ while (1)
+ {
+ if (node->visframe != r_visframecount)
+ return NULL; // not visible at all
+
+ if (node->contents != CONTENTS_NODE)
+ {
+ if (node->contents != CONTENTS_SOLID)
+ return node; // we've reached a non-solid leaf, so it's
+ // visible and not BSP clipped
+ return NULL; // in solid, so not visible
+ }
+
+ splitplane = node->plane;
+ sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);
+
+ if (sides == 3)
+ return node; // this is the splitter
+
+ // not split yet; recurse down the contacted side
+ if (sides & 1)
+ node = node->children[0];
+ else
+ node = node->children[1];
+ }
+}
+
+
+/*
+=============
+RotatedBBox
+
+Returns an axially aligned box that contains the input box at the given rotation
+=============
+*/
+void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)
+{
+ vec3_t tmp, v;
+ int i, j;
+ vec3_t forward, right, up;
+
+ if (!angles[0] && !angles[1] && !angles[2])
+ {
+ VectorCopy (mins, tmins);
+ VectorCopy (maxs, tmaxs);
+ return;
+ }
+
+ for (i=0 ; i<3 ; i++)
+ {
+ tmins[i] = 99999;
+ tmaxs[i] = -99999;
+ }
+
+ AngleVectors (angles, forward, right, up);
+
+ for ( i = 0; i < 8; i++ )
+ {
+ if ( i & 1 )
+ tmp[0] = mins[0];
+ else
+ tmp[0] = maxs[0];
+
+ if ( i & 2 )
+ tmp[1] = mins[1];
+ else
+ tmp[1] = maxs[1];
+
+ if ( i & 4 )
+ tmp[2] = mins[2];
+ else
+ tmp[2] = maxs[2];
+
+
+ VectorScale (forward, tmp[0], v);
+ VectorMA (v, -tmp[1], right, v);
+ VectorMA (v, tmp[2], up, v);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ if (v[j] < tmins[j])
+ tmins[j] = v[j];
+ if (v[j] > tmaxs[j])
+ tmaxs[j] = v[j];
+ }
+ }
+}
+
+/*
+=============
+R_DrawBEntitiesOnList
+=============
+*/
+void R_DrawBEntitiesOnList (void)
+{
+ int i, clipflags;
+ vec3_t oldorigin;
+ vec3_t mins, maxs;
+ float minmaxs[6];
+ mnode_t *topnode;
+
+ if (!r_drawentities->value)
+ return;
+
+ VectorCopy (modelorg, oldorigin);
+ insubmodel = true;
+ r_dlightframecount = r_framecount;
+
+ for (i=0 ; i<r_newrefdef.num_entities ; i++)
+ {
+ currententity = &r_newrefdef.entities[i];
+ currentmodel = currententity->model;
+ if (!currentmodel)
+ continue;
+ if (currentmodel->nummodelsurfaces == 0)
+ continue; // clip brush only
+ if ( currententity->flags & RF_BEAM )
+ continue;
+ if (currentmodel->type != mod_brush)
+ continue;
+ // see if the bounding box lets us trivially reject, also sets
+ // trivial accept status
+ RotatedBBox (currentmodel->mins, currentmodel->maxs,
+ currententity->angles, mins, maxs);
+ VectorAdd (mins, currententity->origin, minmaxs);
+ VectorAdd (maxs, currententity->origin, (minmaxs+3));
+
+ clipflags = R_BmodelCheckBBox (minmaxs);
+ if (clipflags == BMODEL_FULLY_CLIPPED)
+ continue; // off the edge of the screen
+
+ topnode = R_FindTopnode (minmaxs, minmaxs+3);
+ if (!topnode)
+ continue; // no part in a visible leaf
+
+ VectorCopy (currententity->origin, r_entorigin);
+ VectorSubtract (r_origin, r_entorigin, modelorg);
+
+ r_pcurrentvertbase = currentmodel->vertexes;
+
+ // FIXME: stop transforming twice
+ R_RotateBmodel ();
+
+ // calculate dynamic lighting for bmodel
+ R_PushDlights (currentmodel);
+
+ if (topnode->contents == CONTENTS_NODE)
+ {
+ // not a leaf; has to be clipped to the world BSP
+ r_clipflags = clipflags;
+ R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);
+ }
+ else
+ {
+ // falls entirely in one leaf, so we just put all the
+ // edges in the edge list and let 1/z sorting handle
+ // drawing order
+ R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);
+ }
+
+ // put back world rotation and frustum clipping
+ // FIXME: R_RotateBmodel should just work off base_vxx
+ VectorCopy (base_vpn, vpn);
+ VectorCopy (base_vup, vup);
+ VectorCopy (base_vright, vright);
+ VectorCopy (oldorigin, modelorg);
+ R_TransformFrustum ();
+ }
+
+ insubmodel = false;
+}
+
+
+/*
+================
+R_EdgeDrawing
+================
+*/
+void R_EdgeDrawing (void)
+{
+ edge_t ledges[NUMSTACKEDGES +
+ ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
+ surf_t lsurfs[NUMSTACKSURFACES +
+ ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
+
+ if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+ return;
+
+ if (auxedges)
+ {
+ r_edges = auxedges;
+ }
+ else
+ {
+ r_edges = (edge_t *)
+ (((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+ }
+
+ if (r_surfsonstack)
+ {
+ surfaces = (surf_t *)
+ (((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+ surf_max = &surfaces[r_cnumsurfs];
+ // surface 0 doesn't really exist; it's just a dummy because index 0
+ // is used to indicate no edge attached to surface
+ surfaces--;
+ R_SurfacePatch ();
+ }
+
+ R_BeginEdgeFrame ();
+
+ if (r_dspeeds->value)
+ {
+ rw_time1 = Sys_Milliseconds ();
+ }
+
+ R_RenderWorld ();
+
+ if (r_dspeeds->value)
+ {
+ rw_time2 = Sys_Milliseconds ();
+ db_time1 = rw_time2;
+ }
+
+ R_DrawBEntitiesOnList ();
+
+ if (r_dspeeds->value)
+ {
+ db_time2 = Sys_Milliseconds ();
+ se_time1 = db_time2;
+ }
+
+ R_ScanEdges ();
+}
+
+//=======================================================================
+
+
+/*
+=============
+R_CalcPalette
+
+=============
+*/
+void R_CalcPalette (void)
+{
+ static qboolean modified;
+ byte palette[256][4], *in, *out;
+ int i, j;
+ float alpha, one_minus_alpha;
+ vec3_t premult;
+ int v;
+
+ alpha = r_newrefdef.blend[3];
+ if (alpha <= 0)
+ {
+ if (modified)
+ { // set back to default
+ modified = false;
+ R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+ return;
+ }
+ return;
+ }
+
+ modified = true;
+ if (alpha > 1)
+ alpha = 1;
+
+ premult[0] = r_newrefdef.blend[0]*alpha*255;
+ premult[1] = r_newrefdef.blend[1]*alpha*255;
+ premult[2] = r_newrefdef.blend[2]*alpha*255;
+
+ one_minus_alpha = (1.0 - alpha);
+
+ in = (byte *)d_8to24table;
+ out = palette[0];
+ for (i=0 ; i<256 ; i++, in+=4, out+=4)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ v = premult[j] + one_minus_alpha * in[j];
+ if (v > 255)
+ v = 255;
+ out[j] = v;
+ }
+ out[3] = 255;
+ }
+
+ R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] );
+// SWimp_SetPalette( palette[0] );
+}
+
+//=======================================================================
+
+void R_SetLightLevel (void)
+{
+ vec3_t light;
+
+ if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))
+ {
+ r_lightlevel->value = 150.0;
+ return;
+ }
+
+ // save off light value for server to look at (BIG HACK!)
+ R_LightPoint (r_newrefdef.vieworg, light);
+ r_lightlevel->value = 150.0 * light[0];
+}
+
+
+/*
+@@@@@@@@@@@@@@@@
+R_RenderFrame
+
+@@@@@@@@@@@@@@@@
+*/
+void R_RenderFrame (refdef_t *fd)
+{
+ r_newrefdef = *fd;
+
+ if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
+ ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");
+
+ VectorCopy (fd->vieworg, r_refdef.vieworg);
+ VectorCopy (fd->viewangles, r_refdef.viewangles);
+
+ if (r_speeds->value || r_dspeeds->value)
+ r_time1 = Sys_Milliseconds ();
+
+ R_SetupFrame ();
+
+ R_MarkLeaves (); // done here so we know if we're in water
+
+ R_PushDlights (r_worldmodel);
+
+ R_EdgeDrawing ();
+
+ if (r_dspeeds->value)
+ {
+ se_time2 = Sys_Milliseconds ();
+ de_time1 = se_time2;
+ }
+
+ R_DrawEntitiesOnList ();
+
+ if (r_dspeeds->value)
+ {
+ de_time2 = Sys_Milliseconds ();
+ dp_time1 = Sys_Milliseconds ();
+ }
+
+ R_DrawParticles ();
+
+ if (r_dspeeds->value)
+ dp_time2 = Sys_Milliseconds ();
+
+ R_DrawAlphaSurfaces();
+
+ R_SetLightLevel ();
+
+ if (r_dowarp)
+ D_WarpScreen ();
+
+ if (r_dspeeds->value)
+ da_time1 = Sys_Milliseconds ();
+
+ if (r_dspeeds->value)
+ da_time2 = Sys_Milliseconds ();
+
+ R_CalcPalette ();
+
+ if (sw_aliasstats->value)
+ R_PrintAliasStats ();
+
+ if (r_speeds->value)
+ R_PrintTimes ();
+
+ if (r_dspeeds->value)
+ R_PrintDSpeeds ();
+
+ if (sw_reportsurfout->value && r_outofsurfaces)
+ ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);
+
+ if (sw_reportedgeout->value && r_outofedges)
+ ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);
+}
+
+/*
+** R_InitGraphics
+*/
+void R_InitGraphics( int width, int height )
+{
+ vid.width = width;
+ vid.height = height;
+
+ // free z buffer
+ if ( d_pzbuffer )
+ {
+ free( d_pzbuffer );
+ d_pzbuffer = NULL;
+ }
+
+ // free surface cache
+ if ( sc_base )
+ {
+ D_FlushCaches ();
+ free( sc_base );
+ sc_base = NULL;
+ }
+
+ d_pzbuffer = malloc(vid.width*vid.height*2);
+
+ R_InitCaches ();
+
+ R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table );
+}
+
+void SetStereoBuffer(int buf);
+
+/*
+** R_BeginFrame
+*/
+void R_BeginFrame( float camera_separation )
+{
+ extern void Draw_BuildGammaTable( void );
+
+ SetStereoBuffer((camera_separation <= 0.0) ? 0 : 1);
+
+ /*
+ ** rebuild the gamma correction palette if necessary
+ */
+ if ( vid_gamma->modified )
+ {
+ Draw_BuildGammaTable();
+ R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+
+ vid_gamma->modified = false;
+ }
+
+ while ( sw_mode->modified || vid_fullscreen->modified )
+ {
+ rserr_t err;
+
+ /*
+ ** if this returns rserr_invalid_fullscreen then it set the mode but not as a
+ ** fullscreen mode, e.g. 320x200 on a system that doesn't support that res
+ */
+ if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )
+ {
+ R_InitGraphics( vid.width, vid.height );
+
+ sw_state.prev_mode = sw_mode->value;
+ vid_fullscreen->modified = false;
+ sw_mode->modified = false;
+ }
+ else
+ {
+ if ( err == rserr_invalid_mode )
+ {
+ ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );
+ ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );
+ }
+ else if ( err == rserr_invalid_fullscreen )
+ {
+ R_InitGraphics( vid.width, vid.height );
+
+ ri.Cvar_SetValue( "vid_fullscreen", 0);
+ ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );
+ sw_state.prev_mode = sw_mode->value;
+// vid_fullscreen->modified = false;
+// sw_mode->modified = false;
+ }
+ else
+ {
+ ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );
+ }
+ }
+ }
+}
+
+/*
+** R_GammaCorrectAndSetPalette
+*/
+void R_GammaCorrectAndSetPalette( const unsigned char *palette )
+{
+ int i;
+
+ for ( i = 0; i < 256; i++ )
+ {
+ sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];
+ sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];
+ sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];
+ }
+
+ SWimp_SetPalette( sw_state.currentpalette );
+}
+
+/*
+** R_CinematicSetPalette
+*/
+void R_CinematicSetPalette( const unsigned char *palette )
+{
+ byte palette32[1024];
+ int i, j, w;
+ int *d;
+
+ // clear screen to black to avoid any palette flash
+ w = abs(vid.rowbytes)>>2; // stupid negative pitch win32 stuff...
+ for (i=0 ; i<vid.height ; i++, d+=w)
+ {
+ d = (int *)(vid.buffer + i*vid.rowbytes);
+ for (j=0 ; j<w ; j++)
+ d[j] = 0;
+ }
+ // flush it to the screen
+ SWimp_EndFrame ();
+
+ if ( palette )
+ {
+ for ( i = 0; i < 256; i++ )
+ {
+ palette32[i*4+0] = palette[i*3+0];
+ palette32[i*4+1] = palette[i*3+1];
+ palette32[i*4+2] = palette[i*3+2];
+ palette32[i*4+3] = 0xFF;
+ }
+
+ R_GammaCorrectAndSetPalette( palette32 );
+ }
+ else
+ {
+ R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
+ }
+}
+
+/*
+================
+Draw_BuildGammaTable
+================
+*/
+void Draw_BuildGammaTable (void)
+{
+ int i, inf;
+ float g;
+
+ g = vid_gamma->value;
+
+ if (g == 1.0)
+ {
+ for (i=0 ; i<256 ; i++)
+ sw_state.gammatable[i] = i;
+ return;
+ }
+
+ for (i=0 ; i<256 ; i++)
+ {
+ inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
+ if (inf < 0)
+ inf = 0;
+ if (inf > 255)
+ inf = 255;
+ sw_state.gammatable[i] = inf;
+ }
+}
+
+/*
+** R_DrawBeam
+*/
+void R_DrawBeam( entity_t *e )
+{
+#define NUM_BEAM_SEGS 6
+
+ int i;
+
+ vec3_t perpvec;
+ vec3_t direction, normalized_direction;
+ vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
+ vec3_t oldorigin, origin;
+
+ oldorigin[0] = e->oldorigin[0];
+ oldorigin[1] = e->oldorigin[1];
+ oldorigin[2] = e->oldorigin[2];
+
+ origin[0] = e->origin[0];
+ origin[1] = e->origin[1];
+ origin[2] = e->origin[2];
+
+ normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
+ normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
+ normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
+
+ if ( VectorNormalize( normalized_direction ) == 0 )
+ return;
+
+ PerpendicularVector( perpvec, normalized_direction );
+ VectorScale( perpvec, e->frame / 2, perpvec );
+
+ for ( i = 0; i < NUM_BEAM_SEGS; i++ )
+ {
+ RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
+ VectorAdd( start_points[i], origin, start_points[i] );
+ VectorAdd( start_points[i], direction, end_points[i] );
+ }
+
+ for ( i = 0; i < NUM_BEAM_SEGS; i++ )
+ {
+ R_IMFlatShadedQuad( start_points[i],
+ end_points[i],
+ end_points[(i+1)%NUM_BEAM_SEGS],
+ start_points[(i+1)%NUM_BEAM_SEGS],
+ e->skinnum & 0xFF,
+ e->alpha );
+ }
+}
+
+
+//===================================================================
+
+/*
+============
+R_SetSky
+============
+*/
+// 3dstudio environment map names
+char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+int r_skysideimage[6] = {5, 2, 4, 1, 0, 3};
+extern mtexinfo_t r_skytexinfo[6];
+void R_SetSky (char *name, float rotate, vec3_t axis)
+{
+ int i;
+ char pathname[MAX_QPATH];
+
+ strncpy (skyname, name, sizeof(skyname)-1);
+ skyrotate = rotate;
+ VectorCopy (axis, skyaxis);
+
+ for (i=0 ; i<6 ; i++)
+ {
+ Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);
+ r_skytexinfo[i].image = R_FindImage (pathname, it_sky);
+ }
+}
+
+
+/*
+===============
+Draw_GetPalette
+===============
+*/
+void Draw_GetPalette (void)
+{
+ byte *pal, *out;
+ int i;
+ int r, g, b;
+
+ // get the palette and colormap
+ LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);
+ if (!vid.colormap)
+ ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
+ vid.alphamap = vid.colormap + 64*256;
+
+ out = (byte *)d_8to24table;
+ for (i=0 ; i<256 ; i++, out+=4)
+ {
+ r = pal[i*3+0];
+ g = pal[i*3+1];
+ b = pal[i*3+2];
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ }
+
+ free (pal);
+}
+
+struct image_s *R_RegisterSkin (char *name);
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+GetRefAPI
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+refexport_t GetRefAPI (refimport_t rimp)
+{
+ refexport_t re;
+
+ ri = rimp;
+
+ re.api_version = API_VERSION;
+
+ re.BeginRegistration = R_BeginRegistration;
+ re.RegisterModel = R_RegisterModel;
+ re.RegisterSkin = R_RegisterSkin;
+ re.RegisterPic = Draw_FindPic;
+ re.SetSky = R_SetSky;
+ re.EndRegistration = R_EndRegistration;
+
+ re.RenderFrame = R_RenderFrame;
+
+ re.DrawGetPicSize = Draw_GetPicSize;
+ re.DrawPic = Draw_Pic;
+ re.DrawStretchPic = Draw_StretchPic;
+ re.DrawChar = Draw_Char;
+ re.DrawTileClear = Draw_TileClear;
+ re.DrawFill = Draw_Fill;
+ re.DrawFadeScreen= Draw_FadeScreen;
+
+ re.DrawStretchRaw = Draw_StretchRaw;
+
+ re.Init = R_Init;
+ re.Shutdown = R_Shutdown;
+
+ re.CinematicSetPalette = R_CinematicSetPalette;
+ re.BeginFrame = R_BeginFrame;
+ re.EndFrame = SWimp_EndFrame;
+
+ re.AppActivate = SWimp_AppActivate;
+
+ Swap_Init ();
+
+ return re;
+}
+
+#ifndef REF_HARD_LINKED
+// this is only here so the functions in q_shared.c and q_shwin.c can link
+void Sys_Error (char *error, ...)
+{
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, error);
+ vsprintf (text, error, argptr);
+ va_end (argptr);
+
+ ri.Sys_Error (ERR_FATAL, "%s", text);
+}
+
+void Com_Printf (char *fmt, ...)
+{
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr, fmt);
+ vsprintf (text, fmt, argptr);
+ va_end (argptr);
+
+ ri.Con_Printf (PRINT_ALL, "%s", text);
+}
+
+#endif
More information about the quake2
mailing list