diff options
author | Ludvig Strigeus | 2001-10-09 14:30:12 +0000 |
---|---|---|
committer | Ludvig Strigeus | 2001-10-09 14:30:12 +0000 |
commit | c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e (patch) | |
tree | 192b56f3908880c5a513a366f616341bcb47056e /gfx.cpp | |
download | scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.tar.gz scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.tar.bz2 scummvm-rg350-c30932afbe1af874e3a2aeb95fa4ee5de4d6e38e.zip |
Initial revision
svn-id: r3408
Diffstat (limited to 'gfx.cpp')
-rw-r--r-- | gfx.cpp | 1645 |
1 files changed, 1645 insertions, 0 deletions
diff --git a/gfx.cpp b/gfx.cpp new file mode 100644 index 0000000000..bbb5014d0f --- /dev/null +++ b/gfx.cpp @@ -0,0 +1,1645 @@ +/* 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.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); +} + +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() { + removeMouseCursor(); + + 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; + } + } + showMouseCursor(); +} + +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 Scumm::showMouseCursor() { + gdi.unk3 = 1; +} + +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(0xA, 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; + + _colorsInPalette = (size-8) / 3; + + ptr += 8; + + checkRange(256, 0, _colorsInPalette, "Too many colors (%d) in Palette"); + + dest = _currentPalette; + + if (_videoMode==0x13) { + for (i=0; i<_colorsInPalette; 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, _colorsInPalette-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; + removeMouseCursor(); + 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; + + 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; + + 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(); + + 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(); + } + } + + 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(); + } + _drawBmpX++; + a++; + } while (--b); +} + + +void Scumm::decompressBitmap() { + const byte decompress_table[] = { + 0x0, 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x0, + }; + + 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; + } 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) { + removeMouseCursor(); + 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; + + 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::removeMouseCursor() { + gdi.unk3 = 0; + drawMouse(); +} + +void Scumm::drawMouse() { + /* TODO: handle shake here */ + + GDI_removeMouse(); + if (gdi.unk3 && gdi.unk4>0) { + gdi.mouseColor = gdi.mouseColors[((++gdi.mouseColorIndex)>>2)&3]; + gdi.drawMouseX = mouse.x - gdi.hotspot_x; + gdi.drawMouseY = mouse.y - gdi.hotspot_y; + gdi.mouseMaskPtr = gdi.mouseMask + ((gdi.drawMouseX&7)<<6); + gdi.mouseClipMask1 = (gdi.drawMouseX<0) ? 0 : 0xFF; + gdi.mouseClipMask2 = (gdi.drawMouseX>=312) ? 0 : 0xFF; + gdi.mouseClipMask3 = (gdi.drawMouseX>=304) ? 0 : 0xFF; + GDI_drawMouse(); + } +} + +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 fully 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; +} + +void Scumm::GDI_drawMouse() { +#if 0 + 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); +#endif +} + +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); + } +} |