scummvm/engines/cge/vga13h.cpp
2011-06-28 22:36:43 +10:00

1376 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)
//--------------------------------------------------------------------------
static char Report[] = "NearHeap=..... FarHeap=......\n";
#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 }
};
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(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
*/
warning("STUB: Video");
}
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 (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 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(void) {
Contract();
}
BMP_PTR SPRITE::Shp(void) {
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(void) {
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,;/"));
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]", 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)
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), 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)
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(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 :
free(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) {
Graphics::Surface *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)
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) {
// puts(txt);
warning(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(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;
tab[idx].G = *(colP + 1);
tab[idx].B = *(colP + 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;
for (int idx = 0; idx < PAL_CNT; ++idx, ++palP) {
palP->R = (palP->R * lum) >> 6;
palP->G = (palP->G * lum) >> 6;
palP->B = (palP->B * lum) >> 6;
}
if (Mono) {
palP = tab;
for (int idx = 0; idx < PAL_CNT; ++idx, ++palP) {
// Form a greyscalce colour from 30% R, 59% G, 11% B
uint8 intensity = (palP->R * 77) + (palP->G * 151) + (palP->B * 28);
palP->R = intensity;
palP->G = intensity;
palP->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;
}
}
// 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