mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-17 07:07:10 +00:00
1803 lines
29 KiB
C++
1803 lines
29 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* This code is based on original Soltys source code
|
|
* Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
|
|
*/
|
|
|
|
#include "cge/general.h"
|
|
#include "cge/vga13h.h"
|
|
#include "cge/bitmap.h"
|
|
#include "cge/vol.h"
|
|
#include "cge/text.h"
|
|
#include <alloc.h>
|
|
#include <conio.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <dos.h>
|
|
#include <dir.h>
|
|
#include <fcntl.h>
|
|
#include <bios.h>
|
|
#include <io.h>
|
|
|
|
#ifdef DEBUG
|
|
#define REPORT
|
|
#endif
|
|
|
|
#define OK(f) ((f).Error==0)
|
|
#define FADE_STEP 2
|
|
|
|
#define TMR_DIV ((0x8000/TMR_RATE)*2)
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef REPORT
|
|
static char Report[] = "NearHeap=..... FarHeap=......\n";
|
|
#define NREP 9
|
|
#define FREP 24
|
|
#endif
|
|
|
|
|
|
|
|
static VgaRegBlk VideoMode[] = {
|
|
|
|
{ 0x04, VGASEQ, 0x08, 0x04 }, // memory mode
|
|
|
|
{ 0x03, VGAGRA, 0xFF, 0x00 }, // data rotate = 0
|
|
{ 0x05, VGAGRA, 0x03, 0x00 }, // R/W mode = 0
|
|
{ 0x06, VGAGRA, 0x02, 0x00 }, // misc
|
|
|
|
{ 0x14, VGACRT, 0x40, 0x00 }, // underline
|
|
{ 0x13, VGACRT, 0xFF, 0x28 }, // screen width
|
|
{ 0x17, VGACRT, 0xFF, 0xC3 }, // mode control
|
|
|
|
{ 0x11, VGACRT, 0x80, 0x00 }, // vert retrace end
|
|
{ 0x09, VGACRT, 0xEF, 0x01 }, // max scan line
|
|
|
|
{ 0x30, VGAATR, 0x00, 0x20 }, // 256 color mode
|
|
|
|
// { 0x12, VGACRT, 0xFF, 0x6E }, // vert display end
|
|
// { 0x15, VGACRT, 0xFF, 0x7F }, // start vb
|
|
// { 0x10, VGACRT, 0xFF, 0x94 }, // start vr
|
|
|
|
{ 0x00 } };
|
|
|
|
|
|
bool SpeedTest = false;
|
|
SEQ Seq1[] = { { 0, 0, 0, 0, 0 } };
|
|
SEQ Seq2[] = { { 0, 1, 0, 0, 0 }, { 1, 0, 0, 0, 0 } };
|
|
SPRITE * Sys = NULL;
|
|
|
|
extern "C" void SNDMIDIPlay (void);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char * NumStr (char * str, int num)
|
|
{
|
|
char * p = strchr(str, '#');
|
|
if (p) wtom(num, p, 10, 5);
|
|
return str;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void Video (void)
|
|
{
|
|
static uint16 SP_S;
|
|
|
|
asm push bx
|
|
asm push bp
|
|
asm push si
|
|
asm push di
|
|
asm push es
|
|
asm xor bx,bx // video page #0
|
|
SP_S = _SP;
|
|
asm int VIDEO
|
|
_SP = SP_S;
|
|
asm pop es
|
|
asm pop di
|
|
asm pop si
|
|
asm pop bp
|
|
asm pop bx
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint16 * SaveScreen (void)
|
|
{
|
|
uint16 cxy, cur, siz, * scr = NULL, * sav;
|
|
|
|
// horizontal size of text mode screen
|
|
asm mov ah,0x0F // get current video mode
|
|
Video(); // BIOS video service
|
|
asm xchg ah,al // answer in ah
|
|
asm push ax // preserve width
|
|
|
|
// vertical size of text mode screen
|
|
asm mov dl,24 // last row on std screen
|
|
asm xor bx,bx // valid request in BH
|
|
asm mov ax,0x1130 // get EGA's last row #
|
|
Video(); // BIOS video service
|
|
asm inc dl // # of rows = last+1
|
|
|
|
// compute screen size in words
|
|
asm pop ax // restore width
|
|
asm mul dl // width * height
|
|
|
|
siz = _AX;
|
|
|
|
asm mov ax,0x40 // system data segment
|
|
asm mov es,ax
|
|
asm mov ax,0B000H // Mono
|
|
asm cmp byte ptr es:[0x49],0x07
|
|
asm je sto
|
|
asm mov ax,0B800H // Color
|
|
sto: // store screen address
|
|
asm mov word ptr scr+2,ax
|
|
|
|
_AH = 0x0F; Video(); // active page
|
|
|
|
// take cursor shape
|
|
_AH = 0x03; Video(); // get cursor size
|
|
cur = _CX;
|
|
|
|
// take cursor position
|
|
_DH = 0;
|
|
_AH = 0x03; Video(); // get cursor
|
|
cxy = _DX;
|
|
|
|
sav = farnew(uint16, siz+3); // +3 extra uint16s for size and cursor
|
|
if (sav)
|
|
{
|
|
sav[0] = siz;
|
|
sav[1] = cur;
|
|
sav[2] = cxy;
|
|
_fmemcpy(sav+3, scr, siz * 2);
|
|
}
|
|
return sav;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RestoreScreen (uint16 * &sav)
|
|
{
|
|
uint16 * scr = NULL;
|
|
|
|
asm mov ax,0x40 // system data segment
|
|
asm mov es,ax
|
|
asm mov ax,0B000H // Mono
|
|
asm cmp byte ptr es:[0x49],0x07
|
|
asm je sto
|
|
asm mov ax,0B800H // Color
|
|
sto: // store screen address
|
|
asm mov word ptr scr+2,ax
|
|
|
|
_fmemcpy(scr, sav+3, sav[0] * 2);
|
|
|
|
_AH = 0x0F; Video(); // active page
|
|
|
|
// set cursor shape
|
|
_CX = sav[1];
|
|
_AH = 0x01; Video(); // set cursor size
|
|
|
|
// set cursor position
|
|
_DX = sav[2];
|
|
_AH = 0x02; Video(); // set cursor
|
|
|
|
farfree(sav);
|
|
sav = NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DAC MkDAC (uint8 r, uint8 g, uint8 b)
|
|
{
|
|
static DAC x;
|
|
x.R = r;
|
|
x.G = g;
|
|
x.B = b;
|
|
return x;
|
|
}
|
|
|
|
|
|
|
|
|
|
RGB MkRGB (uint8 r, uint8 g, uint8 b)
|
|
{
|
|
static TRGB x;
|
|
x.dac.R = r;
|
|
x.dac.G = g;
|
|
x.dac.B = b;
|
|
return x.rgb;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SPRITE * Locate (int ref)
|
|
{
|
|
SPRITE * spr = VGA::ShowQ.Locate(ref);
|
|
return (spr) ? spr : VGA::SpareQ.Locate(ref);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
bool HEART::Enable = false;
|
|
uint16 * HEART::XTimer = NULL;
|
|
|
|
|
|
|
|
|
|
HEART::HEART (void)
|
|
: ENGINE(TMR_DIV)
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
extern "C" void TimerProc (void)
|
|
{
|
|
static SPRITE * spr;
|
|
static uint8 run = 0;
|
|
|
|
// decrement external timer uint16
|
|
if (HEART::XTimer)
|
|
if (*HEART::XTimer) -- *HEART::XTimer;
|
|
else HEART::XTimer = NULL;
|
|
|
|
if (! run && HEART::Enable) // check overrun flag
|
|
{
|
|
static uint16 oldSP, oldSS;
|
|
|
|
++ run; // disable 2nd call until current lasts
|
|
asm mov ax,ds
|
|
asm mov oldSS,ss
|
|
asm mov oldSP,sp
|
|
asm mov ss,ax
|
|
asm mov sp,0xFF80
|
|
|
|
// system pseudo-sprite
|
|
if (Sys) if (Sys->Time) if (-- Sys->Time == 0) Sys->Tick();
|
|
|
|
for (spr = VGA::ShowQ.First(); spr; spr = spr->Next)
|
|
{
|
|
if (spr->Time) if (!spr->Flags.Hide) if (-- spr->Time == 0) spr->Tick();
|
|
}
|
|
asm mov ss,oldSS
|
|
asm mov sp,oldSP
|
|
-- run;
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
void interrupt ENGINE::NewTimer (...)
|
|
{
|
|
static SPRITE * spr;
|
|
static uint8 run = 0, cntr1 = TMR_RATE1, cntr2 = TMR_RATE2;
|
|
|
|
___1152_Hz___:
|
|
|
|
SNDMIDIPlay();
|
|
asm dec cntr1
|
|
asm jz ___72_Hz___
|
|
asm mov al,0x20 // send...
|
|
asm out 0x020,al // ...e-o-i
|
|
return;
|
|
|
|
___72_Hz___:
|
|
|
|
asm mov cntr1,TMR_RATE1
|
|
asm dec cntr2
|
|
asm jnz my_eoi
|
|
|
|
___18_Hz___:
|
|
|
|
OldTimer();
|
|
asm mov cntr2,TMR_RATE2
|
|
asm jmp short my_int
|
|
|
|
// send E-O-I
|
|
my_eoi:
|
|
asm mov al,0x20
|
|
asm out 0x020,al
|
|
asm sti // enable interrupts
|
|
|
|
my_int: //------72Hz-------//
|
|
|
|
// decrement external timer uint16
|
|
if (HEART::XTimer)
|
|
if (*HEART::XTimer) -- *HEART::XTimer;
|
|
else HEART::XTimer = NULL;
|
|
|
|
if (! run && HEART::Enable) // check overrun flag
|
|
{
|
|
static uint16 oldSP, oldSS;
|
|
|
|
++ run; // disable 2nd call until current lasts
|
|
asm mov ax,ds
|
|
asm mov oldSS,ss
|
|
asm mov oldSP,sp
|
|
asm mov ss,ax
|
|
asm mov sp,0xFF80
|
|
|
|
// system pseudo-sprite
|
|
if (Sys) if (Sys->Time) if (-- Sys->Time == 0) Sys->Tick();
|
|
|
|
for (spr = VGA::ShowQ.First(); spr; spr = spr->Next)
|
|
{
|
|
if (spr->Time) if (!spr->Flags.Hide) if (-- spr->Time == 0) spr->Tick();
|
|
}
|
|
asm mov ss,oldSS
|
|
asm mov sp,oldSP
|
|
-- run;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HEART::SetXTimer (uint16 * ptr)
|
|
{
|
|
if (XTimer && ptr != XTimer) *XTimer = 0;
|
|
XTimer = ptr;
|
|
}
|
|
|
|
|
|
|
|
|
|
void HEART::SetXTimer (uint16 * ptr, uint16 time)
|
|
{
|
|
SetXTimer(ptr);
|
|
*ptr = time;
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SPRITE::SPRITE (BMP_PTR * shp)
|
|
: X(0), Y(0), Z(0), NearPtr(0), TakePtr(0),
|
|
Next(NULL), Prev(NULL), SeqPtr(NO_SEQ), Time(0), //Delay(0),
|
|
Ext(NULL), Ref(-1), Cave(0)
|
|
{
|
|
memset(File, 0, sizeof(File));
|
|
*((uint16 *)&Flags) = 0;
|
|
SetShapeList(shp);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SPRITE::~SPRITE (void)
|
|
{
|
|
Contract();
|
|
}
|
|
|
|
|
|
|
|
|
|
BMP_PTR SPRITE::Shp (void)
|
|
{
|
|
register SPREXT * e = Ext;
|
|
if (e) if (e->Seq)
|
|
{
|
|
int i = e->Seq[SeqPtr].Now;
|
|
#ifdef DEBUG
|
|
if (i >= ShpCnt)
|
|
{
|
|
//char s[256];
|
|
//sprintf(s, "Seq=%p ShpCnt=%d SeqPtr=%d Now=%d Next=%d",
|
|
// Seq, ShpCnt, SeqPtr, Seq[SeqPtr].Now, Seq[SeqPtr].Next);
|
|
//VGA::Exit(s, File);
|
|
VGA::Exit("Invalid PHASE in SPRITE::Shp()", File);
|
|
}
|
|
#endif
|
|
return e->ShpList[i];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BMP_PTR * SPRITE::SetShapeList (BMP_PTR * shp)
|
|
{
|
|
BMP_PTR * r = (Ext) ? Ext->ShpList : NULL;
|
|
|
|
ShpCnt = 0;
|
|
W = 0;
|
|
H = 0;
|
|
|
|
if (shp)
|
|
{
|
|
BMP_PTR * p;
|
|
for (p = shp; *p; p ++)
|
|
{
|
|
BMP_PTR b = (*p); // ->Code();
|
|
if (b->W > W) W = b->W;
|
|
if (b->H > H) H = b->H;
|
|
++ ShpCnt;
|
|
}
|
|
Expand();
|
|
Ext->ShpList = shp;
|
|
if (! Ext->Seq) SetSeq((ShpCnt < 2) ? Seq1 : Seq2);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SPRITE::MoveShapes (uint8 * buf)
|
|
{
|
|
BMP_PTR * p;
|
|
for (p = Ext->ShpList; *p; p ++)
|
|
{
|
|
buf += (*p)->MoveVmap(buf);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool SPRITE::Works (SPRITE * spr)
|
|
{
|
|
if (spr) if (spr->Ext)
|
|
{
|
|
SNAIL::COM * c = spr->Ext->Take;
|
|
if (c != NULL)
|
|
{
|
|
c += spr->TakePtr;
|
|
if (c->Ref == Ref)
|
|
if (c->Com != SNLABEL || (c->Val == 0 || c->Val == Now))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SEQ * SPRITE::SetSeq (SEQ * seq)
|
|
{
|
|
Expand();
|
|
register SEQ * s = Ext->Seq;
|
|
Ext->Seq = seq;
|
|
if (SeqPtr == NO_SEQ) Step(0);
|
|
else
|
|
if (Time == 0) Step(SeqPtr);
|
|
return s;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool SPRITE::SeqTest (int n)
|
|
{
|
|
if (n >= 0) return (SeqPtr == n);
|
|
if (Ext) return (Ext->Seq[SeqPtr].Next == SeqPtr);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SNAIL::COM * SPRITE::SnList (SNLIST type)
|
|
{
|
|
register SPREXT * e = Ext;
|
|
if (e) return (type == NEAR) ? e->Near : e->Take;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SPRITE::SetName (char * n)
|
|
{
|
|
if (Ext)
|
|
{
|
|
if (Ext->Name)
|
|
{
|
|
delete[] Ext->Name;
|
|
Ext->Name = NULL;
|
|
}
|
|
if (n)
|
|
{
|
|
if ((Ext->Name = new char[strlen(n)+1]) != NULL) strcpy(Ext->Name, n);
|
|
else VGA::Exit("No core", n);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SPRITE * SPRITE::Expand (void)
|
|
{
|
|
if (! Ext)
|
|
{
|
|
bool enbl = HEART::Enable;
|
|
HEART::Enable = false;
|
|
if ((Ext = new SPREXT) == NULL) DROP("No core", NULL);
|
|
if (*File)
|
|
{
|
|
static char * Comd[] = { "Name", "Phase", "Seq", "Near", "Take", NULL };
|
|
char line[LINE_MAX], fname[MAXPATH];
|
|
BMP_PTR * shplist = new BMP_PTR [ShpCnt+1];
|
|
SEQ * seq = NULL;
|
|
int shpcnt = 0,
|
|
seqcnt = 0,
|
|
neacnt = 0,
|
|
takcnt = 0,
|
|
maxnow = 0,
|
|
maxnxt = 0,
|
|
lcnt = 0,
|
|
len;
|
|
|
|
SNAIL::COM * nea = NULL;
|
|
SNAIL::COM * tak = NULL;
|
|
MergeExt(fname, File, SPR_EXT);
|
|
if (INI_FILE::Exist(fname)) // sprite description file exist
|
|
{
|
|
INI_FILE sprf(fname);
|
|
if (! OK(sprf))
|
|
{
|
|
VGA::Exit("Bad SPR", fname);
|
|
}
|
|
|
|
while ((len = sprf.Read(line)) != 0)
|
|
{
|
|
++ lcnt;
|
|
if (len && line[len-1] == '\n') line[-- len] = '\0';
|
|
if (len == 0 || *line == '.') continue;
|
|
|
|
switch (TakeEnum(Comd, strtok(line, " =\t")))
|
|
{
|
|
case 0 : // Name
|
|
SetName(strtok(NULL, "")); break;
|
|
case 1 : // Phase
|
|
shplist[shpcnt ++] = new BITMAP(strtok(NULL, " \t,;/"));
|
|
break;
|
|
case 2 : // Seq
|
|
seq = (SEQ *) realloc(seq, (seqcnt + 1) * sizeof(*seq));
|
|
if (seq == NULL)
|
|
VGA::Exit("No core", fname);
|
|
SEQ * s = &seq[seqcnt ++];
|
|
s->Now = atoi(strtok(NULL, " \t,;/"));
|
|
if (s->Now > maxnow) maxnow = s->Now;
|
|
s->Next = atoi(strtok(NULL, " \t,;/"));
|
|
switch (s->Next)
|
|
{
|
|
case 0xFF : s->Next = seqcnt; break;
|
|
case 0xFE : s->Next = seqcnt-1; break;
|
|
}
|
|
if (s->Next > maxnxt) maxnxt = s->Next;
|
|
s->Dx = atoi(strtok(NULL, " \t,;/"));
|
|
s->Dy = atoi(strtok(NULL, " \t,;/"));
|
|
s->Dly = atoi(strtok(NULL, " \t,;/"));
|
|
break;
|
|
case 3 : // Near
|
|
if (NearPtr != NO_PTR)
|
|
{
|
|
nea = (SNAIL::COM *) realloc(nea, (neacnt + 1) * sizeof(*nea));
|
|
if (nea == NULL) VGA::Exit("No core", fname);
|
|
else
|
|
{
|
|
SNAIL::COM * c = &nea[neacnt ++];
|
|
if ((c->Com = (SNCOM) TakeEnum(SNAIL::ComTxt, strtok(NULL, " \t,;/"))) < 0)
|
|
VGA::Exit(NumStr("Bad NEAR in ######", lcnt), fname);
|
|
c->Ref = atoi(strtok(NULL, " \t,;/"));
|
|
c->Val = atoi(strtok(NULL, " \t,;/"));
|
|
c->Ptr = NULL;
|
|
}
|
|
}
|
|
break;
|
|
case 4 : // Take
|
|
if (TakePtr != NO_PTR)
|
|
{
|
|
tak = (SNAIL::COM *) realloc(tak, (takcnt + 1) * sizeof(*tak));
|
|
if (tak == NULL) VGA::Exit("No core", fname);
|
|
else
|
|
{
|
|
SNAIL::COM * c = &tak[takcnt ++];
|
|
if ((c->Com = (SNCOM) TakeEnum(SNAIL::ComTxt, strtok(NULL, " \t,;/"))) < 0)
|
|
VGA::Exit(NumStr("Bad NEAR in ######", lcnt), fname);
|
|
c->Ref = atoi(strtok(NULL, " \t,;/"));
|
|
c->Val = atoi(strtok(NULL, " \t,;/"));
|
|
c->Ptr = NULL;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else // no sprite description: try to read immediately from .BMP
|
|
{
|
|
shplist[shpcnt ++] = new BITMAP(File);
|
|
}
|
|
shplist[shpcnt] = NULL;
|
|
if (seq)
|
|
{
|
|
if (maxnow >= shpcnt) VGA::Exit("Bad PHASE in SEQ", fname);
|
|
if (maxnxt >= seqcnt) VGA::Exit("Bad JUMP in SEQ", fname);
|
|
SetSeq(seq);
|
|
}
|
|
else SetSeq((ShpCnt == 1) ? Seq1 : Seq2);
|
|
disable();
|
|
|
|
SetShapeList(shplist);
|
|
enable();
|
|
if (nea) nea[neacnt-1].Ptr = Ext->Near = nea; else NearPtr = NO_PTR;
|
|
if (tak) tak[takcnt-1].Ptr = Ext->Take = tak; else TakePtr = NO_PTR;
|
|
}
|
|
HEART::Enable = enbl;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
|
|
|
|
|
|
SPRITE * SPRITE::Contract (void)
|
|
{
|
|
register SPREXT * e = Ext;
|
|
if (e)
|
|
{
|
|
if (e->Name) delete[] e->Name;
|
|
if (Flags.BDel && e->ShpList)
|
|
{
|
|
int i;
|
|
for (i = 0; e->ShpList[i]; i ++) delete e->ShpList[i];
|
|
if (MemType(e->ShpList) == NEAR_MEM) delete[] e->ShpList;
|
|
}
|
|
if (MemType(e->Seq) == NEAR_MEM) free(e->Seq);
|
|
if (e->Near) free(e->Near);
|
|
if (e->Take) free(e->Take);
|
|
delete e;
|
|
Ext = NULL;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SPRITE * SPRITE::BackShow (bool fast)
|
|
{
|
|
Expand();
|
|
Show(2);
|
|
Show(1);
|
|
if (fast) Show(0);
|
|
Contract();
|
|
return this;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SPRITE::Step (int nr)
|
|
{
|
|
if (nr >= 0) SeqPtr = nr;
|
|
if (Ext)
|
|
{
|
|
SEQ * seq;
|
|
if (nr < 0) SeqPtr = Ext->Seq[SeqPtr].Next;
|
|
seq = Ext->Seq + SeqPtr;
|
|
if (seq->Dly >= 0)
|
|
{
|
|
Goto(X + (seq->Dx), Y + (seq->Dy));
|
|
Time = seq->Dly;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SPRITE::Tick (void)
|
|
{
|
|
Step();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SPRITE::MakeXlat (uint8 * x)
|
|
{
|
|
if (Ext)
|
|
{
|
|
BMP_PTR * b;
|
|
|
|
if (Flags.Xlat) KillXlat();
|
|
for (b = Ext->ShpList; *b; b ++) (*b)->M = x;
|
|
Flags.Xlat = true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SPRITE::KillXlat (void)
|
|
{
|
|
if (Flags.Xlat && Ext)
|
|
{
|
|
BMP_PTR * b;
|
|
uint8 * m = (*Ext->ShpList)->M;
|
|
|
|
switch (MemType(m))
|
|
{
|
|
case NEAR_MEM : delete[] (uint8 *) m; break;
|
|
case FAR_MEM : farfree(m); break;
|
|
}
|
|
for (b = Ext->ShpList; *b; b ++) (*b)->M = NULL;
|
|
Flags.Xlat = false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SPRITE::Goto (int x, int y)
|
|
{
|
|
int xo = X, yo = Y;
|
|
if (W < SCR_WID)
|
|
{
|
|
if (x < 0) x = 0;
|
|
if (x + W > SCR_WID) x = (SCR_WID - W);
|
|
X = x;
|
|
}
|
|
if (H < SCR_HIG)
|
|
{
|
|
if (y < 0) y = 0;
|
|
if (y + H > SCR_HIG) y = (SCR_HIG - H);
|
|
Y = y;
|
|
}
|
|
if (Next) if (Next->Flags.Slav) Next->Goto(Next->X-xo+X, Next->Y-yo+Y);
|
|
if (Flags.Shad) Prev->Goto(Prev->X-xo+X, Prev->Y-yo+Y);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SPRITE::Center (void)
|
|
{
|
|
Goto((SCR_WID - W) / 2, (SCR_HIG - H) / 2);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SPRITE::Show (void)
|
|
{
|
|
register SPREXT * e;
|
|
asm cli // critic section...
|
|
e = Ext;
|
|
e->x0 = e->x1;
|
|
e->y0 = e->y1;
|
|
e->b0 = e->b1;
|
|
e->x1 = X;
|
|
e->y1 = Y;
|
|
e->b1 = Shp();
|
|
asm sti // ...done!
|
|
if (! Flags.Hide)
|
|
{
|
|
if (Flags.Xlat) e->b1->XShow(e->x1, e->y1);
|
|
else e->b1->Show(e->x1, e->y1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SPRITE::Show (uint16 pg)
|
|
{
|
|
uint8 * a = VGA::Page[1];
|
|
VGA::Page[1] = VGA::Page[pg & 3];
|
|
Shp()->Show(X, Y);
|
|
VGA::Page[1] = a;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SPRITE::Hide (void)
|
|
{
|
|
register SPREXT * e = Ext;
|
|
if (e->b0) e->b0->Hide(e->x0, e->y0);
|
|
}
|
|
|
|
|
|
|
|
|
|
BMP_PTR SPRITE::Ghost (void)
|
|
{
|
|
register SPREXT * e = Ext;
|
|
if (e->b1)
|
|
{
|
|
BMP_PTR bmp = new BITMAP(0, 0, (uint8 *)NULL);
|
|
if (bmp == NULL) VGA::Exit("No core");
|
|
bmp->W = e->b1->W;
|
|
bmp->H = e->b1->H;
|
|
if ((bmp->B = farnew(HideDesc, bmp->H)) == NULL) VGA::Exit("No Core");
|
|
bmp->V = (uint8 *) _fmemcpy(bmp->B, e->b1->B, sizeof(HideDesc) * bmp->H);
|
|
bmp->M = (uint8 *) MK_FP(e->y1, e->x1);
|
|
return bmp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SPRITE * SpriteAt (int x, int y)
|
|
{
|
|
SPRITE * spr = NULL, * tail = VGA::ShowQ.Last();
|
|
if (tail)
|
|
{
|
|
for (spr = tail->Prev; spr; spr = spr->Prev)
|
|
if (! spr->Flags.Hide && ! spr->Flags.Tran)
|
|
if (spr->Shp()->SolidAt(x-spr->X, y-spr->Y))
|
|
break;
|
|
}
|
|
return spr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QUEUE::QUEUE (bool show)
|
|
: Head(NULL), Tail(NULL), Show(show)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
QUEUE::~QUEUE (void)
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
|
|
|
|
|
|
void QUEUE::Clear (void)
|
|
{
|
|
while (Head)
|
|
{
|
|
SPRITE * s = Remove(Head);
|
|
if (s->Flags.Kill) delete s;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void QUEUE::ForAll (void (*fun)(SPRITE *))
|
|
{
|
|
SPRITE * s = Head;
|
|
while (s)
|
|
{
|
|
SPRITE * n = s->Next;
|
|
fun(s);
|
|
s = n;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void QUEUE::Append (SPRITE * spr)
|
|
{
|
|
if (Tail)
|
|
{
|
|
spr->Prev = Tail;
|
|
Tail->Next = spr;
|
|
}
|
|
else Head = spr;
|
|
Tail = spr;
|
|
if (Show) spr->Expand();
|
|
else spr->Contract();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void QUEUE::Insert (SPRITE * spr, SPRITE * nxt)
|
|
{
|
|
if (nxt == Head)
|
|
{
|
|
spr->Next = Head;
|
|
Head = spr;
|
|
if (! Tail) Tail = spr;
|
|
}
|
|
else
|
|
{
|
|
spr->Next = nxt;
|
|
spr->Prev = nxt->Prev;
|
|
if (spr->Prev) spr->Prev->Next = spr;
|
|
}
|
|
if (spr->Next) spr->Next->Prev = spr;
|
|
if (Show) spr->Expand();
|
|
else spr->Contract();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void QUEUE::Insert (SPRITE * spr)
|
|
{
|
|
SPRITE * s;
|
|
for (s = Head; s; s = s->Next)
|
|
if (s->Z > spr->Z)
|
|
break;
|
|
if (s) Insert(spr, s);
|
|
else Append(spr);
|
|
if (Show) spr->Expand();
|
|
else spr->Contract();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SPRITE * QUEUE::Remove (SPRITE * spr)
|
|
{
|
|
if (spr == Head) Head = spr->Next;
|
|
if (spr == Tail) Tail = spr->Prev;
|
|
if (spr->Next) spr->Next->Prev = spr->Prev;
|
|
if (spr->Prev) spr->Prev->Next = spr->Next;
|
|
spr->Prev = NULL;
|
|
spr->Next = NULL;
|
|
return spr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SPRITE * QUEUE::Locate (int ref)
|
|
{
|
|
SPRITE * spr;
|
|
for (spr = Head; spr; spr = spr->Next) if (spr->Ref == ref) return spr;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
uint16 VGA::StatAdr = VGAST1_;
|
|
uint16 VGA::OldMode = 0;
|
|
uint16 * VGA::OldScreen = NULL;
|
|
const char * VGA::Msg = NULL;
|
|
const char * VGA::Nam = NULL;
|
|
DAC * VGA::OldColors = NULL;
|
|
DAC * VGA::NewColors = NULL;
|
|
bool VGA::SetPal = false;
|
|
int VGA::Mono = 0;
|
|
QUEUE VGA::ShowQ = true, VGA::SpareQ = false;
|
|
uint8 * VGA::Page[4] = { (uint8 *) MK_FP(SCR_SEG, 0x0000),
|
|
(uint8 *) MK_FP(SCR_SEG, 0x4000),
|
|
(uint8 *) MK_FP(SCR_SEG, 0x8000),
|
|
(uint8 *) MK_FP(SCR_SEG, 0xC000) };
|
|
|
|
|
|
|
|
|
|
VGA::VGA (int mode)
|
|
: FrmCnt(0)
|
|
{
|
|
extern const char Copr[];
|
|
bool std = true;
|
|
int i;
|
|
for (i = 10; i < 20; i ++)
|
|
{
|
|
char * txt = Text[i];
|
|
if (txt)
|
|
{
|
|
puts(txt);
|
|
#ifndef DEBUG
|
|
std = false;
|
|
#endif
|
|
}
|
|
}
|
|
if (std) puts(Copr);
|
|
SetStatAdr();
|
|
if (StatAdr != VGAST1_) ++ Mono;
|
|
if (IsVga())
|
|
{
|
|
OldColors = farnew(DAC, 256);
|
|
NewColors = farnew(DAC, 256);
|
|
OldScreen = SaveScreen();
|
|
GetColors(OldColors);
|
|
Sunset();
|
|
OldMode = SetMode(mode);
|
|
SetColors();
|
|
Setup(VideoMode);
|
|
Clear();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VGA::~VGA (void)
|
|
{
|
|
Mono = 0;
|
|
if (IsVga())
|
|
{
|
|
Clear();
|
|
SetMode(OldMode);
|
|
SetColors();
|
|
RestoreScreen(OldScreen);
|
|
Sunrise(OldColors);
|
|
if (OldColors) farfree(OldColors);
|
|
if (NewColors) farfree(NewColors);
|
|
if (Msg) fputs(Msg, stderr);
|
|
if (Nam)
|
|
{
|
|
fputs(" [", stderr);
|
|
fputs(Nam, stderr);
|
|
fputc(']', stderr);
|
|
}
|
|
if (Msg || Nam) fputc('\n', stderr);
|
|
#ifdef REPORT
|
|
fputs(Report, stderr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void VGA::SetStatAdr (void)
|
|
{
|
|
asm mov dx,VGAMIr_
|
|
asm in al,dx
|
|
asm test al,1 // CGA addressing mode flag
|
|
asm mov ax,VGAST1_ // CGA addressing
|
|
asm jnz set_mode_adr
|
|
asm xor al,0x60 // MDA addressing
|
|
set_mode_adr:
|
|
StatAdr = _AX;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma argsused
|
|
void VGA::WaitVR (bool on)
|
|
{
|
|
_DX = StatAdr;
|
|
_AH = (on) ? 0x00 : 0x08;
|
|
|
|
asm mov cx,2
|
|
// wait for vertical retrace on (off)
|
|
wait:
|
|
asm in al,dx
|
|
asm xor al,ah
|
|
asm test al,0x08
|
|
asm jnz wait
|
|
asm xor ah,0x08
|
|
asm loop wait
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VGA::Setup (VgaRegBlk * vrb)
|
|
{
|
|
WaitVR(); // *--LOOK!--* resets VGAATR logic
|
|
asm cld
|
|
asm mov si, vrb // take address of parameter table
|
|
asm mov dh,0x03 // higher byte of I/O address is always 3
|
|
|
|
s:
|
|
asm lodsw // take lower byte of I/O address and index
|
|
asm or ah,ah // 0 = end of table
|
|
asm jz xit // no more: exit
|
|
asm or al,al // indexed register?
|
|
asm js single // 7th bit set means single register
|
|
asm mov dl,ah // complete I/O address
|
|
asm out dx,al // put index into control register
|
|
asm inc dx // data register is next to control
|
|
asm in al,dx // take old data
|
|
|
|
write:
|
|
asm mov cl,al // preserve old data
|
|
asm lodsw // take 2 masks from table
|
|
asm xor al,0xFF // invert mask bits
|
|
asm and al,cl // clear bits with "clr" mask
|
|
asm or al,ah // set bits with "set" mask
|
|
asm cmp dl,0xC1 // special case?
|
|
asm jne std2 // no: standard job, otherwise...
|
|
asm dec dx // data out reg shares address with index
|
|
std2:
|
|
asm out dx,al // write new value to register
|
|
asm jmp s
|
|
|
|
single: // read address in al, write address in ah
|
|
asm mov dl,al // complete I/O read address
|
|
asm in al,dx // take old data
|
|
asm mov dl,ah // complete I/O write address
|
|
asm jmp write // continue standard routine
|
|
|
|
xit:
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int VGA::SetMode (int mode)
|
|
{
|
|
Clear();
|
|
// get current mode
|
|
asm mov ah,0x0F
|
|
Video(); // BIOS video service
|
|
asm xor ah,ah
|
|
asm push ax
|
|
|
|
// wait for v-retrace
|
|
WaitVR();
|
|
|
|
// set mode
|
|
asm xor ah,ah
|
|
asm mov al,byte ptr mode
|
|
Video(); // BIOS video service
|
|
SetStatAdr();
|
|
// return previous mode
|
|
asm pop ax
|
|
return _AX;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VGA::GetColors (DAC * tab)
|
|
{
|
|
asm cld
|
|
asm les di,tab // color table
|
|
asm mov dx,0x3C7 // PEL address read mode register
|
|
asm xor al,al // start from address 0
|
|
asm out dx,al // put address
|
|
asm mov cx,256*3 // # of colors
|
|
asm mov dl,0xC9 // PEL data register
|
|
|
|
// asm rep insb // very fast!
|
|
|
|
gc: // much slower:
|
|
asm in al,dx // take 1 color
|
|
asm jmp sto // little delay
|
|
sto:
|
|
asm stosb // store 1 color
|
|
asm loop gc // next one?
|
|
}
|
|
|
|
|
|
|
|
|
|
void VGA::SetColors (DAC * tab, int lum)
|
|
{
|
|
DAC * des = NewColors;
|
|
asm push ds
|
|
|
|
asm les di,des
|
|
asm lds si,tab
|
|
asm mov cx,256*3
|
|
asm xor bx,bx
|
|
asm mov dx,lum
|
|
|
|
copcol:
|
|
asm mov al,[si+bx]
|
|
asm mul dl
|
|
asm shr ax,6
|
|
asm mov es:[di+bx],al
|
|
asm inc bx
|
|
asm cmp bx,cx
|
|
asm jb copcol
|
|
|
|
asm pop ds
|
|
|
|
if (Mono)
|
|
{
|
|
asm add cx,di
|
|
mono:
|
|
asm xor dx,dx
|
|
asm mov al,77 // 30% R
|
|
asm mul byte ptr es:[di].0
|
|
asm add dx,ax
|
|
asm mov al,151 // 59% G
|
|
asm mul byte ptr es:[di].1
|
|
asm add dx,ax
|
|
asm mov al,28 // 11% B
|
|
asm mul byte ptr es:[di].2
|
|
asm add dx,ax
|
|
|
|
asm mov es:[di].0,dh
|
|
asm mov es:[di].1,dh
|
|
asm mov es:[di].2,dh
|
|
|
|
asm add di,3
|
|
asm cmp di,cx
|
|
asm jb mono
|
|
}
|
|
SetPal = true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VGA::SetColors (void)
|
|
{
|
|
_fmemset(NewColors, 0, PAL_SIZ);
|
|
UpdateColors();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VGA::Sunrise (DAC * tab)
|
|
{
|
|
int i;
|
|
for (i = 0; i <= 64; i += FADE_STEP)
|
|
{
|
|
SetColors(tab, i);
|
|
WaitVR();
|
|
UpdateColors();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VGA::Sunset (void)
|
|
{
|
|
DAC tab[256];
|
|
int i;
|
|
GetColors(tab);
|
|
for (i = 64; i >= 0; i -= FADE_STEP)
|
|
{
|
|
SetColors(tab, i);
|
|
WaitVR();
|
|
UpdateColors();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VGA::Show (void)
|
|
{
|
|
SPRITE * spr = ShowQ.First();
|
|
|
|
for (spr = ShowQ.First(); spr; spr = spr->Next) spr->Show();
|
|
Update();
|
|
for (spr = ShowQ.First(); spr; spr = spr->Next) spr->Hide();
|
|
|
|
++ FrmCnt;
|
|
}
|
|
|
|
|
|
|
|
|
|
void VGA::UpdateColors (void)
|
|
{
|
|
DAC * tab = NewColors;
|
|
|
|
asm push ds
|
|
asm cld
|
|
asm lds si,tab // color table
|
|
asm mov dx,0x3C8 // PEL address write mode register
|
|
asm xor al,al // start from address 0
|
|
asm out dx,al // put address
|
|
asm mov cx,256*3 // # of colors
|
|
asm mov dl,0xC9 // PEL data register
|
|
|
|
// asm rep outsb // very fast!
|
|
|
|
// the slower version of above:
|
|
sc:
|
|
asm lodsb // take 1/3 color
|
|
asm out dx,al // put 1/3 color
|
|
asm jmp loop // little delay
|
|
loop:
|
|
asm loop sc // next one?
|
|
|
|
|
|
asm pop ds
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VGA::Update (void)
|
|
{
|
|
uint8 * p = Page[1];
|
|
Page[1] = Page[0];
|
|
Page[0] = p;
|
|
|
|
asm mov dx,VGACRT_
|
|
asm mov al,0x0D
|
|
asm mov ah,byte ptr p
|
|
asm out dx,ax
|
|
asm dec al
|
|
asm mov ah,byte ptr p+1
|
|
asm out dx,ax
|
|
|
|
if (! SpeedTest) WaitVR();
|
|
|
|
if (SetPal)
|
|
{
|
|
UpdateColors();
|
|
SetPal = false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VGA::Clear (uint8 color)
|
|
{
|
|
uint8 * a = (uint8 *) MK_FP(SCR_SEG, 0);
|
|
|
|
asm mov dx,VGASEQ_
|
|
asm mov ax,0x0F02 // map mask register - enable all planes
|
|
asm out dx,ax
|
|
asm les di,a
|
|
asm cld
|
|
|
|
asm mov cx,0xFFFF
|
|
asm mov al,color
|
|
asm rep stosb
|
|
asm stosb
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VGA::CopyPage (uint16 d, uint16 s)
|
|
{
|
|
uint8 * S = Page[s & 3], * D = Page[d & 3];
|
|
|
|
asm mov dx,VGAGRA_
|
|
asm mov al,0x05 // R/W mode
|
|
asm out dx,al
|
|
asm inc dx
|
|
asm in al,dx
|
|
asm and al,0xF4
|
|
asm push ax
|
|
asm push dx
|
|
asm or al,0x01
|
|
asm out dx,al
|
|
|
|
asm mov dx,VGASEQ_
|
|
asm mov ax,0x0F02 // map mask register - enable all planes
|
|
asm out dx,ax
|
|
|
|
asm push ds
|
|
|
|
asm les di,D
|
|
asm lds si,S
|
|
asm cld
|
|
asm mov cx,0x4000
|
|
asm rep movsb
|
|
|
|
asm pop ds
|
|
|
|
asm pop dx
|
|
asm pop ax
|
|
asm out dx,al // end of copy mode
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VGA::Exit (const char * txt, const char * name)
|
|
{
|
|
Msg = txt;
|
|
Nam = name;
|
|
#ifdef REPORT
|
|
wtom(coreleft(), Report + NREP, 10, 5);
|
|
dwtom(farcoreleft(), Report + FREP, 10, 6);
|
|
#endif
|
|
exit(0);
|
|
}
|
|
|
|
|
|
|
|
|
|
void VGA::Exit (int tref, const char * name)
|
|
{
|
|
Exit(Text[tref], name);
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void BITMAP::XShow (int x, int y)
|
|
{
|
|
uint8 rmsk = x % 4,
|
|
mask = 1 << rmsk,
|
|
* scr = VGA::Page[1] + y * (SCR_WID / 4) + x / 4;
|
|
uint8 * m = (char *) M;
|
|
uint8 * v = V;
|
|
|
|
asm push bx
|
|
asm push si
|
|
asm push ds
|
|
|
|
asm cld
|
|
asm les di,scr
|
|
asm lds si,v
|
|
asm mov bx,m
|
|
|
|
|
|
|
|
asm mov al,0x02 // map mask register
|
|
asm mov ah,mask
|
|
|
|
plane:
|
|
// enable output plane
|
|
asm mov dx,VGASEQ_
|
|
asm out dx,ax
|
|
asm push ax
|
|
|
|
// select input plane
|
|
asm mov dx,VGAGRA_
|
|
asm mov al,0x04 // read map select register
|
|
asm mov ah,rmsk
|
|
asm out dx,ax
|
|
|
|
asm push di
|
|
|
|
block:
|
|
asm lodsw
|
|
asm mov cx,ax
|
|
asm and ch,0x3F
|
|
asm test ah,0xC0
|
|
asm jz endpl
|
|
asm jns skip
|
|
asm jnp incsi // replicate?
|
|
asm add si,cx // skip over data block
|
|
asm dec si // fix it before following inc
|
|
|
|
incsi:
|
|
asm inc si
|
|
tint:
|
|
asm mov al,es:[di]
|
|
//-----------------------------------------------
|
|
// asm xlat ss:0 // unsupported with BASM!
|
|
__emit__(0x36, 0xD7); // this stands for above!
|
|
//-----------------------------------------------
|
|
asm stosb
|
|
asm loop tint
|
|
asm jmp block
|
|
|
|
skip:
|
|
asm add di,cx
|
|
asm jmp block
|
|
|
|
endpl:
|
|
asm pop di
|
|
asm pop ax
|
|
asm inc rmsk
|
|
asm shl ah,1
|
|
asm test ah,0x10
|
|
asm jz x_chk
|
|
asm mov ah,0x01
|
|
asm mov rmsk,0
|
|
asm inc di
|
|
x_chk:
|
|
asm cmp ah,mask
|
|
asm jne plane
|
|
asm pop ds
|
|
asm pop si
|
|
asm pop bx
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void BITMAP::Show (int x, int y)
|
|
{
|
|
uint8 mask = 1 << (x & 3),
|
|
* scr = VGA::Page[1] + y * (SCR_WID >> 2) + (x >> 2);
|
|
uint8 * v = V;
|
|
|
|
asm push ds // preserve DS
|
|
|
|
asm cld // normal direction
|
|
asm les di,scr // screen address
|
|
asm lds si,v // picture address
|
|
asm mov dx,VGASEQ_ // VGA reg
|
|
asm mov al,0x02
|
|
asm mov ah,mask
|
|
|
|
plane:
|
|
asm out dx,ax
|
|
asm push ax
|
|
asm push di
|
|
|
|
block:
|
|
asm mov cx,[si] // with ADD faster then LODSW
|
|
asm add si,2
|
|
asm test ch,0xC0
|
|
asm jns skip // 1 (SKP) or 0 (EOI)
|
|
asm jpo repeat // 2 (REP)
|
|
|
|
copy: // 3 (CPY)
|
|
asm and ch,0x3F
|
|
asm shr cx,1
|
|
asm rep movsw
|
|
asm jnc block
|
|
asm movsb
|
|
asm jmp block
|
|
|
|
repeat:
|
|
asm and ch,0x3F
|
|
asm mov al,[si]
|
|
asm inc si
|
|
asm mov ah,al
|
|
asm shr cx,1
|
|
asm rep stosw
|
|
asm jnc block
|
|
asm mov es:[di],al
|
|
asm inc di
|
|
asm jmp block
|
|
|
|
skip:
|
|
asm jz endpl
|
|
asm and ch,0x3F
|
|
asm add di,cx
|
|
asm jmp block
|
|
|
|
endpl:
|
|
asm pop di
|
|
asm pop ax
|
|
asm shl ah,1
|
|
asm test ah,0x10
|
|
asm jz x_chk
|
|
asm mov ah,0x01
|
|
asm inc di
|
|
x_chk:
|
|
asm cmp ah,mask
|
|
asm jne plane
|
|
asm pop ds
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BITMAP::Hide (int x, int y)
|
|
{
|
|
uint8 * scr = VGA::Page[1] + y * (SCR_WID / 4) + x / 4;
|
|
uint16 d = FP_OFF(VGA::Page[2]) - FP_OFF(VGA::Page[1]);
|
|
HideDesc * b = B;
|
|
uint16 extra = ((x & 3) != 0);
|
|
uint16 h = H;
|
|
|
|
// asm push bx
|
|
asm push si
|
|
asm push ds
|
|
|
|
asm cld
|
|
asm les di,scr
|
|
asm mov si,di
|
|
asm add si,d // take bytes from background page
|
|
asm lds bx,b
|
|
|
|
asm mov dx,VGAGRA_
|
|
asm mov al,0x05 // R/W mode
|
|
asm out dx,al
|
|
asm inc dx
|
|
asm in al,dx
|
|
asm and al,0xF4
|
|
asm push ax
|
|
asm push dx
|
|
asm or al,0x01
|
|
asm out dx,al
|
|
|
|
asm mov dx,VGASEQ_
|
|
asm mov ax,0x0F02 // enable all planes
|
|
asm out dx,ax
|
|
|
|
asm mov dx,ds // save DS
|
|
|
|
row:
|
|
// skip block
|
|
asm mov cx,[bx]
|
|
asm add si,cx
|
|
asm add di,cx
|
|
asm mov cx,[bx+2]
|
|
asm add bx,4
|
|
asm add cx,extra
|
|
|
|
asm push es
|
|
asm pop ds // set DS to video seg
|
|
asm rep movsb // move bytes fast
|
|
asm sub si,extra
|
|
asm sub di,extra
|
|
asm mov ds,dx // restore DS
|
|
|
|
asm dec h
|
|
asm jnz row
|
|
|
|
asm pop dx
|
|
asm pop ax
|
|
asm out dx,al // end of copy mode
|
|
|
|
|
|
asm pop ds
|
|
asm pop si
|
|
// asm pop bx
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|