scummvm/gfx.cpp
Ludvig Strigeus 1ec6a43008 fixed bug in GDI_UnkDecode7()
svn-id: r3419
2001-10-10 12:52:21 +00:00

1654 lines
33 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2001 Ludvig Strigeus
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Change Log:
* $Log$
* Revision 1.3 2001/10/10 12:52:21 strigeus
* fixed bug in GDI_UnkDecode7()
*
* Revision 1.2 2001/10/10 10:02:33 strigeus
* alternative mouse cursor
* basic save&load
*
* Revision 1.1.1.1 2001/10/09 14:30:14 strigeus
*
* initial revision
*
*
*/
#include "stdafx.h"
#include "scumm.h"
void Scumm::getGraphicsPerformance() {
int i;
_scummTimer = 0;
for (i=10; i!=0; i--) {
initScreens(0, 0, 320, 200);
}
vm.vars[VAR_PERFORMANCE_1] = _scummTimer;
_scummTimer = 0;
for (i=10; i!=0; i--) {
setDirtyRange(0, 0, 200);
unkVirtScreen2();
}
vm.vars[VAR_PERFORMANCE_2] = _scummTimer;
initScreens(0, 16, 320, 144);
}
void Scumm::initScreens(int a, int b, int w, int h) {
int i;
for (i=0; i<3; i++) {
nukeResource(10, i+1);
nukeResource(10, i+5);
}
if (!getResourceAddress(10,4)) {
initVirtScreen(3, 80, 13, false, false);
}
initVirtScreen(0, b, h-b, true, true);
initVirtScreen(1, 0, b, false, false);
initVirtScreen(2, h, 200-h, false, false);
_screenB = b;
_screenH = h;
}
void Scumm::initVirtScreen(int slot, int top, int height, bool twobufs, bool fourextra) {
VirtScreen *vs = &virtscr[slot];
int size;
assert(height>=0);
assert(slot>=0 && slot<4);
vs->unk1 = 0;
vs->width = 320;
vs->topline = top;
vs->height = height;
vs->alloctwobuffers = twobufs;
vs->fourlinesextra = fourextra;
vs->xstart = 0;
size = vs->width * vs->height;
vs->size = size;
if (vs->fourlinesextra)
size += 320*4;
memset(
createResource(10, slot+1, size),
0,size);
if (twobufs) {
memset(
createResource(10, slot+5, size),
0x23,size);
}
if (slot != 3) {
setDirtyRange(slot, 0, height);
}
}
void Scumm::setDirtyRange(int slot, int top, int bottom) {
int i;
VirtScreen *vs = &virtscr[slot];
for (i=0; i<40; i++) {
vs->tdirty[i] = top;
vs->bdirty[i] = bottom;
}
}
void Scumm::unkVirtScreen2() {
dseg_3DB6 = 1;
updateDirtyScreen(2);
if (_currentRoom != dseg_2456) {
dseg_2456 = (byte)_currentRoom;
dseg_4E8A = 1;
}
if (camera._lastPos == camera._curPos) {
updateDirtyScreen(0);
dseg_4E8A = 1;
dseg_4F8C = _screenStartStrip;
} else {
gdi.readPtr = getResourceAddress(10, 1);
gdi.readOffs = _screenStartStrip;
gdi.drawY = virtscr[0].topline;
gdi.drawHeight = virtscr[0].height;
blitToScreen(this, gdi.readPtr + gdi.readOffs*8, 0, gdi.drawY, 320, gdi.drawHeight);
for (gdi.draw8xPos = 0; gdi.draw8xPos<40; gdi.draw8xPos++) {
virtscr[0].tdirty[gdi.draw8xPos] = (byte)gdi.drawHeight;
virtscr[0].bdirty[gdi.draw8xPos] = 0;
}
}
}
void Scumm::updateDirtyScreen(int slot) {
VirtScreen *vs = &virtscr[slot];
int i;
if (vs->height==0)
return;
gdi.virtScreen = slot;
gdi.drawY = vs->topline;
gdi.drawHeight = vs->height;
gdi.readOffs = 0;
if (vs->fourlinesextra)
gdi.readOffs = _screenStartStrip;
if (_videoMode==0xE) {
for (i=0; i<40; i++) {
gdi.draw8xPos = i;
gdi.drawBottom = vs->bdirty[i];
if (gdi.drawBottom) {
gdi.drawTop = vs->tdirty[i];
drawStripToScreen();
vs->tdirty[i] = (byte)gdi.drawHeight;
vs->bdirty[i] = 0;
}
}
} else {
gdi.drawWidth = 8;
gdi.draw8xPos = 0;
for (i=0; i<40; i++) {
gdi.drawBottom = vs->bdirty[i];
if (gdi.drawBottom) {
gdi.drawTop = vs->tdirty[i];
vs->tdirty[i] = (byte)gdi.drawHeight;
vs->bdirty[i] = 0;
if (i!=39) {
if (vs->bdirty[i+1] == gdi.drawBottom &&
vs->tdirty[i+1] == gdi.drawTop) {
gdi.drawWidth += 8;
continue;
}
drawStripToScreen();
gdi.drawWidth = 8;
} else {
drawStripToScreen();
}
}
gdi.draw8xPos = i+1;
}
}
}
void Scumm::drawStripToScreen() {
if (gdi.drawBottom <= gdi.drawTop)
return;
if (_videoMode==0xE) {
gdi.drawTop &= 0xFE;
if (gdi.drawBottom&1)
gdi.drawBottom++;
}
if (gdi.drawBottom <= gdi.drawTop) {
gdi.drawBottom = gdi.drawTop + 4;
}
if (gdi.drawHeight < gdi.drawTop) {
gdi.drawTop = 0;
}
if (gdi.drawHeight < gdi.drawBottom) {
gdi.drawBottom = gdi.drawHeight;
}
gdi.readPtr = getResourceAddress(10, gdi.virtScreen+1) + (gdi.drawTop*40+gdi.readOffs+gdi.draw8xPos)*8;
blitToScreen(this, gdi.readPtr, gdi.draw8xPos*8, gdi.drawY+gdi.drawTop, gdi.drawWidth, gdi.drawBottom-gdi.drawTop);
}
void blit(byte *dst, byte *src, int w, int h) {
do {
memcpy(dst, src, w);
dst += 320;
src += 320;
} while (--h);
}
/* TODO: writes are being done to this data */
MouseCursor mouse_cursors[4] = {
8,7,{15,15,7,8},
{
0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,
0x00,0x80,0x00,0x80,0x00,0x00,0x7E,0x3F,
0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,
0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00,
},
8,7,{15,15,7,8},
{
0x00,0x00,0x7F,0xFE,0x60,0x06,0x30,0x0C,
0x18,0x18,0x0C,0x30,0x06,0x60,0x03,0xC0,
0x06,0x60,0x0C,0x30,0x19,0x98,0x33,0xCC,
0x67,0xE6,0x7F,0xFE,0x00,0x00,0x00,0x00,
},
8,7,{15,15,7,8},
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
},
8,7,{15,15,7,8},
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
},
};
void Scumm::setCursor(int cursor) {
MouseCursor *cur = &mouse_cursors[cursor];
int i,j;
byte *mask;
const byte *src;
byte shramount;
uint32 data;
debug(1,"Loading cursor %d", cursor);
gdi.hotspot_x = cur->hotspot_x;
gdi.hotspot_y = cur->hotspot_y;
gdi.currentCursor = cursor;
for (i=0; i<4; i++)
gdi.mouseColors[i] = cur->colors[i];
mask = gdi.mouseMask;
shramount = 0;
for(j=0; j<8; j++) {
src = cur->data;
i=16;
do {
/* TODO: endian trouble */
data = ((src[0]<<16) | (src[1]<<8))>>shramount;
src += 2;
mask[0] = (byte)(data>>24);
mask[1] = (byte)(data>>16);
mask[2] = (byte)(data>>8);
mask[3] = (byte)(data);
mask += 4;
} while (--i);
shramount++;
}
}
void Scumm::setCameraAt(int dest) {
int t;
CameraData *cd = &camera;
if (cd->_mode!=2 || abs(dest - cd->_curPos) > 160) {
cd->_curPos = dest;
}
cd->_destPos = dest;
t = vm.vars[VAR_CAMERA_MIN];
if (cd->_curPos < t) cd->_curPos = t;
t = vm.vars[VAR_CAMERA_MAX];
if (cd->_curPos > t) cd->_curPos = t;
if (vm.vars[VAR_SCROLL_SCRIPT]) {
vm.vars[VAR_CAMERA_CUR_POS] = cd->_curPos;
runScript(vm.vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
}
if (cd->_curPos != cd->_lastPos && charset._hasMask)
stopTalk();
}
void Scumm::setCameraFollows(Actor *a) {
int t,i;
CameraData *cd = &camera;
cd->_mode = 2;
cd->_follows = a->number;
if (a->room != _currentRoom) {
startScene(a->room, 0, 0);
cd->_mode = 2;
cd->_curPos = a->x;
setCameraAt(cd->_curPos);
}
t = (a->x >> 3);
if (t-_screenStartStrip < cd->_leftTrigger ||
t-_screenStartStrip > cd->_rightTrigger)
setCameraAt(a->x);
for (i=1,a=getFirstActor(); ++a,i<13; i++) {
if (a->room==_currentRoom)
a->needRedraw = true;
}
runHook(0);
}
void Scumm::initBGBuffers() {
byte *ptr;
int size, itemsize, i;
byte *room;
room = getResourceAddress(1, _roomResource);
ptr = findResource(MKID('RMIH'), findResource(MKID('RMIM'), room));
_numZBuffer = READ_LE_UINT16(ptr+8) + 1;
assert(_numZBuffer>=1 && _numZBuffer<=4);
itemsize = (_scrHeight + 4) * 40;
size = itemsize * _numZBuffer;
memset(createResource(10, 9, size), 0, size);
for (i=0; i<4; i++)
_imgBufOffs[i] = i*itemsize;
}
void Scumm::setPaletteFromRes() {
byte *ptr = getResourceAddress(1, _roomResource) + _CLUT_offs;
uint32 size = READ_BE_UINT32_UNALIGNED(ptr+4);
int i, r, g, b;
byte *dest, *epal;
int numcolor;
numcolor = (size-8) / 3;
ptr += 8;
checkRange(256, 0, numcolor, "Too many colors (%d) in Palette");
dest = _currentPalette;
if (_videoMode==0x13) {
for (i=0; i<numcolor; i++) {
r = *ptr++;
g = *ptr++;
b = *ptr++;
if (i<=15 || r<252 || g<252 || b<252) {
*dest++ = r>>2;
*dest++ = g>>2;
*dest++ = b>>2;
} else {
dest += 3;
}
}
}
if (_videoMode==0xE) {
epal = getResourceAddress(1, _roomResource) + _EPAL_offs + 8;
for (i=0; i<256; i++,epal++) {
_currentPalette[i] = *epal&0xF;
_currentPalette[i+256] = *epal>>4;
}
}
setDirtyColors(0, numcolor-1);
}
void Scumm::setDirtyColors(int min, int max) {
if (_palDirtyMin > min)
_palDirtyMin = min;
if (_palDirtyMax < max)
_palDirtyMax = max;
}
void Scumm::initCycl(byte *ptr) {
int i, j;
for (i=1; i<=16; i++)
_colorCycleDelays[i] = 0;
while ((j=*ptr++) != 0) {
assert(j>=1 && j<=16);
ptr += 2;
_colorCycleCounter[j] = 0;
_colorCycleDelays[j] = 16384 / READ_BE_UINT16_UNALIGNED(ptr);
ptr += 2;
_colorCycleFlags[j] = READ_BE_UINT16_UNALIGNED(ptr);
ptr += 2;
_colorCycleStart[j] = *ptr++;
_colorCycleEnd[j] = *ptr++;
}
}
void Scumm::stopCycle(int i) {
checkRange(16, 0, i, "Stop Cycle %d Out Of Range");
if (i!=0) {
_colorCycleDelays[i] = 0;
return;
}
for (i=1; i<=16; i++)
_colorCycleDelays[i] = 0;
}
void Scumm::cyclePalette() {
int valueToAdd;
int i, num;
byte *start, *end;
byte tmp[3];
if(_videoMode != 0x13)
return;
valueToAdd = vm.vars[VAR_TIMER];
if (valueToAdd < vm.vars[VAR_TIMER_NEXT])
valueToAdd = vm.vars[VAR_TIMER_NEXT];
for (i=1; i<=16; i++) {
if (_colorCycleDelays[i] &&
(_colorCycleCounter[i]+=valueToAdd) >=
_colorCycleDelays[i]) {
do {
_colorCycleCounter[i] -= _colorCycleDelays[i];
} while (_colorCycleDelays[i] <= _colorCycleCounter[i]);
setDirtyColors(_colorCycleStart[i], _colorCycleEnd[i]);
moveMemInPalRes(_colorCycleStart[i], _colorCycleEnd[i],
_colorCycleFlags[i]&2);
start = &_currentPalette[_colorCycleStart[i]*3];
end = &_currentPalette[_colorCycleEnd[i]*3];
num = _colorCycleEnd[i] - _colorCycleStart[i];
if (!(_colorCycleFlags[i]&2)) {
memmove(tmp, end, 3);
memmove(start+3, start, num*3);
memmove(start, tmp, 3);
} else {
memmove(tmp, start, 3);
memmove(start, start+3, num*3);
memmove(end, tmp, 3);
}
}
}
}
void Scumm::moveMemInPalRes(int start, int end, byte direction) {
byte *startptr, *endptr;
byte *startptr2, *endptr2;
int num;
byte tmp[6];
byte tmp2[6];
if (!_palManipCounter)
return;
startptr = getResourceAddress(0xC, 4) + start * 6;
endptr = getResourceAddress(0xC, 4) + end * 6;
startptr2 = getResourceAddress(0xC, 5) + start * 6;
endptr2 = getResourceAddress(0xC, 5) + end * 6;
num = end - start;
if (!direction) {
memmove(tmp, endptr, 6);
memmove(startptr+6, startptr, num*6);
memmove(startptr, tmp, 6);
memmove(tmp2, endptr2, 6);
memmove(startptr2+6, startptr2, num*6);
memmove(startptr2, tmp2, 6);
} else {
memmove(tmp, startptr, 6);
memmove(startptr, startptr+6, num*6);
memmove(endptr, tmp, 6);
memmove(tmp2, startptr2, 6);
memmove(startptr2, startptr2+6, num*6);
memmove(endptr2, tmp2, 6);
}
}
void Scumm::unkVirtScreen4(int a) {
VirtScreen *vs;
setDirtyRange(0, 0, 0);
camera._lastPos = camera._curPos;
dseg_3DB6 = 2;
dseg_3DB6 = 1;
if (dseg_4EA0 == 0)
return;
dseg_4EA0 = 0;
if (a==0)
return;
vs = &virtscr[0];
gdi.bg_ptr = getResourceAddress(0xA, 1) + vs->xstart;
memset(gdi.bg_ptr, 0, vs->size);
switch(a) {
case 1: case 2: case 3:
unkVirtScreen5(a-1);
break;
case 128:
unkScreenEffect6();
break;
case 129:
setDirtyRange(0, 0, vs->height);
dseg_3DB6 = 2;
updateDirtyScreen(0);
/* XXX: EGA_proc4(0); */
break;
case 134:
unkScreenEffect5(0);
break;
case 135:
unkScreenEffect5(1);
break;
}
}
void Scumm::redrawBGAreas() {
int i;
int val;
CameraData *cd = &camera;
if (cd->_curPos!=cd->_lastPos && charset._hasMask)
stopTalk();
val = 0;
if (_fullRedraw==0 && _BgNeedsRedraw) {
for (i=0; i<40; i++) {
if (actorDrawBits[_screenStartStrip + i]&0x8000) {
redrawBGStrip(i, 1);
}
}
}
if (_fullRedraw==0 && cd->_curPos - cd->_lastPos == 8) {
val = 2;
redrawBGStrip(39, 1);
} else if (_fullRedraw==0 && cd->_curPos - cd->_lastPos == -8) {
val = 1;
redrawBGStrip(0, 1);
} else if (_fullRedraw!=0 || cd->_curPos != cd->_lastPos) {
dseg_719E = 0;
_BgNeedsRedraw = 0;
redrawBGStrip(0, 40);
}
drawRoomObjects(val);
_BgNeedsRedraw = 0;
}
const uint32 zplane_tags[] = {
MKID('ZP00'),
MKID('ZP01'),
MKID('ZP02'),
MKID('ZP03')
};
void Scumm::drawBmp(byte *ptr, int a, int b, int c, const char *str, int objnr) {
byte *smap_ptr;
int i;
byte *zplane_list[4];
int t;
VirtScreen *vs;
byte twobufs;
int x;
byte *where_draw_ptr;
checkHeap();
smap_ptr = findResource(MKID('SMAP'), ptr);
if (objnr==209) {
warning("tst");
}
for(i=1; i<_numZBuffer; i++) {
zplane_list[i] = findResource(zplane_tags[i], ptr);
}
t = gdi.numLinesToProcess + _drawBmpY;
vs = &virtscr[gdi.virtScreen];
if (t > vs->height) {
error("%s %d strip drawn to %d below window bottom %d",
str, objnr, t, vs->height);
}
twobufs = vs->alloctwobuffers;
dseg_4174 = vs->size;
if (vs->fourlinesextra)
dseg_4174 += 5*256;
gdi.vertStripNextInc = gdi.numLinesToProcess * 320 - 1;
do {
gdi.smap_ptr = smap_ptr + READ_LE_UINT32(smap_ptr + a*4 + 8);
x = _drawBmpX;
if (vs->fourlinesextra)
x -= _screenStartStrip;
checkHeap();
if (x >= 40)
return;
if (_drawBmpY < vs->tdirty[x])
vs->tdirty[x]=_drawBmpY;
if (t > vs->bdirty[x])
vs->bdirty[x]=t;
gdi.bg_ptr = getResourceAddress(0xA, gdi.virtScreen+1) + (_drawBmpY*40+_drawBmpX)*8;
gdi.where_to_draw_ptr = getResourceAddress(0xA, gdi.virtScreen+5) + (_drawBmpY*40+_drawBmpX)*8;
if (!twobufs) {
gdi.where_to_draw_ptr = gdi.bg_ptr;
}
gdi.mask_ptr = getResourceAddress(0xA, 9) + (_drawBmpY*40+_drawBmpX);
where_draw_ptr = gdi.where_to_draw_ptr;
decompressBitmap();
checkHeap();
if (twobufs) {
gdi.where_to_draw_ptr = where_draw_ptr;
if (vm.vars[VAR_DRAWFLAGS]&2) {
if (hasCharsetMask(x<<3, _drawBmpY, (x+1)<<3, t))
draw8ColWithMasking();
else {
blit(gdi.bg_ptr, gdi.where_to_draw_ptr, 8, gdi.numLinesToProcess);
}
} else {
if (hasCharsetMask(x<<3, _drawBmpY, (x+1)<<3, t))
clear8ColWithMasking();
else
clear8Col();
}
}
checkHeap();
for (i=1; i<_numZBuffer; i++) {
if (!zplane_list[i])
continue;
gdi.z_plane_ptr = zplane_list[i] + READ_LE_UINT16(zplane_list[i] + a*2 + 8);
gdi.mask_ptr_dest = getResourceAddress(0xA, 9) + _drawBmpY*40 + _drawBmpX + _imgBufOffs[i];
if (dseg_4E3B!=0 && c!=0)
decompressMaskImgOr();
else
decompressMaskImg();
}
checkHeap();
_drawBmpX++;
a++;
} while (--b);
}
void Scumm::decompressBitmap() {
const byte decompress_table[] = {
0x0, 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x0,
};
dseg_4E3B = 0;
byte code = *gdi.smap_ptr++;
switch(code) {
case 1:
GDI_UnkDecode7();
break;
case 14: case 15: case 16: case 17: case 18:
gdi.decomp_shr = code - 10;
gdi.decomp_mask = decompress_table[code - 10];
GDI_UnkDecode6();
break;
case 24: case 25: case 26: case 27: case 28:
gdi.decomp_shr = code - 20;
gdi.decomp_mask = decompress_table[code - 20];
GDI_UnkDecode5();
break;
case 34: case 35: case 36: case 37: case 38:
dseg_4E3B = 1;
gdi.decomp_shr = code - 30;
gdi.decomp_mask = decompress_table[code - 30];
GDI_UnkDecode4();
break;
case 44: case 45: case 46: case 47: case 48:
dseg_4E3B = 1;
gdi.decomp_shr = code - 40;
gdi.decomp_mask = decompress_table[code - 40];
GDI_UnkDecode2();
break;
case 64: case 65: case 66: case 67: case 68:
gdi.decomp_shr = code - 60;
gdi.decomp_mask = decompress_table[code - 60];
GDI_UnkDecode1();
break;
case 84: case 85: case 86: case 87: case 88:
dseg_4E3B = 1;
gdi.decomp_shr = code - 80;
gdi.decomp_mask = decompress_table[code - 80];
GDI_UnkDecode3();
break;
}
}
int Scumm::hasCharsetMask(int x, int y, int x2, int y2) {
if (!charset._hasMask || y > charset._mask_bottom || x > charset._mask_right ||
y2 < charset._mask_top || x2 < charset._mask_left )
return 0;
return 1;
}
void Scumm::draw8ColWithMasking() {
int height = gdi.numLinesToProcess;
byte *mask = gdi.mask_ptr;
byte *dst = gdi.bg_ptr;
byte *src = gdi.where_to_draw_ptr;
byte maskbits;
do {
maskbits = *mask;
if (maskbits) {
if (!(maskbits&0x80)) dst[0] = src[0];
if (!(maskbits&0x40)) dst[1] = src[1];
if (!(maskbits&0x20)) dst[2] = src[2];
if (!(maskbits&0x10)) dst[3] = src[3];
if (!(maskbits&0x08)) dst[4] = src[4];
if (!(maskbits&0x04)) dst[5] = src[5];
if (!(maskbits&0x02)) dst[6] = src[6];
if (!(maskbits&0x01)) dst[7] = src[7];
} else {
/* alignment safe */
((uint32*)dst)[0] = ((uint32*)src)[0];
((uint32*)dst)[1] = ((uint32*)src)[1];
}
src += 320;
dst += 320;
mask += 40;
} while (--height);
}
void Scumm::clear8ColWithMasking() {
int height = gdi.numLinesToProcess;
byte *mask = gdi.mask_ptr;
byte *dst = gdi.bg_ptr;
byte maskbits;
do {
maskbits = *mask;
if (!maskbits) {
((uint32*)dst)[1] = ((uint32*)dst)[0] = 0;
} else {
if (!(maskbits&0x80)) dst[0] = 0;
if (!(maskbits&0x40)) dst[1] = 0;
if (!(maskbits&0x20)) dst[2] = 0;
if (!(maskbits&0x10)) dst[3] = 0;
if (!(maskbits&0x08)) dst[4] = 0;
if (!(maskbits&0x04)) dst[5] = 0;
if (!(maskbits&0x02)) dst[6] = 0;
if (!(maskbits&0x01)) dst[7] = 0;
}
dst += 320;
mask += 40;
} while (--height);
}
void Scumm::clear8Col() {
int height = gdi.numLinesToProcess;
byte *dst = gdi.bg_ptr;
do {
((uint32*)dst)[1] = ((uint32*)dst)[0] = 0;
dst += 320;
} while (--height);
}
void Scumm::decompressMaskImg() {
byte *src = gdi.z_plane_ptr;
byte *dst = gdi.mask_ptr_dest;
int height = gdi.numLinesToProcess;
byte b, c;
while(1) {
b = *src++;
if (b&0x80) {
b&=0x7F;
c = *src++;
do {
*dst = c;
dst += 40;
if (!--height)
return;
} while (--b);
} else {
do {
*dst = *src++;
dst += 40;
if (!--height)
return;
} while (--b);
}
}
}
void Scumm::decompressMaskImgOr() {
byte *src = gdi.z_plane_ptr;
byte *dst = gdi.mask_ptr_dest;
int height = gdi.numLinesToProcess;
byte b, c;
while(1) {
b = *src++;
if (b&0x80) {
b&=0x7F;
c = *src++;
do {
*dst |= c;
dst += 40;
if (!--height)
return;
} while (--b);
} else {
do {
*dst |= *src++;
dst += 40;
if (!--height)
return;
} while (--b);
}
}
}
void Scumm::redrawBGStrip(int start, int num) {
int s = _screenStartStrip + start;
gdi.virtScreen = 0;
actorDrawBits[s]|=0x8000;
_drawBmpX = s;
_drawBmpY = 0;
gdi.numLinesToProcess = virtscr[0].height;
if (gdi.numLinesToProcess > _scrHeight) {
error("Screen Y size %d > Room height %d",
gdi.numLinesToProcess,
_scrHeight);
}
drawBmp(
getResourceAddress(1, _roomResource) + _IM00_offs,
s,
num,
0,
"Room",
_roomResource);
}
#define READ_BIT (cl--,bit = bits&1, bits>>=1,bit)
#define FILL_BITS if (cl <= 8) { bits |= (*src++ << cl); cl += 8;}
void Scumm::GDI_UnkDecode1() {
byte *src = gdi.smap_ptr;
byte *dst = gdi.where_to_draw_ptr;
byte color = *src++;
uint bits = *src++;
byte cl = 8;
byte bit;
gdi.tempNumLines = gdi.numLinesToProcess;
do {
gdi.currentX = 8;
do {
FILL_BITS
*dst++=color;
if (!READ_BIT) {}
else if (READ_BIT) {
color += (bits&7)-4;
cl-=3;
bits>>=3;
} else {
FILL_BITS
color = bits&gdi.decomp_mask;
cl -= gdi.decomp_shr;
bits >>= gdi.decomp_shr;
}
} while (--gdi.currentX);
dst += 312;
} while (--gdi.tempNumLines);
}
void Scumm::GDI_UnkDecode2() {
byte *src = gdi.smap_ptr;
byte *dst = gdi.where_to_draw_ptr;
byte color = *src++;
int8 inc = -1;
uint bits = *src++;
byte cl = 8;
byte bit;
gdi.tempNumLines = gdi.numLinesToProcess;
do {
gdi.currentX = 8;
do {
FILL_BITS
if (color!=gdi.transparency)
*dst=color;
dst++;
if (!READ_BIT) {}
else if (!READ_BIT) {
FILL_BITS
color = bits&gdi.decomp_mask;
bits >>= gdi.decomp_shr;
cl -= gdi.decomp_shr;
inc = -1;
} else if (!READ_BIT) {
color += inc;
} else {
inc = -inc;
color += inc;
}
} while (--gdi.currentX);
dst += 312;
} while (--gdi.tempNumLines);
}
void Scumm::GDI_UnkDecode3() {
byte *src = gdi.smap_ptr;
byte *dst = gdi.where_to_draw_ptr;
byte color = *src++;
uint bits = *src++;
byte cl = 8;
byte bit;
gdi.tempNumLines = gdi.numLinesToProcess;
do {
gdi.currentX = 8;
do {
FILL_BITS
if (color!=gdi.transparency) *dst=color;
dst++;
if (!READ_BIT) {}
else if (READ_BIT) {
color += (bits&7)-4;
cl-=3;
bits>>=3;
} else {
FILL_BITS
color = bits&gdi.decomp_mask;
cl -= gdi.decomp_shr;
bits >>= gdi.decomp_shr;
}
} while (--gdi.currentX);
dst += 312;
} while (--gdi.tempNumLines);
}
void Scumm::GDI_UnkDecode4() {
byte *src = gdi.smap_ptr;
byte *dst = gdi.where_to_draw_ptr;
byte color = *src++;
int8 inc = -1;
uint bits = *src++;
byte cl = 8;
byte bit;
gdi.currentX = 8;
do {
gdi.tempNumLines = gdi.numLinesToProcess;
do {
FILL_BITS
if (color!=gdi.transparency)
*dst=color;
dst+=320;
if (!READ_BIT) {}
else if (!READ_BIT) {
FILL_BITS
color = bits&gdi.decomp_mask;
bits >>= gdi.decomp_shr;
cl -= gdi.decomp_shr;
inc = -1;
} else if (!READ_BIT) {
color += inc;
} else {
inc = -inc;
color += inc;
}
} while (--gdi.tempNumLines);
dst -= gdi.vertStripNextInc;
} while (--gdi.currentX);
}
void Scumm::GDI_UnkDecode5() {
byte *src = gdi.smap_ptr;
byte *dst = gdi.where_to_draw_ptr;
byte color = *src++;
int8 inc = -1;
uint bits = *src++;
byte cl = 8;
byte bit;
gdi.tempNumLines = gdi.numLinesToProcess;
do {
gdi.currentX = 8;
do {
FILL_BITS
*dst++=color;
if (!READ_BIT) {}
else if (!READ_BIT) {
FILL_BITS
color = bits&gdi.decomp_mask;
bits >>= gdi.decomp_shr;
cl -= gdi.decomp_shr;
inc = -1;
} else if (!READ_BIT) {
color += inc;
} else {
inc = -inc;
color += inc;
}
} while (--gdi.currentX);
dst += 312;
} while (--gdi.tempNumLines);
}
void Scumm::GDI_UnkDecode6() {
byte *src = gdi.smap_ptr;
byte *dst = gdi.where_to_draw_ptr;
byte color = *src++;
int8 inc = -1;
uint bits = *src++;
byte cl = 8;
byte bit;
gdi.currentX = 8;
do {
gdi.tempNumLines = gdi.numLinesToProcess;
do {
FILL_BITS
*dst=color;
dst+=320;
if (!READ_BIT) {}
else if (!READ_BIT) {
FILL_BITS
color = bits&gdi.decomp_mask;
bits >>= gdi.decomp_shr;
cl -= gdi.decomp_shr;
inc = -1;
} else if (!READ_BIT) {
color += inc;
} else {
inc = -inc;
color += inc;
}
} while (--gdi.tempNumLines);
dst -= gdi.vertStripNextInc;
} while (--gdi.currentX);
}
void Scumm::GDI_UnkDecode7() {
byte *src = gdi.smap_ptr;
byte *dst = gdi.where_to_draw_ptr;
int height = gdi.numLinesToProcess;
do {
/* Endian safe */
#if defined(SCUMM_NEED_ALIGNMENT)
memcpy(dst, src, 8);
#else
((uint32*)dst)[0] = ((uint32*)src)[0];
((uint32*)dst)[1] = ((uint32*)src)[1];
#endif
dst += 320;
src += 8;
} while (--height);
}
#undef READ_BIT
#undef FILL_BITS
void Scumm::restoreCharsetBg() {
dseg_4E3C = 0;
if (charset._mask_left != -1) {
restoreBG(charset._mask_left, charset._mask_top, charset._mask_right, charset._mask_bottom);
charset._hasMask = false;
charset._mask_left = -1;
}
_stringXpos2[0] = _stringXPos[0];
_stringYpos2[0] = _stringYPos[0];
}
void Scumm::restoreBG(int left, int top, int right, int bottom) {
VirtScreen *vs;
int topline, height, width, widthmod;
if (left==right || top==bottom)
return;
if (top<0) top=0;
if (findVirtScreen(top) == -1)
return;
vs = &virtscr[gdi.virtScreen];
topline = vs->topline;
height = topline + vs->height;
if (gdi.virtScreen==0) {
left += _lastXstart - vs->xstart;
right += _lastXstart - vs->xstart;
}
right++;
if (left<0) left=0;
if (right<0)right=0;
if (left>320)
return;
if (right>320)
right=320;
if (bottom>=height)
bottom=height;
updateDirtyRect(gdi.virtScreen, left, right, top-topline,bottom-topline, 0x4000);
vs = &virtscr[gdi.virtScreen];
height = (top-topline) * 320 + vs->xstart + left;
gdi.bg_ptr = getResourceAddress(0xA, gdi.virtScreen+1) + height;
gdi.where_to_draw_ptr = getResourceAddress(0xA, gdi.virtScreen+5) + height;
gdi.mask_ptr = getResourceAddress(0xA, 9) + top * 40 + (left>>3) + _screenStartStrip;
if (gdi.virtScreen==0) {
gdi.mask_ptr += vs->topline * 216;
}
height = bottom - top;
width = right - left;
widthmod = (width >> 2) + 2;
if (vs->alloctwobuffers && _currentRoom!=0 && vm.vars[VAR_DRAWFLAGS]&2) {
blit(gdi.bg_ptr, gdi.where_to_draw_ptr, width, height);
if (gdi.virtScreen==0 && charset._hasMask && height) {
do {
memset(gdi.mask_ptr, 0, widthmod);
gdi.mask_ptr += 40;
} while (--height);
}
} else {
if (height) {
do {
memset(gdi.bg_ptr, dseg_4E3C, width);
gdi.bg_ptr+=320;
} while (--height);
}
}
}
void Scumm::updateDirtyRect(int virt, int left, int right, int top, int bottom, uint16 dirtybits) {
VirtScreen *vs = &virtscr[virt];
int lp,rp;
uint16 *sp;
int num;
if (top > vs->height || bottom < 0)
return;
if (top<0)
top=0;
if (bottom > vs->height)
bottom = vs->height;
if (virt==0 && dirtybits) {
rp = (right >> 3) + _screenStartStrip;
lp = (left >> 3) + _screenStartStrip;
if (lp<0) lp=0;
if (rp >= 160)
rp = 159;
if (lp <= rp) {
num = rp - lp + 1;
sp = &actorDrawBits[lp];
do {
*sp++ |= dirtybits;
} while (--num);
}
}
rp = right >> 3;
lp = left >> 3;
if (lp>=40 || rp<0)
return;
if (lp<0) lp=0;
if (rp>=40) rp=39;
while (lp<=rp) {
if (top < vs->tdirty[lp])
vs->tdirty[lp] = top;
if (bottom > vs->bdirty[lp])
vs->bdirty[lp] = bottom;
lp++;
}
}
int Scumm::findVirtScreen(int y) {
VirtScreen *vs = virtscr;
int i;
gdi.virtScreen=-1;
for(i=0; i<3; i++,vs++) {
if (y >= vs->topline && y <= vs->topline+vs->height) {
gdi.virtScreen = i;
return i;
}
}
return -1;
}
void Scumm::unkVirtScreen5(int a) {
/* XXX: not implemented */
warning("stub unkVirtScreen5(%d)", a);
}
void Scumm::unkScreenEffect6() {
/* XXX: not implemented */
warning("stub unkScreenEffect6");
}
void Scumm::unkScreenEffect5(int a) {
/* XXX: not implemented */
warning("stub unkScreenEffect5(%d)",a);
}
void Scumm::setShake(int mode) {
if (mode!=-1)
_shakeMode = mode;
else
mode = 0;
/* XXX: not implemented */
warning("stub setShake(%d)",mode);
}
void Scumm::clearUpperMask() {
memset(
getResourceAddress(0xA, 9),
0,
_imgBufOffs[1] - _imgBufOffs[0]
);
}
void Scumm::moveCamera() {
CameraData *cd = &camera;
int pos = cd->_curPos;
int actorx, t;
Actor *a;
cd->_curPos &= 0xFFF8;
if (cd->_curPos < vm.vars[VAR_CAMERA_MIN]) {
if (vm.vars[VAR_CAMERA_FAST])
cd->_curPos = vm.vars[VAR_CAMERA_MIN];
else
cd->_curPos += 8;
cameraMoved();
return;
}
if (cd->_curPos > vm.vars[VAR_CAMERA_MAX]) {
if (vm.vars[VAR_CAMERA_FAST])
cd->_curPos = vm.vars[VAR_CAMERA_MAX];
else
cd->_curPos-=8;
cameraMoved();
return;
}
if (cd->_mode==2) {
a = derefActorSafe(cd->_follows, "moveCamera");
actorx = a->x;
t = (actorx>>3) - _screenStartStrip;
if (t < cd->_leftTrigger || t > cd->_rightTrigger) {
if (vm.vars[VAR_CAMERA_FAST]) {
if (t > 35)
cd->_destPos = actorx + 80;
if (t < 5)
cd->_destPos = actorx - 80;
} else
cd->_movingToActor = 1;
}
}
if (cd->_movingToActor) {
a = derefActorSafe(cd->_follows, "moveCamera(2)");
cd->_destPos = a->x;
}
if (cd->_destPos < vm.vars[VAR_CAMERA_MIN])
cd->_destPos = vm.vars[VAR_CAMERA_MIN];
if (cd->_destPos > vm.vars[VAR_CAMERA_MAX])
cd->_destPos = vm.vars[VAR_CAMERA_MAX];
if (vm.vars[VAR_CAMERA_FAST]) {
cd->_curPos = cd->_destPos;
} else {
if (cd->_curPos < cd->_destPos)
cd->_curPos+=8;
if (cd->_curPos > cd->_destPos)
cd->_curPos-=8;
}
/* a is set a bit above */
if (cd->_movingToActor && cd->_curPos>>3 == a->x>>3) {
cd->_movingToActor = 0;
}
cameraMoved();
if (pos != cd->_curPos && vm.vars[VAR_SCROLL_SCRIPT]) {
vm.vars[VAR_CAMERA_CUR_POS] = cd->_curPos;
runScript(vm.vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
}
}
void Scumm::cameraMoved() {
CameraData *cd = &camera;
if (cd->_curPos < 160) {
cd->_curPos = 160;
} else if (cd->_curPos + 160 >= _scrWidthIn8Unit<<3) {
cd->_curPos = (_scrWidthIn8Unit-20)<<3;
}
_screenStartStrip = (cd->_curPos >> 3) - 20;
_screenEndStrip = _screenStartStrip + 39;
virtscr[0].xstart = _screenStartStrip << 3;
}
void Scumm::palManipulate() {
byte *srcptr, *destptr;
byte *pal;
int i,j;
if (!_palManipCounter)
return;
srcptr = getResourceAddress(0xC, 4) + _palManipStart*6;
destptr = getResourceAddress(0xC, 5) + _palManipStart*6;
pal = _currentPalette + _palManipStart * 3;
i = _palManipStart;
while (i < _palManipEnd) {
j = (*((uint16*)srcptr) += *(uint16*)destptr );
*pal++ = j>>8;
srcptr += 2;
destptr += 2;
j = (*((uint16*)srcptr) += *(uint16*)destptr );
*pal++ = j>>8;
srcptr += 2;
destptr += 2;
j = (*((uint16*)srcptr) += *(uint16*)destptr );
*pal++ = j>>8;
srcptr += 2;
destptr += 2;
i++;
}
setDirtyColors(_palManipStart, _palManipEnd);
if (!--_palManipCounter) {
nukeResource(0xC, 4);
nukeResource(0xC, 5);
}
}
void Scumm::screenEffect(int effect) {
dseg_3DB6 = 1;
warning("stub screenEffect(%d)",effect);
/* TODO: not implemented */
dseg_4EA0 = 1;
}
void Scumm::resetActorBgs() {
Actor *a;
int i,bitpos;
int top,bottom;
uint16 onlyActorFlags;
for(i=0; i<40; i++) {
onlyActorFlags = (actorDrawBits[_screenStartStrip + i]&=0x3FFF);
a = getFirstActor();
bitpos = 1;
while (onlyActorFlags) {
if(onlyActorFlags&1 && a->top!=0xFF && a->needBgReset) {
top = a->top;
bottom = a->bottom;
if (a->top < virtscr[0].tdirty[i])
virtscr[0].tdirty[i] = a->top;
if (a->bottom > virtscr[0].bdirty[i])
virtscr[0].bdirty[i] = a->bottom;
actorDrawBits[_screenStartStrip + i] ^= bitpos;
gdi.where_to_draw_ptr = getResourceAddress(0xA, 5)
+ ((top * 40 + _screenStartStrip + i)<<3);
gdi.bg_ptr = getResourceAddress(0xA, 1)
+ ((top * 40 + _screenStartStrip + i)<<3);
gdi.mask_ptr = getResourceAddress(0xA, 9)
+ (top * 40 + _screenStartStrip + i);
gdi.numLinesToProcess = bottom - top;
if (gdi.numLinesToProcess) {
if (vm.vars[VAR_DRAWFLAGS]&2) {
if(hasCharsetMask(i<<3, top, (i+1)<<3, bottom))
draw8ColWithMasking();
else
blit(gdi.bg_ptr, gdi.where_to_draw_ptr, 8, gdi.numLinesToProcess);
} else {
clear8Col();
}
}
}
bitpos<<=1;
onlyActorFlags>>=1;
a++;
}
}
for(i=1,a=getFirstActor(); ++a,i<13; i++) {
a->needBgReset = false;
}
}
void Scumm::setPalColor(int index, int r, int g, int b) {
if(_videoMode==0x13) {
_currentPalette[index*3+0] = r>>2;
_currentPalette[index*3+1] = g>>2;
_currentPalette[index*3+2] = b>>2;
}
if (_videoMode==0xE) {
/* TODO: implement this */
warning("stub setPalColor(%d,%d,%d,%d)",index,r,g,b);
}
}
void Scumm::drawMouse() {
/* TODO: handle shake here */
::drawMouse(this,
mouse.x - gdi.hotspot_x,
mouse.y - gdi.hotspot_y,
gdi.mouseColors[((++gdi.mouseColorIndex)>>2)&3],
gdi.mouseMask + ((gdi.drawMouseX&7)<<6),
gdi.unk4>0
);
}
void Scumm::setCursorHotspot(int cursor, int x, int y) {
MouseCursor *cur = &mouse_cursors[cursor];
cur->hotspot_x = x;
cur->hotspot_y = y;
}
void Scumm::setCursorImg(int cursor, int img) {
MouseCursor *cur = &mouse_cursors[cursor];
byte *ptr;
ptr = getResourceAddress(6, 1);
// offs = ((uint32*)ptr)[img+1];
// if (!offs)
// return;
warning("setCursorImg: not implemented");
}
byte Scumm::isMaskActiveAt(int l, int t, int r, int b, byte *mem) {
int w,h,inc,i;
mem += b*40 + (l>>3);
w = (r>>3) - (l>>3) + 1;
inc = w+40;
h = b-t-1;
do {
for(i=0; i<w; i++)
if (mem[i])
return true;
mem -= 40;
} while (--h);
return false;
}
#if 0
void Scumm::GDI_drawMouse() {
byte *dst,*src,*dstorg;
int y,h;
byte color,val;
byte mask1,mask2,mask3;
int offs = gdi.drawMouseY*320 + (gdi.drawMouseX&0xFFF8);
/* XXX: check bounds here */
if (offs<0 || offs > 320*200 - 16*320)
return;
gdi.backupIsWhere = _vgabuf + offs;
src = gdi.backupIsWhere;
dst = gdi.mouseBackup;
h=16;
do {
memcpy(dst,src,24);
dst+=24;
src+=320;
} while (--h);
src = gdi.mouseMaskPtr;
color = gdi.mouseColor;
dstorg = gdi.backupIsWhere;
h=16;
do {
src++;
mask1 = *src++;
mask2 = *src++;
mask3 = *src++;
y = gdi.drawMouseY++;
if (y>199)
mask1 = mask2 = 0;
val = mask1 & gdi.mouseClipMask1;
dst = dstorg;
do {
if(val&0x80)
*dst = color;
dst++;
} while (val<<=1);
val = mask2 & gdi.mouseClipMask2;
dst = dstorg + 8;
do {
if(val&0x80)
*dst = color;
dst++;
} while (val<<=1);
val = mask3 & gdi.mouseClipMask3;
dst = dstorg + 16;
do {
if(val&0x80)
*dst = color;
dst++;
} while (val<<=1);
dstorg += 320;
} while (--h);
}
void Scumm::GDI_removeMouse() {
byte *dst,*src,h;
if (gdi.backupIsWhere) {
dst = gdi.backupIsWhere;
gdi.backupIsWhere = NULL;
src = gdi.mouseBackup;
h=16;
do {
memcpy(dst,src,24);
dst+=320;
src+=24;
} while (--h);
}
}
#endif