ref: eff0a337f498aa7cf3a4735a8be5a5b3ace172d9
dir: /src/i_video.c/
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id: i_video.c 44 2005-08-06 17:30:30Z fraggle $
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005 Simon Howard
//
// 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.
//
// $Log$
// Revision 1.14 2005/08/06 17:30:30 fraggle
// Only change palette on screen updates
//
// Revision 1.13 2005/08/04 22:23:07 fraggle
// Use zone memory function. Add command line options
//
// Revision 1.12 2005/08/04 19:54:56 fraggle
// Use keysym value rather than unicode value (fixes problems with shift
// key)
//
// Revision 1.11 2005/08/04 18:42:15 fraggle
// Silence compiler warnings
//
// Revision 1.10 2005/08/04 01:13:46 fraggle
// Loading disk
//
// Revision 1.9 2005/08/03 22:19:52 fraggle
// Set some flags to fix palette and improve performance
//
// Revision 1.8 2005/08/03 21:58:02 fraggle
// Working scale*2
//
// Revision 1.7 2005/07/25 20:50:55 fraggle
// mouse
//
// Revision 1.6 2005/07/24 02:14:04 fraggle
// Move to SDL for graphics.
// Translate key scancodes to correct internal format when reading
// settings from config file - backwards compatible with config files
// for original exes
//
// Revision 1.5 2005/07/23 21:32:47 fraggle
// Add missing errno.h, fix crash on startup when no IWAD present
//
// Revision 1.4 2005/07/23 19:17:11 fraggle
// Use ANSI-standard limit constants. Remove LINUX define.
//
// Revision 1.3 2005/07/23 17:27:04 fraggle
// Stop crash on shutdown
//
// Revision 1.2 2005/07/23 16:44:55 fraggle
// Update copyright to GNU GPL
//
// Revision 1.1.1.1 2005/07/23 16:19:58 fraggle
// Initial import
//
//
// DESCRIPTION:
// DOOM graphics stuff for X11, UNIX.
//
//-----------------------------------------------------------------------------
static const char
rcsid[] = "$Id: i_video.c 44 2005-08-06 17:30:30Z fraggle $";
#include <ctype.h>
#include <SDL.h>
#include "w_wad.h"
#include "z_zone.h"
#include "doomstat.h"
#include "i_system.h"
#include "v_video.h"
#include "m_argv.h"
#include "m_swap.h"
#include "d_main.h"
#include "doomdef.h"
static SDL_Surface *screen;
#define POINTER_WARP_COUNTDOWN 1
// palette
static SDL_Color palette[256];
static boolean palette_to_set;
// Fake mouse handling.
// This cannot work properly w/o DGA.
// Needs an invisible mouse cursor at least.
boolean grabMouse;
// Blocky mode,
// replace each 320x200 pixel with multiply*multiply pixels.
// According to Dave Taylor, it still is a bonehead thing
// to use ....
static int multiply=1;
// disk image data and background overwritten by the disk to be
// restored by EndRead
static byte *disk_image = NULL;
static int disk_image_w, disk_image_h;
static byte *saved_background;
void I_BeginRead(void)
{
int y;
if (disk_image == NULL)
return;
// save background and copy the disk image in
for (y=0; y<disk_image_h; ++y)
{
byte *screenloc =
screens[0]
+ (SCREENHEIGHT - 1 - disk_image_h + y) * SCREENWIDTH
+ (SCREENWIDTH - 1 - disk_image_w);
memcpy(saved_background + y * disk_image_w,
screenloc,
disk_image_w);
memcpy(screenloc, disk_image + y * disk_image_w, disk_image_w);
}
SDL_UpdateRect(screen,
screen->w - disk_image_w, screen->h - disk_image_h,
disk_image_w, disk_image_h);
}
void I_EndRead(void)
{
int y;
if (disk_image == NULL)
return;
// save background and copy the disk image in
for (y=0; y<disk_image_h; ++y)
{
byte *screenloc =
screens[0]
+ (SCREENHEIGHT - 1 - disk_image_h + y) * SCREENWIDTH
+ (SCREENWIDTH - 1 - disk_image_w);
memcpy(screenloc, saved_background + y * disk_image_w, disk_image_w);
}
SDL_UpdateRect(screen,
screen->w - disk_image_w, screen->h - disk_image_h,
disk_image_w, disk_image_h);
}
static void LoadDiskImage(void)
{
patch_t *disk;
int y;
disk = (patch_t *) W_CacheLumpName("STDISK", PU_STATIC);
V_DrawPatch(0, 0, 0, disk);
disk_image_w = SHORT(disk->width);
disk_image_h = SHORT(disk->height);
disk_image = Z_Malloc(disk_image_w * disk_image_h, PU_STATIC, NULL);
saved_background = Z_Malloc(disk_image_w * disk_image_h, PU_STATIC, NULL);
for (y=0; y<disk_image_h; ++y)
{
memcpy(disk_image + disk_image_w * y,
screens[0] + SCREENWIDTH * y,
disk_image_w);
}
Z_Free(disk);
}
//
// Translates the SDL key
//
int xlatekey(SDL_keysym *sym)
{
switch(sym->sym)
{
case SDLK_LEFT: return KEY_LEFTARROW;
case SDLK_RIGHT: return KEY_RIGHTARROW;
case SDLK_DOWN: return KEY_DOWNARROW;
case SDLK_UP: return KEY_UPARROW;
case SDLK_ESCAPE: return KEY_ESCAPE;
case SDLK_RETURN: return KEY_ENTER;
case SDLK_TAB: return KEY_TAB;
case SDLK_F1: return KEY_F1;
case SDLK_F2: return KEY_F2;
case SDLK_F3: return KEY_F3;
case SDLK_F4: return KEY_F4;
case SDLK_F5: return KEY_F5;
case SDLK_F6: return KEY_F6;
case SDLK_F7: return KEY_F7;
case SDLK_F8: return KEY_F8;
case SDLK_F9: return KEY_F9;
case SDLK_F10: return KEY_F10;
case SDLK_F11: return KEY_F11;
case SDLK_F12: return KEY_F12;
case SDLK_BACKSPACE: return KEY_BACKSPACE;
case SDLK_DELETE: return KEY_DEL;
case SDLK_PAUSE: return KEY_PAUSE;
case SDLK_EQUALS:
case SDLK_KP_EQUALS: return KEY_EQUALS;
case SDLK_MINUS: return KEY_MINUS;
case SDLK_LSHIFT:
case SDLK_RSHIFT:
return KEY_RSHIFT;
case SDLK_LCTRL:
case SDLK_RCTRL:
return KEY_RCTRL;
case SDLK_LALT:
case SDLK_LMETA:
case SDLK_RALT:
case SDLK_RMETA:
return KEY_RALT;
case SDLK_CAPSLOCK: return KEY_CAPSLOCK;
case SDLK_SCROLLOCK: return KEY_SCRLCK;
case SDLK_KP0: return KEYP_0;
case SDLK_KP1: return KEYP_1;
case SDLK_KP2: return KEYP_2;
case SDLK_KP3: return KEYP_3;
case SDLK_KP4: return KEYP_4;
case SDLK_KP5: return KEYP_5;
case SDLK_KP6: return KEYP_6;
case SDLK_KP7: return KEYP_7;
case SDLK_KP8: return KEYP_8;
case SDLK_KP9: return KEYP_9;
case SDLK_HOME: return KEY_HOME;
case SDLK_INSERT: return KEY_INS;
case SDLK_END: return KEY_END;
case SDLK_PAGEUP: return KEY_PGUP;
case SDLK_PAGEDOWN: return KEY_PGDN;
case SDLK_KP_MULTIPLY: return KEYP_MULTIPLY;
case SDLK_KP_PLUS: return KEYP_PLUS;
case SDLK_KP_MINUS: return KEYP_MINUS;
case SDLK_KP_DIVIDE: return KEYP_DIVIDE;
default:
return tolower(sym->sym);
}
}
void I_ShutdownGraphics(void)
{
SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
//
// I_StartFrame
//
void I_StartFrame (void)
{
// er?
}
static int mousebuttonstate(void)
{
Uint8 state = SDL_GetMouseState(NULL, NULL);
int result = 0;
if (state & SDL_BUTTON(1))
result |= 1;
if (state & SDL_BUTTON(2))
result |= 2;
if (state & SDL_BUTTON(3))
result |= 4;
return result;
}
boolean mousemoved = false;
void I_GetEvent(void)
{
SDL_Event sdlevent;
event_t event;
// put event-grabbing stuff in here
while (SDL_PollEvent(&sdlevent))
{
switch (sdlevent.type)
{
case SDL_KEYDOWN:
event.type = ev_keydown;
event.data1 = xlatekey(&sdlevent.key.keysym);
D_PostEvent(&event);
break;
case SDL_KEYUP:
event.type = ev_keyup;
event.data1 = xlatekey(&sdlevent.key.keysym);
D_PostEvent(&event);
break;
case SDL_MOUSEMOTION:
event.type = ev_mouse;
event.data1 = mousebuttonstate();
event.data2 = sdlevent.motion.xrel * 8;
event.data3 = -sdlevent.motion.yrel * 8;
D_PostEvent(&event);
break;
case SDL_MOUSEBUTTONDOWN:
event.type = ev_mouse;
event.data1 = mousebuttonstate();
event.data2 = event.data3 = 0;
D_PostEvent(&event);
break;
case SDL_MOUSEBUTTONUP:
event.type = ev_mouse;
event.data1 = mousebuttonstate();
event.data2 = event.data3 = 0;
D_PostEvent(&event);
break;
#if 0
case ButtonPress:
event.type = ev_mouse;
event.data1 =
(X_event.xbutton.state & Button1Mask)
| (X_event.xbutton.state & Button2Mask ? 2 : 0)
| (X_event.xbutton.state & Button3Mask ? 4 : 0)
| (X_event.xbutton.button == Button1)
| (X_event.xbutton.button == Button2 ? 2 : 0)
| (X_event.xbutton.button == Button3 ? 4 : 0);
event.data2 = event.data3 = 0;
D_PostEvent(&event);
// fprintf(stderr, "b");
break;
case ButtonRelease:
event.type = ev_mouse;
event.data1 =
(X_event.xbutton.state & Button1Mask)
| (X_event.xbutton.state & Button2Mask ? 2 : 0)
| (X_event.xbutton.state & Button3Mask ? 4 : 0);
// suggest parentheses around arithmetic in operand of |
event.data1 =
event.data1
^ (X_event.xbutton.button == Button1 ? 1 : 0)
^ (X_event.xbutton.button == Button2 ? 2 : 0)
^ (X_event.xbutton.button == Button3 ? 4 : 0);
event.data2 = event.data3 = 0;
D_PostEvent(&event);
// fprintf(stderr, "bu");
break;
case MotionNotify:
event.type = ev_mouse;
event.data1 =
(X_event.xmotion.state & Button1Mask)
| (X_event.xmotion.state & Button2Mask ? 2 : 0)
| (X_event.xmotion.state & Button3Mask ? 4 : 0);
event.data2 = (X_event.xmotion.x - lastmousex) << 2;
event.data3 = (lastmousey - X_event.xmotion.y) << 2;
if (event.data2 || event.data3)
{
lastmousex = X_event.xmotion.x;
lastmousey = X_event.xmotion.y;
if (X_event.xmotion.x != X_width/2 &&
X_event.xmotion.y != X_height/2)
{
D_PostEvent(&event);
// fprintf(stderr, "m");
mousemoved = false;
} else
{
mousemoved = true;
}
}
break;
case Expose:
case ConfigureNotify:
break;
default:
if (doShm && X_event.type == X_shmeventtype) shmFinished = true;
break;
#endif
}
}
}
//
// I_StartTic
//
void I_StartTic (void)
{
I_GetEvent();
#if 0
if (!X_display)
return;
while (XPending(X_display))
I_GetEvent();
// Warp the pointer back to the middle of the window
// or it will wander off - that is, the game will
// loose input focus within X11.
if (grabMouse)
{
if (!--doPointerWarp)
{
XWarpPointer( X_display,
None,
X_mainWindow,
0, 0,
0, 0,
X_width/2, X_height/2);
doPointerWarp = POINTER_WARP_COUNTDOWN;
}
}
mousemoved = false;
#endif
}
//
// I_UpdateNoBlit
//
void I_UpdateNoBlit (void)
{
// what is this?
}
//
// I_FinishUpdate
//
void I_FinishUpdate (void)
{
static int lasttic;
int tics;
int i;
// UNUSED static unsigned char *bigscreen=0;
// draws little dots on the bottom of the screen
if (devparm)
{
i = I_GetTime();
tics = i - lasttic;
lasttic = i;
if (tics > 20) tics = 20;
for (i=0 ; i<tics*2 ; i+=2)
screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
for ( ; i<20*2 ; i+=2)
screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
}
// scales the screen size before blitting it
if (multiply == 2)
{
unsigned int *olineptrs[2];
unsigned int *ilineptr;
int x, y, i;
unsigned int twoopixels;
unsigned int twomoreopixels;
unsigned int fouripixels;
unsigned int X_width = screen->pitch;
Uint8 *screen_pixels = (Uint8 *) screen->pixels;
SDL_LockSurface(screen);
ilineptr = (unsigned int *) (screens[0]);
for (i=0 ; i<2 ; i++)
olineptrs[i] = (unsigned int *) &screen_pixels[i*X_width];
y = SCREENHEIGHT;
while (y--)
{
x = SCREENWIDTH;
do
{
fouripixels = *ilineptr++;
twoopixels = (fouripixels & 0xff000000)
| ((fouripixels>>8) & 0xffff00)
| ((fouripixels>>16) & 0xff);
twomoreopixels = ((fouripixels<<16) & 0xff000000)
| ((fouripixels<<8) & 0xffff00)
| (fouripixels & 0xff);
#ifdef __BIG_ENDIAN__
*olineptrs[0]++ = twoopixels;
*olineptrs[1]++ = twoopixels;
*olineptrs[0]++ = twomoreopixels;
*olineptrs[1]++ = twomoreopixels;
#else
*olineptrs[0]++ = twomoreopixels;
*olineptrs[1]++ = twomoreopixels;
*olineptrs[0]++ = twoopixels;
*olineptrs[1]++ = twoopixels;
#endif
} while (x-=4);
olineptrs[0] += X_width/4;
olineptrs[1] += X_width/4;
}
SDL_UnlockSurface(screen);
}
#if 0
else if (multiply == 3)
{
unsigned int *olineptrs[3];
unsigned int *ilineptr;
int x, y, i;
unsigned int fouropixels[3];
unsigned int fouripixels;
ilineptr = (unsigned int *) (screens[0]);
for (i=0 ; i<3 ; i++)
olineptrs[i] = (unsigned int *) &image->data[i*X_width];
y = SCREENHEIGHT;
while (y--)
{
x = SCREENWIDTH;
do
{
fouripixels = *ilineptr++;
fouropixels[0] = (fouripixels & 0xff000000)
| ((fouripixels>>8) & 0xff0000)
| ((fouripixels>>16) & 0xffff);
fouropixels[1] = ((fouripixels<<8) & 0xff000000)
| (fouripixels & 0xffff00)
| ((fouripixels>>8) & 0xff);
fouropixels[2] = ((fouripixels<<16) & 0xffff0000)
| ((fouripixels<<8) & 0xff00)
| (fouripixels & 0xff);
#ifdef __BIG_ENDIAN__
*olineptrs[0]++ = fouropixels[0];
*olineptrs[1]++ = fouropixels[0];
*olineptrs[2]++ = fouropixels[0];
*olineptrs[0]++ = fouropixels[1];
*olineptrs[1]++ = fouropixels[1];
*olineptrs[2]++ = fouropixels[1];
*olineptrs[0]++ = fouropixels[2];
*olineptrs[1]++ = fouropixels[2];
*olineptrs[2]++ = fouropixels[2];
#else
*olineptrs[0]++ = fouropixels[2];
*olineptrs[1]++ = fouropixels[2];
*olineptrs[2]++ = fouropixels[2];
*olineptrs[0]++ = fouropixels[1];
*olineptrs[1]++ = fouropixels[1];
*olineptrs[2]++ = fouropixels[1];
*olineptrs[0]++ = fouropixels[0];
*olineptrs[1]++ = fouropixels[0];
*olineptrs[2]++ = fouropixels[0];
#endif
} while (x-=4);
olineptrs[0] += 2*X_width/4;
olineptrs[1] += 2*X_width/4;
olineptrs[2] += 2*X_width/4;
}
}
else if (multiply == 4)
{
// Broken. Gotta fix this some day.
void Expand4(unsigned *, double *);
Expand4 ((unsigned *)(screens[0]), (double *) (image->data));
}
#endif
// draw to screen
if (palette_to_set)
{
SDL_SetColors(screen, palette, 0, 256);
palette_to_set = 0;
}
else
{
SDL_Flip(screen);
}
}
//
// I_ReadScreen
//
void I_ReadScreen (byte* scr)
{
memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
}
//
// I_SetPalette
//
void I_SetPalette (byte *doompalette)
{
int i;
for (i=0; i<256; ++i)
{
palette[i].r = *doompalette++;
palette[i].g = *doompalette++;
palette[i].b = *doompalette++;
}
palette_to_set = 1;
}
void I_InitGraphics(void)
{
int flags = 0;
SDL_Init(SDL_INIT_VIDEO);
flags |= SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF;
// default to fullscreen mode, allow override with command line
// nofullscreen because we love prboom
if (!M_CheckParm("-window") && !M_CheckParm("-nofullscreen"))
{
flags |= SDL_FULLSCREEN;
}
// scale-by-2 mode
if (M_CheckParm("-2"))
{
multiply = 2;
}
screen = SDL_SetVideoMode(SCREENWIDTH*multiply, SCREENHEIGHT*multiply, 8, flags);
if (screen == NULL)
{
I_Error("Error setting video mode: %s\n", SDL_GetError());
}
if (multiply == 1)
screens[0] = (unsigned char *) (screen->pixels);
else
screens[0] = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
SDL_ShowCursor(0);
SDL_WM_GrabInput(SDL_GRAB_ON);
LoadDiskImage();
{
SDL_Event dummy;
while (SDL_PollEvent(&dummy));
}
}
unsigned exptable[256];
void InitExpand (void)
{
int i;
for (i=0 ; i<256 ; i++)
exptable[i] = i | (i<<8) | (i<<16) | (i<<24);
}
double exptable2[256*256];
void InitExpand2 (void)
{
int i;
int j;
// UNUSED unsigned iexp, jexp;
double* exp;
union
{
double d;
unsigned u[2];
} pixel;
exp = exptable2;
for (i=0 ; i<256 ; i++)
{
pixel.u[0] = i | (i<<8) | (i<<16) | (i<<24);
for (j=0 ; j<256 ; j++)
{
pixel.u[1] = j | (j<<8) | (j<<16) | (j<<24);
*exp++ = pixel.d;
}
}
}
int inited;
void
Expand4
( unsigned* lineptr,
double* xline )
{
double dpixel;
unsigned x;
unsigned y;
unsigned fourpixels;
unsigned step;
double* exp;
exp = exptable2;
if (!inited)
{
inited = 1;
InitExpand2 ();
}
step = 3*SCREENWIDTH/2;
y = SCREENHEIGHT-1;
do
{
x = SCREENWIDTH;
do
{
fourpixels = lineptr[0];
dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
xline[0] = dpixel;
xline[160] = dpixel;
xline[320] = dpixel;
xline[480] = dpixel;
dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
xline[1] = dpixel;
xline[161] = dpixel;
xline[321] = dpixel;
xline[481] = dpixel;
fourpixels = lineptr[1];
dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
xline[2] = dpixel;
xline[162] = dpixel;
xline[322] = dpixel;
xline[482] = dpixel;
dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
xline[3] = dpixel;
xline[163] = dpixel;
xline[323] = dpixel;
xline[483] = dpixel;
fourpixels = lineptr[2];
dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
xline[4] = dpixel;
xline[164] = dpixel;
xline[324] = dpixel;
xline[484] = dpixel;
dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
xline[5] = dpixel;
xline[165] = dpixel;
xline[325] = dpixel;
xline[485] = dpixel;
fourpixels = lineptr[3];
dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
xline[6] = dpixel;
xline[166] = dpixel;
xline[326] = dpixel;
xline[486] = dpixel;
dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
xline[7] = dpixel;
xline[167] = dpixel;
xline[327] = dpixel;
xline[487] = dpixel;
lineptr+=4;
xline+=8;
} while (x-=16);
xline += step;
} while (y--);
}