Files
Catacomb3D/ID_VW.C
2026-03-12 19:22:23 +01:00

1542 lines
28 KiB
C

/* Catacomb 3-D Source Code
* Copyright (C) 1993-2014 Flat Rock Software
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
// ID_VW.C
#include "ID_HEADS.H"
/*
=============================================================================
LOCAL CONSTANTS
=============================================================================
*/
#define VIEWWIDTH 40
#define PIXTOBLOCK 4 // 16 pixels to an update block
/*
=============================================================================
GLOBAL VARIABLES
=============================================================================
*/
cardtype videocard; // set by VW_Startup
grtype grmode; // CGAgr, EGAgr, VGAgr
unsigned bufferofs; // hidden area to draw to before displaying
unsigned displayofs; // origin of the visable screen
unsigned panx,pany; // panning adjustments inside port in pixels
unsigned pansx,pansy; // panning adjustments inside port in screen
// block limited pixel values (ie 0/8 for ega x)
unsigned panadjust; // panx/pany adjusted by screen resolution
unsigned screenseg; // normally 0xa000 / 0xb800
unsigned linewidth;
unsigned ylookup[VIRTUALHEIGHT];
unsigned fontnumber; // 0 based font number for drawing
boolean screenfaded;
pictabletype _seg *pictable;
pictabletype _seg *picmtable;
spritetabletype _seg *spritetable;
int bordercolor;
/*
=============================================================================
LOCAL VARIABLES
=============================================================================
*/
void VWL_MeasureString (char far *string, word *width, word *height,
fontstruct _seg *font);
void VWL_DrawCursor (void);
void VWL_EraseCursor (void);
void VWL_DBSetup (void);
void VWL_UpdateScreenBlocks (void);
int bordercolor;
int cursorvisible;
int cursornumber,cursorwidth,cursorheight,cursorx,cursory;
memptr cursorsave;
unsigned cursorspot;
//===========================================================================
/*
=======================
=
= VW_Startup
=
=======================
*/
static char *ParmStrings[] = {"HIDDENCARD",""};
void VW_Startup (void)
{
int i;
asm cld;
videocard = 0;
for (i = 1;i < _argc;i++)
if (US_CheckParm(_argv[i],ParmStrings) == 0)
{
videocard = EGAcard;
break;
}
if (!videocard)
videocard = VW_VideoID ();
#if GRMODE == EGAGR
grmode = EGAGR;
if (videocard != EGAcard && videocard != VGAcard)
Quit ("Improper video card! If you really have an EGA/VGA card that I am not \n"
"detecting, use the -HIDDENCARD command line parameter!");
EGAWRITEMODE(0);
#endif
#if GRMODE == CGAGR
grmode = CGAGR;
if (videocard < CGAcard || videocard > VGAcard)
Quit ("Improper video card! If you really have a CGA card that I am not \n"
"detecting, use the -HIDDENCARD command line parameter!");
MM_GetPtr (&(memptr)screenseg,0x10000l); // grab 64k for floating screen
#endif
cursorvisible = 0;
}
//===========================================================================
/*
=======================
=
= VW_Shutdown
=
=======================
*/
void VW_Shutdown (void)
{
VW_SetScreenMode (TEXTGR);
#if GRMODE == EGAGR
VW_SetLineWidth (80);
#endif
}
//===========================================================================
/*
========================
=
= VW_SetScreenMode
= Call BIOS to set TEXT / CGAgr / EGAgr / VGAgr
=
========================
*/
void VW_SetScreenMode (int grmode)
{
switch (grmode)
{
case TEXTGR: _AX = 3;
geninterrupt (0x10);
screenseg=0xb000;
break;
case CGAGR: _AX = 4;
geninterrupt (0x10); // screenseg is actually a main mem buffer
break;
case EGAGR: _AX = 0xd;
geninterrupt (0x10);
screenseg=0xa000;
break;
#ifdef VGAGAME
case VGAGR:{
char extern VGAPAL; // deluxepaint vga pallet .OBJ file
void far *vgapal = &VGAPAL;
SetCool256 (); // custom 256 color mode
screenseg=0xa000;
_ES = FP_SEG(vgapal);
_DX = FP_OFF(vgapal);
_BX = 0;
_CX = 0x100;
_AX = 0x1012;
geninterrupt(0x10); // set the deluxepaint pallet
break;
#endif
}
VW_SetLineWidth(SCREENWIDTH);
}
/*
=============================================================================
SCREEN FADES
=============================================================================
*/
char colors[7][17]=
{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,0},
{0,0,0,0,0,0,0,0,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0},
{0,1,2,3,4,5,6,7,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0},
{0,1,2,3,4,5,6,7,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0},
{0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f}};
void VW_ColorBorder (int color)
{
_AH=0x10;
_AL=1;
_BH=color;
geninterrupt (0x10);
bordercolor = color;
}
void VW_SetPalette(byte *palette)
{
byte p;
word i;
for (i = 0;i < 15;i++)
{
p = palette[i];
colors[0][i] = 0;
colors[1][i] = (p > 0x10)? (p & 0x0f) : 0;
colors[2][i] = (p > 0x10)? p : 0;
colors[3][i] = p;
colors[4][i] = (p > 0x10)? 0x1f : p;
colors[5][i] = 0x1f;
}
}
void VW_SetDefaultColors(void)
{
#if GRMODE == EGAGR
colors[3][16] = bordercolor;
_ES=FP_SEG(&colors[3]);
_DX=FP_OFF(&colors[3]);
_AX=0x1002;
geninterrupt(0x10);
screenfaded = false;
#endif
}
void VW_FadeOut(void)
{
#if GRMODE == EGAGR
int i;
for (i=3;i>=0;i--)
{
colors[i][16] = bordercolor;
_ES=FP_SEG(&colors[i]);
_DX=FP_OFF(&colors[i]);
_AX=0x1002;
geninterrupt(0x10);
VW_WaitVBL(6);
}
screenfaded = true;
#endif
}
void VW_FadeIn(void)
{
#if GRMODE == EGAGR
int i;
for (i=0;i<4;i++)
{
colors[i][16] = bordercolor;
_ES=FP_SEG(&colors[i]);
_DX=FP_OFF(&colors[i]);
_AX=0x1002;
geninterrupt(0x10);
VW_WaitVBL(6);
}
screenfaded = false;
#endif
}
void VW_FadeUp(void)
{
#if GRMODE == EGAGR
int i;
for (i=3;i<6;i++)
{
colors[i][16] = bordercolor;
_ES=FP_SEG(&colors[i]);
_DX=FP_OFF(&colors[i]);
_AX=0x1002;
geninterrupt(0x10);
VW_WaitVBL(6);
}
screenfaded = true;
#endif
}
void VW_FadeDown(void)
{
#if GRMODE == EGAGR
int i;
for (i=5;i>2;i--)
{
colors[i][16] = bordercolor;
_ES=FP_SEG(&colors[i]);
_DX=FP_OFF(&colors[i]);
_AX=0x1002;
geninterrupt(0x10);
VW_WaitVBL(6);
}
screenfaded = false;
#endif
}
/*
========================
=
= VW_SetAtrReg
=
= Sets an attribute (pallete / border) register
= Does NOT vsync!
=
========================
*/
void VW_SetAtrReg (int reg, int value)
{
asm cli
asm mov dx,STATUS_REGISTER_1
asm in al,dx
asm mov dx,ATR_INDEX
asm mov al,BYTE PTR [reg]
asm out dx,al
asm mov al,BYTE PTR [value]
asm out dx,al
asm mov dx,0x3da
asm in al,dx
asm mov dx,ATR_INDEX
asm mov al,0x20
asm out dx,al
asm sti
}
//===========================================================================
/*
====================
=
= VW_SetLineWidth
=
= Must be an even number of bytes
=
====================
*/
void VW_SetLineWidth (int width)
{
int i,offset;
#if GRMODE == EGAGR
//
// set wide virtual screen
//
asm mov dx,CRTC_INDEX
asm mov al,CRTC_OFFSET
asm mov ah,[BYTE PTR width]
asm shr ah,1
asm out dx,ax
#endif
//
// set up lookup tables
//
linewidth = width;
offset = 0;
for (i=0;i<VIRTUALHEIGHT;i++)
{
ylookup[i]=offset;
offset += width;
}
}
//===========================================================================
/*
====================
=
= VW_SetSplitScreen
=
====================
*/
void VW_SetSplitScreen (int linenum)
{
VW_WaitVBL (1);
if (videocard==VGAcard)
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));
if (videocard==VGAcard)
{
outportb (CRTC_INDEX,CRTC_MAXSCANLINE);
outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1) & (255-64));
}
}
//===========================================================================
/*
====================
=
= VW_ClearVideo
=
====================
*/
void VW_ClearVideo (int color)
{
#if GRMODE == EGAGR
EGAWRITEMODE(2);
EGAMAPMASK(15);
#endif
asm mov es,[screenseg]
asm xor di,di
asm mov cx,0xffff
asm mov al,[BYTE PTR color]
asm rep stosb
asm stosb
#if GRMODE == EGAGR
EGAWRITEMODE(0);
#endif
}
//===========================================================================
#if NUMPICS>0
/*
====================
=
= VW_DrawPic
=
= X in bytes, y in pixels, chunknum is the #defined picnum
=
====================
*/
void VW_DrawPic(unsigned x, unsigned y, unsigned chunknum)
{
int picnum = chunknum - STARTPICS;
memptr source;
unsigned dest,width,height;
source = grsegs[chunknum];
dest = ylookup[y]+x+bufferofs;
width = pictable[picnum].width;
height = pictable[picnum].height;
VW_MemToScreen(source,dest,width,height);
}
#endif
#if NUMPICM>0
/*
====================
=
= VW_DrawMPic
=
= X in bytes, y in pixels, chunknum is the #defined picnum
=
====================
*/
void VW_DrawMPic(unsigned x, unsigned y, unsigned chunknum)
{
int picnum = chunknum - STARTPICM;
memptr source;
unsigned dest,width,height;
source = grsegs[chunknum];
dest = ylookup[y]+x+bufferofs;
width = picmtable[picnum].width;
height = picmtable[picnum].height;
VW_MaskBlock(source,0,dest,width,height,width*height);
}
void VW_ClipDrawMPic(unsigned x, int y, unsigned chunknum)
{
int picnum = chunknum - STARTPICM;
memptr source;
unsigned dest,width,ofs,plane;
int height;
source = grsegs[chunknum];
width = picmtable[picnum].width;
height = picmtable[picnum].height;
plane = width*height;
ofs = 0;
if (y<0)
{
ofs= -y*width;
height+=y;
y=0;
}
else if (y+height>216)
{
height-=(y-216);
}
dest = ylookup[y]+x+bufferofs;
if (height<1)
return;
VW_MaskBlock(source,ofs,dest,width,height,plane);
}
#endif
//===========================================================================
#if NUMSPRITES>0
/*
====================
=
= VW_DrawSprite
=
= X and Y in pixels, it will match the closest shift possible
=
= To do:
= Add vertical clipping!
= Make the shifts act as center points, rather than break points
=
====================
*/
void VW_DrawSprite(int x, int y, unsigned chunknum)
{
spritetabletype far *spr;
spritetype _seg *block;
unsigned dest,shift;
spr = &spritetable[chunknum-STARTSPRITES];
block = (spritetype _seg *)grsegs[chunknum];
y+=spr->orgy>>G_P_SHIFT;
x+=spr->orgx>>G_P_SHIFT;
#if GRMODE == EGAGR
shift = (x&7)/2;
#endif
#if GRMODE == CGAGR
shift = 0;
#endif
dest = bufferofs + ylookup[y];
if (x>=0)
dest += x/SCREENXDIV;
else
dest += (x+1)/SCREENXDIV;
VW_MaskBlock (block,block->sourceoffset[shift],dest,
block->width[shift],spr->height,block->planesize[shift]);
}
#endif
/*
==================
=
= VW_Hlin
=
==================
*/
#if GRMODE == EGAGR
unsigned char leftmask[8] = {0xff,0x7f,0x3f,0x1f,0xf,7,3,1};
unsigned char rightmask[8] = {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};
void VW_Hlin(unsigned xl, unsigned xh, unsigned y, unsigned color)
{
unsigned dest,xlb,xhb,maskleft,maskright,mid;
xlb=xl/8;
xhb=xh/8;
EGAWRITEMODE(2);
EGAMAPMASK(15);
maskleft = leftmask[xl&7];
maskright = rightmask[xh&7];
mid = xhb-xlb-1;
dest = bufferofs+ylookup[y]+xlb;
if (xlb==xhb)
{
//
// entire line is in one byte
//
maskleft&=maskright;
asm mov es,[screenseg]
asm mov di,[dest]
asm mov dx,GC_INDEX
asm mov al,GC_BITMASK
asm mov ah,[BYTE PTR maskleft]
asm out dx,ax // mask off pixels
asm mov al,[BYTE PTR color]
asm xchg al,[es:di] // load latches and write pixels
goto done;
}
asm mov es,[screenseg]
asm mov di,[dest]
asm mov dx,GC_INDEX
asm mov bh,[BYTE PTR color]
//
// draw left side
//
asm mov al,GC_BITMASK
asm mov ah,[BYTE PTR maskleft]
asm out dx,ax // mask off pixels
asm mov al,bh
asm mov bl,[es:di] // load latches
asm stosb
//
// draw middle
//
asm mov ax,GC_BITMASK + 255*256
asm out dx,ax // no masking
asm mov al,bh
asm mov cx,[mid]
asm rep stosb
//
// draw right side
//
asm mov al,GC_BITMASK
asm mov ah,[BYTE PTR maskright]
asm out dx,ax // mask off pixels
asm xchg bh,[es:di] // load latches and write pixels
done:
EGABITMASK(255);
EGAWRITEMODE(0);
}
#endif
#if GRMODE == CGAGR
unsigned char pixmask[4] = {0xc0,0x30,0x0c,0x03};
unsigned char leftmask[4] = {0xff,0x3f,0x0f,0x03};
unsigned char rightmask[4] = {0xc0,0xf0,0xfc,0xff};
unsigned char colorbyte[4] = {0,0x55,0xaa,0xff};
//
// could be optimized for rep stosw
//
void VW_Hlin(unsigned xl, unsigned xh, unsigned y, unsigned color)
{
unsigned dest,xlb,xhb,mid;
byte maskleft,maskright;
color = colorbyte[color]; // expand 2 color bits to 8
xlb=xl/4;
xhb=xh/4;
maskleft = leftmask[xl&3];
maskright = rightmask[xh&3];
mid = xhb-xlb-1;
dest = bufferofs+ylookup[y]+xlb;
asm mov es,[screenseg]
if (xlb==xhb)
{
//
// entire line is in one byte
//
maskleft&=maskright;
asm mov ah,[maskleft]
asm mov bl,[BYTE PTR color]
asm and bl,[maskleft]
asm not ah
asm mov di,[dest]
asm mov al,[es:di]
asm and al,ah // mask out pixels
asm or al,bl // or in color
asm mov [es:di],al
return;
}
asm mov di,[dest]
asm mov bh,[BYTE PTR color]
//
// draw left side
//
asm mov ah,[maskleft]
asm mov bl,bh
asm and bl,[maskleft]
asm not ah
asm mov al,[es:di]
asm and al,ah // mask out pixels
asm or al,bl // or in color
asm stosb
//
// draw middle
//
asm mov al,bh
asm mov cx,[mid]
asm rep stosb
//
// draw right side
//
asm mov ah,[maskright]
asm mov bl,bh
asm and bl,[maskright]
asm not ah
asm mov al,[es:di]
asm and al,ah // mask out pixels
asm or al,bl // or in color
asm stosb
}
#endif
/*
==================
=
= VW_Bar
=
= Pixel addressable block fill routine
=
==================
*/
#if GRMODE == CGAGR
void VW_Bar (unsigned x, unsigned y, unsigned width, unsigned height,
unsigned color)
{
unsigned xh = x+width-1;
while (height--)
VW_Hlin (x,xh,y++,color);
}
#endif
#if GRMODE == EGAGR
void VW_Bar (unsigned x, unsigned y, unsigned width, unsigned height,
unsigned color)
{
unsigned dest,xh,xlb,xhb,maskleft,maskright,mid;
xh = x+width-1;
xlb=x/8;
xhb=xh/8;
EGAWRITEMODE(2);
EGAMAPMASK(15);
maskleft = leftmask[x&7];
maskright = rightmask[xh&7];
mid = xhb-xlb-1;
dest = bufferofs+ylookup[y]+xlb;
if (xlb==xhb)
{
//
// entire line is in one byte
//
maskleft&=maskright;
asm mov es,[screenseg]
asm mov di,[dest]
asm mov dx,GC_INDEX
asm mov al,GC_BITMASK
asm mov ah,[BYTE PTR maskleft]
asm out dx,ax // mask off pixels
asm mov ah,[BYTE PTR color]
asm mov dx,[linewidth]
yloop1:
asm mov al,ah
asm xchg al,[es:di] // load latches and write pixels
asm add di,dx // down to next line
asm dec [height]
asm jnz yloop1
goto done;
}
asm mov es,[screenseg]
asm mov di,[dest]
asm mov bh,[BYTE PTR color]
asm mov dx,GC_INDEX
asm mov si,[linewidth]
asm sub si,[mid] // add to di at end of line to get to next scan
asm dec si
//
// draw left side
//
yloop2:
asm mov al,GC_BITMASK
asm mov ah,[BYTE PTR maskleft]
asm out dx,ax // mask off pixels
asm mov al,bh
asm mov bl,[es:di] // load latches
asm stosb
//
// draw middle
//
asm mov ax,GC_BITMASK + 255*256
asm out dx,ax // no masking
asm mov al,bh
asm mov cx,[mid]
asm rep stosb
//
// draw right side
//
asm mov al,GC_BITMASK
asm mov ah,[BYTE PTR maskright]
asm out dx,ax // mask off pixels
asm mov al,bh
asm xchg al,[es:di] // load latches and write pixels
asm add di,si // move to start of next line
asm dec [height]
asm jnz yloop2
done:
EGABITMASK(255);
EGAWRITEMODE(0);
}
#endif
//==========================================================================
/*
==================
=
= VW_MeasureString
=
==================
*/
#if NUMFONT+NUMFONTM>0
void
VWL_MeasureString (char far *string, word *width, word *height, fontstruct _seg *font)
{
*height = font->height;
for (*width = 0;*string;string++)
*width += font->width[*((byte far *)string)]; // proportional width
}
void VW_MeasurePropString (char far *string, word *width, word *height)
{
VWL_MeasureString(string,width,height,(fontstruct _seg *)grsegs[STARTFONT+fontnumber]);
}
void VW_MeasureMPropString (char far *string, word *width, word *height)
{
VWL_MeasureString(string,width,height,(fontstruct _seg *)grsegs[STARTFONTM+fontnumber]);
}
#endif
/*
=============================================================================
CGA stuff
=============================================================================
*/
#if GRMODE == CGAGR
#define CGACRTCWIDTH 40
/*
==========================
=
= VW_CGAFullUpdate
=
==========================
*/
void VW_CGAFullUpdate (void)
{
byte *update;
boolean halftile;
unsigned x,y,middlerows,middlecollumns;
displayofs = bufferofs+panadjust;
asm mov ax,0xb800
asm mov es,ax
asm mov si,[displayofs]
asm xor di,di
asm mov bx,100 // pairs of scan lines to copy
asm mov dx,[linewidth]
asm sub dx,80
asm mov ds,[screenseg]
asm test si,1
asm jz evenblock
//
// odd source
//
asm mov ax,39 // words accross screen
copytwolineso:
asm movsb
asm mov cx,ax
asm rep movsw
asm movsb
asm add si,dx
asm add di,0x2000-80 // go to the interlaced bank
asm movsb
asm mov cx,ax
asm rep movsw
asm movsb
asm add si,dx
asm sub di,0x2000 // go to the non interlaced bank
asm dec bx
asm jnz copytwolineso
asm jmp blitdone
//
// even source
//
evenblock:
asm mov ax,40 // words accross screen
copytwolines:
asm mov cx,ax
asm rep movsw
asm add si,dx
asm add di,0x2000-80 // go to the interlaced bank
asm mov cx,ax
asm rep movsw
asm add si,dx
asm sub di,0x2000 // go to the non interlaced bank
asm dec bx
asm jnz copytwolines
blitdone:
asm mov ax,ss
asm mov ds,ax
asm mov es,ax
asm xor ax,ax // clear out the update matrix
asm mov cx,UPDATEWIDE*UPDATEHIGH/2
asm mov di,[baseupdateptr]
asm rep stosw
updateptr = baseupdateptr;
*(unsigned *)(updateptr + UPDATEWIDE*PORTTILESHIGH) = UPDATETERMINATE;
}
#endif
/*
=============================================================================
CURSOR ROUTINES
These only work in the context of the double buffered update routines
=============================================================================
*/
/*
====================
=
= VWL_DrawCursor
=
= Background saves, then draws the cursor at cursorspot
=
====================
*/
void VWL_DrawCursor (void)
{
cursorspot = bufferofs + ylookup[cursory+pansy]+(cursorx+pansx)/SCREENXDIV;
VW_ScreenToMem(cursorspot,cursorsave,cursorwidth,cursorheight);
VWB_DrawSprite(cursorx,cursory,cursornumber);
}
//==========================================================================
/*
====================
=
= VWL_EraseCursor
=
====================
*/
void VWL_EraseCursor (void)
{
VW_MemToScreen(cursorsave,cursorspot,cursorwidth,cursorheight);
VW_MarkUpdateBlock ((cursorx+pansx)&SCREENXMASK,cursory+pansy,
( (cursorx+pansx)&SCREENXMASK)+cursorwidth*SCREENXDIV-1,
cursory+pansy+cursorheight-1);
}
//==========================================================================
/*
====================
=
= VW_ShowCursor
=
====================
*/
void VW_ShowCursor (void)
{
cursorvisible++;
}
//==========================================================================
/*
====================
=
= VW_HideCursor
=
====================
*/
void VW_HideCursor (void)
{
cursorvisible--;
}
//==========================================================================
/*
====================
=
= VW_MoveCursor
=
====================
*/
#define MAXCURSORX (319-24)
#define MAXCURSORY (199-24)
void VW_MoveCursor (int x, int y)
{
if (x>MAXCURSORX)
x=MAXCURSORX;
if (y>MAXCURSORY)
y=MAXCURSORY; // catacombs hack to keep cursor on screen
cursorx = x;
cursory = y;
}
//==========================================================================
/*
====================
=
= VW_SetCursor
=
= Load in a sprite to be used as a cursor, and allocate background save space
=
====================
*/
void VW_SetCursor (int spritenum)
{
VW_FreeCursor ();
cursornumber = spritenum;
CA_CacheGrChunk (spritenum);
MM_SetLock (&grsegs[spritenum],true);
cursorwidth = spritetable[spritenum-STARTSPRITES].width+1;
cursorheight = spritetable[spritenum-STARTSPRITES].height;
MM_GetPtr (&cursorsave,cursorwidth*cursorheight*5);
MM_SetLock (&cursorsave,true);
}
/*
====================
=
= VW_FreeCursor
=
= Frees the memory used by the cursor and its background save
=
====================
*/
void VW_FreeCursor (void)
{
if (cursornumber)
{
MM_SetLock (&grsegs[cursornumber],false);
MM_SetPurge (&grsegs[cursornumber],3);
MM_SetLock (&cursorsave,false);
MM_FreePtr (&cursorsave);
cursornumber = 0;
}
}
/*
=============================================================================
Double buffer management routines
=============================================================================
*/
/*
======================
=
= VW_InitDoubleBuffer
=
======================
*/
void VW_InitDoubleBuffer (void)
{
#if GRMODE == EGAGR
VW_SetScreen (displayofs+panadjust,0); // no pel pan
#endif
}
/*
======================
=
= VW_FixRefreshBuffer
=
= Copies the view page to the buffer page on page flipped refreshes to
= avoid a one frame shear around pop up windows
=
======================
*/
void VW_FixRefreshBuffer (void)
{
#if GRMODE == EGAGR
VW_ScreenToScreen (displayofs,bufferofs,PORTTILESWIDE*4*CHARWIDTH,
(PORTTILESHIGH-1)*16);
#endif
}
/*
======================
=
= VW_QuitDoubleBuffer
=
======================
*/
void VW_QuitDoubleBuffer (void)
{
}
/*
=======================
=
= VW_MarkUpdateBlock
=
= Takes a pixel bounded block and marks the tiles in bufferblocks
= Returns 0 if the entire block is off the buffer screen
=
=======================
*/
int VW_MarkUpdateBlock (int x1, int y1, int x2, int y2)
{
int x,y,xt1,yt1,xt2,yt2,nextline;
byte *mark;
xt1 = x1>>PIXTOBLOCK;
yt1 = y1>>PIXTOBLOCK;
xt2 = x2>>PIXTOBLOCK;
yt2 = y2>>PIXTOBLOCK;
if (xt1<0)
xt1=0;
else if (xt1>=UPDATEWIDE-1)
return 0;
if (yt1<0)
yt1=0;
else if (yt1>UPDATEHIGH)
return 0;
if (xt2<0)
return 0;
else if (xt2>=UPDATEWIDE-1)
xt2 = UPDATEWIDE-2;
if (yt2<0)
return 0;
else if (yt2>=UPDATEHIGH)
yt2 = UPDATEHIGH-1;
mark = updateptr + uwidthtable[yt1] + xt1;
nextline = UPDATEWIDE - (xt2-xt1) - 1;
for (y=yt1;y<=yt2;y++)
{
for (x=xt1;x<=xt2;x++)
*mark++ = 1; // this tile will need to be updated
mark += nextline;
}
return 1;
}
/*
===========================
=
= VW_UpdateScreen
=
= Updates any changed areas of the double buffer and displays the cursor
=
===========================
*/
void VW_UpdateScreen (void)
{
if (cursorvisible>0)
VWL_DrawCursor();
#if GRMODE == EGAGR
VWL_UpdateScreenBlocks();
asm mov ax,ds
asm mov es,ax
asm mov di,[updateptr] // cat3d patch
asm xor ax,ax // clear out the update matrix
asm mov cx,UPDATEWIDE*UPDATEHIGH/2
asm rep stosw
*(unsigned *)(updateptr + UPDATEWIDE*PORTTILESHIGH) = UPDATETERMINATE;
asm cli
asm mov cx,[displayofs]
asm add cx,[panadjust]
asm mov dx,CRTC_INDEX
asm mov al,0ch // start address high register
asm out dx,al
asm inc dx
asm mov al,ch
asm out dx,al
asm dec dx
asm mov al,0dh // start address low register
asm out dx,al
asm mov al,cl
asm inc dx
asm out dx,al
asm sti
#endif
#if GRMODE == CGAGR
VW_CGAFullUpdate();
#endif
if (cursorvisible>0)
VWL_EraseCursor();
}
void VWB_DrawTile8 (int x, int y, int tile)
{
x+=pansx;
y+=pansy;
if (VW_MarkUpdateBlock (x&SCREENXMASK,y,(x&SCREENXMASK)+7,y+7))
VW_DrawTile8 (x/SCREENXDIV,y,tile);
}
void VWB_DrawTile8M (int x, int y, int tile)
{
int xb;
x+=pansx;
y+=pansy;
xb = x/SCREENXDIV; // use intermediate because VW_DT8M is macro
if (VW_MarkUpdateBlock (x&SCREENXMASK,y,(x&SCREENXMASK)+7,y+7))
VW_DrawTile8M (xb,y,tile);
}
void VWB_DrawTile16 (int x, int y, int tile)
{
x+=pansx;
y+=pansy;
if (VW_MarkUpdateBlock (x&SCREENXMASK,y,(x&SCREENXMASK)+15,y+15))
VW_DrawTile16 (x/SCREENXDIV,y,tile);
}
void VWB_DrawTile16M (int x, int y, int tile)
{
int xb;
x+=pansx;
y+=pansy;
xb = x/SCREENXDIV; // use intermediate because VW_DT16M is macro
if (VW_MarkUpdateBlock (x&SCREENXMASK,y,(x&SCREENXMASK)+15,y+15))
VW_DrawTile16M (xb,y,tile);
}
#if NUMPICS
void VWB_DrawPic (int x, int y, int chunknum)
{
// mostly copied from drawpic
int picnum = chunknum - STARTPICS;
memptr source;
unsigned dest,width,height;
x+=pansx;
y+=pansy;
x/= SCREENXDIV;
source = grsegs[chunknum];
dest = ylookup[y]+x+bufferofs;
width = pictable[picnum].width;
height = pictable[picnum].height;
if (VW_MarkUpdateBlock (x*SCREENXDIV,y,(x+width)*SCREENXDIV-1,y+height-1))
VW_MemToScreen(source,dest,width,height);
}
#endif
#if NUMPICM>0
void VWB_DrawMPic(int x, int y, int chunknum)
{
// mostly copied from drawmpic
int picnum = chunknum - STARTPICM;
memptr source;
unsigned dest,width,height;
x+=pansx;
y+=pansy;
x/=SCREENXDIV;
source = grsegs[chunknum];
dest = ylookup[y]+x+bufferofs;
width = picmtable[picnum].width;
height = picmtable[picnum].height;
if (VW_MarkUpdateBlock (x*SCREENXDIV,y,(x+width)*SCREENXDIV-1,y+height-1))
VW_MaskBlock(source,0,dest,width,height,width*height);
}
#endif
void VWB_Bar (int x, int y, int width, int height, int color)
{
x+=pansx;
y+=pansy;
if (VW_MarkUpdateBlock (x,y,x+width,y+height-1) )
VW_Bar (x,y,width,height,color);
}
#if NUMFONT
void VWB_DrawPropString (char far *string)
{
int x,y;
x = px+pansx;
y = py+pansy;
VW_DrawPropString (string);
VW_MarkUpdateBlock(x,y,x+bufferwidth*8-1,y+bufferheight-1);
}
#endif
#if NUMFONTM
void VWB_DrawMPropString (char far *string)
{
int x,y;
x = px+pansx;
y = py+pansy;
VW_DrawMPropString (string);
VW_MarkUpdateBlock(x,y,x+bufferwidth*8-1,y+bufferheight-1);
}
#endif
#if NUMSPRITES
void VWB_DrawSprite(int x, int y, int chunknum)
{
spritetabletype far *spr;
spritetype _seg *block;
unsigned dest,shift,width,height;
x+=pansx;
y+=pansy;
spr = &spritetable[chunknum-STARTSPRITES];
block = (spritetype _seg *)grsegs[chunknum];
y+=spr->orgy>>G_P_SHIFT;
x+=spr->orgx>>G_P_SHIFT;
#if GRMODE == EGAGR
shift = (x&7)/2;
#endif
#if GRMODE == CGAGR
shift = 0;
#endif
dest = bufferofs + ylookup[y];
if (x>=0)
dest += x/SCREENXDIV;
else
dest += (x+1)/SCREENXDIV;
width = block->width[shift];
height = spr->height;
if (VW_MarkUpdateBlock (x&SCREENXMASK,y,(x&SCREENXMASK)+width*SCREENXDIV-1
,y+height-1))
VW_MaskBlock (block,block->sourceoffset[shift],dest,
width,height,block->planesize[shift]);
}
#endif
void VWB_Plot (int x, int y, int color)
{
x+=pansx;
y+=pansy;
if (VW_MarkUpdateBlock (x,y,x,y))
VW_Plot(x,y,color);
}
void VWB_Hlin (int x1, int x2, int y, int color)
{
x1+=pansx;
x2+=pansx;
y+=pansy;
if (VW_MarkUpdateBlock (x1,y,x2,y))
VW_Hlin(x1,x2,y,color);
}
void VWB_Vlin (int y1, int y2, int x, int color)
{
x+=pansx;
y1+=pansy;
y2+=pansy;
if (VW_MarkUpdateBlock (x,y1,x,y2))
VW_Vlin(y1,y2,x,color);
}
//===========================================================================