home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 February / chip_20022115.iso / amiga / chipgame / scummvm_aga.lha / ScummVM_AGA / src / gfx.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-01-05  |  39.9 KB  |  1,929 lines

  1. /* ScummVM - Scumm Interpreter
  2.  * Copyright (C) 2001  Ludvig Strigeus
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  *
  18.  * $Header: /cvsroot/scummvm/scummvm/gfx.cpp,v 1.16 2001/11/09 18:54:14 strigeus Exp $
  19.  *
  20.  */
  21.  
  22. #include "stdafx.h"
  23. #include "scumm.h"
  24.  
  25. void Scumm::getGraphicsPerformance() {
  26.     int i;
  27.  
  28.     for (i=10; i!=0; i--) {
  29.         initScreens(0, 0, 320, 200);
  30.     }
  31.  
  32.     _vars[VAR_PERFORMANCE_1] = 0;//_scummTimer;
  33.  
  34.     for (i=10; i!=0; i--) {
  35.         setDirtyRange(0, 0, 200);
  36.         drawDirtyScreenParts();
  37.     }
  38.  
  39.     _vars[VAR_PERFORMANCE_2] = 0;//_scummTimer;
  40.     
  41.     initScreens(0, 16, 320, 144);
  42. }
  43.  
  44. void Scumm::initScreens(int a, int b, int w, int h) {
  45.     int i;
  46.  
  47.     for (i=0; i<3; i++) {
  48.         nukeResource(rtBuffer, i+1);
  49.         nukeResource(rtBuffer, i+5);
  50.     }
  51.  
  52.     if (!getResourceAddress(rtBuffer,4)) {
  53.         initVirtScreen(3, 80, 13, false, false);
  54.     }
  55.     initVirtScreen(0, b, h-b, true, true);
  56.     initVirtScreen(1, 0, b, false, false);
  57.     initVirtScreen(2, h, 200-h, false, false);
  58.  
  59.     _screenB = b;
  60.     _screenH = h;
  61.  
  62. }
  63.  
  64. void Scumm::initVirtScreen(int slot, int top, int height, bool twobufs, bool fourextra) {
  65.     VirtScreen *vs = &virtscr[slot];
  66.     int size;
  67.  
  68.     assert(height>=0);
  69.     assert(slot>=0 && slot<4);
  70.  
  71.     vs->number = slot;
  72.     vs->unk1 = 0;
  73.     vs->width = 320;
  74.     vs->topline = top;
  75.     vs->height = height;
  76.     vs->alloctwobuffers = twobufs;
  77.     vs->scrollable = fourextra;
  78.     vs->xstart = 0;
  79.     size = vs->width * vs->height;
  80.     vs->size = size;
  81.     if (vs->scrollable)
  82.         size += 320*4;
  83.  
  84.     createResource(rtBuffer, slot+1, size);
  85.  
  86.     if (twobufs) {
  87.         createResource(rtBuffer, slot+5, size);
  88.     }
  89.  
  90.     if (slot != 3) {
  91.         setDirtyRange(slot, 0, height);
  92.     }
  93. }
  94.  
  95. void Scumm::setDirtyRange(int slot, int top, int bottom) {
  96.     int i;
  97.     VirtScreen *vs = &virtscr[slot];
  98.     for (i=0; i<40; i++) {
  99.         vs->tdirty[i] = top;
  100.         vs->bdirty[i] = bottom;
  101.     }
  102. }
  103.  
  104. void Scumm::drawDirtyScreenParts() {
  105.     int i;
  106.     VirtScreen *vs;
  107.  
  108.     updateDirtyScreen(2);
  109.  
  110.     if (camera._lastPos == camera._curPos) {
  111.         updateDirtyScreen(0);
  112.     } else {
  113.         vs = &virtscr[0];
  114.  
  115.         blitToScreen(this, getResourceAddress(rtBuffer, 1) + _screenStartStrip*8,
  116.             0, vs->topline, 320, vs->height);
  117.  
  118.         for (i = 0; i<40; i++) {
  119.             vs->tdirty[i] = (byte)vs->height;
  120.             vs->bdirty[i] = 0;
  121.         }
  122.     }
  123. }
  124.  
  125. void Scumm::updateDirtyScreen(int slot) {
  126.     gdi.updateDirtyScreen(&virtscr[slot]);
  127. }
  128.  
  129. void Gdi::updateDirtyScreen(VirtScreen *vs) {
  130.     int i;
  131.     int start,w,top,bottom;
  132.  
  133.     if (vs->height==0)
  134.         return;
  135.  
  136.     _readOffs = 0;
  137.     if (vs->scrollable)
  138.         _readOffs = vs->xstart;
  139.  
  140.     w = 8;
  141.     start = 0;
  142.  
  143.     for (i=0; i<40; i++) {
  144.         bottom = vs->bdirty[i];
  145.         if (bottom) {
  146.             top = vs->tdirty[i];
  147.             vs->tdirty[i] = (byte)vs->height;
  148.             vs->bdirty[i] = 0;
  149.             if (i!=39 && vs->bdirty[i+1] == (byte)bottom &&    vs->tdirty[i+1] == (byte)top) {
  150.                 w += 8;
  151.                 continue;
  152.             }
  153.             drawStripToScreen(vs, start, w, top, bottom);
  154.             w = 8;
  155.         }
  156.         start = i+1;
  157.     }
  158. }
  159.  
  160. void Gdi::drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b) {
  161.     byte *ptr;
  162.  
  163.     if (b <= t)
  164.         return;
  165.  
  166.     if (t > vs->height)
  167.         t = 0;
  168.  
  169.     if (b > vs->height)
  170.         b = vs->height;
  171.  
  172.     ptr = _vm->getResourceAddress(rtBuffer, vs->number+1) + (t*40+x)*8 + _readOffs;
  173.     blitToScreen(_vm, ptr, x*8, vs->topline+t, w, b-t);
  174. }
  175.  
  176. void blit(byte *dst, byte *src, int w, int h) {
  177.     assert(h>0);
  178.     do {
  179.         memcpy(dst, src, w);
  180.         dst += 320;
  181.         src += 320;
  182.     } while (--h);
  183. }
  184.  
  185. /* TODO: writes are being done to this data */
  186. MouseCursor mouse_cursors[4] = {
  187.     8,7,{15,15,7,8},
  188.     {
  189.     0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,
  190.     0x00,0x80,0x00,0x80,0x00,0x00,0x7E,0x3F,
  191.     0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,
  192.     0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00,
  193.     },
  194.     8,7,{15,15,7,8},
  195.     {
  196.     0x00,0x00,0x7F,0xFE,0x60,0x06,0x30,0x0C,
  197.     0x18,0x18,0x0C,0x30,0x06,0x60,0x03,0xC0,
  198.     0x06,0x60,0x0C,0x30,0x19,0x98,0x33,0xCC,
  199.     0x67,0xE6,0x7F,0xFE,0x00,0x00,0x00,0x00,
  200.     },
  201.  
  202.     8,7,{15,15,7,8},
  203.     {
  204.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  205.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  206.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  207.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  208.     },
  209.     8,7,{15,15,7,8},
  210.     {
  211.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  212.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  213.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  214.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  215.     },
  216.  
  217. };
  218.  
  219. void Scumm::setCursor(int cursor) {
  220.     MouseCursor *cur = &mouse_cursors[cursor];
  221.     int i,j;
  222.     byte *mask;
  223.     const byte *src;
  224.     byte shramount;
  225.     uint32 data;
  226.  
  227.     debug(1,"Loading cursor %d", cursor);
  228.     gdi._hotspot_x = cur->hotspot_x;
  229.     gdi._hotspot_y = cur->hotspot_y;
  230.     gdi._currentCursor = cursor;
  231.  
  232.     for (i=0; i<4; i++)
  233.         gdi._mouseColors[i] = cur->colors[i];
  234.     
  235.     mask = gdi._mouseMask;
  236.     shramount = 0;
  237.  
  238.     for(j=0; j<8; j++) {
  239.         src = cur->data;    
  240.         i=16;
  241.         do {
  242.             data = ((src[0]<<16) | (src[1]<<8))>>shramount;
  243.             src += 2;
  244.             mask[0] = (byte)(data>>24);
  245.             mask[1] = (byte)(data>>16);
  246.             mask[2] = (byte)(data>>8);
  247.             mask[3] = (byte)(data);
  248.             mask += 4;
  249.         } while (--i);
  250.         shramount++;
  251.     }
  252. }
  253.  
  254. void Scumm::setCameraAt(int dest) {
  255.     int t;
  256.     CameraData *cd = &camera;
  257.  
  258.     if (cd->_mode!=2 || abs(dest - cd->_curPos) > 160) {
  259.         cd->_curPos = dest;
  260.     }
  261.     cd->_destPos = dest;
  262.  
  263.     t = _vars[VAR_CAMERA_MIN];
  264.     if (cd->_curPos < t) cd->_curPos = t;
  265.  
  266.     t = _vars[VAR_CAMERA_MAX];
  267.     if (cd->_curPos > t) cd->_curPos = t;
  268.  
  269.     if (_vars[VAR_SCROLL_SCRIPT]) {
  270.         _vars[VAR_CAMERA_CUR_POS] = cd->_curPos;
  271.         runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
  272.     }
  273.  
  274.     if (cd->_curPos != cd->_lastPos && charset._hasMask)
  275.         stopTalk();
  276. }
  277.  
  278. void Scumm::setCameraFollows(Actor *a) {
  279.     int t,i;
  280.     CameraData *cd = &camera;
  281.  
  282.     cd->_mode = 2;
  283.     cd->_follows = a->number;
  284.  
  285.     if (a->room != _currentRoom) {
  286.         startScene(a->room, 0, 0);
  287.         cd->_mode = 2;
  288.         cd->_curPos = a->x;
  289.         setCameraAt(cd->_curPos);
  290.     }
  291.  
  292.     t = (a->x >> 3);
  293.  
  294.     if (t-_screenStartStrip < cd->_leftTrigger ||
  295.           t-_screenStartStrip > cd->_rightTrigger)
  296.         setCameraAt(a->x);
  297.  
  298.     for (i=1,a=getFirstActor(); ++a,i<13; i++) {
  299.         if (a->room==_currentRoom)
  300.             a->needRedraw = true;
  301.     }
  302.     runHook(0);
  303. }
  304.  
  305. void Scumm::initBGBuffers() {
  306.     byte *ptr;
  307.     int size, itemsize, i;
  308.     byte *room;
  309.  
  310.     room = getResourceAddress(rtRoom, _roomResource);
  311.  
  312.     ptr = findResource(MKID('RMIH'), findResource(MKID('RMIM'), room, 0), 0);
  313.  
  314.     gdi._numZBuffer = READ_LE_UINT16(ptr+8) + 1;
  315.  
  316.     assert(gdi._numZBuffer>=1 && gdi._numZBuffer<=4);
  317.     
  318.     itemsize = (_scrHeight + 4) * 40;
  319.     size = itemsize * gdi._numZBuffer;
  320.  
  321.     createResource(rtBuffer, 9, size);
  322.     
  323.     for (i=0; i<4; i++)
  324.         gdi._imgBufOffs[i] = i*itemsize;
  325. }
  326.  
  327. void Scumm::setPaletteFromPtr(byte *ptr) {
  328.     uint32 size = READ_BE_UINT32_UNALIGNED(ptr+4);
  329.     int i, r, g, b;
  330.     byte *dest, *epal;
  331.     int numcolor;
  332.  
  333.     numcolor = (size-8) / 3;
  334.  
  335.     ptr += 8;
  336.  
  337.     checkRange(256, 0, numcolor, "Too many colors (%d) in Palette");
  338.  
  339.     dest = _currentPalette;
  340.  
  341.     for (i=0; i<numcolor; i++) {
  342.         r = *ptr++;
  343.         g = *ptr++;
  344.         b = *ptr++;
  345.         if (i<=15 || r<252 || g<252 || b<252) {
  346.             *dest++ = r>>2;
  347.             *dest++ = g>>2;
  348.             *dest++ = b>>2;
  349.         } else {
  350.             dest += 3;
  351.         }
  352.     }
  353.  
  354. #if 0
  355.     if (_videoMode==0xE) {
  356.         epal = getResourceAddress(rtRoom, _roomResource) + _EPAL_offs + 8;
  357.         for (i=0; i<256; i++,epal++) {
  358.             _currentPalette[i] = *epal&0xF;
  359.             _currentPalette[i+256] = *epal>>4;
  360.         }
  361.     }
  362. #endif
  363.  
  364.     setDirtyColors(0, numcolor-1);
  365. }
  366.  
  367. void Scumm::setPaletteFromRes() {
  368.     byte *ptr;
  369.     ptr = getResourceAddress(rtRoom, _roomResource) + _CLUT_offs;
  370.     setPaletteFromPtr(ptr);
  371. }
  372.  
  373.  
  374. void Scumm::setDirtyColors(int min, int max) {
  375.     if (_palDirtyMin > min)
  376.         _palDirtyMin = min;
  377.     if (_palDirtyMax < max)
  378.         _palDirtyMax = max;
  379. }
  380.  
  381. void Scumm::initCycl(byte *ptr) {
  382.     int i, j;
  383.     ColorCycle *cycl;
  384.  
  385.     for (i=0,cycl=_colorCycle; i<16; i++,cycl++)
  386.         cycl->delay = 0;
  387.  
  388.     while ((j=*ptr++) != 0) {
  389.         if (j<1 || j>16) {
  390.             error("Invalid color cycle index %d", j);
  391.         }
  392.         cycl = &_colorCycle[j-1];
  393.  
  394.         ptr += 2;
  395.         cycl->counter = 0;
  396.         cycl->delay = 16384 / READ_BE_UINT16_UNALIGNED(ptr);
  397.         ptr += 2;
  398.         cycl->flags = READ_BE_UINT16_UNALIGNED(ptr);
  399.         ptr += 2;
  400.         cycl->start = *ptr++;
  401.         cycl->end = *ptr++;
  402.     }
  403. }
  404.  
  405. void Scumm::stopCycle(int i) {
  406.     ColorCycle *cycl;
  407.  
  408.     checkRange(16, 0, i, "Stop Cycle %d Out Of Range");
  409.     if (i!=0) {
  410.         _colorCycle[i-1].delay = 0;
  411.         return;
  412.     }
  413.  
  414.     for (i=0,cycl=_colorCycle; i<16; i++,cycl++)
  415.         cycl->delay = 0;
  416. }
  417.  
  418. void Scumm::cyclePalette() {
  419.     ColorCycle *cycl;
  420.     int valueToAdd;
  421.     int i, num;
  422.     byte *start, *end;
  423.     byte tmp[3];
  424.  
  425.     valueToAdd = _vars[VAR_TIMER];
  426.     if (valueToAdd < _vars[VAR_TIMER_NEXT])
  427.         valueToAdd = _vars[VAR_TIMER_NEXT];
  428.  
  429.     for (i=0,cycl=_colorCycle; i<16; i++,cycl++) {
  430.         if (cycl->delay &&
  431.             (cycl->counter+=valueToAdd) >= cycl->delay) {
  432.             do {
  433.                 cycl->counter -= cycl->delay;
  434.             } while (cycl->delay <= cycl->counter);
  435.  
  436.             setDirtyColors(cycl->start, cycl->end);
  437.             moveMemInPalRes(cycl->start, cycl->end, cycl->flags&2);
  438.             start = &_currentPalette[cycl->start*3];
  439.             end = &_currentPalette[cycl->end*3];
  440.  
  441.             num = cycl->end - cycl->start;
  442.  
  443.             if (!(cycl->flags&2)) {
  444.                 memmove(tmp, end, 3);
  445.                 memmove(start+3, start, num*3);
  446.                 memmove(start, tmp, 3);
  447.             } else {
  448.                 memmove(tmp, start, 3);
  449.                 memmove(start, start+3, num*3);
  450.                 memmove(end, tmp, 3);
  451.             }
  452.         }
  453.     }
  454. }
  455.  
  456. void Scumm::moveMemInPalRes(int start, int end, byte direction) {
  457.     byte *startptr, *endptr;
  458.     byte *startptr2, *endptr2;
  459.     int num;
  460.     byte tmp[6];
  461.     byte tmp2[6];
  462.  
  463.     if (!_palManipCounter)    
  464.         return;
  465.  
  466.     startptr = getResourceAddress(rtTemp, 4) + start * 6;
  467.     endptr = getResourceAddress(rtTemp, 4) + end * 6;
  468.  
  469.     startptr2 = getResourceAddress(rtTemp, 5) + start * 6;
  470.     endptr2 = getResourceAddress(rtTemp, 5) + end * 6;
  471.  
  472.     num = end - start;
  473.     
  474.     if (!direction) {
  475.         memmove(tmp, endptr, 6);
  476.         memmove(startptr+6, startptr, num*6);
  477.         memmove(startptr, tmp, 6);
  478.         memmove(tmp2, endptr2, 6);
  479.         memmove(startptr2+6, startptr2, num*6);
  480.         memmove(startptr2, tmp2, 6);
  481.     } else {
  482.         memmove(tmp, startptr, 6);
  483.         memmove(startptr, startptr+6, num*6);
  484.         memmove(endptr, tmp, 6);
  485.         memmove(tmp2, startptr2, 6);
  486.         memmove(startptr2, startptr2+6, num*6);
  487.         memmove(endptr2, tmp2, 6);
  488.     }
  489. }
  490.  
  491. void Scumm::unkVirtScreen4(int a) {
  492.     VirtScreen *vs;
  493.  
  494.     setDirtyRange(0, 0, 0);
  495.     camera._lastPos = camera._curPos;
  496.     if (!_screenEffectFlag)
  497.         return;
  498.     _screenEffectFlag = false;
  499.     
  500.     if (a==0)
  501.         return;
  502.  
  503.     vs = &virtscr[0];
  504.     gdi._backbuff_ptr = getResourceAddress(rtBuffer, 1) + vs->xstart;
  505.     memset(gdi._backbuff_ptr, 0, vs->size);
  506.  
  507.     switch(a) {
  508.     case 1: case 2: case 3:
  509.         unkScreenEffect7(a-1);
  510.         break;
  511.     case 128:
  512.         unkScreenEffect6();
  513.         break;
  514.     case 129:
  515.         setDirtyRange(0, 0, vs->height);
  516.         updateDirtyScreen(0);
  517.         /* XXX: EGA_proc4(0); */
  518.         break;
  519.     case 134:
  520.         unkScreenEffect5(0);
  521.         break;
  522.     case 135:
  523.         unkScreenEffect5(1);
  524.         break;
  525.     default:
  526.         error("unkVirtScreen4: default case %d", a);
  527.     }
  528. }
  529.  
  530. void Scumm::redrawBGAreas() {
  531.     int i;
  532.     int val;
  533.     CameraData *cd = &camera;
  534.  
  535.     if (cd->_curPos!=cd->_lastPos && charset._hasMask)
  536.         stopTalk();
  537.  
  538.     val = 0;
  539.  
  540.     if (_fullRedraw==0 && _BgNeedsRedraw) {
  541.         for (i=0; i<40; i++) {
  542.             if (actorDrawBits[_screenStartStrip + i]&0x8000) {
  543.                 redrawBGStrip(i, 1);
  544.             }
  545.         }
  546.     }
  547.  
  548.     if (_fullRedraw==0 && cd->_curPos - cd->_lastPos == 8) {
  549.         val = 2;
  550.         redrawBGStrip(39, 1);
  551.     } else if (_fullRedraw==0 && cd->_curPos - cd->_lastPos == -8) {
  552.         val = 1;
  553.         redrawBGStrip(0, 1);
  554.     } else if (_fullRedraw!=0 || cd->_curPos != cd->_lastPos) {
  555.         _BgNeedsRedraw = 0;
  556.         redrawBGStrip(0, 40);
  557.     }
  558.  
  559.     drawRoomObjects(val);
  560.     _BgNeedsRedraw = 0;
  561. }
  562.  
  563. const uint32 zplane_tags[] = {
  564.     MKID('ZP00'),
  565.     MKID('ZP01'),
  566.     MKID('ZP02'),
  567.     MKID('ZP03')
  568. };
  569.  
  570. void Gdi::drawBitmap(byte *ptr, VirtScreen *vs, int x, int y, int h, int stripnr, int numstrip, bool flag) {
  571.     byte *smap_ptr,*where_draw_ptr;
  572.     int i;
  573.     byte *zplane_list[4];
  574.     int bottom;
  575.     byte twobufs;
  576.     int numzbuf;
  577.     int sx;
  578.     
  579.     CHECK_HEAP
  580.  
  581.     smap_ptr = findResource(MKID('SMAP'), ptr, 0);
  582.  
  583.     numzbuf = _disable_zbuffer ? 0 : _numZBuffer;
  584.  
  585.     for(i=1; i<numzbuf; i++) {
  586.         zplane_list[i] = findResource(zplane_tags[i], ptr, 0);
  587.     }
  588.  
  589.     bottom = y + h;
  590.     if (bottom > vs->height) {
  591.         error("Gdi::drawBitmap, strip drawn to %d below window bottom %d", bottom, vs->height);
  592.     }
  593.  
  594.     twobufs = vs->alloctwobuffers;
  595.  
  596.     _vertStripNextInc = h * 320 - 1;
  597.  
  598.     _numLinesToProcess = h;
  599.  
  600.     do {
  601.         _smap_ptr = smap_ptr + READ_LE_UINT32(smap_ptr + stripnr*4 + 8);
  602.  
  603.         CHECK_HEAP
  604.  
  605.         sx = x;
  606.         if (vs->scrollable)
  607.             sx -= vs->xstart>>3;
  608.     
  609.         if ((uint)sx >= 40) 
  610.             return;
  611.  
  612.         if (y < vs->tdirty[sx])
  613.             vs->tdirty[sx]=y;
  614.  
  615.         if (bottom > vs->bdirty[sx])
  616.             vs->bdirty[sx] = bottom;
  617.         
  618.         _backbuff_ptr = _vm->getResourceAddress(rtBuffer, vs->number+1) + (y*40+x)*8;
  619.         _bgbak_ptr = _vm->getResourceAddress(rtBuffer, vs->number+5) + (y*40+x)*8;
  620.         if (!twobufs) {
  621.             _bgbak_ptr = _backbuff_ptr;
  622.         }
  623.         _mask_ptr = _vm->getResourceAddress(rtBuffer, 9) + (y*40+x);
  624.  
  625.         where_draw_ptr = _bgbak_ptr;
  626.         decompressBitmap();
  627.  
  628.         CHECK_HEAP
  629.  
  630.         if (twobufs) {
  631.             _bgbak_ptr = where_draw_ptr;
  632.             
  633.             if (_vm->hasCharsetMask(sx<<3, y, (sx+1)<<3, bottom)) {
  634.                 if (_vm->_vars[VAR_V5_DRAWFLAGS]&2)
  635.                     draw8ColWithMasking();
  636.                 else
  637.                     clear8ColWithMasking();
  638.             } else {
  639.                 if (_vm->_vars[VAR_V5_DRAWFLAGS]&2)
  640.                     blit(_backbuff_ptr, _bgbak_ptr, 8, h);
  641.                 else
  642.                     clear8Col();
  643.             }
  644.         }
  645.         CHECK_HEAP
  646.  
  647.         for (i=1; i<numzbuf; i++) {
  648.             if (!zplane_list[i])
  649.                 continue;
  650.             _z_plane_ptr = zplane_list[i] + READ_LE_UINT16(zplane_list[i] + stripnr*2 + 8);
  651.             _mask_ptr_dest = _vm->getResourceAddress(rtBuffer, 9) + y*40 + x + _imgBufOffs[i];
  652.             if (_useOrDecompress && flag)
  653.                 decompressMaskImgOr();
  654.             else
  655.                 decompressMaskImg();
  656.         }
  657.         CHECK_HEAP
  658.         x++;
  659.         stripnr++;
  660.     } while (--numstrip);
  661. }
  662.  
  663.  
  664. void Gdi::decompressBitmap() {
  665.     const byte decompress_table[] = {
  666.         0x0, 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x0,
  667.     };
  668.  
  669.     _useOrDecompress = false;
  670.  
  671.     byte code = *_smap_ptr++;
  672.  
  673.     assert(_numLinesToProcess);
  674.  
  675.     switch(code) {
  676.     case 1:
  677.         unkDecode7();
  678.         break;
  679.     case 14: case 15: case 16: case 17: case 18:
  680.         _decomp_shr = code - 10;
  681.         _decomp_mask = decompress_table[code - 10];
  682.         unkDecode6();
  683.         break;
  684.  
  685.     case 24: case 25: case 26: case 27: case 28:
  686.         _decomp_shr = code - 20;
  687.         _decomp_mask = decompress_table[code - 20];
  688.         unkDecode5();
  689.         break;
  690.     
  691.     case 34: case 35: case 36: case 37: case 38:
  692.         _useOrDecompress = true;
  693.         _decomp_shr = code - 30;
  694.         _decomp_mask = decompress_table[code - 30 ];
  695.         unkDecode4();
  696.         break;
  697.  
  698.     case 44: case 45: case 46: case 47: case 48:
  699.         _useOrDecompress = true;
  700.         _decomp_shr = code - 40;
  701.         _decomp_mask = decompress_table[code - 40];
  702.         unkDecode2();
  703.         break;
  704.  
  705.     case 64: case 65: case 66: case 67: case 68:
  706.         _decomp_shr = code - 60;
  707.         _decomp_mask = decompress_table[code - 60];
  708.         unkDecode1();
  709.         break;
  710.  
  711.     case 84: case 85: case 86: case 87: case 88:
  712.         _useOrDecompress = true;
  713.         _decomp_shr = code - 80;
  714.         _decomp_mask = decompress_table[code - 80];
  715.         unkDecode3();
  716.         break;
  717.  
  718.     /* New since version 6 */
  719.     case 104: case 105: case 106: case 107: case 108:
  720.         _decomp_shr = code - 100;
  721.         _decomp_mask = decompress_table[code - 100];
  722.         unkDecode1();
  723.         break;
  724.     
  725.     /* New since version 6 */
  726.     case 124: case 125: case 126: case 127: case 128:
  727.         _useOrDecompress = true;
  728.         _decomp_shr = code - 120;
  729.         _decomp_mask = decompress_table[code - 120];
  730.         unkDecode3();
  731.         break;
  732.  
  733.     default:
  734.         error("Gdi::decompressBitmap: default case %d", code);
  735.     }
  736. }
  737.  
  738. int Scumm::hasCharsetMask(int x, int y, int x2, int y2) {
  739.     if (!charset._hasMask || y > gdi._mask_bottom || x > gdi._mask_right || 
  740.         y2 < gdi._mask_top || x2 < gdi._mask_left )    
  741.         return 0;
  742.     return 1;
  743. }
  744.  
  745. void Gdi::draw8ColWithMasking() {
  746.     int height = _numLinesToProcess;
  747.     byte *mask = _mask_ptr;
  748.     byte *dst = _backbuff_ptr;
  749.     byte *src = _bgbak_ptr;
  750.     byte maskbits;
  751.  
  752.     do {
  753.         maskbits = *mask;
  754.         if (maskbits) {
  755.             if (!(maskbits&0x80)) dst[0] = src[0];
  756.             if (!(maskbits&0x40)) dst[1] = src[1];
  757.             if (!(maskbits&0x20)) dst[2] = src[2];
  758.             if (!(maskbits&0x10)) dst[3] = src[3];
  759.             if (!(maskbits&0x08)) dst[4] = src[4];
  760.             if (!(maskbits&0x04)) dst[5] = src[5];
  761.             if (!(maskbits&0x02)) dst[6] = src[6];
  762.             if (!(maskbits&0x01)) dst[7] = src[7];
  763.         } else {
  764. /* alignment safe */
  765.             ((uint32*)dst)[0] = ((uint32*)src)[0];
  766.             ((uint32*)dst)[1] = ((uint32*)src)[1];
  767.         }
  768.         src += 320;
  769.         dst += 320;
  770.         mask += 40;
  771.     } while (--height);
  772. }
  773.  
  774. void Gdi::clear8ColWithMasking() {
  775.     int height = _numLinesToProcess;
  776.     byte *mask = _mask_ptr;
  777.     byte *dst = _backbuff_ptr;
  778.     byte maskbits;
  779.  
  780.     do {
  781.         maskbits = *mask;
  782.         if (!maskbits) {
  783.             ((uint32*)dst)[1] = ((uint32*)dst)[0] = 0;
  784.         } else {
  785.             if (!(maskbits&0x80)) dst[0] = 0;
  786.             if (!(maskbits&0x40)) dst[1] = 0;
  787.             if (!(maskbits&0x20)) dst[2] = 0;
  788.             if (!(maskbits&0x10)) dst[3] = 0;
  789.             if (!(maskbits&0x08)) dst[4] = 0;
  790.             if (!(maskbits&0x04)) dst[5] = 0;
  791.             if (!(maskbits&0x02)) dst[6] = 0;
  792.             if (!(maskbits&0x01)) dst[7] = 0;
  793.         }
  794.         dst += 320;
  795.         mask += 40;
  796.     } while (--height);
  797. }
  798.  
  799. void Gdi::clear8Col() {
  800.     int height = _numLinesToProcess;
  801.     byte *dst = _backbuff_ptr;
  802.     do {
  803.         ((uint32*)dst)[1] = ((uint32*)dst)[0] = 0;
  804.         dst += 320;
  805.     } while (--height);
  806. }
  807.  
  808. void Gdi::decompressMaskImg() {
  809.     byte *src = _z_plane_ptr;
  810.     byte *dst = _mask_ptr_dest;
  811.     int height = _numLinesToProcess;
  812.     byte b, c;
  813.  
  814.     while(1) {
  815.         b = *src++;
  816.  
  817.         if (b&0x80) {
  818.             b&=0x7F;
  819.             c = *src++;
  820.  
  821.             do {
  822.                 *dst = c;
  823.                 dst += 40;
  824.                 if (!--height)
  825.                     return;
  826.             } while (--b);
  827.         } else {
  828.             do {
  829.                 *dst = *src++;
  830.                 dst += 40;
  831.                 if (!--height)
  832.                     return;
  833.             } while (--b);
  834.         }
  835.     }
  836. }
  837.  
  838. void Gdi::decompressMaskImgOr() {
  839.     byte *src = _z_plane_ptr;
  840.     byte *dst = _mask_ptr_dest;
  841.     int height = _numLinesToProcess;
  842.     byte b, c;
  843.  
  844.     while(1) {
  845.         b = *src++;
  846.         if (b&0x80) {
  847.             b&=0x7F;
  848.             c = *src++;
  849.  
  850.             do {
  851.                 *dst |= c;
  852.                 dst += 40;
  853.                 if (!--height)
  854.                     return;
  855.             } while (--b);
  856.         } else {
  857.             do {
  858.                 *dst |= *src++;
  859.                 dst += 40;
  860.                 if (!--height)
  861.                     return;
  862.             } while (--b);
  863.         }
  864.     }
  865. }
  866.  
  867. void Scumm::redrawBGStrip(int start, int num) {
  868.     int s = _screenStartStrip + start;
  869.  
  870.     assert(s>=0 && s<sizeof(actorDrawBits)/sizeof(actorDrawBits[0]));
  871.  
  872.     _curVirtScreen = &virtscr[0];
  873.  
  874.     actorDrawBits[s]|=0x8000;
  875.     if (_curVirtScreen->height > _scrHeight) {
  876.         error("Screen Y size %d < Room height %d",
  877.             _curVirtScreen->height,
  878.             _scrHeight);
  879.     }
  880.  
  881.     gdi.drawBitmap(getResourceAddress(rtRoom, _roomResource)+_IM00_offs,
  882.         _curVirtScreen, s, 0, _curVirtScreen->height, s, num, 0);
  883. }
  884.  
  885. #define READ_BIT (cl--,bit = bits&1, bits>>=1,bit)
  886. #define FILL_BITS if (cl <= 8) { bits |= (*src++ << cl); cl += 8;}
  887.  
  888. void Gdi::unkDecode1() {
  889.     byte *src = _smap_ptr;
  890.     byte *dst = _bgbak_ptr;
  891.     byte color = *src++;
  892.     uint bits = *src++;
  893.     byte cl = 8;
  894.     byte bit;
  895.     byte incm,reps;
  896.     _tempNumLines = _numLinesToProcess;
  897.  
  898.     do {    
  899.         _currentX = 8;
  900.         do {
  901.             FILL_BITS
  902.             *dst++=color;
  903.  
  904. againPos:;
  905.  
  906.             if (!READ_BIT) {} 
  907.             else if (READ_BIT) {
  908.                 incm = (bits&7)-4;
  909.                 cl-=3;
  910.                 bits>>=3;
  911.                 if (!incm) {
  912.                     FILL_BITS
  913.                     reps = bits&0xFF;
  914.                     do {
  915.                         if (!--_currentX) {
  916.                             _currentX = 8;
  917.                             dst += 312;
  918.                             if (!--_tempNumLines)
  919.                                 return;
  920.                         }
  921.                         *dst++=color;
  922.                     } while (--reps);
  923.                     bits>>=8;
  924.                     bits |= (*src++)<<(cl-8);
  925.                     goto againPos;
  926.                 } else {
  927.                     color += incm;
  928.                 }
  929.             } else {
  930.                 FILL_BITS
  931.                 color = bits&_decomp_mask;
  932.                 cl -= _decomp_shr;
  933.                 bits >>= _decomp_shr;
  934.             }
  935.         } while (--_currentX);
  936.         dst += 312;
  937.     } while (--_tempNumLines);
  938. }
  939.  
  940. void Gdi::unkDecode2() {
  941.     byte *src = _smap_ptr;
  942.     byte *dst = _bgbak_ptr;
  943.     byte color = *src++;
  944.     int8 inc = -1;
  945.     uint bits = *src++;
  946.     byte cl = 8;
  947.     byte bit;
  948.  
  949.     _tempNumLines = _numLinesToProcess;
  950.  
  951.     do {    
  952.         _currentX = 8;
  953.         do {
  954.             FILL_BITS
  955.             if (color!=_transparency)
  956.                 *dst=color;
  957.             dst++;
  958.             if (!READ_BIT) {}
  959.             else if (!READ_BIT) {
  960.                 FILL_BITS
  961.                 color = bits&_decomp_mask;
  962.                 bits >>= _decomp_shr;
  963.                 cl -= _decomp_shr;
  964.                 inc = -1;
  965.             } else if (!READ_BIT) {
  966.                 color += inc;
  967.             } else {
  968.                 inc = -inc;
  969.                 color += inc;
  970.             }
  971.         } while (--_currentX);
  972.         dst += 312;
  973.     } while (--_tempNumLines);
  974. }
  975.  
  976. void Gdi::unkDecode3() {
  977.     byte *src = _smap_ptr;
  978.     byte *dst = _bgbak_ptr;
  979.     byte color = *src++;
  980.     uint bits = *src++;
  981.     byte cl = 8;
  982.     byte bit;
  983.     byte incm,reps;
  984.  
  985.     _tempNumLines = _numLinesToProcess;
  986.  
  987.     do {    
  988.         _currentX = 8;
  989.         do {
  990.             FILL_BITS
  991.             if (color!=_transparency) *dst=color;
  992.             dst++;
  993.  
  994. againPos:;
  995.             if (!READ_BIT) {}
  996.             else if (READ_BIT) {
  997.                 incm = (bits&7)-4;
  998.                 
  999.                 cl-=3;
  1000.                 bits>>=3;
  1001.                 if (incm) {
  1002.                     color += incm;
  1003.                 } else {
  1004.                     FILL_BITS
  1005.                     reps = bits&0xFF;
  1006.                     if (color==_transparency) {
  1007.                         do {
  1008.                             if (!--_currentX) {
  1009.                                 _currentX = 8;
  1010.                                 dst += 312;
  1011.                                 if (!--_tempNumLines)
  1012.                                     return;
  1013.                             }
  1014.                             dst++;
  1015.                         } while (--reps);
  1016.                     } else {
  1017.                         do {
  1018.                             if (!--_currentX) {
  1019.                                 _currentX = 8;
  1020.                                 dst += 312;
  1021.                                 if (!--_tempNumLines)
  1022.                                     return;
  1023.                             }
  1024.                             *dst++=color;
  1025.                         } while (--reps);
  1026.                     }
  1027.                     bits>>=8;
  1028.                     bits |= (*src++)<<(cl-8);
  1029.                     goto againPos;
  1030.                 }
  1031.             } else {
  1032.                 FILL_BITS
  1033.                 color = bits&_decomp_mask;
  1034.                 cl -= _decomp_shr;
  1035.                 bits >>= _decomp_shr;
  1036.             }
  1037.         } while (--_currentX);
  1038.         dst += 312;
  1039.     } while (--_tempNumLines);
  1040. }
  1041.  
  1042.  
  1043. void Gdi::unkDecode4() {
  1044.     byte *src = _smap_ptr;
  1045.     byte *dst = _bgbak_ptr;
  1046.     byte color = *src++;
  1047.     int8 inc = -1;
  1048.     uint bits = *src++;
  1049.     byte cl = 8;
  1050.     byte bit;
  1051.     
  1052.     _currentX = 8;
  1053.     do {    
  1054.         _tempNumLines = _numLinesToProcess;
  1055.         do {
  1056.             FILL_BITS
  1057.             if (color!=_transparency)
  1058.                 *dst=color;
  1059.             dst+=320;
  1060.             if (!READ_BIT) {}
  1061.             else if (!READ_BIT) {
  1062.                 FILL_BITS
  1063.                 color = bits&_decomp_mask;
  1064.                 bits >>= _decomp_shr;
  1065.                 cl -= _decomp_shr;
  1066.                 inc = -1;
  1067.             } else if (!READ_BIT) {
  1068.                 color += inc;
  1069.             } else {
  1070.                 inc = -inc;
  1071.                 color += inc;
  1072.             }
  1073.         } while (--_tempNumLines);    
  1074.         dst -= _vertStripNextInc;
  1075.     } while (--_currentX);
  1076. }
  1077.  
  1078. void Gdi::unkDecode5() {
  1079.     byte *src = _smap_ptr;
  1080.     byte *dst = _bgbak_ptr;
  1081.     byte color = *src++;
  1082.     int8 inc = -1;
  1083.     uint bits = *src++;
  1084.     byte cl = 8;
  1085.     byte bit;
  1086.  
  1087.     _tempNumLines = _numLinesToProcess;
  1088.  
  1089.     do {    
  1090.         _currentX = 8;
  1091.         do {
  1092.             FILL_BITS
  1093.             *dst++=color;
  1094.             if (!READ_BIT) {}
  1095.             else if (!READ_BIT) {
  1096.                 FILL_BITS
  1097.                 color = bits&_decomp_mask;
  1098.                 bits >>= _decomp_shr;
  1099.                 cl -= _decomp_shr;
  1100.                 inc = -1;
  1101.             } else if (!READ_BIT) {
  1102.                 color += inc;
  1103.             } else {
  1104.                 inc = -inc;
  1105.                 color += inc;
  1106.             }
  1107.         } while (--_currentX);
  1108.         dst += 312;
  1109.     } while (--_tempNumLines);
  1110. }
  1111.  
  1112. void Gdi::unkDecode6() {
  1113.     byte *src = _smap_ptr;
  1114.     byte *dst = _bgbak_ptr;
  1115.     byte color = *src++;
  1116.     int8 inc = -1;
  1117.     uint bits = *src++;
  1118.     byte cl = 8;
  1119.     byte bit;
  1120.     
  1121.     _currentX = 8;
  1122.     do {    
  1123.         _tempNumLines = _numLinesToProcess;
  1124.         do {
  1125.             FILL_BITS
  1126.             *dst=color;
  1127.             dst+=320;
  1128.             if (!READ_BIT) {}
  1129.             else if (!READ_BIT) {
  1130.                 FILL_BITS
  1131.                 color = bits&_decomp_mask;
  1132.                 bits >>= _decomp_shr;
  1133.                 cl -= _decomp_shr;
  1134.                 inc = -1;
  1135.             } else if (!READ_BIT) {
  1136.                 color += inc;
  1137.             } else {
  1138.                 inc = -inc;
  1139.                 color += inc;
  1140.             }
  1141.         } while (--_tempNumLines);    
  1142.         dst -= _vertStripNextInc;
  1143.     } while (--_currentX);
  1144. }
  1145.  
  1146. void Gdi::unkDecode7() {
  1147.     byte *src = _smap_ptr;
  1148.     byte *dst = _bgbak_ptr;
  1149.     int height = _numLinesToProcess;
  1150.     do {
  1151.         /* Endian safe */
  1152. #if defined(SCUMM_NEED_ALIGNMENT)
  1153.         memcpy(dst, src, 8);
  1154. #else
  1155.         ((uint32*)dst)[0] = ((uint32*)src)[0];
  1156.         ((uint32*)dst)[1] = ((uint32*)src)[1];
  1157. #endif
  1158.         dst += 320;
  1159.         src += 8;
  1160.     } while (--height);
  1161. }
  1162.  
  1163. #undef READ_BIT
  1164. #undef FILL_BITS
  1165.  
  1166. void Scumm::restoreCharsetBg() {
  1167.     _bkColor = 0;
  1168.     if (gdi._mask_left != -1) {
  1169.         restoreBG(gdi._mask_left, gdi._mask_top, gdi._mask_right, gdi._mask_bottom);
  1170.         charset._hasMask = false;
  1171.         gdi._mask_left = -1;
  1172.         charset._strLeft = -1;
  1173.         charset._left = -1;
  1174.     }
  1175.     
  1176.     charset._xpos2 = string[0].xpos;
  1177.     charset._ypos2 = string[0].ypos;
  1178. }
  1179.  
  1180. void Scumm::restoreBG(int left, int top, int right, int bottom) {
  1181.     VirtScreen *vs;
  1182.     int topline, height, width, widthmod;
  1183.     byte *backbuff,*bgbak,*mask;
  1184.  
  1185.     if (left==right || top==bottom)
  1186.         return;
  1187.     if (top<0) top=0;
  1188.     
  1189.     if ((vs=findVirtScreen(top)) == NULL)
  1190.         return;
  1191.  
  1192.     topline = vs->topline;
  1193.     height = topline + vs->height;
  1194.     if (vs->number==0) {
  1195.         left += _lastXstart - vs->xstart;
  1196.         right += _lastXstart - vs->xstart;
  1197.     }
  1198.  
  1199.     right++;
  1200.     if (left<0) left=0;
  1201.     if (right<0)right=0;
  1202.     if (left>320)
  1203.         return;
  1204.     if (right>320)
  1205.         right=320;
  1206.     if (bottom>=height)
  1207.         bottom=height;
  1208.  
  1209.     updateDirtyRect(vs->number, left, right, top-topline,bottom-topline, 0x4000);
  1210.  
  1211.     height = (top-topline) * 320 + vs->xstart + left;
  1212.     
  1213.     backbuff = getResourceAddress(rtBuffer, vs->number+1) + height;
  1214.     bgbak = getResourceAddress(rtBuffer, vs->number+5) + height;
  1215.     mask = getResourceAddress(rtBuffer, 9) + top * 40 + (left>>3) + _screenStartStrip;
  1216.     if (vs->number==0) {
  1217.         mask += vs->topline * 216;
  1218.     }
  1219.  
  1220.     height = bottom - top;
  1221.     width = right - left;
  1222.     widthmod = (width >> 2) + 2;
  1223.  
  1224.     if (vs->alloctwobuffers && _currentRoom!=0 && _vars[VAR_V5_DRAWFLAGS]&2) {
  1225.         blit(backbuff, bgbak, width, height);
  1226.         if (vs->number==0 && charset._hasMask && height) {
  1227.             do {
  1228.                 memset(mask, 0, widthmod);
  1229.                 mask += 40;
  1230.             } while (--height);
  1231.         }
  1232.     } else {
  1233.         if (height) {
  1234.             do {
  1235.                 memset(backbuff, _bkColor, width);
  1236.                 backbuff+=320;
  1237.             } while (--height);
  1238.         }
  1239.     }
  1240. }
  1241.  
  1242. void Scumm::updateDirtyRect(int virt, int left, int right, int top, int bottom, uint16 dirtybits) {
  1243.     VirtScreen *vs = &virtscr[virt];
  1244.     int lp,rp;
  1245.     uint16 *sp;
  1246.     int num;
  1247.  
  1248.     if (top > vs->height || bottom < 0)
  1249.         return;
  1250.     
  1251.     if (top<0)
  1252.         top=0;
  1253.     if (bottom > vs->height)
  1254.         bottom = vs->height;
  1255.  
  1256.     if (virt==0 && dirtybits) {
  1257.         rp = (right >> 3) + _screenStartStrip;
  1258.         lp = (left >> 3) + _screenStartStrip;
  1259.         if (lp<0) lp=0;
  1260.         if (rp >= 200)
  1261.             rp = 200;
  1262.         if (lp <= rp) {
  1263.             num = rp - lp + 1;
  1264.             sp = &actorDrawBits[lp];
  1265.             do {
  1266.                 *sp++ |= dirtybits;
  1267.             } while (--num);
  1268.         }
  1269.     }
  1270.  
  1271.     setVirtscreenDirty(vs, left, top, right, bottom);
  1272. }
  1273.  
  1274. void Scumm::setVirtscreenDirty(VirtScreen *vs, int left, int top, int right, int bottom) {
  1275.     int lp = left >> 3;
  1276.     int rp = right >> 3;
  1277.  
  1278.     if (lp>=40 || rp<0)
  1279.         return;
  1280.     if (lp<0) lp=0;
  1281.     if (rp>=40) rp=39;
  1282.  
  1283.     while (lp<=rp) {
  1284.         if (top < vs->tdirty[lp])
  1285.             vs->tdirty[lp] = top;
  1286.         if (bottom > vs->bdirty[lp])
  1287.             vs->bdirty[lp] = bottom;
  1288.         lp++;
  1289.     }    
  1290. }
  1291.  
  1292. VirtScreen *Scumm::findVirtScreen(int y) {
  1293.     VirtScreen *vs = virtscr;
  1294.     int i;
  1295.     
  1296.     for(i=0; i<3; i++,vs++) {
  1297.         if (y >= vs->topline && y < vs->topline+vs->height) {
  1298.             return _curVirtScreen=vs;
  1299.         }    
  1300.     }
  1301.     return _curVirtScreen=NULL;
  1302. }
  1303.  
  1304. void Scumm::unkScreenEffect1() {
  1305.     /* XXX: not implemented */
  1306.     warning("stub unkScreenEffect1()");
  1307. }
  1308.  
  1309. void Scumm::unkScreenEffect2() {
  1310.     /* XXX: not implemented */
  1311.     warning("stub unkScreenEffect2()");
  1312. }
  1313.  
  1314. void Scumm::unkScreenEffect3() {
  1315.     /* XXX: not implemented */
  1316.     warning("stub unkScreenEffect3()");
  1317. }
  1318.  
  1319. void Scumm::unkScreenEffect4() {
  1320.     /* XXX: not implemented */
  1321.     warning("stub unkScreenEffect4()");
  1322. }
  1323.  
  1324. static const int8 screen_eff7_table1[4][16] = {
  1325.     {1,1,-1,1,-1,1,-1,-1,
  1326.      1,-1,-1,-1,1,1,1,-1},
  1327.     {0,1,2,1,2,0,2,1,
  1328.      2,0,2,1,0,0,0,0},
  1329.     {-2,-1,0,-1,-2,-1,-2,0
  1330.     -2,-1,-2,0,0,0,0,0},
  1331.     {0,-1,-2,-1,-2,0,-2,-1
  1332.     -2,0,-2,-1,0,0,0,0}
  1333. };
  1334.  
  1335. static const byte screen_eff7_table2[4][16] = {
  1336.     {0,0,39,0,39,0,39,24,
  1337.     0,24,39,24,0,0,0,24},
  1338.     {0,0,0,0,0,0,0,0,
  1339.     1,0,1,0,255,0,0,0},
  1340.     {39,24,39,24,39,24,39,24,
  1341.     38,24,38,24,255,0,0,0},
  1342.     {0,24,39,24,39,0,39,24,
  1343.     38,0,38,24,255,0,0,0}
  1344. };
  1345.  
  1346. static const byte screen_eff7_table3[4] = {
  1347.     13,25,25,25
  1348. };
  1349.  
  1350. void Scumm::unkScreenEffect7(int a) {
  1351.     int tab_1[16];
  1352.     int tab_2[16];
  1353.     int i,j;
  1354.     int bottom;
  1355.     int *tab2_ptr;
  1356.     int l,t,r,b;
  1357.  
  1358.     for (i=0; i<16; i++) {
  1359.         tab_1[i] = screen_eff7_table1[a][i];
  1360.         j = screen_eff7_table2[a][i];
  1361.         if (j==24)
  1362.             j = (virtscr[0].height>>3)-1;
  1363.         tab_2[i] = j;
  1364.     }
  1365.  
  1366.     bottom = virtscr[0].height >> 3;
  1367.     for (j=0; j < screen_eff7_table3[a]; j++) {
  1368.         for (i=0; i<4; i++) {
  1369.             l = tab_2[i*4];
  1370.             t = tab_2[i*4+1];
  1371.             r = tab_2[i*4+2];
  1372.             b = tab_2[i*4+3];
  1373.             if (t==b) {
  1374.                 while (l <= r) {
  1375.                     if (l>=0 && l<40 && (uint)t<(uint)bottom) {
  1376.                         virtscr[0].tdirty[l] = t<<3;
  1377.                         virtscr[0].bdirty[l] = (t+1)<<3;
  1378.                     }
  1379.                     l++;
  1380.                 }
  1381.             } else {
  1382.                 /* DE92 */
  1383.                 if (l<0 || l>=40 || b<=t)
  1384.                     continue;
  1385.                 if (b>bottom)
  1386.                     b=bottom;
  1387.                 virtscr[0].tdirty[l] = t<<3;
  1388.                 virtscr[0].bdirty[l] = (b+1)<<3;
  1389.             }
  1390.             updateDirtyScreen(0);
  1391.         }
  1392.  
  1393.         for (i=0; i<16; i++)
  1394.             tab_2[i] += tab_1[i];
  1395.         
  1396.         updateScreen(this);
  1397.         waitForTimer(this);
  1398.     }
  1399. }
  1400.  
  1401. void Scumm::unkScreenEffect6() {
  1402.     /* XXX: not implemented */
  1403.     warning("stub unkScreenEffect6");
  1404. }
  1405.     
  1406. void Scumm::unkScreenEffect5(int a) {
  1407.     /* XXX: not implemented */
  1408.     warning("stub unkScreenEffect5(%d)",a);
  1409. }
  1410.  
  1411. void Scumm::setShake(int mode) {
  1412.     if (mode!=-1)
  1413.         _shakeMode = mode;
  1414.     else
  1415.         mode = 0;
  1416.     /* XXX: not implemented */
  1417.     warning("stub setShake(%d)",mode);
  1418. }
  1419.  
  1420. void Gdi::clearUpperMask() {
  1421.     memset(
  1422.         _vm->getResourceAddress(rtBuffer, 9),
  1423.         0,
  1424.         _imgBufOffs[1] - _imgBufOffs[0]
  1425.     );
  1426. }
  1427.  
  1428. void Scumm::moveCamera() {
  1429.     CameraData *cd = &camera;
  1430.     int pos = cd->_curPos;
  1431.     int actorx, t;
  1432.     Actor *a;
  1433.  
  1434.     cd->_curPos &= 0xFFF8;
  1435.  
  1436.     if (cd->_curPos < _vars[VAR_CAMERA_MIN]) {
  1437.         if (_vars[VAR_CAMERA_FAST])
  1438.             cd->_curPos = _vars[VAR_CAMERA_MIN];
  1439.         else
  1440.             cd->_curPos += 8;
  1441.         cameraMoved();
  1442.         return;
  1443.     }
  1444.  
  1445.     if (cd->_curPos > _vars[VAR_CAMERA_MAX]) {
  1446.         if (_vars[VAR_CAMERA_FAST])
  1447.             cd->_curPos = _vars[VAR_CAMERA_MAX];
  1448.         else
  1449.             cd->_curPos-=8;
  1450.         cameraMoved();
  1451.         return;
  1452.     }
  1453.  
  1454.     if (cd->_mode==2) {
  1455.         a = derefActorSafe(cd->_follows, "moveCamera");
  1456.         
  1457.         actorx = a->x;
  1458.         t = (actorx>>3) - _screenStartStrip;
  1459.         
  1460.         if (t < cd->_leftTrigger || t > cd->_rightTrigger) {
  1461.             if (_vars[VAR_CAMERA_FAST]) {
  1462.                 if (t > 35)
  1463.                     cd->_destPos = actorx + 80;
  1464.                 if (t < 5)
  1465.                     cd->_destPos = actorx - 80;
  1466.             } else 
  1467.                 cd->_movingToActor = 1;
  1468.         }
  1469.     }
  1470.  
  1471.     if (cd->_movingToActor) {
  1472.         a = derefActorSafe(cd->_follows, "moveCamera(2)");
  1473.         cd->_destPos = a->x;
  1474.     }
  1475.  
  1476.     if (cd->_destPos < _vars[VAR_CAMERA_MIN])
  1477.         cd->_destPos = _vars[VAR_CAMERA_MIN];
  1478.  
  1479.     if (cd->_destPos > _vars[VAR_CAMERA_MAX])
  1480.         cd->_destPos = _vars[VAR_CAMERA_MAX];
  1481.  
  1482.     if (_vars[VAR_CAMERA_FAST]) {
  1483.         cd->_curPos = cd->_destPos;
  1484.     } else {
  1485.         if (cd->_curPos < cd->_destPos)
  1486.             cd->_curPos+=8;
  1487.         if (cd->_curPos > cd->_destPos)
  1488.             cd->_curPos-=8;
  1489.     }
  1490.  
  1491.     /* a is set a bit above */
  1492.     if (cd->_movingToActor && cd->_curPos>>3 == a->x>>3) {
  1493.         cd->_movingToActor = 0;
  1494.     }
  1495.  
  1496.     cameraMoved();
  1497.  
  1498.     if (pos != cd->_curPos && _vars[VAR_SCROLL_SCRIPT]) {
  1499.         _vars[VAR_CAMERA_CUR_POS] = cd->_curPos;
  1500.         runScript(_vars[VAR_SCROLL_SCRIPT], 0, 0, 0);
  1501.     }
  1502. }
  1503.  
  1504. void Scumm::cameraMoved() {
  1505.     CameraData *cd = &camera;
  1506.  
  1507.     if (cd->_curPos < 160) {
  1508.         cd->_curPos = 160;
  1509.     } else if (cd->_curPos + 160 >= _scrWidthIn8Unit<<3) {
  1510.         cd->_curPos = (_scrWidthIn8Unit-20)<<3;
  1511.     }
  1512.  
  1513.     _screenStartStrip = (cd->_curPos >> 3) - 20;
  1514.     _screenEndStrip = _screenStartStrip + 39;
  1515.     virtscr[0].xstart = _screenStartStrip << 3;
  1516. }
  1517.  
  1518. void Scumm::panCameraTo(int x) {
  1519.     CameraData *cd = &camera;
  1520.     cd->_destPos = x;
  1521.     cd->_mode = 3;
  1522.     cd->_movingToActor = 0;
  1523. }
  1524.  
  1525. void Scumm::actorFollowCamera(int act) {
  1526.     int old;
  1527.     CameraData *cd = &camera;
  1528.  
  1529.     /* mi1 compatibilty */
  1530.     if (act==0) {
  1531.         cd->_mode = 1;
  1532.         cd->_follows = 0;
  1533.         cd->_movingToActor = 0;
  1534.         return;
  1535.     }
  1536.     
  1537.     old = cd->_follows;
  1538.     setCameraFollows(derefActorSafe(act, "actorFollowCamera"));
  1539.     if (cd->_follows != old) 
  1540.         runHook(0);
  1541.  
  1542.     cd->_movingToActor = 0;
  1543. }
  1544.  
  1545. void Scumm::setCameraAtEx(int at) {
  1546.     CameraData *cd = &camera;
  1547.     cd->_mode = 1;
  1548.     cd->_curPos = at;
  1549.     setCameraAt(at);
  1550.     cd->_movingToActor = 0;
  1551. }
  1552.  
  1553. void Scumm::palManipulate() {
  1554.     byte *srcptr, *destptr;
  1555.     byte *pal;
  1556.     int i,j;
  1557.  
  1558.     if (!_palManipCounter)
  1559.         return;
  1560.     srcptr = getResourceAddress(rtTemp, 4) + _palManipStart*6;
  1561.     destptr = getResourceAddress(rtTemp, 5) + _palManipStart*6;
  1562.     pal = _currentPalette + _palManipStart * 3;
  1563.  
  1564.     i = _palManipStart;
  1565.     while (i < _palManipEnd) {
  1566.         j = (*((uint16*)srcptr) += *(uint16*)destptr );
  1567.         *pal++ = j>>8;
  1568.         srcptr += 2;
  1569.         destptr += 2;
  1570.  
  1571.         j = (*((uint16*)srcptr) += *(uint16*)destptr );
  1572.         *pal++ = j>>8;
  1573.         srcptr += 2;
  1574.         destptr += 2;
  1575.  
  1576.         j = (*((uint16*)srcptr) += *(uint16*)destptr );
  1577.         *pal++ = j>>8;
  1578.         srcptr += 2;
  1579.         destptr += 2;
  1580.  
  1581.         i++;
  1582.     }
  1583.     setDirtyColors(_palManipStart, _palManipEnd);
  1584.     if (!--_palManipCounter) {
  1585.         nukeResource(rtTemp, 4);
  1586.         nukeResource(rtTemp, 5);
  1587.     }
  1588. }
  1589.  
  1590. void Scumm::screenEffect(int effect) {
  1591.     switch(effect) {
  1592.     case 1:
  1593.     case 2:
  1594.     case 3:        unkScreenEffect7(effect-1);    break;
  1595.     case 128:    unkScreenEffect6(); break;
  1596.     case 130:    unkScreenEffect1(); break;
  1597.     case 131:    unkScreenEffect2();    break;
  1598.     case 132:    unkScreenEffect3();    break;
  1599.     case 133:    unkScreenEffect4();    break;
  1600.     case 134:    unkScreenEffect5(0); break;
  1601.     case 135:    unkScreenEffect5(1); break;
  1602.     case 129: break;
  1603.     default:
  1604.         warning("Unknown screen effect, %d", effect);
  1605.     }
  1606.     _screenEffectFlag = true;
  1607. }
  1608.  
  1609. void Scumm::resetActorBgs() {
  1610.     Actor *a;
  1611.     int i,bitpos;
  1612.     int top,bottom;
  1613.     uint16 onlyActorFlags;
  1614.     int offs;
  1615.     
  1616.     for(i=0; i<40; i++) {
  1617.         onlyActorFlags = (actorDrawBits[_screenStartStrip + i]&=0x3FFF);
  1618.         a = getFirstActor();
  1619.         bitpos = 1;
  1620.  
  1621.         while (onlyActorFlags) {
  1622.             if(onlyActorFlags&1 && a->top!=0xFF && a->needBgReset) {
  1623.                 top = a->top;
  1624.                 bottom = a->bottom;
  1625.                 actorDrawBits[_screenStartStrip + i] ^= bitpos;
  1626.                 gdi.resetBackground(a->top, a->bottom, i);
  1627.  
  1628.             }
  1629.             bitpos<<=1;
  1630.             onlyActorFlags>>=1;
  1631.             a++;
  1632.         }
  1633.     }
  1634.  
  1635.     for(i=1,a=getFirstActor(); ++a,i<13; i++) {
  1636.         a->needBgReset = false;
  1637.     }
  1638. }
  1639.  
  1640. void Gdi::resetBackground(byte top, byte bottom, int strip) {
  1641.     VirtScreen *vs = &_vm->virtscr[0];
  1642.     int offs;
  1643.  
  1644.     if (top < vs->tdirty[strip])
  1645.         vs->tdirty[strip] = top;
  1646.  
  1647.     if (bottom > vs->bdirty[strip])
  1648.         vs->bdirty[strip] = bottom;
  1649.     
  1650.     offs = (top * 40 + _vm->_screenStartStrip + strip);
  1651.     _mask_ptr = _vm->getResourceAddress(rtBuffer, 9)    + offs;
  1652.     _bgbak_ptr = _vm->getResourceAddress(rtBuffer, 5)    + (offs<<3);
  1653.     _backbuff_ptr = _vm->getResourceAddress(rtBuffer, 1)    + (offs<<3);
  1654.     
  1655.     _numLinesToProcess = bottom - top;
  1656.     if (_numLinesToProcess) {
  1657.         if (_vm->_vars[VAR_V5_DRAWFLAGS]&2) {
  1658.             if(_vm->hasCharsetMask(strip<<3, top, (strip+1)<<3, bottom))
  1659.                 draw8ColWithMasking();
  1660.             else
  1661.                 blit(_backbuff_ptr, _bgbak_ptr, 8, _numLinesToProcess);
  1662.         } else {
  1663.             clear8Col();
  1664.         }
  1665.     }
  1666. }
  1667.  
  1668. void Scumm::setPalColor(int index, int r, int g, int b) {
  1669.     _currentPalette[index*3+0] = r>>2;
  1670.     _currentPalette[index*3+1] = g>>2;
  1671.     _currentPalette[index*3+2] = b>>2;
  1672.     setDirtyColors(index,index);
  1673. }
  1674.  
  1675. void Scumm::drawMouse() {
  1676.     /* TODO: handle shake here */
  1677.  
  1678.     if (_cursorAnimate) {
  1679.         if (!(_cursorAnimateIndex&0x3))
  1680.             decompressDefaultCursor((_cursorAnimateIndex>>2)&3);
  1681.         _cursorAnimateIndex++;
  1682.         
  1683.     }
  1684.  
  1685.     ::drawMouse(this, 
  1686.         mouse.x - _cursorHotspotX, 
  1687.         mouse.y - _cursorHotspotY,
  1688.         _cursorWidth,
  1689.         _cursorHeight,
  1690.         _grabbedCursor,
  1691.         gdi._cursorActive>0
  1692.     );
  1693. }
  1694.  
  1695. void Scumm::setCursorHotspot(int cursor, int x, int y) {
  1696.     MouseCursor *cur = &mouse_cursors[cursor];
  1697.     cur->hotspot_x = x;
  1698.     cur->hotspot_y = y;
  1699. }
  1700.  
  1701. void Scumm::setCursorHotspot2(int x,int y) {
  1702.     _cursorHotspotX = x;
  1703.     _cursorHotspotY = y;
  1704. }
  1705.  
  1706. byte Scumm::isMaskActiveAt(int l, int t, int r, int b, byte *mem) {
  1707.     int w,h,i;
  1708.     
  1709.     l>>=3;
  1710.     if (l<0) l = 0;
  1711.     if (t<0) t = 0;
  1712.  
  1713.     r>>=3;
  1714.     if (r>39) r=39;
  1715.  
  1716.     mem += l + t*40;
  1717.  
  1718.     w = r-l;
  1719.     h = b-t+1;
  1720.  
  1721.     do {
  1722.         for(i=0; i<=w; i++)
  1723.             if (mem[i])
  1724.                 return true;
  1725.         mem += 40;
  1726.     } while (--h);
  1727.     
  1728.     return false;
  1729. }
  1730.  
  1731. void Scumm::setPalette(int palindex) {
  1732.     byte *pals;
  1733.  
  1734.     _curPalIndex = palindex;
  1735.     pals = getPalettePtr();
  1736.     if (pals==NULL)
  1737.         error("invalid palette %d", palindex);
  1738.     setPaletteFromPtr(pals);
  1739. }
  1740.  
  1741. byte *Scumm::findPalInPals(byte *pal, int index) {
  1742.     byte *offs;
  1743.     uint32 size;    
  1744.  
  1745.     pal = findResource(MKID('WRAP'), pal, 0);
  1746.     if (pal==NULL)
  1747.         return NULL;
  1748.  
  1749.     offs = findResource(MKID('OFFS'),pal, 0);
  1750.     if (offs==NULL)
  1751.         return NULL;
  1752.  
  1753.     size = (READ_BE_UINT32_UNALIGNED(offs+4)-8) >> 2;
  1754.     
  1755.     if ((uint32)index >= (uint32)size)
  1756.         return NULL;
  1757.  
  1758.     return offs + READ_LE_UINT32(offs + 8 + index * sizeof(uint32));
  1759. }
  1760.  
  1761. byte *Scumm::getPalettePtr() {
  1762.     byte *cptr;
  1763.  
  1764.     cptr = getResourceAddress(rtRoom, _roomResource);
  1765.     if (_CLUT_offs) {
  1766.         cptr += _CLUT_offs;
  1767.     } else {
  1768.         cptr = findPalInPals(cptr + _PALS_offs, _curPalIndex);
  1769.     }
  1770.     return cptr;
  1771. }
  1772.  
  1773. void Scumm::darkenPalette(int a, int b, int c, int d, int e) {
  1774.     byte *cptr, *cur;
  1775.     int num;
  1776.     byte color;
  1777.  
  1778.     cptr = getPalettePtr();
  1779.     cptr += 8 + a*3;
  1780.     cur = _currentPalette + a*3;
  1781.     if (a <= b) {
  1782.         num = b - a + 1;
  1783.  
  1784.         do {
  1785.             if (c != 0xFF) {
  1786.                 color = *cptr++ * (c>>2) / 0xFF;
  1787.             } else {
  1788.                 color = *cptr++ >> 2;
  1789.             }
  1790.             if(color>63) color = 63;
  1791.             *cur++=color;
  1792.  
  1793.             if (d != 0xFF) {
  1794.                 color = *cptr++ * (d>>2) / 0xFF;
  1795.             } else {
  1796.                 color = *cptr++ >> 2;
  1797.             }
  1798.             if(color>63) color = 63;
  1799.             *cur++=color;
  1800.  
  1801.             if (e != 0xFF) {
  1802.                 color = *cptr++ * (e>>2) / 0xFF;
  1803.             } else {
  1804.                 color = *cptr++ >> 2;
  1805.             }
  1806.             if(color>63) color = 63;
  1807.             *cur++=color;
  1808.         } while (--num);
  1809.     }
  1810.     setDirtyColors(a,b);
  1811. }
  1812.  
  1813. void Scumm::grabCursor(int x, int y, int w, int h) {
  1814.     VirtScreen *vs = findVirtScreen(y);
  1815.  
  1816.     if (vs==NULL) {
  1817.         warning("grabCursor: invalid Y %d", y);
  1818.         return;
  1819.     }
  1820.  
  1821.     grabCursor(
  1822.         getResourceAddress(rtBuffer, vs->number+1) + (y-vs->topline)*320 + x, 
  1823.         w,h);
  1824.  
  1825. }
  1826.  
  1827. void Scumm::decompressBomp(byte *dst, byte *src, int w, int h) {
  1828.     int len,num;
  1829.     byte code,color;
  1830.  
  1831.     src += 8;
  1832.  
  1833.     do {
  1834.         len = w;
  1835.         src += 2;
  1836.         while (len) {
  1837.             code = *src++;
  1838.             num = (code>>1)+1;
  1839.             if (num>len) num=len;
  1840.             len -= num;
  1841.             if (code&1) {
  1842.                 color = *src++;
  1843.                 do *dst++ = color; while (--num);
  1844.             } else {
  1845.                 do *dst++ = *src++; while (--num);
  1846.             }
  1847.         }
  1848.     } while (--h);
  1849. }
  1850.  
  1851. void Scumm::grabCursor(byte *ptr, int width, int height) {
  1852.     uint size;
  1853.     byte *dst;
  1854.     
  1855.     size = width * height;
  1856.     if (size > sizeof(_grabbedCursor))
  1857.         error("grabCursor: grabbed cursor too big");
  1858.  
  1859.     _cursorWidth = width;
  1860.     _cursorHeight = height;
  1861.     _cursorAnimate = 0;
  1862.  
  1863.     dst = _grabbedCursor;
  1864.     for(;height;height--) {
  1865.         memcpy(dst, ptr, width);
  1866.         dst += width;
  1867.         ptr += 320;
  1868.     }
  1869.  
  1870. }
  1871.  
  1872. void Scumm::useIm01Cursor(byte *im, int w, int h) {
  1873.     VirtScreen *vs = &virtscr[0];
  1874.     
  1875.     w<<=3;
  1876.     h<<=3;
  1877.     
  1878.     drawBox(0,0,w-1,h-1,0xFF);
  1879.  
  1880.     vs->alloctwobuffers = false;
  1881.     gdi._disable_zbuffer = true;
  1882.     gdi.drawBitmap(im, vs, _screenStartStrip, 0, h, 0, w>>3, 0);
  1883.     vs->alloctwobuffers = true;
  1884.     gdi._disable_zbuffer = false;
  1885.  
  1886.     grabCursor(getResourceAddress(rtBuffer, 1) + vs->xstart, w, h);
  1887.     
  1888.     blit(getResourceAddress(rtBuffer, 1) + vs->xstart, getResourceAddress(rtBuffer, 5) + vs->xstart, w, h);
  1889. }
  1890.  
  1891. void Scumm::useBompCursor(byte *im, int width, int height) {
  1892.     uint size;
  1893.  
  1894.     width<<=3;
  1895.     height<<=3;
  1896.     
  1897.     size = width * height;
  1898.     if (size > sizeof(_grabbedCursor))
  1899.         error("useBompCursor: cursor too big");
  1900.  
  1901.     _cursorWidth = width;
  1902.     _cursorHeight = height;
  1903.     _cursorAnimate = 0;
  1904.  
  1905.     decompressBomp(_grabbedCursor, im+10, width, height);
  1906. }
  1907.  
  1908. static const byte default_cursor_colors[4] = {
  1909.     15,15,7,8
  1910. };
  1911.  
  1912. void Scumm::decompressDefaultCursor(int index) {
  1913.     int i;
  1914.     byte color;
  1915.  
  1916.     memset(_grabbedCursor, 0xFF, sizeof(_grabbedCursor));
  1917.     _cursorWidth = 16;
  1918.     _cursorHeight = 16;
  1919.     _cursorHotspotX = 8;
  1920.     _cursorHotspotY = 7;
  1921.  
  1922.     color = default_cursor_colors[index];
  1923.     
  1924.     for(i=0; i<16; i++) {
  1925.         _grabbedCursor[16*8+i] = color;
  1926.         _grabbedCursor[16*i+8] = color;
  1927.     }
  1928. }
  1929.