aboutsummaryrefslogtreecommitdiff
path: root/engines/agi/picture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/agi/picture.cpp')
-rw-r--r--engines/agi/picture.cpp1101
1 files changed, 619 insertions, 482 deletions
diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index 58dfb9db68..951d67a0c0 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -31,8 +31,11 @@ PictureMgr::PictureMgr(AgiBase *agi, GfxMgr *gfx) {
_vm = agi;
_gfx = gfx;
+ _resourceNr = 0;
_data = NULL;
- _flen = _foffs = 0;
+ _dataSize = 0;
+ _dataOffset = 0;
+ _dataOffsetNibble = false;
_patCode = _patNum = _priOn = _scrOn = _scrColor = _priColor = 0;
_xOffset = _yOffset = 0;
@@ -44,257 +47,38 @@ PictureMgr::PictureMgr(AgiBase *agi, GfxMgr *gfx) {
}
void PictureMgr::putVirtPixel(int x, int y) {
- uint8 *p;
-
- x += _xOffset;
- y += _yOffset;
+ byte drawMask = 0;
if (x < 0 || y < 0 || x >= _width || y >= _height)
return;
- p = &_vm->_game.sbuf16c[y * _width + x];
+ x += _xOffset;
+ y += _yOffset;
if (_priOn)
- *p = (_priColor << 4) | (*p & 0x0f);
+ drawMask |= GFX_SCREEN_MASK_PRIORITY;
if (_scrOn)
- *p = _scrColor | (*p & 0xf0);
-}
+ drawMask |= GFX_SCREEN_MASK_VISUAL;
-#if 0
-static void drawProc(int x, int y, int c, void *data) {
- ((PictureMgr *)data)->putVirtPixel(x, y);
+ _gfx->putPixel(x, y, drawMask, _scrColor, _priColor);
}
-#endif
-
-/**
- * Draw an AGI line.
- * A line drawing routine sent by Joshua Neal, modified by Stuart George
- * (fixed >>2 to >>1 and some other bugs like x1 instead of y1, etc.)
- * @param x1 x coordinate of start point
- * @param y1 y coordinate of start point
- * @param x2 x coordinate of end point
- * @param y2 y coordinate of end point
- */
-void PictureMgr::drawLine(int x1, int y1, int x2, int y2) {
- x1 = CLIP(x1, 0, _width - 1);
- x2 = CLIP(x2, 0, _width - 1);
- y1 = CLIP(y1, 0, _height - 1);
- y2 = CLIP(y2, 0, _height - 1);
-
-#if 0
- Graphics::drawLine(x1, y1, x2, y2, 0, drawProc, this);
-#else
- int i, x, y, deltaX, deltaY, stepX, stepY, errorX, errorY, detdelta;
-
- // Vertical line
-
- if (x1 == x2) {
- if (y1 > y2) {
- SWAP(y1, y2);
- }
-
- for (; y1 <= y2; y1++)
- putVirtPixel(x1, y1);
-
- return;
- }
-
- // Horizontal line
-
- if (y1 == y2) {
- if (x1 > x2) {
- SWAP(x1, x2);
- }
- for (; x1 <= x2; x1++)
- putVirtPixel(x1, y1);
- return;
- }
-
- y = y1;
- x = x1;
- stepY = 1;
- deltaY = y2 - y1;
- if (deltaY < 0) {
- stepY = -1;
- deltaY = -deltaY;
- }
-
- stepX = 1;
- deltaX = x2 - x1;
- if (deltaX < 0) {
- stepX = -1;
- deltaX = -deltaX;
- }
-
- if (deltaY > deltaX) {
- i = deltaY;
- detdelta = deltaY;
- errorX = deltaY / 2;
- errorY = 0;
+byte PictureMgr::getNextByte() {
+ if (!_dataOffsetNibble) {
+ return _data[_dataOffset++];
} else {
- i = deltaX;
- detdelta = deltaX;
- errorX = 0;
- errorY = deltaX / 2;
+ byte curByte = _data[_dataOffset++] << 4;
+ return (_data[_dataOffset] >> 4) | curByte;
}
-
- putVirtPixel(x, y);
-
- do {
- errorY += deltaY;
- if (errorY >= detdelta) {
- errorY -= detdelta;
- y += stepY;
- }
-
- errorX += deltaX;
- if (errorX >= detdelta) {
- errorX -= detdelta;
- x += stepX;
- }
-
- putVirtPixel(x, y);
- i--;
- } while (i > 0);
-#endif
}
-/**
- * Draw a relative AGI line.
- * Draws short lines relative to last position. (drawing action 0xF7)
- */
-void PictureMgr::dynamicDrawLine() {
- int x1, y1, disp, dx, dy;
-
- if ((x1 = nextByte()) >= _minCommand ||
- (y1 = nextByte()) >= _minCommand) {
- _foffs--;
- return;
- }
-
- putVirtPixel(x1, y1);
-
- for (;;) {
- if ((disp = nextByte()) >= _minCommand)
- break;
-
- dx = ((disp & 0xf0) >> 4) & 0x0f;
- dy = (disp & 0x0f);
-
- if (dx & 0x08)
- dx = -(dx & 0x07);
- if (dy & 0x08)
- dy = -(dy & 0x07);
-
- drawLine(x1, y1, x1 + dx, y1 + dy);
- x1 += dx;
- y1 += dy;
- }
- _foffs--;
-}
-
-/**************************************************************************
-** absoluteLine
-**
-** Draws long lines to actual locations (cf. relative) (drawing action 0xF6)
-**************************************************************************/
-void PictureMgr::absoluteDrawLine() {
- int x1, y1, x2, y2;
-
- if ((x1 = nextByte()) >= _minCommand ||
- (y1 = nextByte()) >= _minCommand) {
- _foffs--;
- return;
- }
-
- putVirtPixel(x1, y1);
-
- for (;;) {
- if ((x2 = nextByte()) >= _minCommand)
- break;
-
- if ((y2 = nextByte()) >= _minCommand)
- break;
-
- drawLine(x1, y1, x2, y2);
- x1 = x2;
- y1 = y2;
- }
- _foffs--;
-}
-
-/**************************************************************************
-** okToFill
-**************************************************************************/
-int PictureMgr::isOkFillHere(int x, int y) {
- uint8 p;
-
- x += _xOffset;
- y += _yOffset;
-
- if (x < 0 || x >= _width || y < 0 || y >= _height)
- return false;
-
- p = _vm->_game.sbuf16c[y * _width + x];
-
- if (_flags & kPicFTrollMode)
- return ((p & 0x0f) != 11 && (p & 0x0f) != _scrColor);
-
- if (!_priOn && _scrOn && _scrColor != 15)
- return (p & 0x0f) == 15;
-
- if (_priOn && !_scrOn && _priColor != 4)
- return (p >> 4) == 4;
-
- return (_scrOn && (p & 0x0f) == 15 && _scrColor != 15);
-}
-
-/**************************************************************************
-** agi_fill
-**************************************************************************/
-void PictureMgr::agiFill(unsigned int x, unsigned int y) {
- if (!_scrOn && !_priOn)
- return;
-
- // Push initial pixel on the stack
- Common::Stack<Common::Point> stack;
- stack.push(Common::Point(x,y));
-
- // Exit if stack is empty
- while (!stack.empty()) {
- Common::Point p = stack.pop();
- unsigned int c;
- int newspanUp, newspanDown;
-
- if (!isOkFillHere(p.x, p.y))
- continue;
-
- // Scan for left border
- for (c = p.x - 1; isOkFillHere(c, p.y); c--)
- ;
-
- newspanUp = newspanDown = 1;
- for (c++; isOkFillHere(c, p.y); c++) {
- putVirtPixel(c, p.y);
- if (isOkFillHere(c, p.y - 1)) {
- if (newspanUp) {
- stack.push(Common::Point(c,p.y-1));
- newspanUp = 0;
- }
- } else {
- newspanUp = 1;
- }
-
- if (isOkFillHere(c, p.y + 1)) {
- if (newspanDown) {
- stack.push(Common::Point(c,p.y+1));
- newspanDown = 0;
- }
- } else {
- newspanDown = 1;
- }
- }
+byte PictureMgr::getNextNibble() {
+ if (!_dataOffsetNibble) {
+ _dataOffsetNibble = true;
+ return _data[_dataOffset] >> 4;
+ } else {
+ _dataOffsetNibble = false;
+ return _data[_dataOffset++] & 0x0F;
}
}
@@ -303,43 +87,43 @@ void PictureMgr::agiFill(unsigned int x, unsigned int y) {
**
** Draws an xCorner (drawing action 0xF5)
**************************************************************************/
-void PictureMgr::xCorner(bool skipOtherCoords) {
+void PictureMgr::draw_xCorner(bool skipOtherCoords) {
int x1, x2, y1, y2;
- if ((x1 = nextByte()) >= _minCommand ||
- (y1 = nextByte()) >= _minCommand) {
- _foffs--;
+ if ((x1 = getNextByte()) >= _minCommand ||
+ (y1 = getNextByte()) >= _minCommand) {
+ _dataOffset--;
return;
}
putVirtPixel(x1, y1);
for (;;) {
- x2 = nextByte();
+ x2 = getNextByte();
if (x2 >= _minCommand)
break;
if (skipOtherCoords)
- if (nextByte() >= _minCommand)
+ if (getNextByte() >= _minCommand)
break;
- drawLine(x1, y1, x2, y1);
+ draw_Line(x1, y1, x2, y1);
x1 = x2;
if (skipOtherCoords)
- if (nextByte() >= _minCommand)
+ if (getNextByte() >= _minCommand)
break;
- y2 = nextByte();
+ y2 = getNextByte();
if (y2 >= _minCommand)
break;
- drawLine(x1, y1, x1, y2);
+ draw_Line(x1, y1, x1, y2);
y1 = y2;
}
- _foffs--;
+ _dataOffset--;
}
/**************************************************************************
@@ -350,9 +134,9 @@ void PictureMgr::xCorner(bool skipOtherCoords) {
void PictureMgr::yCorner(bool skipOtherCoords) {
int x1, x2, y1, y2;
- if ((x1 = nextByte()) >= _minCommand ||
- (y1 = nextByte()) >= _minCommand) {
- _foffs--;
+ if ((x1 = getNextByte()) >= _minCommand ||
+ (y1 = getNextByte()) >= _minCommand) {
+ _dataOffset--;
return;
}
@@ -360,44 +144,30 @@ void PictureMgr::yCorner(bool skipOtherCoords) {
for (;;) {
if (skipOtherCoords)
- if (nextByte() >= _minCommand)
+ if (getNextByte() >= _minCommand)
break;
- y2 = nextByte();
+ y2 = getNextByte();
if (y2 >= _minCommand)
break;
- drawLine(x1, y1, x1, y2);
+ draw_Line(x1, y1, x1, y2);
y1 = y2;
- x2 = nextByte();
+ x2 = getNextByte();
if (x2 >= _minCommand)
break;
if (skipOtherCoords)
- if (nextByte() >= _minCommand)
+ if (getNextByte() >= _minCommand)
break;
- drawLine(x1, y1, x2, y1);
+ draw_Line(x1, y1, x2, y1);
x1 = x2;
}
- _foffs--;
-}
-
-/**************************************************************************
-** fill
-**
-** AGI flood fill. (drawing action 0xF8)
-**************************************************************************/
-void PictureMgr::fill() {
- int x1, y1;
-
- while ((x1 = nextByte()) < _minCommand && (y1 = nextByte()) < _minCommand)
- agiFill(x1, y1);
-
- _foffs--;
+ _dataOffset--;
}
/**************************************************************************
@@ -406,7 +176,6 @@ void PictureMgr::fill() {
** Draws pixels, circles, squares, or splatter brush patterns depending
** on the pattern code.
**************************************************************************/
-
void PictureMgr::plotPattern(int x, int y) {
static const uint16 binary_list[] = {0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100,
0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};
@@ -532,267 +301,600 @@ void PictureMgr::plotBrush() {
for (;;) {
if (_patCode & 0x20) {
- if ((_patNum = nextByte()) >= _minCommand)
+ if ((_patNum = getNextByte()) >= _minCommand)
break;
_patNum = (_patNum >> 1) & 0x7f;
}
- if ((x1 = nextByte()) >= _minCommand)
+ if ((x1 = getNextByte()) >= _minCommand)
break;
- if ((y1 = nextByte()) >= _minCommand)
+ if ((y1 = getNextByte()) >= _minCommand)
break;
plotPattern(x1, y1);
}
- _foffs--;
+ _dataOffset--;
}
/**************************************************************************
** Draw AGI picture
**************************************************************************/
-
void PictureMgr::drawPicture() {
- uint8 act;
- int drawing;
- int iteration = 0;
-
_patCode = 0;
_patNum = 0;
- _priOn = _scrOn = false;
- _scrColor = (_pictureVersion == AGIPIC_C64) ? 0x0 : 0xf;
- _priColor = 0x4;
+ _priOn = false;
+ _scrOn = false;
+ _scrColor = 15;
+ _priColor = 4;
+
+ switch (_pictureVersion) {
+ case AGIPIC_C64:
+ drawPictureC64();
+ break;
+ case AGIPIC_V1:
+ drawPictureV1();
+ break;
+ case AGIPIC_V15:
+ drawPictureV15();
+ break;
+ case AGIPIC_V2:
+ drawPictureV2();
+ break;
+ case AGIPIC_256:
+ drawPictureAGI256();
+ break;
+ default:
+ break;
+ }
+}
- drawing = 1;
+void PictureMgr::drawPictureC64() {
+ byte curByte;
- debugC(8, kDebugLevelMain, "Drawing v2 picture");
- for (drawing = 1; drawing && _foffs < _flen;) {
- act = nextByte();
+ debugC(8, kDebugLevelMain, "Drawing C64 picture");
- if (_pictureVersion == AGIPIC_C64 && act >= 0xf0 && act <= 0xfe) {
- _scrColor = act - 0xf0;
+ _scrColor = 0x0;
+
+ while (_dataOffset < _dataSize) {
+ curByte = getNextByte();
+
+ if ((curByte >= 0xF0) && (curByte <= 0xFE)) {
+ _scrColor = curByte & 0x0F;
continue;
}
- switch (act) {
- case 0xe0: // x-corner (C64)
- xCorner();
+ switch (curByte) {
+ case 0xe0: // x-corner
+ draw_xCorner();
break;
- case 0xe1: // y-corner (C64)
+ case 0xe1: // y-corner
yCorner();
break;
- case 0xe2: // dynamic draw lines (C64)
- dynamicDrawLine();
+ case 0xe2: // dynamic draw lines
+ draw_LineShort();
break;
- case 0xe3: // absolute draw lines (C64)
- absoluteDrawLine();
+ case 0xe3: // absolute draw lines
+ draw_LineAbsolute();
break;
- case 0xe4: // fill (C64)
- _scrColor = nextByte();
- _scrColor &= 0xF; // for v3 drawing diff
- fill();
+ case 0xe4: // fill
+ draw_SetColor();
+ draw_Fill();
break;
- case 0xe5: // enable screen drawing (C64)
+ case 0xe5: // enable screen drawing
_scrOn = true;
break;
- case 0xe6: // plot brush (C64)
- _patCode = nextByte();
+ case 0xe6: // plot brush
+ _patCode = getNextByte();
plotBrush();
break;
- case 0xf0: // set color on screen (AGI pic v2)
- if (_pictureVersion == AGIPIC_V15)
- break;
+ case 0xfb:
+ draw_LineShort();
+ break;
+ case 0xff: // end of data
+ return;
+ default:
+ warning("Unknown picture opcode (%x) at (%x)", curByte, _dataOffset - 1);
+ break;
+ }
+ }
+}
+
+void PictureMgr::drawPictureV1() {
+ byte curByte;
+
+ debugC(8, kDebugLevelMain, "Drawing V1 picture");
- _scrColor = nextByte();
- _scrColor &= 0xF; // for v3 drawing diff
+ while (_dataOffset < _dataSize) {
+ curByte = getNextByte();
+
+ switch (curByte) {
+ case 0xf1:
+ draw_SetColor();
_scrOn = true;
+ _priOn = false;
break;
- case 0xf1:
- if (_pictureVersion == AGIPIC_V1) {
- _scrColor = nextByte();
- _scrColor &= 0xF; // for v3 drawing diff
- _scrOn = true;
- _priOn = false;
- } else if (_pictureVersion == AGIPIC_V15) { // set color on screen
- _scrColor = nextByte();
- _scrColor &= 0xF;
- _scrOn = true;
- } else if (_pictureVersion == AGIPIC_V2) { // disable screen drawing
- _scrOn = false;
- }
+ case 0xf3:
+ draw_SetColor();
+ _scrOn = true;
+ draw_SetPriority();
+ _priOn = true;
break;
- case 0xf2: // set color on priority (AGI pic v2)
- if (_pictureVersion == AGIPIC_V15)
- break;
-
- _priColor = nextByte();
- _priColor &= 0xf; // for v3 drawing diff
+ case 0xfa:
+ _scrOn = false;
_priOn = true;
+ draw_LineAbsolute();
+ _scrOn = true;
+ _priOn = false;
break;
- case 0xf3:
- if (_pictureVersion == AGIPIC_V1) {
- _scrColor = nextByte();
- _scrColor &= 0xF; // for v3 drawing diff
- _scrOn = true;
- _priColor = nextByte();
- _priColor &= 0xf; // for v3 drawing diff
- _priOn = true;
- }
+ case 0xff: // end of data
+ return;
+ default:
+ warning("Unknown picture opcode (%x) at (%x)", curByte, _dataOffset - 1);
+ break;
+ }
+ }
+}
- if (_pictureVersion == AGIPIC_V15 && (_flags & kPicFf3Stop))
- drawing = 0;
+void PictureMgr::drawPictureV15() {
+ byte curByte;
- if (_pictureVersion == AGIPIC_V2) // disable priority screen
- _priOn = false;
- break;
- case 0xf4: // y-corner
- if (_pictureVersion == AGIPIC_V15)
- break;
+ debugC(8, kDebugLevelMain, "Drawing V1.5 picture");
- yCorner();
- break;
- case 0xf5: // x-corner
- if (_pictureVersion == AGIPIC_V15)
- break;
+ while (_dataOffset < _dataSize) {
+ curByte = getNextByte();
- xCorner();
+ switch (curByte) {
+ case 0xf0:
+ // happens in all Troll's Tale pictures
+ // TODO: figure out what it was meant for
break;
- case 0xf6: // absolute draw lines
- if (_pictureVersion == AGIPIC_V15)
- break;
-
- absoluteDrawLine();
+ case 0xf1:
+ draw_SetColor();
+ _scrOn = true;
break;
- case 0xf7: // dynamic draw lines
- if (_pictureVersion == AGIPIC_V15)
- break;
-
- dynamicDrawLine();
+ case 0xf3:
+ if (_flags & kPicFf3Stop)
+ return;
break;
- case 0xf8: // fill
- if (_pictureVersion == AGIPIC_V15) {
- yCorner(true);
- } else if (_pictureVersion == AGIPIC_V2) {
- fill();
- }
+ case 0xf8:
+ yCorner(true);
break;
- case 0xf9: // set pattern
- if (_pictureVersion == AGIPIC_V15) {
- xCorner(true);
- } else if (_pictureVersion == AGIPIC_V2) {
- _patCode = nextByte();
+ case 0xf9:
+ draw_xCorner(true);
+ break;
+ case 0xfa:
+ // TODO: is this really correct?
+ draw_LineAbsolute();
+ break;
+ case 0xfb:
+ // TODO: is this really correct?
+ draw_LineAbsolute();
+ break;
+ case 0xfe:
+ draw_SetColor();
+ _scrOn = true;
+ draw_Fill();
+ break;
+ case 0xff: // end of data
+ return;
+ default:
+ warning("Unknown picture opcode (%x) at (%x)", curByte, _dataOffset - 1);
+ break;
+ }
+ }
+}
- if (_vm->getGameType() == GType_PreAGI)
- plotBrush();
+void PictureMgr::drawPictureV2() {
+ byte curByte;
+ bool nibbleMode = false;
+ bool mickeyCrystalAnimation = false;
+ int mickeyIteration = 0;
+
+ debugC(8, kDebugLevelMain, "Drawing V2/V3 picture");
+
+ if (_vm->_game.dirPic[_resourceNr].flags & RES_PICTURE_V3_NIBBLE_PARM) {
+ // check, if this resource uses nibble mode (0xF0 + 0xF2 commands take nibbles instead of bytes)
+ nibbleMode = true;
+ }
+
+ if ((_flags & kPicFStep) && _vm->getGameType() == GType_PreAGI) {
+ mickeyCrystalAnimation = true;
+ }
+
+ while (_dataOffset < _dataSize) {
+ curByte = getNextByte();
+
+ switch (curByte) {
+ case 0xf0:
+ if (!nibbleMode) {
+ draw_SetColor();
+ } else {
+ draw_SetNibbleColor();
}
+ _scrOn = true;
break;
- case 0xfa: // plot brush
- if (_pictureVersion == AGIPIC_V1) {
- _scrOn = false;
- _priOn = true;
- absoluteDrawLine();
- _scrOn = true;
- _priOn = false;
- } else if (_pictureVersion == AGIPIC_V15) {
- absoluteDrawLine();
- } else if (_pictureVersion == AGIPIC_V2) {
- plotBrush();
- }
+ case 0xf1:
+ _scrOn = false;
break;
- case 0xfb:
- if (_pictureVersion == AGIPIC_V1) {
- dynamicDrawLine();
- } else if (_pictureVersion == AGIPIC_V15) {
- absoluteDrawLine();
+ case 0xf2:
+ if (!nibbleMode) {
+ draw_SetPriority();
+ } else {
+ draw_SetNibblePriority();
}
+ _priOn = true;
break;
- case 0xfc: // fill (AGI pic v1)
- if (_pictureVersion == AGIPIC_V15)
- break;
+ case 0xf3:
+ _priOn = false;
+ break;
+ case 0xf4:
+ yCorner();
+ break;
+ case 0xf5:
+ draw_xCorner();
+ break;
+ case 0xf6:
+ draw_LineAbsolute();
+ break;
+ case 0xf7:
+ draw_LineShort();
+ break;
+ case 0xf8:
+ draw_Fill();
+ break;
+ case 0xf9:
+ _patCode = getNextByte();
- _scrColor = nextByte();
- _scrColor &= 0xF;
- _priColor = nextByte();
- _priColor &= 0xf;
- fill();
+ if (_vm->getGameType() == GType_PreAGI)
+ plotBrush();
break;
- case 0xfe: // fill (AGI pic v1.5)
- _scrColor = nextByte();
- _scrColor &= 0xF;
- _scrOn = true;
- fill();
+ case 0xfa:
+ plotBrush();
break;
- case 0xff: // end of pic data
- drawing = 0;
+ case 0xfc:
+ draw_SetColor();
+ draw_SetPriority();
+ draw_Fill();
break;
+ case 0xff: // end of data
+ return;
default:
- warning("Unknown picture opcode (%x) at (%x)", act, _foffs - 1);
+ warning("Unknown picture opcode (%x) at (%x)", curByte, _dataOffset - 1);
+ break;
}
// This is used by Mickey for the crystal animation
// One frame of the crystal animation is shown on each iteration, based on _currentStep
- if ((_flags & kPicFStep) && _vm->getGameType() == GType_PreAGI && _currentStep == iteration) {
- int storedXOffset = _xOffset;
- int storedYOffset = _yOffset;
- // Note that picture coordinates are correct for Mickey only
- showPic(10, 0, _width, _height);
- _xOffset = storedXOffset;
- _yOffset = storedYOffset;
- _currentStep++;
- if (_currentStep > 14) // crystal animation is 15 frames
- _currentStep = 0;
- // reset the picture step flag - it will be set when the next frame of the crystal animation is drawn
- _flags &= ~kPicFStep;
- return; // return back to the game loop
+ if (mickeyCrystalAnimation) {
+ if (_currentStep == mickeyIteration) {
+ int storedXOffset = _xOffset;
+ int storedYOffset = _yOffset;
+ // Note that picture coordinates are correct for Mickey only
+ showPic(10, 0, _width, _height);
+ _xOffset = storedXOffset;
+ _yOffset = storedYOffset;
+ _currentStep++;
+ if (_currentStep > 14) // crystal animation is 15 frames
+ _currentStep = 0;
+ // reset the picture step flag - it will be set when the next frame of the crystal animation is drawn
+ _flags &= ~kPicFStep;
+ return; // return back to the game loop
+ }
+ mickeyIteration++;
+ }
+ }
+}
+
+void PictureMgr::drawPictureAGI256() {
+ const uint32 maxFlen = _width * _height;
+ int16 x = 0;
+ int16 y = 0;
+ byte *dataPtr = _data;
+ byte *dataEndPtr = _data + _dataSize;
+ byte color = 0;
+
+ debugC(8, kDebugLevelMain, "Drawing AGI256 picture");
+
+ while (dataPtr < dataEndPtr) {
+ color = *dataPtr++;
+ _gfx->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, color, 0);
+
+ x++;
+ if (x >= _width) {
+ x = 0;
+ y++;
+ if (y >= _height) {
+ break;
+ }
+ }
+ }
+
+ if (_dataSize < maxFlen) {
+ warning("Undersized AGI256 picture resource %d, using it anyway. Filling rest with white.", _resourceNr);
+ while (_dataSize < maxFlen) {
+ x++;
+ if (x >= _width) {
+ x = 0;
+ y++;
+ if (y >= _height)
+ break;
+ }
+ _gfx->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, 15, 0);
}
+ } else if (_dataSize > maxFlen)
+ warning("Oversized AGI256 picture resource %d, decoding only %ux%u part of it", _resourceNr, _width, _height);
+}
+
+void PictureMgr::draw_SetColor() {
+ _scrColor = getNextByte();
+
+ // For CGA, replace the color with its mixture color
+ switch (_vm->_renderMode) {
+ case RENDERMODE_CGA:
+ _scrColor = _gfx->getCGAMixtureColor(_scrColor);
+ break;
+ default:
+ break;
+ }
+}
+
+void PictureMgr::draw_SetPriority() {
+ _priColor = getNextByte();
+}
- iteration++;
+// this gets a nibble instead of a full byte
+// used by some V3 games, special resource flag RES_PICTURE_V3_NIBBLE_PARM is set
+void PictureMgr::draw_SetNibbleColor() {
+ _scrColor = getNextNibble();
+
+ // For CGA, replace the color with its mixture color
+ switch (_vm->_renderMode) {
+ case RENDERMODE_CGA:
+ _scrColor = _gfx->getCGAMixtureColor(_scrColor);
+ break;
+ default:
+ break;
}
}
+void PictureMgr::draw_SetNibblePriority() {
+ _priColor = getNextNibble();
+}
+
/**
- * convert AGI v3 format picture to AGI v2 format
+ * Draw an AGI line.
+ * A line drawing routine sent by Joshua Neal, modified by Stuart George
+ * (fixed >>2 to >>1 and some other bugs like x1 instead of y1, etc.)
+ * @param x1 x coordinate of start point
+ * @param y1 y coordinate of start point
+ * @param x2 x coordinate of end point
+ * @param y2 y coordinate of end point
*/
-uint8 *PictureMgr::convertV3Pic(uint8 *src, uint32 len) {
- uint8 d, old = 0, x, *in, *xdata, *out, mode = 0;
- uint32 i, ulen;
+void PictureMgr::draw_Line(int16 x1, int16 y1, int16 x2, int16 y2) {
+ x1 = CLIP<int16>(x1, 0, _width - 1);
+ x2 = CLIP<int16>(x2, 0, _width - 1);
+ y1 = CLIP<int16>(y1, 0, _height - 1);
+ y2 = CLIP<int16>(y2, 0, _height - 1);
+
+ int i, x, y, deltaX, deltaY, stepX, stepY, errorX, errorY, detdelta;
- xdata = (uint8 *)malloc(len + len / 2);
+ // Vertical line
+
+ if (x1 == x2) {
+ if (y1 > y2) {
+ SWAP(y1, y2);
+ }
- out = xdata;
- in = src;
+ for (; y1 <= y2; y1++)
+ putVirtPixel(x1, y1);
- for (i = ulen = 0; i < len; i++, ulen++) {
- d = *in++;
+ return;
+ }
- *out++ = x = mode ? ((d & 0xF0) >> 4) + ((old & 0x0F) << 4) : d;
+ // Horizontal line
- if (x == 0xFF) {
- ulen++;
- break;
+ if (y1 == y2) {
+ if (x1 > x2) {
+ SWAP(x1, x2);
+ }
+ for (; x1 <= x2; x1++)
+ putVirtPixel(x1, y1);
+ return;
+ }
+
+ y = y1;
+ x = x1;
+
+ stepY = 1;
+ deltaY = y2 - y1;
+ if (deltaY < 0) {
+ stepY = -1;
+ deltaY = -deltaY;
+ }
+
+ stepX = 1;
+ deltaX = x2 - x1;
+ if (deltaX < 0) {
+ stepX = -1;
+ deltaX = -deltaX;
+ }
+
+ if (deltaY > deltaX) {
+ i = deltaY;
+ detdelta = deltaY;
+ errorX = deltaY / 2;
+ errorY = 0;
+ } else {
+ i = deltaX;
+ detdelta = deltaX;
+ errorX = 0;
+ errorY = deltaX / 2;
+ }
+
+ putVirtPixel(x, y);
+
+ do {
+ errorY += deltaY;
+ if (errorY >= detdelta) {
+ errorY -= detdelta;
+ y += stepY;
}
- if (x == 0xf0 || x == 0xf2) {
- if (mode) {
- *out++ = d & 0x0F;
- ulen++;
+ errorX += deltaX;
+ if (errorX >= detdelta) {
+ errorX -= detdelta;
+ x += stepX;
+ }
+
+ putVirtPixel(x, y);
+ i--;
+ } while (i > 0);
+}
+
+/**
+ * Draw a relative AGI line.
+ * Draws short lines relative to last position. (drawing action 0xF7)
+ */
+void PictureMgr::draw_LineShort() {
+ int x1, y1, disp, dx, dy;
+
+ if ((x1 = getNextByte()) >= _minCommand ||
+ (y1 = getNextByte()) >= _minCommand) {
+ _dataOffset--;
+ return;
+ }
+
+ putVirtPixel(x1, y1);
+
+ for (;;) {
+ if ((disp = getNextByte()) >= _minCommand)
+ break;
+
+ dx = ((disp & 0xf0) >> 4) & 0x0f;
+ dy = (disp & 0x0f);
+
+ if (dx & 0x08)
+ dx = -(dx & 0x07);
+ if (dy & 0x08)
+ dy = -(dy & 0x07);
+
+ draw_Line(x1, y1, x1 + dx, y1 + dy);
+ x1 += dx;
+ y1 += dy;
+ }
+ _dataOffset--;
+}
+
+/**************************************************************************
+** absoluteLine
+**
+** Draws long lines to actual locations (cf. relative) (drawing action 0xF6)
+**************************************************************************/
+void PictureMgr::draw_LineAbsolute() {
+ int16 x1, y1, x2, y2;
+
+ if ((x1 = getNextByte()) >= _minCommand ||
+ (y1 = getNextByte()) >= _minCommand) {
+ _dataOffset--;
+ return;
+ }
+
+ putVirtPixel(x1, y1);
+
+ for (;;) {
+ if ((x2 = getNextByte()) >= _minCommand)
+ break;
+
+ if ((y2 = getNextByte()) >= _minCommand)
+ break;
+
+ draw_Line(x1, y1, x2, y2);
+ x1 = x2;
+ y1 = y2;
+ }
+ _dataOffset--;
+}
+
+// flood fill
+void PictureMgr::draw_Fill() {
+ int16 x1, y1;
+
+ while ((x1 = getNextByte()) < _minCommand && (y1 = getNextByte()) < _minCommand)
+ draw_Fill(x1, y1);
+
+ _dataOffset--;
+}
+
+void PictureMgr::draw_Fill(int16 x, int16 y) {
+ if (!_scrOn && !_priOn)
+ return;
+
+ // Push initial pixel on the stack
+ Common::Stack<Common::Point> stack;
+ stack.push(Common::Point(x,y));
+
+ // Exit if stack is empty
+ while (!stack.empty()) {
+ Common::Point p = stack.pop();
+ unsigned int c;
+ bool newspanUp, newspanDown;
+
+ if (!draw_FillCheck(p.x, p.y))
+ continue;
+
+ // Scan for left border
+ for (c = p.x - 1; draw_FillCheck(c, p.y); c--)
+ ;
+
+ newspanUp = newspanDown = true;
+ for (c++; draw_FillCheck(c, p.y); c++) {
+ putVirtPixel(c, p.y);
+ if (draw_FillCheck(c, p.y - 1)) {
+ if (newspanUp) {
+ stack.push(Common::Point(c,p.y-1));
+ newspanUp = false;
+ }
} else {
- d = *in++;
- *out++ = (d & 0xF0) >> 4;
- i++, ulen++;
+ newspanUp = true;
}
- mode = !mode;
+ if (draw_FillCheck(c, p.y + 1)) {
+ if (newspanDown) {
+ stack.push(Common::Point(c,p.y+1));
+ newspanDown = false;
+ }
+ } else {
+ newspanDown = true;
+ }
}
-
- old = d;
}
+}
- free(src);
- xdata = (uint8 *)realloc(xdata, ulen);
+int PictureMgr::draw_FillCheck(int16 x, int16 y) {
+ byte screenColor;
+ byte screenPriority;
- return xdata;
+ if (x < 0 || x >= _width || y < 0 || y >= _height)
+ return false;
+
+ x += _xOffset;
+ y += _yOffset;
+
+ screenColor = _gfx->getColor(x, y);
+ screenPriority = _gfx->getPriority(x, y);
+
+ if (_flags & kPicFTrollMode)
+ return ((screenColor != 11) && (screenColor != _scrColor));
+
+ if (!_priOn && _scrOn && _scrColor != 15)
+ return (screenColor == 15);
+
+ if (_priOn && !_scrOn && _priColor != 4)
+ return screenPriority == 4;
+
+ return (_scrOn && screenColor == 15 && _scrColor != 15);
}
/**
@@ -804,8 +906,8 @@ uint8 *PictureMgr::convertV3Pic(uint8 *src, uint32 len) {
* @param clear clear AGI screen before drawing
* @param agi256 load an AGI256 picture resource
*/
-int PictureMgr::decodePicture(int n, int clr, bool agi256, int pic_width, int pic_height) {
- debugC(8, kDebugLevelResources, "(%d)", n);
+int PictureMgr::decodePicture(int16 resourceNr, bool clear, bool agi256, int16 pic_width, int16 pic_height) {
+ debugC(8, kDebugLevelResources, "(%d)", resourceNr);
_patCode = 0;
_patNum = 0;
@@ -813,32 +915,28 @@ int PictureMgr::decodePicture(int n, int clr, bool agi256, int pic_width, int pi
_scrColor = 0xF;
_priColor = 0x4;
- _data = _vm->_game.pictures[n].rdata;
- _flen = _vm->_game.dirPic[n].len;
- _foffs = 0;
+ _resourceNr = resourceNr;
+ _data = _vm->_game.pictures[resourceNr].rdata;
+ _dataSize = _vm->_game.dirPic[resourceNr].len;
+ _dataOffset = 0;
+ _dataOffsetNibble = false;
_width = pic_width;
_height = pic_height;
- if (clr && !agi256) // 256 color pictures should always fill the whole screen, so no clearing for them.
- memset(_vm->_game.sbuf16c, 0x4f, _width * _height); // Clear 16 color AGI screen (Priority 4, color white).
+ if (clear && !agi256) { // 256 color pictures should always fill the whole screen, so no clearing for them.
+ _gfx->clear(15, 4); // Clear 16 color AGI screen (Priority 4, color white).
+ }
if (!agi256) {
drawPicture(); // Draw 16 color picture.
} else {
- const uint32 maxFlen = _width * _height;
- memcpy(_vm->_game.sbuf256c, _data, MIN(_flen, maxFlen)); // Draw 256 color picture.
-
- if (_flen < maxFlen) {
- warning("Undersized AGI256 picture resource %d, using it anyway. Filling rest with white.", n);
- memset(_vm->_game.sbuf256c + _flen, 0x0f, maxFlen - _flen); // Fill missing area with white.
- } else if (_flen > maxFlen)
- warning("Oversized AGI256 picture resource %d, decoding only %ux%u part of it", n, _width, _height);
+ drawPictureAGI256();
}
- if (clr)
+ if (clear)
_vm->clearImageStack();
- _vm->recordImageStackCall(ADD_PIC, n, clr, agi256, 0, 0, 0, 0);
+ _vm->recordImageStackCall(ADD_PIC, resourceNr, clear, agi256, 0, 0, 0, 0);
return errOK;
}
@@ -860,14 +958,15 @@ int PictureMgr::decodePicture(byte* data, uint32 length, int clr, int pic_width,
_priColor = 0x4;
_data = data;
- _flen = length;
- _foffs = 0;
+ _dataSize = length;
+ _dataOffset = 0;
+ _dataOffsetNibble = false;
_width = pic_width;
_height = pic_height;
if (clr) // 256 color pictures should always fill the whole screen, so no clearing for them.
- memset(_vm->_game.sbuf16c, 0x4f, _width * _height); // Clear 16 color AGI screen (Priority 4, color white).
+ clear();
drawPicture(); // Draw 16 color picture.
@@ -891,29 +990,66 @@ int PictureMgr::unloadPicture(int n) {
}
void PictureMgr::clear() {
- memset(_vm->_game.sbuf16c, 0x4f, _width * _height);
+ _gfx->clear(15, 4); // Clear 16 color AGI screen (Priority 4, color white).
+}
+
+void PictureMgr::showPic() {
+ debugC(8, kDebugLevelMain, "Show picture!");
+
+ _gfx->render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT);
}
/**
* Show AGI picture.
* This function copies a ``hidden'' AGI picture to the output device.
*/
-void PictureMgr::showPic(int x, int y, int pic_width, int pic_height) {
- int i, y1;
- int offset;
+void PictureMgr::showPic(int16 x, int16 y, int16 pic_width, int16 pic_height) {
_width = pic_width;
_height = pic_height;
debugC(8, kDebugLevelMain, "Show picture!");
- i = 0;
- offset = _vm->_game.lineMinPrint * CHAR_LINES;
- for (y1 = y; y1 < y + _height; y1++) {
- _gfx->putPixelsA(x, y1 + offset, _width, &_vm->_game.sbuf16c[i]);
- i += _width;
+ // render block requires lower left coordinate!
+ _gfx->render_Block(x, pic_height + y - 1, pic_width, pic_height);
+}
+
+void PictureMgr::showPicWithTransition() {
+ _width = SCRIPT_WIDTH;
+ _height = SCRIPT_HEIGHT;
+
+ debugC(8, kDebugLevelMain, "Show picture!");
+
+ if (!_vm->_game.automaticRestoreGame) {
+ // only do transitions when we are not restoring a saved game
+
+ if (!_vm->_game.gfxMode) {
+ // if we are not yet in graphics mode, set graphics mode palette now
+ // TODO: maybe change text mode to use different colors for drawing
+ // so that we don't have to change palettes at all
+ _gfx->setPalette(true);
+ }
+
+ switch (_vm->_renderMode) {
+ case RENDERMODE_AMIGA:
+ case RENDERMODE_APPLE_II_GS:
+ // Platform Amiga/Apple II GS -> render and do Amiga transition
+ _gfx->render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT, false);
+ _gfx->transition_Amiga();
+ return;
+ break;
+ case RENDERMODE_ATARI_ST:
+ // Platform Atari ST used a different transition, looks "high-res" (full 320x168)
+ _gfx->render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT, false);
+ _gfx->transition_AtariSt();
+ return;
+ default:
+ // Platform PC -> render directly
+ // Macintosh AGI also doesn't seem to have any transitions
+ break;
+ }
}
- _gfx->flushScreen();
+ _gfx->render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT);
}
// preagi needed functions (for plotPattern)
@@ -933,8 +1069,9 @@ void PictureMgr::setPictureVersion(AgiPictureVersion version) {
void PictureMgr::setPictureData(uint8 *data, int len) {
_data = data;
- _flen = len;
- _foffs = 0;
+ _dataSize = len;
+ _dataOffset = 0;
+ _dataOffsetNibble = false;
_flags = 0;
}