scummvm/engines/cge/vga13h.cpp
2011-07-02 01:02:14 +02:00

1392 lines
28 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 "common/rect.h"
#include "graphics/palette.h"
#include "cge/general.h"
#include "cge/vga13h.h"
#include "cge/bitmap.h"
#include "cge/vol.h"
#include "cge/text.h"
#include "cge/cge_main.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "cge/cge.h"
namespace CGE {
#define FADE_STEP 2
#define TMR_DIV ((0x8000/TMR_RATE)*2)
#define NREP 9
#define FREP 24
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, 0x00, 0x00, 0x00 }
};
bool SpeedTest = false;
Seq _seq1[] = { { 0, 0, 0, 0, 0 } };
Seq _seq2[] = { { 0, 1, 0, 0, 0 }, { 1, 0, 0, 0, 0 } };
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() {
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;
memcpy(sav+3, scr, siz * 2);
}
return sav;
*/
warning("STUB: SaveScreen");
return 0;
}
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
memcpy(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
free(sav);
sav = NULL;
*/
warning("STUB: RestoreScreen");
}
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);
}
Heart::Heart(void)
: Engine_(TMR_DIV) {
_enable = false;
_xTimer = NULL;
}
/*
extern "C" void TimerProc() {
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 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--;
}
*/
warning("STUB: Engine_::NewTimer");
}
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(CGEEngine *vm, 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), _vm(vm) {
memset(_file, 0, sizeof(_file));
*((uint16 *)&_flags) = 0;
setShapeList(shp);
}
Sprite::~Sprite() {
contract();
}
BMP_PTR Sprite::shp() {
register SprExt *e = _ext;
if (e)
if (e->_seq) {
int i = e->_seq[_seqPtr].Now;
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);
error("Invalid PHASE in SPRITE::Shp() %s", _file);
}
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
error("No core [%s]", n);
}
}
}
Sprite *Sprite::expand() {
if (!_ext) {
bool enbl = _heart->_enable;
_heart->_enable = false;
if ((_ext = new SprExt) == NULL)
error("No core");
if (*_file) {
static const 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;
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 (!(sprf._error==0))
error("Bad SPR [%s]", fname);
int len = 0, lcnt = 0;
while ((len = sprf.read((uint8 *)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,;/"), true);
break;
}
case 2 : { // Seq
seq = (Seq *) realloc(seq, (seqcnt + 1) * sizeof(*seq));
if (seq == NULL)
error("No core [%s]", 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)
error("No core [%s]", fname);
else {
SNAIL::COM *c = &nea[neacnt++];
if ((c->Com = (SNCOM) takeEnum(SNAIL::ComTxt, strtok(NULL, " \t,;/"))) < 0)
error("%s [%s]", (const char*)NumStr("Bad NEAR in ######", lcnt), (const char*)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)
error("No core [%s]", fname);
else {
SNAIL::COM *c = &tak[takcnt++];
if ((c->Com = (SNCOM) takeEnum(SNAIL::ComTxt, strtok(NULL, " \t,;/"))) < 0)
error("%s [%s]", NumStr("Bad NEAR in ######", lcnt), (const char *)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, true);
}
shplist[shpcnt] = NULL;
if (seq) {
if (maxnow >= shpcnt)
error("Bad PHASE in SEQ [%s]", fname);
if (maxnxt >= seqcnt)
error("Bad JUMP in SEQ [%s]", fname);
setSeq(seq);
} else
setSeq((_shpCnt == 1) ? _seq1 : _seq2);
//disable(); // disable interupt
setShapeList(shplist);
//enable(); // enable interupt
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() {
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) {
gotoxy(_x + (seq->Dx), _y + (seq->Dy));
_time = seq->Dly;
}
}
}
void Sprite::tick() {
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() {
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 :
free(m);
break;
default:
warning("Unhandled MemType in Sprite::KillXlat()");
break;
}
for (b = _ext->_shpList; *b; b++)
(*b)->_m = NULL;
_flags._xlat = false;
}
}
void Sprite::gotoxy(int x, int y) {
int xo = _x, yo = _y;
if (_x < 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->gotoxy(_next->_x - xo + _x, _next->_y - yo + _y);
if (_flags._shad)
_prev->gotoxy(_prev->_x - xo + _x, _prev->_y - yo + _y);
}
void Sprite::center() {
gotoxy((SCR_WID - _w) / 2, (SCR_HIG - _h) / 2);
}
void Sprite::show() {
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) {
Graphics::Surface *a = VGA::Page[1];
VGA::Page[1] = VGA::Page[pg & 3];
shp()->show(_x, _y);
VGA::Page[1] = a;
}
void Sprite::hide() {
register SprExt *e = _ext;
if (e->_b0)
e->_b0->hide(e->_x0, e->_y0);
}
BMP_PTR Sprite::ghost() {
register SprExt *e = _ext;
if (e->_b1) {
BMP_PTR bmp = new Bitmap(0, 0, (uint8 *)NULL);
if (bmp == NULL)
error("No core");
bmp->_w = e->_b1->_w;
bmp->_h = e->_b1->_h;
if ((bmp->_b = farnew(HideDesc, bmp->_h)) == NULL)
error("No Core");
bmp->_v = (uint8 *) memcpy(bmp->_b, e->_b1->_b, sizeof(HideDesc) * bmp->_h);
// TODO offset correctly in the surface using y1 pitch and x1 and not via offset segment
//bmp->_m = (uint8 *) MK_FP(e->y1, e->x1);
warning("FIXME: SPRITE::Ghost");
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;
}
//extern const char Copr[];
Graphics::Surface *VGA::Page[4];
Dac *VGA::SysPal;
void VGA::init() {
for (int idx = 0; idx < 4; ++idx) {
Page[idx] = new Graphics::Surface();
Page[idx]->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
}
SysPal = new Dac[PAL_CNT];
}
void VGA::deinit() {
for (int idx = 0; idx < 4; ++idx)
delete Page[idx];
delete[] SysPal;
}
VGA::VGA(int mode)
: FrmCnt(0), OldMode(0), OldScreen(NULL), StatAdr(VGAST1_),
Msg(NULL), Nam(NULL), SetPal(false), Mono(0) {
OldColors = NULL;
NewColors = NULL;
ShowQ = new QUEUE(true);
SpareQ = new QUEUE(false);
bool std = true;
int i;
for (i = 10; i < 20; i++) {
char *txt = Text->getText(i);
if (txt) {
warning("%s", txt);
std = false;
}
}
if (std)
// warning(Copr);
warning("TODO: Fix 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(0);
}
}
VGA::~VGA(void) {
Mono = 0;
if (isVga()) {
Common::String buffer = "";
Clear(0);
SetMode(OldMode);
SetColors();
RestoreScreen(OldScreen);
Sunrise(OldColors);
if (OldColors)
free(OldColors);
if (NewColors)
free(NewColors);
if (Msg)
buffer = Common::String(Msg);
if (Nam)
buffer = buffer + " [" + Nam + "]";
warning("%s", buffer.c_str());
}
}
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;
*/
warning("STUB: VGA::SetStatADR");
}
#pragma argsused
void VGA::WaitVR(bool on) {
// Since some of the game parts rely on using vertical sync as a delay mechanism,
// we're introducing a short delay to simulate it
g_system->delayMillis(10);
}
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:
*/
warning("STUB: VGA::Setup");
}
int VGA::SetMode(int mode) {
// ScummVM provides it's own vieo services
return 0;
}
void VGA::GetColors(Dac *tab) {
byte palData[PAL_SIZ];
g_system->getPaletteManager()->grabPalette(palData, 0, PAL_CNT);
pal2DAC(palData, tab);
}
void VGA::pal2DAC(const byte *palData, Dac *tab) {
const byte *colP = palData;
for (int idx = 0; idx < PAL_CNT; ++idx, colP += 3) {
tab[idx]._r = *colP >> 2;
tab[idx]._g = *(colP + 1) >> 2;
tab[idx]._b = *(colP + 2) >> 2;
}
}
void VGA::DAC2pal(const Dac *tab, byte *palData) {
for (int idx = 0; idx < PAL_CNT; ++idx, palData += 3) {
*palData = tab[idx]._r << 2;
*(palData + 1) = tab[idx]._g << 2;
*(palData + 2) = tab[idx]._b << 2;
}
}
void VGA::SetColors(Dac *tab, int lum) {
Dac *palP = tab, *destP = NewColors;
for (int idx = 0; idx < PAL_CNT; ++idx, ++palP, ++destP) {
destP->_r = (palP->_r * lum) >> 6;
destP->_g = (palP->_g * lum) >> 6;
destP->_b = (palP->_b * lum) >> 6;
}
if (Mono) {
destP = NewColors;
for (int idx = 0; idx < PAL_CNT; ++idx, ++palP) {
// Form a greyscalce colour from 30% R, 59% G, 11% B
uint8 intensity = (destP->_r * 77) + (destP->_g * 151) + (destP->_b * 28);
destP->_r = intensity;
destP->_g = intensity;
destP->_b = intensity;
}
}
SetPal = true;
}
void VGA::SetColors(void) {
memset(NewColors, 0, PAL_SIZ);
UpdateColors();
}
void VGA::Sunrise(Dac *tab) {
for (int i = 0; i <= 64; i += FADE_STEP) {
SetColors(tab, i);
WaitVR(true);
UpdateColors();
}
}
void VGA::Sunset(void) {
Dac tab[256];
GetColors(tab);
for (int i = 64; i >= 0; i -= FADE_STEP) {
SetColors(tab, i);
WaitVR(true);
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) {
byte palData[PAL_SIZ];
DAC2pal(NewColors, palData);
g_system->getPaletteManager()->setPalette(palData, 0, 256);
}
void VGA::Update(void) {
SWAP(VGA::Page[0], VGA::Page[1]);
if (SetPal) {
UpdateColors();
SetPal = false;
}
g_system->copyRectToScreen((const byte *)VGA::Page[0]->getBasePtr(0, 0), SCR_WID, 0, 0, SCR_WID, SCR_HIG);
g_system->updateScreen();
}
void VGA::Clear(uint8 color) {
for (int paneNum = 0; paneNum < 4; ++paneNum)
Page[paneNum]->fillRect(Common::Rect(0, 0, SCR_WID, SCR_HIG), color);
}
void VGA::CopyPage(uint16 d, uint16 s) {
Page[d]->copyFrom(*Page[s]);
}
//--------------------------------------------------------------------------
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
*/
warning("STUB: BITMAP::xShow");
}
void Bitmap::show(int x, int y) {
const byte *srcP = (const byte *)_v;
byte *destEndP = (byte *)VGA::Page[1]->pixels + (SCR_WID * SCR_HIG);
// Loop through processing data for each plane. The game originally ran in plane mapped mode, where a
// given plane holds each fourth pixel sequentially. So to handle an entire picture, each plane's data
// must be decompressed and inserted into the surface
for (int planeCtr = 0; planeCtr < 4; ++planeCtr) {
byte *destP = (byte *)VGA::Page[1]->getBasePtr(x + planeCtr, y);
for (;;) {
uint16 v = READ_LE_UINT16(srcP);
srcP += 2;
int cmd = v >> 14;
int count = v & 0x3FFF;
if (cmd == 0) {
// End of image
break;
}
assert(destP < destEndP);
// Handle a set of pixels
while (count-- > 0) {
// Transfer operation
switch (cmd) {
case 1:
// SKIP
break;
case 2:
// REPEAT
*destP = *srcP;
break;
case 3:
// COPY
*destP = *srcP++;
break;
}
// Move to next dest position
destP += 4;
}
if (cmd == 2)
++srcP;
}
}
/*
DEBUG code to display image immediately
// Temporary
g_system->copyRectToScreen((const byte *)VGA::Page[1]->getBasePtr(0, 0), SCR_WID, 0, 0, SCR_WID, SCR_HIG);
byte palData[PAL_SIZ];
VGA::DAC2pal(VGA::SysPal, palData);
g_system->getPaletteManager()->setPalette(palData, 0, PAL_CNT);
g_system->updateScreen();
g_system->delayMillis(5000);
*/
}
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
*/
warning("STUB: Bitmap::hide");
}
} // End of namespace CGE