// ID_VL.C
#include dos.h
#include alloc.h
#include mem.h
#include string.h
#include "ID_HEAD.H"
#include "ID_VL.H"
#pragma hdrstop
//
// SC_INDEX is expected to stay at SC_MAPMASK for proper operation
//
unsigned bufferofs;
unsigned displayofs,pelpan;
unsigned screenseg=screenSEG; // set to 0xa000 for asm convenience
unsigned linewidth;
unsigned ylookup[MAXSCANLINES];
boolean screenfaded;
unsigned bordercolor;
boolean fastpalette; // if true, use outsb to set
byte far palette1[256][3],far palette2[256][3];
//===========================================================================
// asm
int VL_videoID (void);
void VL_SetCRTC (int crtc);
void VL_Setscreen (int crtc, int pelpan);
void VL_WaitVBL (int vbls);
//===========================================================================
/*
=======================
=
= VL_Startup
=
=======================
*/
#if 0
void VL_Startup (void)
{
if ( !MS_CheckParm ("HIDDENCARD") && VL_videoID () != 5)
MS_Quit ("You need a VGA graphics card to run this!");
asm cld; // all string instructions assume forward
}
#endif
/*
=======================
=
= VL_Startup // WOLFENSTEIN HACK
=
=======================
*/
static char *ParmStrings[] = {"HIDDENCARD",""};
void VL_Startup (void)
{
int i,videocard;
asm cld;
videocard = VL_videoID ();
for (i = 1;i _argc;i++)
if (US_CheckParm(_argv[i],ParmStrings) == 0)
{
videocard = 5;
break;
}
if (videocard != 5)
Quit ("Improper video card! If you really have a VGA card that I am not \n"
"detecting, use the -HIDDENCARD command line parameter!");
}
/*
=======================
=
= VL_Shutdown
=
=======================
*/
void VL_Shutdown (void)
{
VL_SetTextMode ();
}
/*
=======================
=
= VL_SetVGAPlaneMode
=
=======================
*/
void VL_SetVGAPlaneMode (void)
{
asm mov ax,0x13
asm int 0x10
VL_DePlaneVGA ();
VGAMAPMASK(15);
VL_SetLineWidth (40);
}
/*
=======================
=
= VL_SetTextMode
=
=======================
*/
void VL_SetTextMode (void)
{
asm mov ax,3
asm int 0x10
}
//===========================================================================
/*
=================
=
= VL_Clearvideo
=
= Fill the entire video buffer with a given color
=
=================
*/
void VL_Clearvideo (byte color)
{
asm mov dx,GC_INDEX
asm mov al,GC_Mode
asm out dx,al
asm inc dx
asm in al,dx
asm and al,0xfc // write Mode 0 to store directly to video
asm out dx,al
asm mov dx,SC_INDEX
asm mov ax,SC_MAPMASK+15*256
asm out dx,ax // write through all four planes
asm mov ax,screenSEG
asm mov es,ax
asm mov al,[color]
asm mov ah,al
asm mov cx,0x8000 // 0x8000 words, clearing 8 video bytes/word
asm xor di,di
asm rep stosw
}
/*
=============================================================================
VGA REGISTER MANAGEMENT ROUTINES
=============================================================================
*/
/*
=================
=
= VL_DePlaneVGA
=
=================
*/
void VL_DePlaneVGA (void)
{
//
// change CPU addressing to non linear Mode
//
//
// turn off chain 4 and odd/even
//
outportb (SC_INDEX,SC_MEMMode);
outportb (SC_INDEX+1,(inportb(SC_INDEX+1)&~8)|4);
outportb (SC_INDEX,SC_MAPMASK); // leave this set throughought
//
// turn off odd/even and set write Mode 0
//
outportb (GC_INDEX,GC_Mode);
outportb (GC_INDEX+1,inportb(GC_INDEX+1)&~0x13);
//
// turn off chain
//
outportb (GC_INDEX,GC_MISCELLANEOUS);
outportb (GC_INDEX+1,inportb(GC_INDEX+1)&~2);
//
// clear the entire buffer space, because int 10h only did 16 k / plane
//
VL_Clearvideo (0);
//
// change CRTC scanning from doubleword to byte Mode, allowing >64k scans
//
outportb (CRTC_INDEX,CRTC_UNDERLINE);
outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1)&~0x40);
outportb (CRTC_INDEX,CRTC_Mode);
outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1)|0x40);
}
//===========================================================================
/*
====================
=
= VL_SetLineWidth
=
= Line witdh is in WORDS, 40 words is normal width for vgaplanegr
=
====================
*/
void VL_SetLineWidth (unsigned width)
{
int i,offset;
//
// set wide virtual screen
//
outport (CRTC_INDEX,CRTC_OFFSET+width*256);
//
// set up lookup tables
//
linewidth = width*2;
offset = 0;
for (i=0;i MAXSCANLINES;i++)
{
ylookup[i]=offset;
offset += linewidth;
}
}
/*
====================
=
= VL_SetSplitscreen
=
====================
*/
void VL_SetSplitscreen (int linenum)
{
VL_WaitVBL (1);
linenum=linenum*2-1;
outportb (CRTC_INDEX,CRTC_LINECOMPARE);
outportb (CRTC_INDEX+1,linenum % 256);
outportb (CRTC_INDEX,CRTC_OVERFLOW);
outportb (CRTC_INDEX+1, 1+16*(linenum/256));
outportb (CRTC_INDEX,CRTC_MAXSCANLINE);
outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1) & (255-64));
}
/*
=============================================================================
palette OPS
To avoid snow, do a WaitVBL BEFORE calling these
=============================================================================
*/
/*
=================
=
= VL_Fillpalette
=
=================
*/
void VL_Fillpalette (int red, int green, int blue)
{
int i;
outportb (PEL_WRITE_ADR,0);
for (i=0;i 256;i++)
{
outportb (PEL_DATA,red);
outportb (PEL_DATA,green);
outportb (PEL_DATA,blue);
}
}
//===========================================================================
/*
=================
=
= VL_SetColor
=
=================
*/
void VL_SetColor (int color, int red, int green, int blue)
{
outportb (PEL_WRITE_ADR,color);
outportb (PEL_DATA,red);
outportb (PEL_DATA,green);
outportb (PEL_DATA,blue);
}
//===========================================================================
/*
=================
=
= VL_GetColor
=
=================
*/
void VL_GetColor (int color, int *red, int *green, int *blue)
{
outportb (PEL_READ_ADR,color);
*red = inportb (PEL_DATA);
*green = inportb (PEL_DATA);
*blue = inportb (PEL_DATA);
}
//===========================================================================
/*
=================
=
= VL_Setpalette
=
= If fast palette setting has been tested for, it is used
= (some cards don't like outsb palette setting)
=
=================
*/
void VL_Setpalette (byte far *palette)
{
int i;
// outportb (PEL_WRITE_ADR,0);
// for (i=0;i 768;i++)
// outportb(PEL_DATA,*palette++);
asm mov dx,PEL_WRITE_ADR
asm mov al,0
asm out dx,al
asm mov dx,PEL_DATA
asm lds si,[palette]
asm test [ss:fastpalette],1
asm jz slowset
//
// set palette fast for cards that can take it
//
asm mov cx,768
asm rep outsb
asm jmp done
//
// set palette slowly for some video cards
//
slowset:
asm mov cx,256
setloop:
asm lodsb
asm out dx,al
asm lodsb
asm out dx,al
asm lodsb
asm out dx,al
asm loop setloop
done:
asm mov ax,ss
asm mov ds,ax
}
//===========================================================================
/*
=================
=
= VL_Getpalette
=
= This does not use the port string instructions,
= due to some incompatabilities
=
=================
*/
void VL_Getpalette (byte far *palette)
{
int i;
outportb (PEL_READ_ADR,0);
for (i=0;i 768;i++)
*palette++ = inportb(PEL_DATA);
}
//===========================================================================
/*
=================
=
= VL_FadeOut
=
= Fades the current palette to the given color in the given number of steps
=
=================
*/
void VL_FadeOut (int start, int end, int red, int green, int blue, int steps)
{
int i,j,orig,delta;
byte far *origptr, far *newptr;
VL_WaitVBL(1);
VL_Getpalette (&palette1[0][0]);
_fmemcpy (palette2,palette1,768);
//
// fade through intermediate frames
//
for (i=0;i steps;i++)
{
origptr = &palette1[start][0];
newptr = &palette2[start][0];
for (j=start;j =end;j++)
{
orig = *origptr++;
delta = red-orig;
*newptr++ = orig + delta * i / steps;
orig = *origptr++;
delta = green-orig;
*newptr++ = orig + delta * i / steps;
orig = *origptr++;
delta = blue-orig;
*newptr++ = orig + delta * i / steps;
}
VL_WaitVBL(1);
VL_Setpalette (&palette2[0][0]);
}
//
// final color
//
VL_Fillpalette (red,green,blue);
screenfaded = true;
}
/*
=================
=
= VL_FadeIn
=
=================
*/
void VL_FadeIn (int start, int end, byte far *palette, int steps)
{
int i,j,delta;
VL_WaitVBL(1);
VL_Getpalette (&palette1[0][0]);
_fmemcpy (&palette2[0][0],&palette1[0][0],sizeof(palette1));
start *= 3;
end = end*3+2;
//
// fade through intermediate frames
//
for (i=0;i steps;i++)
{
for (j=start;j =end;j++)
{
delta = palette[j]-palette1[0][j];
palette2[0][j] = palette1[0][j] + delta * i / steps;
}
VL_WaitVBL(1);
VL_Setpalette (&palette2[0][0]);
}
//
// final color
//
VL_Setpalette (palette);
screenfaded = false;
}
/*
=================
=
= VL_TestpaletteSet
=
= Sets the palette with outsb, then reads it in and compares
= If it compares ok, fastpalette is set to true.
=
=================
*/
void VL_TestpaletteSet (void)
{
int i;
for (i=0;i 768;i++)
palette1[0][i] = i;
fastpalette = true;
VL_Setpalette (&palette1[0][0]);
VL_Getpalette (&palette2[0][0]);
if (_fmemcmp (&palette1[0][0],&palette2[0][0],768))
fastpalette = false;
}
/*
==================
=
= VL_ColorBorder
=
==================
*/
void VL_ColorBorder (int color)
{
_AH=0x10;
_AL=1;
_BH=color;
geninterrupt (0x10);
bordercolor = color;
}
/*
=============================================================================
PIXEL OPS
=============================================================================
*/
byte pixmasks[4] = {1,2,4,8};
byte leftmasks[4] = {15,14,12,8};
byte rightmasks[4] = {1,3,7,15};
/*
=================
=
= VL_Plot
=
=================
*/
void VL_Plot (int x, int y, int color)
{
byte mask;
mask = pixmasks[x&3];
VGAMAPMASK(mask);
*(byte far *)MK_FP(screenSEG,bufferofs+(ylookup[y]+(x>>2))) = color;
VGAMAPMASK(15);
}
/*
=================
=
= VL_Hlin
=
=================
*/
void VL_Hlin (unsigned x, unsigned y, unsigned width, unsigned color)
{
unsigned xbyte;
byte far *dest;
byte leftmask,rightmask;
int midbytes;
xbyte = x>>2;
leftmask = leftmasks[x&3];
rightmask = rightmasks[(x+width-1)&3];
midbytes = ((x+width+3)>>2) - xbyte - 2;
dest = MK_FP(screenSEG,bufferofs+ylookup[y]+xbyte);
if (midbytes 0)
{
// all in one byte
VGAMAPMASK(leftmask&rightmask);
*dest = color;
VGAMAPMASK(15);
return;
}
VGAMAPMASK(leftmask);
*dest++ = color;
VGAMAPMASK(15);
_fmemset (dest,color,midbytes);
dest+=midbytes;
VGAMAPMASK(rightmask);
*dest = color;
VGAMAPMASK(15);
}
/*
=================
=
= VL_Vlin
=
=================
*/
void VL_Vlin (int x, int y, int height, int color)
{
byte far *dest,mask;
mask = pixmasks[x&3];
VGAMAPMASK(mask);
dest = MK_FP(screenSEG,bufferofs+ylookup[y]+(x>>2));
while (height--)
{
*dest = color;
dest += linewidth;
}
VGAMAPMASK(15);
}
/*
=================
=
= VL_Bar
=
=================
*/
void VL_Bar (int x, int y, int width, int height, int color)
{
byte far *dest;
byte leftmask,rightmask;
int midbytes,linedelta;
leftmask = leftmasks[x&3];
rightmask = rightmasks[(x+width-1)&3];
midbytes = ((x+width+3)>>2) - (x>>2) - 2;
linedelta = linewidth-(midbytes+1);
dest = MK_FP(screenSEG,bufferofs+ylookup[y]+(x>>2));
if (midbytes 0)
{
// all in one byte
VGAMAPMASK(leftmask&rightmask);
while (height--)
{
*dest = color;
dest += linewidth;
}
VGAMAPMASK(15);
return;
}
while (height--)
{
VGAMAPMASK(leftmask);
*dest++ = color;
VGAMAPMASK(15);
_fmemset (dest,color,midbytes);
dest+=midbytes;
VGAMAPMASK(rightmask);
*dest = color;
dest+=linedelta;
}
VGAMAPMASK(15);
}
/*
============================================================================
MEMORY OPS
============================================================================
*/
/*
=================
=
= VL_MemToLatch
=
=================
*/
void VL_MemToLatch (byte far *source, int width, int height, unsigned dest)
{
unsigned count;
byte plane,mask;
count = ((width+3)/4)*height;
mask = 1;
for (plane = 0; plane 4 ; plane++)
{
VGAMAPMASK(mask);
mask = 1;
asm mov cx,count
asm mov ax,screenSEG
asm mov es,ax
asm mov di,[dest]
asm lds si,[source]
asm rep movsb
asm mov ax,ss
asm mov ds,ax
source+= count;
}
}
//===========================================================================
/*
=================
=
= VL_MemToscreen
=
= Draws a block of data to the screen.
=
=================
*/
void VL_MemToscreen (byte far *source, int width, int height, int x, int y)
{
byte far *screen,far *dest,mask;
int plane;
width>>=2;
dest = MK_FP(screenSEG,bufferofs+ylookup[y]+(x>>2) );
mask = 1 (x&3);
for (plane = 0; plane 4; plane++)
{
VGAMAPMASK(mask);
mask = 1;
if (mask == 16)
mask = 1;
screen = dest;
for (y=0;y height;y++,screen+=linewidth,source+=width)
_fmemcpy (screen,source,width);
}
}
//==========================================================================
/*
=================
=
= VL_MaskedToscreen
=
= masks a block of main memory to the screen.
=
=================
*/
void VL_MaskedToscreen (byte far *source, int width, int height, int x, int y)
{
byte far *screen,far *dest,mask;
byte far *maskptr;
int plane;
width>>=2;
dest = MK_FP(screenSEG,bufferofs+ylookup[y]+(x>>2) );
// mask = 1 (x&3);
// maskptr = source;
for (plane = 0; plane 4; plane++)
{
VGAMAPMASK(mask);
mask = 1;
if (mask == 16)
mask = 1;
screen = dest;
for (y=0;y height;y++,screen+=linewidth,source+=width)
_fmemcpy (screen,source,width);
}
}
//==========================================================================
/*
=================
=
= VL_LatchToscreen
=
=================
*/
void VL_LatchToscreen (unsigned source, int width, int height, int x, int y)
{
VGAWRITEMode(1);
VGAMAPMASK(15);
asm mov di,[y] // dest = bufferofs+ylookup[y]+(x>>2)
asm shl di,1
asm mov di,[WORD PTR ylookup+di]
asm add di,[bufferofs]
asm mov ax,[x]
asm shr ax,2
asm add di,ax
asm mov si,[source]
asm mov ax,[width]
asm mov bx,[linewidth]
asm sub bx,ax
asm mov dx,[height]
asm mov cx,screenSEG
asm mov ds,cx
asm mov es,cx
drawline:
asm mov cx,ax
asm rep movsb
asm add di,bx
asm dec dx
asm jnz drawline
asm mov ax,ss
asm mov ds,ax
VGAWRITEMode(0);
}
//===========================================================================
#if 0
/*
=================
=
= VL_screenToscreen
=
=================
*/
void VL_screenToscreen (unsigned source, unsigned dest,int width, int height)
{
VGAWRITEMode(1);
VGAMAPMASK(15);
asm mov si,[source]
asm mov di,[dest]
asm mov ax,[width]
asm mov bx,[linewidth]
asm sub bx,ax
asm mov dx,[height]
asm mov cx,screenSEG
asm mov ds,cx
asm mov es,cx
drawline:
asm mov cx,ax
asm rep movsb
asm add si,bx
asm add di,bx
asm dec dx
asm jnz drawline
asm mov ax,ss
asm mov ds,ax
VGAWRITEMode(0);
}
#endif
/*
=============================================================================
STRING OUTPUT ROUTINES
=============================================================================
*/
/*
===================
=
= VL_DrawTile8String
=
===================
*/
void VL_DrawTile8String (char *str, char far *tile8ptr, int printx, int printy)
{
int i;
unsigned far *dest,far *screen,far *src;
dest = MK_FP(screenSEG,bufferofs+ylookup[printy]+(printx>>2));
while (*str)
{
src = (unsigned far *)(tile8ptr + (*str 6));
// each character is 64 bytes
VGAMAPMASK(1);
screen = dest;
for (i=0;i 8;i++,screen+=linewidth)
*screen = *src++;
VGAMAPMASK(2);
screen = dest;
for (i=0;i 8;i++,screen+=linewidth)
*screen = *src++;
VGAMAPMASK(4);
screen = dest;
for (i=0;i 8;i++,screen+=linewidth)
*screen = *src++;
VGAMAPMASK(8);
screen = dest;
for (i=0;i 8;i++,screen+=linewidth)
*screen = *src++;
str++;
printx += 8;
dest+=2;
}
}
/*
===================
=
= VL_DrawLatch8String
=
===================
*/
void VL_DrawLatch8String (char *str, unsigned tile8ptr, int printx, int printy)
{
int i;
unsigned src,dest;
dest = bufferofs+ylookup[printy]+(printx>>2);
VGAWRITEMode(1);
VGAMAPMASK(15);
while (*str)
{
src = tile8ptr + (*str 4); // each character is 16 latch bytes
asm mov si,[src]
asm mov di,[dest]
asm mov dx,[linewidth]
asm mov ax,screenSEG
asm mov ds,ax
asm lodsw
asm mov [di],ax
asm add di,dx
asm lodsw
asm mov [di],ax
asm add di,dx
asm lodsw
asm mov [di],ax
asm add di,dx
asm lodsw
asm mov [di],ax
asm add di,dx
asm lodsw
asm mov [di],ax
asm add di,dx
asm lodsw
asm mov [di],ax
asm add di,dx
asm lodsw
asm mov [di],ax
asm add di,dx
asm lodsw
asm mov [di],ax
asm add di,dx
asm mov ax,ss
asm mov ds,ax
str++;
printx += 8;
dest+=2;
}
VGAWRITEMode(0);
}
/*
===================
=
= VL_SizeTile8String
=
===================
*/
void VL_SizeTile8String (char *str, int *width, int *height)
{
*height = 8;
*width = 8*strlen(str);
}
; ID_VL.asm
IDEAL
ModeL MEDIUM,C
INCLUDE 'ID_VL.EQU'
screenSEG = 0a000h
UPDATEWIDE = 20
UPDATEHIGH = 13
DATASEG
EXTRN bufferofs :WORD
EXTRN displayofs :WORD
EXTRN ylookup :WORD
EXTRN linewidth :WORD
EXTRN blockstarts :WORD ;offsets from drawofs for each update block
EXTRN update :BYTE
CODESEG
;=================
;
; VH_Updatescreen
;
;=================
PROC VH_Updatescreen
PUBLIC VH_Updatescreen
USES si,di
mov dx,SC_INDEX
mov ax,SC_MAPMASK+15*256
out dx,ax
mov dx,GC_INDEX
mov al,GC_Mode
out dx,al
inc dx
in al,dx
and al,252
or al,1
out dx,al
mov bx,UPDATEWIDE*UPDATEHIGH-1 ; bx is the tile number
mov dx,[linewidth]
;
; see if the tile needs to be copied
;
@@checktile:
test [update+bx],1
jnz @@copytile
@@next:
dec bx
jns @@checktile
;
; done
;
mov dx,GC_INDEX+1
in al,dx
and al,NOT 3
or al,0
out dx,al
ret
;
; copy a tile
;
@@copytile:
mov [update+bx],0
shl bx,1
mov si,[blockstarts+bx]
shr bx,1
mov di,si
add si,[bufferofs]
add di,[displayofs]
mov ax,screenSEG
mov ds,ax
REPT 16
mov al,[si]
mov [di],al
mov al,[si+1]
mov [di+1],al
mov al,[si+2]
mov [di+2],al
mov al,[si+3]
mov [di+3],al
add si,dx
add di,dx
ENDM
mov ax,ss
mov ds,ax
jmp @@next
ENDP
END
// ID_VH.H
#define WHITE 15 // graphics Mode independant colors
#define BLACK 0
#define FIRSTCOLOR 1
#define SECONDCOLOR 12
#define F_WHITE 15
#define F_BLACK 0
#define F_FIRSTCOLOR 1
#define F_SECONDCOLOR 12
//===========================================================================
#define MAXSHIFTS 1
typedef struct
{
int width,
height,
orgx,orgy,
xl,yl,xh,yh,
shifts;
} spritetabletype;
typedef struct
{
unsigned sourceoffset[MAXSHIFTS];
unsigned planesize[MAXSHIFTS];
unsigned width[MAXSHIFTS];
byte data[];
} spritetype; // the memptr for each sprite points to this
typedef struct
{
int width,height;
} pictabletype;
typedef struct
{
int height;
int location[256];
char width[256];
} fontstruct;
//===========================================================================
extern pictabletype _seg *pictable;
extern pictabletype _seg *picmtable;
extern spritetabletype _seg *spritetable;
extern byte fontcolor;
extern int fontnumber;
extern int px,py;
//
// Double buffer management routines
//
void VW_InitDoubleBuffer (void);
int VW_MarkUpdateBlock (int x1, int y1, int x2, int y2);
void VW_Updatescreen (void);
//
// Mode independant routines
// coordinates in pixels, rounded to best screen res
// regions marked in double buffer
//
void VWB_DrawTile8 (int x, int y, int tile);
void VWB_DrawTile8M (int x, int y, int tile);
void VWB_DrawTile16 (int x, int y, int tile);
void VWB_DrawTile16M (int x, int y, int tile);
void VWB_DrawPic (int x, int y, int chunknum);
void VWB_DrawMPic(int x, int y, int chunknum);
void VWB_Bar (int x, int y, int width, int height, int color);
void VWB_DrawPropString (char far *string);
void VWB_DrawMPropString (char far *string);
void VWB_DrawSprite (int x, int y, int chunknum);
void VWB_Plot (int x, int y, int color);
void VWB_Hlin (int x1, int x2, int y, int color);
void VWB_Vlin (int y1, int y2, int x, int color);
//
// wolfenstein EGA compatability stuff
//
extern byte far gamepal;
void VH_SetDefaultColors (void);
#define VW_Startup VL_Startup
#define VW_Shutdown VL_Shutdown
#define VW_SetCRTC VL_SetCRTC
#define VW_Setscreen VL_Setscreen
#define VW_Bar VL_Bar
#define VW_Plot VL_Plot
#define VW_Hlin(x,z,y,c) VL_Hlin(x,y,(z)-(x)+1,c)
#define VW_Vlin(y,z,x,c) VL_Vlin(x,y,(z)-(y)+1,c)
#define VW_DrawPic VH_DrawPic
#define VW_SetSplitscreen VL_SetSplitscreen
#define VW_SetLineWidth VL_SetLineWidth
#define VW_ColorBorder VL_ColorBorder
#define VW_WaitVBL VL_WaitVBL
#define VW_FadeIn() VL_FadeIn(0,255,&gamepal,30);
#define VW_FadeOut() VL_FadeOut(0,255,0,0,0,30);
#define VW_screenToscreen VL_screenToscreen
#define VW_SetDefaultColors VH_SetDefaultColors
void VW_MeasurePropString (char far *string, word *width, word *height);
#define EGAMAPMASK(x) VGAMAPMASK(x)
#define EGAWRITEMode(x) VGAWRITEMode(x)
//#define VW_MemToscreen VL_MemToLatch
#define MS_Quit Quit
#define LatchDrawChar(x,y,p) VL_LatchToscreen(latchpics[0]+(p)*16,2,8,x,y)
#define LatchDrawTile(x,y,p) VL_LatchToscreen(latchpics[1]+(p)*64,4,16,x,y)
void LatchDrawPic (unsigned x, unsigned y, unsigned picnum);
void LoadLatchMem (void);
boolean FizzleFade (unsigned source, unsigned dest,
unsigned width,unsigned height, unsigned frames,boolean abortable);
#define NUMLATCHPICS 100
extern unsigned latchpics[NUMLATCHPICS];
extern unsigned freelatch;