From 5e351b0c312a921f9e2e8090462afec5cce7dbb1 Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Sat, 27 Nov 2004 17:50:23 +0000 Subject: moved all the HE wiz stuff to a separate module, with minor cleanups and simplifications svn-id: r15921 --- scumm/actor.cpp | 2 +- scumm/akos.cpp | 5 +- scumm/charset.cpp | 8 +- scumm/gfx.cpp | 467 +--------------- scumm/gfx.h | 12 +- scumm/intern.h | 46 +- scumm/module.mk | 1 + scumm/saveload.cpp | 2 +- scumm/script_v72he.cpp | 536 ------------------- scumm/script_v7he.cpp | 103 +--- scumm/script_v80he.cpp | 46 -- scumm/script_v90he.cpp | 274 +--------- scumm/scumm.cpp | 14 +- scumm/scumm.h | 16 +- scumm/wiz_he.cpp | 1392 ++++++++++++++++++++++++++++++++++++++++++++++++ scumm/wiz_he.h | 111 ++++ 16 files changed, 1529 insertions(+), 1506 deletions(-) create mode 100644 scumm/wiz_he.cpp create mode 100644 scumm/wiz_he.h (limited to 'scumm') diff --git a/scumm/actor.cpp b/scumm/actor.cpp index 9609ae41ef..6d6f953d3c 100644 --- a/scumm/actor.cpp +++ b/scumm/actor.cpp @@ -1921,7 +1921,7 @@ void ScummEngine::postProcessAuxQueue() { uint8 *dst2 = pvs->getBackPixels(0, pvs->topline); switch (comp) { case 1: - gdi.copyAuxImage(dst1, dst2, axfd + 10, pvs->w, pvs->h, x, y, w, h, NULL); + _wiz.copyAuxImage(dst1, dst2, axfd + 10, pvs->w, pvs->h, x, y, w, h); break; default: warning("unimplemented compression type %d", comp); diff --git a/scumm/akos.cpp b/scumm/akos.cpp index bf615c6fe1..48b4e09c43 100644 --- a/scumm/akos.cpp +++ b/scumm/akos.cpp @@ -1234,10 +1234,7 @@ byte AkosRenderer::codec32(int xmoveCur, int ymoveCur) { _draw_bottom = dst.bottom; byte *dstPtr = (byte *)_out.pixels + dst.left + dst.top * _out.pitch; - - for (int i = 0; i < 256; i++) - _vm->gdi._wizImagePalette[i] = i; - _vm->gdi.decompressWizImage(dstPtr, _out.pitch, dst, _srcptr, src); + _vm->_wiz.decompressWizImage(dstPtr, _out.pitch, dst, _srcptr, src); return 0; } diff --git a/scumm/charset.cpp b/scumm/charset.cpp index 76128abc7f..b997110a65 100644 --- a/scumm/charset.cpp +++ b/scumm/charset.cpp @@ -1394,10 +1394,10 @@ void CharsetRendererClassic::printChar(int chr) { src = dst; src.moveTo(0, 0); - memset(_vm->gdi._wizImagePalette, 255, sizeof(_vm->gdi._wizImagePalette)); - memcpy(_vm->gdi._wizImagePalette, _vm->_charsetColorMap, 16); - - _vm->gdi.decompressWizImage(dstPtr, vs->w, dst, charPtr, src); + byte imagePalette[256]; + memset(imagePalette, 255, sizeof(imagePalette)); + memcpy(imagePalette, _vm->_charsetColorMap, 16); + _vm->_wiz.decompressWizImage(dstPtr, vs->w, dst, charPtr, src, imagePalette); if (_blitAlso && vs->hasTwoBuffers) _vm->gdi.copyVirtScreenBuffers(dst); diff --git a/scumm/gfx.cpp b/scumm/gfx.cpp index a98f4cf13e..96405490e5 100644 --- a/scumm/gfx.cpp +++ b/scumm/gfx.cpp @@ -1437,7 +1437,7 @@ void Gdi::drawBMAPObject(const byte *ptr, VirtScreen *vs, int obj, int x, int y, if (code == 8 || code == 9) { Common::Rect rScreen(0, 0, vs->w, vs->h); byte *dst = (byte *)_vm->virtscr[0].backBuf + scrX; - copyWizImage(dst, bmap_ptr, vs->w, vs->h, x - scrX, y, w, h, &rScreen); + _vm->_wiz.copyWizImage(dst, bmap_ptr, vs->w, vs->h, x - scrX, y, w, h, &rScreen); } Common::Rect rect1(x, y, x + w, y + h); @@ -1453,471 +1453,6 @@ void Gdi::drawBMAPObject(const byte *ptr, VirtScreen *vs, int obj, int x, int y, } } -static bool calcClipRects(int dst_w, int dst_h, int src_x, int src_y, int src_w, int src_h, const Common::Rect *rect, Common::Rect &srcRect, Common::Rect &dstRect) { - Common::Rect r3; - if (rect) { - r3 = *rect; - Common::Rect r4(dst_w, dst_h); - if (r3.intersects(r4)) { - r3.clip(r4); - } else { - return false; - } - } else { - r3 = Common::Rect(dst_w, dst_h); - } - dstRect = Common::Rect(src_x, src_y, src_x + src_w, src_y + src_h); - dstRect.clip(r3); - srcRect = dstRect; - srcRect.moveTo(0, 0); - return srcRect.isValidRect() && dstRect.isValidRect(); -} - -void Gdi::copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect) { - Common::Rect r1, r2; - if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { - for (int i = 0; i < 256; i++) - _wizImagePalette[i] = i; - dst += r2.left + r2.top * dstw; - decompressWizImage(dst, dstw, r2, src, r1); - } -} - -void Gdi::copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor) { - Common::Rect r1, r2; - if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { - if (flags & 0x400) { - int l = r1.left; - int r = r1.right; - r1.left = srcw - r; - r1.right = srcw - l; - } - if (flags & 0x800) { - int t = r1.top; - int b = r1.bottom; - r1.top = srch - b; - r1.bottom = srch - t; - } - if (!palPtr) { - for (int i = 0; i < 256; i++) { - _wizImagePalette[i] = i; - } - palPtr = _wizImagePalette; - } - int h = r1.height(); - int w = r1.width(); - dst += r2.left + r2.top * dstw; - while (h--) { - for (int i = 0; i < w; ++i) { - uint8 col = *src++; - if (transColor == -1 || transColor != col) { - dst[i] = palPtr[col]; - } - } - dst += dstw; - } - } -} - -void Gdi::decompressWizImage(uint8 *dst, int dstPitch, const Common::Rect &dstRect, const uint8 *src, const Common::Rect &srcRect) { - const uint8 *dataPtr, *dataPtrNext; - uint8 *dstPtr, *dstPtrNext; - uint32 code; - uint8 databit; - int h, w, xoff; - uint16 off; - int color; - - dstPtr = dst; - dataPtr = src; - - // Skip over the first 'srcRect->top' lines in the data - h = srcRect.top; - while (h--) { - dataPtr += READ_LE_UINT16(dataPtr) + 2; - } - h = srcRect.height(); - if (h <= 0) - return; - w = srcRect.width(); - if (w <= 0) - return; - - while (h--) { - xoff = srcRect.left; - off = READ_LE_UINT16(dataPtr); - w = srcRect.right - srcRect.left; - dstPtrNext = dstPitch + dstPtr; - dataPtrNext = off + 2 + dataPtr; - dataPtr += 2; - if (off == 0) - goto dec_next; - - // Skip over the leftmost 'srcRect->left' pixels. - // TODO: This code could be merged (at a loss of efficency) with the - // loop below which does the actual drawing. - while (xoff > 0) { - code = *dataPtr++; - databit = code & 1; - code >>= 1; - if (databit) { - xoff -= code; - if (xoff < 0) { - code = -xoff; - goto dec_sub1; - } - } else { - databit = code & 1; - code = (code >> 1) + 1; - if (databit) { - ++dataPtr; - xoff -= code; - if (xoff < 0) { - code = -xoff; - --dataPtr; - goto dec_sub2; - } - } else { - dataPtr += code; - xoff -= code; - if (xoff < 0) { - dataPtr += xoff; - code = -xoff; - goto dec_sub3; - } - } - } - } - - while (w > 0) { - code = *dataPtr++; - databit = code & 1; - code >>= 1; - if (databit) { -dec_sub1: dstPtr += code; - w -= code; - } else { - databit = code & 1; - code = (code >> 1) + 1; - if (databit) { -dec_sub2: w -= code; - if (w < 0) { - code += w; - } - color = _wizImagePalette[*dataPtr++]; - memset(dstPtr, color, code); - dstPtr += code; - } else { -dec_sub3: w -= code; - if (w < 0) { - code += w; - } - while (code--) { - color = _wizImagePalette[*dataPtr++]; - *dstPtr++ = color; - } - } - } - } -dec_next: - dataPtr = dataPtrNext; - dstPtr = dstPtrNext; - } -} - -int Gdi::isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h) { - int ret = 0; - while (y != 0) { - data += READ_LE_UINT16(data) + 2; - --y; - } - uint16 off = READ_LE_UINT16(data); data += 2; - if (off != 0) { - if (x == 0) { - ret = (~*data) & 1; - } else { - do { - uint8 code = *data++; - if (code & 1) { - code >>= 1; - if (code > x) { - ret = 0; - break; - } - x -= code; - } else if (code & 2) { - code = (code >> 2) + 1; - if (code > x) { - ret = 1; - break; - } - x -= code; - ++data; - } else { - code = (code >> 2) + 1; - if (code > x) { - ret = 1; - break; - } - x -= code; - data += code; - } - } while (x > 0); - } - } - return ret; -} - -uint8 Gdi::getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color) { - uint8 c; - if (x >= 0 && x < w && y >= 0 && y < h) { - c = *(data + y * w + x); - } else { - c = color; - } - return c; -} - -uint8 Gdi::getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color) { - uint8 c = color; - if (x >= 0 && x < w && y >= 0 && y < h) { - while (y != 0) { - data += READ_LE_UINT16(data) + 2; - --y; - } - uint16 off = READ_LE_UINT16(data); data += 2; - if (off != 0) { - if (x == 0) { - c = (*data & 1) ? color : *data; - } else { - do { - uint8 code = *data++; - if (code & 1) { - code >>= 1; - if (code > x) { - c = color; - break; - } - x -= code; - } else if (code & 2) { - code = (code >> 2) + 1; - if (code > x) { - c = *data; - break; - } - x -= code; - ++data; - } else { - code = (code >> 2) + 1; - if (code > x) { - c = *(data + x); - break; - } - x -= code; - data += code; - } - } while (x > 0); - } - } - } - return c; -} - -void Gdi::computeWizHistogram(uint32 *histogram, const uint8 *data, const Common::Rect *srcRect) { - int y = srcRect->top; - while (y != 0) { - data += READ_LE_UINT16(data) + 2; - --y; - } - int ih = srcRect->height(); - while (ih--) { - uint16 off = READ_LE_UINT16(data); data += 2; - if (off != 0) { - const uint8 *p = data; - int x1 = srcRect->left; - int x2 = srcRect->right; - uint8 code; - while (x1 > 0) { - code = *p++; - if (code & 1) { - code >>= 1; - if (code > x1) { - code -= x1; - x2 -= code; - break; - } - x1 -= code; - } else if (code & 2) { - code = (code >> 2) + 1; - if (code > x1) { - code -= x1; - goto dec_sub2; - } - x1 -= code; - ++p; - } else { - code = (code >> 2) + 1; - if (code > x1) { - code -= x1; - p += x1; - goto dec_sub3; - } - x1 -= code; - p += code; - } - } - while (x2 > 0) { - code = *p++; - if (code & 1) { - code >>= 1; - x2 -= code; - } else if (code & 2) { - code = (code >> 2) + 1; -dec_sub2: x2 -= code; - if (x2 < 0) { - code += x2; - } - histogram[*p++] += code; - } else { - code = (code >> 2) + 1; -dec_sub3: x2 -= code; - if (x2 < 0) { - code += x2; - } - int n = code; - while (n--) { - ++histogram[*p++]; - } - } - } - data += off; - } - } -} - -void Gdi::computeRawWizHistogram(uint32 *histogram, const uint8 *data, int srcPitch, const Common::Rect *srcRect) { - data += srcRect->top * srcPitch + srcRect->left; - int iw = srcRect->width(); - int ih = srcRect->height(); - while (ih--) { - for (int i = 0; i < iw; ++i) { - ++histogram[data[i]]; - } - data += srcPitch; - } -} - -void Gdi::copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect) { - Common::Rect r1, r2; - if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { - decompressAuxImage(dst1, dst2, dstw, r2, src, r1); - } -} - -void Gdi::decompressAuxImage(uint8 *dst1, uint8 *dst2, int dstPitch, const Common::Rect &dstRect, const uint8 *src, const Common::Rect &srcRect) { - const uint8 *dataPtr, *dataPtrNext; - uint8 *dst1Ptr, *dst2Ptr, *dst1PtrNext, *dst2PtrNext; - int h, w, xoff; - uint16 off; - uint8 code; - - dst1Ptr = dst1 + dstRect.left + dstRect.top * dstPitch; - dst2Ptr = dst2 + dstRect.left + dstRect.top * dstPitch; - dataPtr = src; - - // Skip over the first 'srcRect->top' lines in the data - h = srcRect.top; - while (h--) { - dataPtr += READ_LE_UINT16(dataPtr) + 2; - } - h = srcRect.height(); - if (h <= 0) - return; - w = srcRect.width(); - if (w <= 0) - return; - - while (h--) { - xoff = srcRect.left; - off = READ_LE_UINT16(dataPtr); - w = srcRect.right - srcRect.left; - dst1PtrNext = dstPitch + dst1Ptr; - dst2PtrNext = dstPitch + dst2Ptr; - dataPtrNext = off + 2 + dataPtr; - dataPtr += 2; - if (off == 0) - goto dec_next; - - // Skip over the leftmost 'srcRect->left' pixels. - // TODO: This code could be merged (at a loss of efficency) with the - // loop below which does the actual drawing. - while (xoff > 0) { - code = *dataPtr++; - if (code & 1) { - code >>= 1; - if (code > xoff) { - code -= xoff; - goto dec_sub1; - } - xoff -= code; - } else if (code & 2) { - code = (code >> 2) + 1; - if (code > xoff) { - code -= xoff; - goto dec_sub2; - } - xoff -= code; - ++dataPtr; - } else { - code = (code >> 2) + 1; - if (code > xoff) { - code -= xoff; - dataPtr += xoff; - goto dec_sub3; - } - xoff -= code; - dataPtr += code; - } - } - while (w > 0) { - code = *dataPtr++; - if (code & 1) { - code >>= 1; -dec_sub1: dst1Ptr += code; - dst2Ptr += code; - w -= code; - } else if (code & 2) { - code = (code >> 2) + 1; -dec_sub2: w -= code; - if (w >= 0) { - memset(dst1Ptr, *dataPtr++, code); - dst1Ptr += code; - dst2Ptr += code; - } else { - code += w; - memset(dst1Ptr, *dataPtr, code); - } - } else { - code = (code >> 2) + 1; -dec_sub3: w -= code; - if (w >= 0) { - memcpy(dst1Ptr, dst2Ptr, code); - dst1Ptr += code; - dst2Ptr += code; - } else { - code += w; - memcpy(dst1Ptr, dst2Ptr, code); - } - } - } - -dec_next: - dataPtr = dataPtrNext; - dst1Ptr = dst1PtrNext; - dst2Ptr = dst2PtrNext; - } -} - void Gdi::copyVirtScreenBuffers(const Common::Rect &rect) { const int rw = rect.width(); const int rh = rect.height(); diff --git a/scumm/gfx.h b/scumm/gfx.h index 65e15d717f..cf0b41f12f 100644 --- a/scumm/gfx.h +++ b/scumm/gfx.h @@ -205,7 +205,6 @@ class Gdi { ScummEngine *_vm; public: - byte _wizImagePalette[256]; int _numZBuffer; int _imgBufOffs[8]; @@ -277,16 +276,7 @@ public: void drawBMAPBg(const byte *ptr, VirtScreen *vs, int startstrip); void drawBMAPObject(const byte *ptr, VirtScreen *vs, int obj, int x, int y, int w, int h); - void copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect); - void copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor); - void decompressWizImage(uint8 *dst, int dstPitch, const Common::Rect &dstRect, const uint8 *src, const Common::Rect &srcRect); - int isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h); - uint8 getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color); - uint8 getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color); - void computeWizHistogram(uint32 *histogram, const uint8 *data, const Common::Rect *srcRect); - void computeRawWizHistogram(uint32 *histogram, const uint8 *data, int srcPitch, const Common::Rect *srcRect); - void copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect); - void decompressAuxImage(uint8 *dst1, uint8 *dst2, int dstPitch, const Common::Rect &dstRect, const uint8 *src, const Common::Rect &srcRect); + void copyVirtScreenBuffers(const Common::Rect &rect); void disableZBuffer() { _zbufferDisabled = true; } diff --git a/scumm/intern.h b/scumm/intern.h index f013558d3b..cd9f748f2a 100644 --- a/scumm/intern.h +++ b/scumm/intern.h @@ -659,10 +659,6 @@ protected: void appendSubstring(int dst, int src, int len2, int len); int findObject(int x, int y, int num, int *args); - void polygonErase(int fromId, int toId); - bool polygonContains(const WizPolygon &pol, int x, int y); - bool polygonDefined(int id); - int polygonHit(int id, int x, int y); virtual void setCursorFromImg(uint img, uint room, uint imgindex); @@ -709,25 +705,14 @@ protected: byte data[1]; //14 } GCC_PACK; - struct WizImage { - int resNum; - int x1; - int y1; - int flags; - int state; - int unk; - }; - #if !defined(__GNUC__) #pragma END_PACK_STRUCTS #endif const OpcodeEntryV72he *_opcodesV72he; - WizImage _wizImages[255]; - uint16 _wizImagesNum; public: - ScummEngine_v72he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16]) : ScummEngine_v70he(detector, syst, gs, md5sum), _wizImagesNum(0) {} + ScummEngine_v72he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16]) : ScummEngine_v70he(detector, syst, gs, md5sum) {} protected: virtual void setupScummVars(); @@ -747,12 +732,12 @@ protected: int readFileToArray(int slot, int32 size); void writeFileFromArray(int slot, int resID); + void captureWizImage(int restype, int resnum, const Common::Rect& r, bool frontBuffer, int compType); void displayWizImage(const WizImage *pwi); void getWizImageDim(int resnum, int state, int32 &w, int32 &h); uint8 *drawWizImage(int restype, const WizImage *pwi); void drawWizPolygon(int resnum, int state, int id, int flags); void flushWizBuffer(); - void captureWizImage(int restype, int resnum, const Common::Rect& r, bool frontBuffer, int compType); virtual void decodeParseString(int a, int b); void decodeScriptString(byte *dst, bool scriptString = false); @@ -856,31 +841,6 @@ protected: int _heObject, _heObjectNum; int _hePaletteNum; - - struct WizParameters { - byte filename[260]; - Common::Rect box; - int processFlags; - int processMode; - int unk_11C; - int unk_120; - int unk_124; - int unk_128; - int unk_12C; - int unk_130; - int unk_134; - int unk_138; - int compType; - int unk_14C; - int angle; - int zoom; - int unk_15C; - int unk_160; - uint8 remapColor[256]; - uint8 remapIndex[256]; - int remapNum; - WizImage img; - }; const OpcodeEntryV90he *_opcodesV90he; WizParameters _wizParams; @@ -895,10 +855,10 @@ protected: virtual void executeOpcode(byte i); virtual const char *getOpcodeDesc(byte i); - int getWizImageStates(int resnum); void drawWizComplexPolygon(int resnum, int state, int po_x, int po_y, int arg14, int angle, int zoom, const Common::Rect *r); void displayWizComplexImage(const WizParameters *params); void processWizImage(const WizParameters *params); + int getWizImageStates(int resnum); int isWizPixelNonTransparent(int restype, int resnum, int state, int x, int y, int flags); uint8 getWizPixelColor(int restype, int resnum, int state, int x, int y, int flags); int computeWizHistogram(int resnum, int state, int x, int y, int w, int h); diff --git a/scumm/module.mk b/scumm/module.mk index 701ef2a223..4e23c3aa93 100644 --- a/scumm/module.mk +++ b/scumm/module.mk @@ -51,6 +51,7 @@ MODULE_OBJS := \ scumm/usage_bits.o \ scumm/vars.o \ scumm/verbs.o \ + scumm/wiz_he.o \ scumm/imuse_digi/dimuse.o \ scumm/imuse_digi/dimuse_bndmgr.o \ scumm/imuse_digi/dimuse_codecs.o \ diff --git a/scumm/saveload.cpp b/scumm/saveload.cpp index 4c495f28d5..95d4c548a4 100644 --- a/scumm/saveload.cpp +++ b/scumm/saveload.cpp @@ -727,7 +727,7 @@ void ScummEngine::saveOrLoad(Serializer *s, uint32 savegameVersion) { s->saveLoadArrayOf(vm.slot, NUM_SCRIPT_SLOT, sizeof(vm.slot[0]), scriptSlotEntries); if (_heversion >= 71) - s->saveLoadArrayOf(_wizPolygons, _wizNumPolygons, sizeof(_wizPolygons[0]), polygonEntries); + s->saveLoadArrayOf(_wiz._polygons, ARRAYSIZE(_wiz._polygons), sizeof(_wiz._polygons[0]), polygonEntries); s->saveLoadArrayOf(_objs, _numLocalObjects, sizeof(_objs[0]), objectEntries); if (s->isLoading() && savegameVersion < VER(13)) { // Since roughly v13 of the save games, the objs storage has changed a bit diff --git a/scumm/script_v72he.cpp b/scumm/script_v72he.cpp index 47ffe6d35e..9f5193dbd7 100644 --- a/scumm/script_v72he.cpp +++ b/scumm/script_v72he.cpp @@ -683,252 +683,6 @@ void ScummEngine_v72he::o72_getObjectImageY() { push(_objs[objnum].y_pos); } -struct wizPackCtx { - uint32 len; - uint8 saveCode; - uint8 saveBuf[0x100]; -}; - -static void wizPackType1Helper1(uint8 *&dst, int len, byte newColor, byte prevColor, wizPackCtx *ctx) { - assert(len > 0); - if (newColor == prevColor) { - do { - int blockLen = MIN(len, 0x7F); - len -= blockLen; - if (dst) { - *dst++ = (blockLen * 2) | 1; - } - ++ctx->len; - } while (len > 0); - } else { - do { - int blockLen = MIN(len, 0x40); - len -= blockLen; - if (dst) { - *dst++ = ((blockLen - 1) * 4) | 2; - } - ++ctx->len; - if (dst) { - *dst++ = newColor; - } - ++ctx->len; - } while (len > 0); - } -} - -static void wizPackType1Helper2(uint8 *&dst, int len, wizPackCtx *ctx) { - assert(len > 0); - const uint8 *src = ctx->saveBuf; - do { - int blockLen = MIN(len, 0x40); - len -= blockLen; - if (dst) { - *dst++ = (blockLen - 1) * 4; - } - ++ctx->len; - while (blockLen--) { - if (dst) { - *dst++ = *src++; - } - ++ctx->len; - } - } while (len > 0); -} - -static int wizPackType1(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt, uint8 tColor) { - debug(1, "wizPackType1(%d, [%d,%d,%d,%d])", tColor, rCapt.left, rCapt.top, rCapt.right, rCapt.bottom); - wizPackCtx ctx; - memset(&ctx, 0, sizeof(ctx)); - - src += rCapt.top * srcPitch + rCapt.left; - int w = rCapt.width(); - int h = rCapt.height(); - - uint8 *nextDstPtr, *curDstPtr; - uint8 curColor, prevColor; - int saveBufPos; - - nextDstPtr = curDstPtr = 0; - - int dataSize = 0; - while (h--) { - if (dst) { - curDstPtr = dst; - nextDstPtr = dst; - dst += 2; - } - dataSize += 2; - int numBytes = 0; - - int i, code; - for (i = 0; i < w; ++i) { - if (src[i] != tColor) - break; - } - if (i != w) { - curDstPtr = dst; - ctx.len = 0; - prevColor = ctx.saveBuf[0] = *src; - const uint8 *curSrcPtr = src + 1; - saveBufPos = 1; - code = (tColor - ctx.saveBuf[0] == 0) ? 1 : 0; - int curw = w; - while (curw--) { - ctx.saveBuf[saveBufPos] = curColor = *curSrcPtr++; - ++saveBufPos; - if (code == 0) { - if (curColor == tColor) { - --saveBufPos; - wizPackType1Helper2(curDstPtr, saveBufPos, &ctx); - code = saveBufPos = 1; - ctx.saveBuf[0] = curColor; - numBytes = 0; - prevColor = curColor; - continue; - } - if (saveBufPos > 0x80) { - --saveBufPos; - wizPackType1Helper2(curDstPtr, saveBufPos, &ctx); - saveBufPos = 1; - ctx.saveBuf[0] = curColor; - numBytes = 0; - prevColor = curColor; - continue; - } - if (prevColor != curColor) { - numBytes = saveBufPos - 1; - prevColor = curColor; - continue; - } - code = 1; - if (numBytes != 0) { - if (saveBufPos - numBytes < 3) { - code = 0; - } else { - wizPackType1Helper2(curDstPtr, numBytes, &ctx); - } - } - } - if (prevColor != curColor || saveBufPos - numBytes > 0x80) { - saveBufPos -= numBytes; - --saveBufPos; - wizPackType1Helper1(curDstPtr, saveBufPos, prevColor, tColor, &ctx); - saveBufPos = 1; - numBytes = 0; - ctx.saveBuf[0] = curColor; - code = (tColor - ctx.saveBuf[0] == 0) ? 1 : 0; - } - prevColor = curColor; - } - if (code == 0) { - wizPackType1Helper2(curDstPtr, saveBufPos, &ctx); - } else { - saveBufPos -= numBytes; - wizPackType1Helper1(curDstPtr, saveBufPos, prevColor, tColor, &ctx); - } - dataSize += ctx.len; - src += srcPitch; - if (dst) { - dst += ctx.len; - *(uint16 *)nextDstPtr = TO_LE_16(ctx.len); - } - } - } - return dataSize; -} - -static int wizPackType0(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt, uint8 tColor) { - int w = rCapt.width(); - int h = rCapt.height(); - int size = w * h; - if (dst) { - src += rCapt.top * srcPitch + rCapt.left; - while (h--) { - memcpy(dst, src, w); - dst += w; - src += srcPitch; - } - } - return size; -} - -void ScummEngine_v72he::captureWizImage(int resType, int resNum, const Common::Rect& r, bool frontBuffer, int compType) { - debug(1, "ScummEngine_v72he::captureWizImage(%d, %d, %d, [%d,%d,%d,%d])", resType, resNum, compType, r.left, r.top, r.right, r.bottom); - uint8 *src = NULL; - VirtScreen *pvs = &virtscr[kMainVirtScreen]; - if (frontBuffer) { - src = pvs->getPixels(0, 0); - } else { - src = pvs->getBackPixels(0, 0); - } - Common::Rect rCapt(0, 0, pvs->w, pvs->h); - if (rCapt.intersects(r)) { - rCapt.clip(r); - const uint8 *palPtr = _currentPalette; - - int w = rCapt.width(); - int h = rCapt.height(); - int tColor = (VAR_WIZ_TCOLOR != 0xFF) ? VAR(VAR_WIZ_TCOLOR) : 5; - - // compute compressed size - int dataSize = 0; - int headerSize = palPtr ? 1080 : 36; - switch (compType) { - case 1: - dataSize = wizPackType1(0, src, pvs->pitch, rCapt, tColor); - break; - case 0: - dataSize = wizPackType0(0, src, pvs->pitch, rCapt, tColor); - break; - default: - warning("unhandled compression type %d", compType); - break; - } - - // alignment - dataSize = (dataSize + 1) & ~1; - int wizSize = headerSize + dataSize; - // write header - uint8 *wizImg = createResource(resType, resNum, dataSize + headerSize); - *(uint32 *)(wizImg + 0x00) = MKID('AWIZ'); - *(uint32 *)(wizImg + 0x04) = TO_BE_32(wizSize); - *(uint32 *)(wizImg + 0x08) = MKID('WIZH'); - *(uint32 *)(wizImg + 0x0C) = TO_BE_32(0x14); - *(uint32 *)(wizImg + 0x10) = TO_LE_32(compType); - *(uint32 *)(wizImg + 0x14) = TO_LE_32(w); - *(uint32 *)(wizImg + 0x18) = TO_LE_32(h); - int curSize = 0x1C; - if (palPtr) { - *(uint32 *)(wizImg + 0x1C) = MKID('RGBS'); - *(uint32 *)(wizImg + 0x20) = TO_BE_32(0x308); - memcpy(wizImg + 0x24, palPtr, 0x300); - *(uint32 *)(wizImg + 0x324) = MKID('RMAP'); - *(uint32 *)(wizImg + 0x328) = TO_BE_32(0x10C); - *(uint32 *)(wizImg + 0x32C) = 0; - curSize = 0x330; - for (int i = 0; i < 256; ++i) { - wizImg[curSize] = i; - ++curSize; - } - } - *(uint32 *)(wizImg + curSize + 0x0) = MKID('WIZD'); - *(uint32 *)(wizImg + curSize + 0x4) = TO_BE_32(dataSize + 8); - curSize += 8; - - // write compressed data - switch (compType) { - case 1: - wizPackType1(wizImg + headerSize, src, pvs->pitch, rCapt, tColor); - break; - case 0: - wizPackType0(wizImg + headerSize, src, pvs->pitch, rCapt, tColor); - break; - default: - break; - } - } -} - void ScummEngine_v72he::o72_captureWizImage() { Common::Rect grab; grab.bottom = pop() + 1; @@ -1713,296 +1467,6 @@ void ScummEngine_v72he::o72_traceStatus() { pop(); } -void ScummEngine_v72he::displayWizImage(const WizImage *pwi) { - if (_fullRedraw) { - assert(_wizImagesNum < ARRAYSIZE(_wizImages)); - memcpy(&_wizImages[_wizImagesNum], pwi, sizeof(WizImage)); - ++_wizImagesNum; - } else if (pwi->flags & 0x40) { - drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags); - } else { - drawWizImage(rtImage, pwi); - } -} - -void ScummEngine_v72he::getWizImageDim(int resnum, int state, int32 &w, int32 &h) { - const uint8 *dataPtr = getResourceAddress(rtImage, resnum); - if (dataPtr) { - const uint8 *wizh = findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); - w = READ_LE_UINT32(wizh + 0x4); - h = READ_LE_UINT32(wizh + 0x8); - } else { - w = 0; - h = 0; - } -} - -uint8 *ScummEngine_v72he::drawWizImage(int restype, const WizImage *pwi) { - debug(1, "drawWizImage(%d, %d, %d, %d, 0x%X)", restype, pwi->resNum, pwi->x1, pwi->y1, pwi->flags); - uint8 *dst = NULL; - const uint8 *dataPtr = getResourceAddress(restype, pwi->resNum); - if (dataPtr) { - const uint8 *rmap = NULL; - const uint8 *xmap = findWrappedBlock(MKID('XMAP'), dataPtr, pwi->state, 0); - - const uint8 *wizh = findWrappedBlock(MKID('WIZH'), dataPtr, pwi->state, 0); - assert(wizh); - uint32 comp = READ_LE_UINT32(wizh + 0x0); - uint32 width = READ_LE_UINT32(wizh + 0x4); - uint32 height = READ_LE_UINT32(wizh + 0x8); - assert(comp == 0 || comp == 1 || comp == 2 || comp == 3 || comp == 10 || comp == 11); - - const uint8 *wizd = findWrappedBlock(MKID('WIZD'), dataPtr, pwi->state, 0); - assert(wizd); - if (pwi->flags & 1) { - const uint8 *pal = findWrappedBlock(MKID('RGBS'), dataPtr, pwi->state, 0); - assert(pal); - setPaletteFromPtr(pal, 256); - } - if (pwi->flags & 2) { - rmap = findWrappedBlock(MKID('RMAP'), dataPtr, pwi->state, 0); - assert(rmap); - const uint8 *rgbs = findWrappedBlock(MKID('RGBS'), dataPtr, pwi->state, 0); - assert(rgbs); - warning("drawWizImage() unhandled flag 0x2"); - // XXX modify 'RMAP' buffer - } - if (pwi->flags & 4) { - warning("WizImage printing is unimplemented"); - return NULL; - } - uint32 cw, ch; - if (pwi->flags & 0x20) { - dst = (uint8 *)malloc(width * height); - int color = 255; // FIXME: should be (VAR_WIZ_TCOLOR != 0xFF) ? VAR(VAR_WIZ_TCOLOR) : 5; - memset(dst, color, width * height); - cw = width; - ch = height; - } else { - VirtScreen *pvs = &virtscr[kMainVirtScreen]; - if (pwi->flags & 0x10) { - dst = pvs->getPixels(0, pvs->topline); - } else { - dst = pvs->getBackPixels(0, pvs->topline); - } - cw = pvs->w; - ch = pvs->h; - } - Common::Rect rScreen(cw, ch); - // XXX handle 'XMAP' / 'RMAP' data - if (comp == 1) { - if (pwi->flags & 0x80) { - warning("drawWizImage() unhandled flag 0x80"); - } else if (pwi->flags & 0x100) { - warning("drawWizImage() unhandled flag 0x100"); - } else { - gdi.copyWizImage(dst, wizd, cw, ch, pwi->x1, pwi->y1, width, height, &rScreen); - } - } else if (comp == 0 || comp == 2) { - const uint8 *trns = findWrappedBlock(MKID('TRNS'), dataPtr, pwi->state, 0); - int color = (trns == NULL) ? VAR(VAR_WIZ_TCOLOR) : -1; - const uint8 *pal = xmap; - if (pwi->flags & 2) { - pal = rmap + 4; - } - gdi.copyRawWizImage(dst, wizd, cw, ch, pwi->x1, pwi->y1, width, height, &rScreen, pwi->flags, pal, color); - } else { - warning("unhandled wiz compression type %d", comp); - } - - if (!(pwi->flags & 0x20)) { - Common::Rect rImage(pwi->x1, pwi->y1, pwi->x1 + width, pwi->y1 + height); - if (rImage.intersects(rScreen)) { - rImage.clip(rScreen); - if (!(pwi->flags & 8) && pwi->flags & 0x18) { - ++rImage.bottom; - markRectAsDirty(kMainVirtScreen, rImage); - } else { - gdi.copyVirtScreenBuffers(rImage); - } - } - } - } - return dst; -} - -struct PolygonDrawData { - struct InterArea { - bool valid; - int32 xmin; - int32 xmax; - int32 x1; - int32 y1; - int32 x2; - int32 y2; - }; - Common::Point pto; - InterArea *ia; - int areasNum; - - PolygonDrawData(int n) { - areasNum = n; - ia = new InterArea[areasNum]; - memset(ia, 0, sizeof(InterArea) * areasNum); - } - - ~PolygonDrawData() { - delete[] ia; - } - - void calcIntersection(const Common::Point *p1, const Common::Point *p2, const Common::Point *p3, const Common::Point *p4) { - int32 x1_acc = p1->x << 0x10; - int32 x3_acc = p3->x << 0x10; - int32 y3_acc = p3->y << 0x10; - uint16 dy = ABS(p2->y - p1->y) + 1; - int32 x1_step = ((p2->x - p1->x) << 0x10) / dy; - int32 x3_step = ((p4->x - p3->x) << 0x10) / dy; - int32 y3_step = ((p4->y - p3->y) << 0x10) / dy; - - int iaidx = p1->y - pto.y; - while (dy--) { - assert(iaidx >= 0 && iaidx < areasNum); - InterArea *pia = &ia[iaidx]; - int32 tx1 = x1_acc >> 0x10; - int32 tx3 = x3_acc >> 0x10; - int32 ty3 = y3_acc >> 0x10; - - if (!pia->valid || pia->xmin > tx1) { - pia->xmin = tx1; - pia->x1 = tx3; - pia->y1 = ty3; - } - if (!pia->valid || pia->xmax < tx1) { - pia->xmax = tx1; - pia->x2 = tx3; - pia->y2 = ty3; - } - pia->valid = true; - - x1_acc += x1_step; - x3_acc += x3_step; - y3_acc += y3_step; - - if (p2->y <= p1->y) { - --iaidx; - } else { - ++iaidx; - } - } - } -}; - -void ScummEngine_v72he::drawWizPolygon(int resnum, int state, int id, int flags) { - int i; - WizPolygon *wp = NULL; - for (i = 0; i < _wizNumPolygons; ++i) { - if (_wizPolygons[i].id == id) { - wp = &_wizPolygons[i]; - break; - } - } - if (!wp) { - error("Polygon %d is not defined", id); - } - if (wp->numVerts != 5) { - error("Invalid point count %d for Polygon %d", wp->numVerts, id); - } - WizImage wi; - wi.resNum = resnum; - wi.state = state; - wi.x1 = wi.y1 = 0; - wi.flags = 0x20; - uint8 *srcWizBuf = drawWizImage(rtImage, &wi); - if (srcWizBuf) { - uint8 *dst; - VirtScreen *pvs = &virtscr[kMainVirtScreen]; - if (flags & 0x10) { - dst = pvs->getPixels(0, 0); - } else { - dst = pvs->getBackPixels(0, 0); - } - if (wp->bound.left < 0 || wp->bound.top < 0 || wp->bound.right >= pvs->w || wp->bound.bottom >= pvs->h) { - error("Invalid coords polygon %d", wp->id); - } - - int32 wizW, wizH; - getWizImageDim(resnum, state, wizW, wizH); - Common::Point bbox[4]; - bbox[0].x = 0; - bbox[0].y = 0; - bbox[1].x = wizW - 1; - bbox[1].y = 0; - bbox[2].x = wizW - 1; - bbox[2].y = wizH - 1; - bbox[3].x = 0; - bbox[3].y = wizH - 1; - - int16 xmin_p, xmax_p, ymin_p, ymax_p; - xmin_p = xmax_p = wp->vert[0].x; - ymin_p = ymax_p = wp->vert[0].y; - for (i = 1; i < 4; ++i) { - xmin_p = MIN(wp->vert[i].x, xmin_p); - xmax_p = MAX(wp->vert[i].x, xmax_p); - ymin_p = MIN(wp->vert[i].y, ymin_p); - ymax_p = MAX(wp->vert[i].y, ymax_p); - } - - int16 xmin_b, xmax_b, ymin_b, ymax_b; - xmin_b = 0; - xmax_b = wizW - 1; - ymin_b = 0; - ymax_b = wizH - 1; - - PolygonDrawData pdd(ymax_p - ymin_p + 1); - pdd.pto.x = xmin_p; - pdd.pto.y = ymin_p; - - for (i = 0; i < 3; ++i) { - pdd.calcIntersection(&wp->vert[i], &wp->vert[i + 1], &bbox[i], &bbox[i + 1]); - } - pdd.calcIntersection(&wp->vert[3], &wp->vert[0], &bbox[3], &bbox[0]); - - uint yoff = pdd.pto.y * pvs->w; - for (i = 0; i < pdd.areasNum; ++i) { - PolygonDrawData::InterArea *pia = &pdd.ia[i]; - uint16 dx = pia->xmax - pia->xmin + 1; - uint8 *dstPtr = dst + pia->xmin + yoff; - int32 x_acc = pia->x1 << 0x10; - int32 y_acc = pia->y1 << 0x10; - int32 x_step = ((pia->x2 - pia->x1) << 0x10) / dx; - int32 y_step = ((pia->y2 - pia->y1) << 0x10) / dx; - while (dx--) { - uint srcWizOff = (y_acc >> 0x10) * wizW + (x_acc >> 0x10); - assert(srcWizOff < (uint32)(wizW * wizH)); - x_acc += x_step; - y_acc += y_step; - *dstPtr++ = srcWizBuf[srcWizOff]; - } - yoff += pvs->pitch; - } - - if (flags & 0x10) { - markRectAsDirty(kMainVirtScreen, wp->bound); - } else { - gdi.copyVirtScreenBuffers(wp->bound); - } - - free(srcWizBuf); - } -} - -void ScummEngine_v72he::flushWizBuffer() { - for (int i = 0; i < _wizImagesNum; ++i) { - WizImage *pwi = &_wizImages[i]; - if (pwi->flags & 0x40) { - drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags); - } else { - drawWizImage(rtImage, pwi); - } - } - _wizImagesNum = 0; -} - void ScummEngine_v72he::o72_kernelGetFunctions() { int args[29]; int retval; diff --git a/scumm/script_v7he.cpp b/scumm/script_v7he.cpp index 8cfdceb0e1..e12f018f01 100644 --- a/scumm/script_v7he.cpp +++ b/scumm/script_v7he.cpp @@ -416,8 +416,8 @@ int ScummEngine_v70he::findObject(int x, int y, int num, int *args) { continue; // Check polygon bounds - if (polygonDefined(_objs[i].obj_nr)) { - if (polygonHit(_objs[i].obj_nr, x, y) != 0) + if (_wiz.polygonDefined(_objs[i].obj_nr)) { + if (_wiz.polygonHit(_objs[i].obj_nr, x, y) != 0) result = _objs[i].obj_nr; else if (VAR_POLYGONS_ONLY != 0xFF && VAR(VAR_POLYGONS_ONLY)) continue; @@ -1042,116 +1042,23 @@ void ScummEngine_v70he::o70_polygonOps() { vert1y = pop(); vert1x = pop(); id = pop(); - - polygonStore(id, (subOp == 69 || subOp == 248), vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, - vert4x, vert4y); + _wiz.polygonStore(id, (subOp == 69 || subOp == 248), vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y); break; case 28: // HE 100 case 247: toId = pop(); fromId = pop(); - - polygonErase(fromId, toId); + _wiz.polygonErase(fromId, toId); break; default: error("o70_polygonOps: default case %d", subOp); } } -void ScummEngine::polygonStore(int id, bool flag, int vert1x, int vert1y, int vert2x, - int vert2y, int vert3x, int vert3y, int vert4x, int vert4y) { - WizPolygon *wp = NULL; - for (int i = 0; i < _wizNumPolygons; ++i) { - if (_wizPolygons[i].id == 0) { - wp = &_wizPolygons[i]; - break; - } - } - if (!wp) { - error("ScummEngine::polygonStore: out of polygon slot, max = %d", - _wizNumPolygons); - } - - wp->vert[0].x = vert1x; - wp->vert[0].y = vert1y; - wp->vert[1].x = vert2x; - wp->vert[1].y = vert2y; - wp->vert[2].x = vert3x; - wp->vert[2].y = vert3y; - wp->vert[3].x = vert4x; - wp->vert[3].y = vert4y; - wp->vert[4].x = vert1x; - wp->vert[4].y = vert1y; - wp->id = id; - wp->numVerts = 5; - wp->flag = flag; - - wp->bound.left = 10000; - wp->bound.top = 10000; - wp->bound.right = -10000; - wp->bound.bottom = -10000; - - // compute bounding box - for (int j = 0; j < wp->numVerts; j++) { - Common::Rect r(wp->vert[j].x, wp->vert[j].y, wp->vert[j].x + 1, wp->vert[j].y + 1); - wp->bound.extend(r); - } -} - -void ScummEngine_v70he::polygonErase(int fromId, int toId) { - for (int i = 0; i < _wizNumPolygons; i++) { - if (_wizPolygons[i].id >= fromId && _wizPolygons[i].id <= toId) - memset(&_wizPolygons[i], 0, sizeof(WizPolygon)); - } -} - void ScummEngine_v70he::o70_polygonHit() { int y = pop(); int x = pop(); - - push(polygonHit(0, x, y)); -} - -int ScummEngine_v70he::polygonHit(int id, int x, int y) { - for (int i = 0; i < _wizNumPolygons; i++) { - if ((!id || _wizPolygons[i].id == id) && _wizPolygons[i].bound.contains(x, y)) { - if (polygonContains(_wizPolygons[i], x, y)) { - return _wizPolygons[i].id; - } - } - } - - return 0; -} - -bool ScummEngine_v70he::polygonDefined(int id) { - for (int i = 0; i < _wizNumPolygons; i++) - if (_wizPolygons[i].id == id) - return true; - - return false; -} - -bool ScummEngine_v70he::polygonContains(const WizPolygon &pol, int x, int y) { - int pi = pol.numVerts - 1; - bool diry = (y < pol.vert[pi].y); - bool curdir; - bool r = false; - - for (int i = 0; i < pol.numVerts; i++) { - curdir = (y <= pol.vert[i].y); - - if (curdir != diry) { - if (((pol.vert[pi].y - pol.vert[i].y) * (pol.vert[i].x - x) <= - (pol.vert[pi].x - pol.vert[i].x) * (pol.vert[i].y - y)) == diry) - r = !r; - } - - pi = i; - diry = curdir; - } - - return r; + push(_wiz.polygonHit(0, x, y)); } } // End of namespace Scumm diff --git a/scumm/script_v80he.cpp b/scumm/script_v80he.cpp index f4806a9c86..4070a27d98 100644 --- a/scumm/script_v80he.cpp +++ b/scumm/script_v80he.cpp @@ -543,52 +543,6 @@ void ScummEngine_v80he::o80_cursorCommand() { VAR(VAR_USERPUT) = _userPut; } -void ScummEngine_v80he::loadImgSpot(int resId, int state, int16 &x, int16 &y) { - const uint8 *dataPtr = getResourceAddress(rtImage, resId); - if (!dataPtr) { - warning("loadImgSpot: unknown Image %d", resId); - x = y = 0; - return; - } - - const uint8 *spotPtr = findWrappedBlock(MKID('SPOT'), dataPtr, state, 0); - - if (spotPtr) { - x = (int16)READ_LE_UINT32(spotPtr + 0); - y = (int16)READ_LE_UINT32(spotPtr + 4); - } else { - x = 0; - y = 0; - } -} - -void ScummEngine_v80he::loadWizCursor(int resId, int resType, bool state) { - int16 x, y; - loadImgSpot(resId, 0, x, y); - if (x < 0) { - x = 0; - } else if (x > 32) { - x = 32; - } - if (y < 0) { - y = 0; - } else if (y > 32) { - y = 32; - } - - WizImage wi; - wi.resNum = resId; - wi.x1 = wi.y1 = 0; - wi.state = 0; - wi.flags = 0x20; - uint8 *cursor = drawWizImage(rtImage, &wi); - int32 cw, ch; - getWizImageDim(resId, 0, cw, ch); - setCursorFromBuffer(cursor, cw, ch, cw); - setCursorHotspot(x, y); - free(cursor); -} - void ScummEngine_v80he::o80_setState() { int state = pop(); int obj = pop(); diff --git a/scumm/script_v90he.cpp b/scumm/script_v90he.cpp index 11b72709a9..8d311cf9dd 100644 --- a/scumm/script_v90he.cpp +++ b/scumm/script_v90he.cpp @@ -476,176 +476,6 @@ void ScummEngine_v90he::o90_jumpToScriptUnk() { runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args); } -void ScummEngine_v90he::drawWizComplexPolygon(int resnum, int state, int po_x, int po_y, int arg14, int angle, int zoom, const Common::Rect *r) { - Common::Point pts[4]; - int32 w, h; - getWizImageDim(resnum, state, w, h); - - pts[1].x = pts[2].x = w / 2 - 1; - pts[0].x = pts[0].y = pts[1].y = pts[3].x = -w / 2; - pts[2].y = pts[3].y = h / 2 - 1; - - // transform points - if (zoom != 256) { - for (int i = 0; i < 4; ++i) { - pts[i].x = pts[i].x * zoom / 256; - pts[i].y = pts[i].y * zoom / 256; - } - } - if (angle != 0) { - double alpha = angle * PI / 180.; - double cos_alpha = cos(alpha); - double sin_alpha = sin(alpha); - for (int i = 0; i < 4; ++i) { - int16 x = pts[i].x; - int16 y = pts[i].y; - pts[i].x = (int16)(x * cos_alpha - y * sin_alpha); - pts[i].y = (int16)(y * cos_alpha + x * sin_alpha); - } - } - for (int i = 0; i < 4; ++i) { - pts[i].x += po_x; - pts[i].y += po_y; - } - // XXX drawWizPolygonPoints(resnum, state, pts, r, VAR(117)); - warning("ScummEngine_v90he::drawWizComplexPolygon() partially implemented"); -} - -void ScummEngine_v90he::displayWizComplexImage(const WizParameters *params) { - // XXX merge with ScummEngine_v72he::displayWizImage - int zoom = 256; - if (params->processFlags & 0x8) { - zoom = params->zoom; - } - int rotationAngle = 0; - if (params->processFlags & 0x10) { - rotationAngle = params->angle; - } - int state = 0; - if (params->processFlags & 0x400) { - state = params->img.state; - } - int flags = 0; - if (params->processFlags & 0x20) { - flags = params->img.flags; - } - int po_x = 0; - int po_y = 0; - if (params->processFlags & 0x1) { - po_x = params->img.x1; - po_y = params->img.y1; - } - int unk = 0; - if (params->processFlags & 0x4) { - unk = params->unk_15C; - } - const Common::Rect *r = NULL; - if (params->processFlags & 0x200) { - r = ¶ms->box; - } - - if (_fullRedraw) { - assert(_wizImagesNum < ARRAYSIZE(_wizImages)); - WizImage *pwi = &_wizImages[_wizImagesNum]; - pwi->resNum = params->img.resNum; - pwi->x1 = po_x; - pwi->y1 = po_y; - pwi->state = state; - pwi->flags = flags; - pwi->unk = unk; - ++_wizImagesNum; - } else if (params->processFlags & 0x18) { - drawWizComplexPolygon(params->img.resNum, state, po_x, po_y, unk, rotationAngle, zoom, r); - } else if (flags & 0x40) { - drawWizPolygon(params->img.resNum, state, po_x, flags); // XXX , VAR(117)); - } else { - if ((flags & 0x200) || (flags & 0x24)) { - warning("ScummEngine_v90he::displayWizComplexImage() unhandled flags = 0x%X", flags); - } - // XXX flags 0x200, 0x24 - WizImage wi; - wi.resNum = params->img.resNum; - wi.x1 = po_x; - wi.y1 = po_y; - wi.state = state; - wi.flags = flags; - wi.unk = unk; - drawWizImage(rtImage, &wi); - } -} - -void ScummEngine_v90he::processWizImage(const WizParameters *params) { - debug(1, "ScummEngine_v90he::processWizImage()"); - switch (params->processMode) { - case 1: - displayWizComplexImage(params); - break; - case 2: - captureWizImage(rtImage, params->img.resNum, params->box, (params->img.flags & 8) == 8, params->compType); - break; - case 3: - if (params->processFlags & 0x800) { - File f; - if (!f.open((const char *)params->filename, File::kFileReadMode)) { - warning("Unable to open for read '%s'", params->filename); - } else { - uint32 id = f.readUint32BE(); - if (id != MKID('AWIZ') && id != MKID('MULT')) { - VAR(VAR_GAME_LOADED) = -1; - } else { - uint32 size = f.readUint32BE(); - f.seek(0, SEEK_SET); - byte *p = createResource(rtImage, params->img.resNum, size); - if (f.read(p, size) != size) { - nukeResource(rtImage, params->img.resNum); - warning("i/o error when reading '%s'", params->filename); - VAR(VAR_GAME_LOADED) = -2; - } else { - VAR(VAR_GAME_LOADED) = 0; - } - } - f.close(); - } - } - break; - case 4: - if (params->processFlags & 0x800) { - if (params->unk_14C != 0) { - VAR(119) = -1; - } else { - File f; - if (!f.open((const char *)params->filename, File::kFileWriteMode)) { - warning("Unable to open for write '%s'", params->filename); - VAR(119) = -3; - } else { - byte *p = getResourceAddress(rtImage, params->img.resNum); - uint32 size = READ_BE_UINT32(p + 4); - if (f.write(p, size) != size) { - warning("i/o error when writing '%s'", params->filename); - VAR(119) = -2; - } else { - VAR(119) = 0; - } - f.close(); - } - } - } - break; - case 6: - // HE 99+ - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - warning("unhandled processWizImage mode %d", params->processMode); - break; - default: - warning("invalid processWizImage mode %d", params->processMode); - } -} - void ScummEngine_v90he::o90_wizImageOps() { int a, b; int subOp = fetchScriptByte(); @@ -1176,108 +1006,6 @@ void ScummEngine_v90he::o90_unknown28() { debug(1,"o90_unknown28 stub (%d)", subOp); } -int ScummEngine_v90he::getWizImageStates(int resnum) { - const uint8 *dataPtr = getResourceAddress(rtImage, resnum); - assert(dataPtr); - if (READ_UINT32(dataPtr) == MKID('MULT')) { - const byte *offs, *wrap; - - wrap = findResource(MKID('WRAP'), dataPtr); - if (wrap == NULL) - return 1; - - offs = findResourceData(MKID('OFFS'), wrap); - if (offs == NULL) - return 1; - - return(getResourceDataSize(offs) / 4); - } else { - return 1; - } -} - -int ScummEngine_v90he::isWizPixelNonTransparent(int restype, int resnum, int state, int x, int y, int flags) { - int ret = 0; - const uint8 *data = getResourceAddress(restype, resnum); - assert(data); - const uint8 *wizh = findWrappedBlock(MKID('WIZH'), data, state, 0); - assert(wizh); - uint32 c = READ_LE_UINT32(wizh + 0x0); - int w = READ_LE_UINT32(wizh + 0x4); - int h = READ_LE_UINT32(wizh + 0x8); - const uint8 *wizd = findWrappedBlock(MKID('WIZD'), data, state, 0); - assert(wizd); - if (x >= 0 && x < w && y >= 0 && y < h) { - if (flags & 0x400) { - x = w - x - 1; - } - if (flags & 0x800) { - y = h - y - 1; - } - if (c == 1) { - ret = gdi.isWizPixelNonTransparent(wizd, x, y, w, h); - } else if (c == 0 || c == 2 || c == 3) { - ret = gdi.getRawWizPixelColor(wizd, x, y, w, h, VAR(VAR_WIZ_TCOLOR)) != VAR(VAR_WIZ_TCOLOR) ? 1 : 0; - } - } - return ret; -} - -uint8 ScummEngine_v90he::getWizPixelColor(int restype, int resnum, int state, int x, int y, int flags) { - uint8 color; - const uint8 *data = getResourceAddress(restype, resnum); - assert(data); - const uint8 *wizh = findWrappedBlock(MKID('WIZH'), data, state, 0); - assert(wizh); - uint32 c = READ_LE_UINT32(wizh + 0x0); - uint32 w = READ_LE_UINT32(wizh + 0x4); - uint32 h = READ_LE_UINT32(wizh + 0x8); - const uint8 *wizd = findWrappedBlock(MKID('WIZD'), data, state, 0); - assert(wizd); - if (c == 1) { - color = gdi.getWizPixelColor(wizd, x, y, w, h, VAR(VAR_WIZ_TCOLOR)); - } else if (c == 0 || c == 2 || c == 3) { - color = gdi.getRawWizPixelColor(wizd, x, y, w, h, VAR(VAR_WIZ_TCOLOR)); - } else { - color = VAR(VAR_WIZ_TCOLOR); - } - return color; -} - -int ScummEngine_v90he::computeWizHistogram(int resnum, int state, int x, int y, int w, int h) { - writeVar(0, 0); - defineArray(0, kDwordArray, 0, 0, 0, 255); - if (readVar(0) != 0) { - const uint8 *data = getResourceAddress(rtImage, resnum); - assert(data); - const uint8 *wizh = findWrappedBlock(MKID('WIZH'), data, state, 0); - assert(wizh); - uint32 ic = READ_LE_UINT32(wizh + 0x0); - uint32 iw = READ_LE_UINT32(wizh + 0x4); - uint32 ih = READ_LE_UINT32(wizh + 0x8); - const uint8 *wizd = findWrappedBlock(MKID('WIZD'), data, state, 0); - assert(wizd); - Common::Rect rWiz(iw, ih); - Common::Rect rCap(x, y, w + 1, h + 1); - if (rCap.intersects(rWiz)) { - rCap.clip(rWiz); - uint32 histogram[0x100]; - memset(histogram, 0, sizeof(histogram)); - if (ic == 1) { - gdi.computeWizHistogram(histogram, wizd, &rCap); - } else if (ic == 0) { - gdi.computeRawWizHistogram(histogram, wizd, w, &rCap); - } else { - warning("Unable to return histogram for type %d", ic); - } - for (int i = 0; i < 0x100; ++i) { - writeArray(0, 0, i, histogram[i]); - } - } - } - return readVar(0); -} - void ScummEngine_v90he::o90_getWizData() { int state, resId; int32 w, h; @@ -1494,7 +1222,7 @@ void ScummEngine_v90he::o90_getPolygonOverlap() { wp.vert[i].x = args1[i * 2 + 0]; wp.vert[i].y = args1[i * 2 + 1]; } - push(polygonContains(wp, args2[0], args2[1]) ? 1 : 0); + push(_wiz.polygonContains(wp, args2[0], args2[1]) ? 1 : 0); } } break; diff --git a/scumm/scumm.cpp b/scumm/scumm.cpp index de512d26c2..29a4681e44 100644 --- a/scumm/scumm.cpp +++ b/scumm/scumm.cpp @@ -690,8 +690,6 @@ ScummEngine::ScummEngine(GameDetector *detector, OSystem *syst, const ScummGameS _costumeRenderer = NULL; _2byteFontPtr = 0; _V1TalkingActor = 0; - _wizNumPolygons = 200; // Used as constant in original - _wizPolygons = NULL; _actorClipOverride.top = 0; _actorClipOverride.bottom = 480; @@ -1300,12 +1298,6 @@ void ScummEngine_v60he::scummInit() { // setCursorHotspot(8, 7); if (_gameId == GID_FUNPACK) setCursorHotspot(16, 16); - - if (_heversion >= 70) { - free(_wizPolygons); - - _wizPolygons = (WizPolygon *)calloc(_wizNumPolygons, sizeof(WizPolygon)); - } } void ScummEngine_v90he::scummInit() { @@ -1797,8 +1789,8 @@ void ScummEngine::startScene(int room, Actor *a, int objectNr) { stopCycle(0); _sound->processSoundQues(); - if (_heversion >= 71 && _wizPolygons) { - memset(_wizPolygons, 0, _wizNumPolygons * sizeof(WizPolygon)); + if (_heversion >= 71) { + memset(_wiz._polygons, 0, sizeof(_wiz._polygons)); } // For HE80+ games @@ -2354,7 +2346,7 @@ void ScummEngine::initRoomSubBlocks() { vert4y = READ_LE_UINT32(ptr + 36); ptr += 40; - polygonStore(id, flag, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y); + _wiz.polygonStore(id, flag, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y); } } diff --git a/scumm/scumm.h b/scumm/scumm.h index 03be6cbea4..f6974feb45 100644 --- a/scumm/scumm.h +++ b/scumm/scumm.h @@ -31,6 +31,7 @@ #include "scumm/gfx.h" #include "scumm/script.h" +#include "scumm/wiz_he.h" namespace GUI { class Dialog; @@ -311,14 +312,6 @@ struct LangIndexNode { int32 offset; }; -struct WizPolygon { - Common::Point vert[5]; - Common::Rect bound; - int id; - int numVerts; - bool flag; -}; - struct AuxBlock { bool visible; Common::Rect r; @@ -362,6 +355,9 @@ public: /** Graphics manager */ Gdi gdi; + + /** Wiz graphics manager (HE) */ + Wiz _wiz; protected: /** Central resource data. */ @@ -663,8 +659,6 @@ protected: uint32 *_heV7RoomIntOffsets; const byte *_resourceLastSearchBuf; // FIXME: need to put it to savefile? uint32 _resourceLastSearchSize; // FIXME: need to put it to savefile? - int _wizNumPolygons; - WizPolygon *_wizPolygons; void allocateArrays(); void openRoom(int room); @@ -705,8 +699,6 @@ protected: void loadRoomObjects(); void loadRoomObjectsSmall(); void loadRoomObjectsOldBundle(); - void polygonStore(int id, bool flag, int vert1x, int vert1y, int vert2x, int vert2y, - int vert3x, int vert3y, int vert4x, int vert4y); virtual void readArrayFromIndexFile(); virtual void readMAXS(int blockSize); diff --git a/scumm/wiz_he.cpp b/scumm/wiz_he.cpp new file mode 100644 index 0000000000..6e68454a7d --- /dev/null +++ b/scumm/wiz_he.cpp @@ -0,0 +1,1392 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2004 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" + +#include "scumm/intern.h" +#include "scumm/resource.h" +#include "scumm/scumm.h" +#include "scumm/wiz_he.h" + +namespace Scumm { + +Wiz::Wiz() { + _imagesNum = 0; + memset(&_images, 0, sizeof(_images)); + memset(&_polygons, 0, sizeof(_polygons)); +} + +void Wiz::polygonStore(int id, bool flag, int vert1x, int vert1y, int vert2x, int vert2y, int vert3x, int vert3y, int vert4x, int vert4y) { + WizPolygon *wp = NULL; + for (int i = 0; i < ARRAYSIZE(_polygons); ++i) { + if (_polygons[i].id == 0) { + wp = &_polygons[i]; + break; + } + } + if (!wp) { + error("Wiz::polygonStore: out of polygon slot, max = %d", ARRAYSIZE(_polygons)); + } + + wp->vert[0].x = vert1x; + wp->vert[0].y = vert1y; + wp->vert[1].x = vert2x; + wp->vert[1].y = vert2y; + wp->vert[2].x = vert3x; + wp->vert[2].y = vert3y; + wp->vert[3].x = vert4x; + wp->vert[3].y = vert4y; + wp->vert[4].x = vert1x; + wp->vert[4].y = vert1y; + wp->id = id; + wp->numVerts = 5; + wp->flag = flag; + + wp->bound.left = 10000; + wp->bound.top = 10000; + wp->bound.right = -10000; + wp->bound.bottom = -10000; + + // compute bounding box + for (int j = 0; j < wp->numVerts; j++) { + Common::Rect r(wp->vert[j].x, wp->vert[j].y, wp->vert[j].x + 1, wp->vert[j].y + 1); + wp->bound.extend(r); + } +} + +void Wiz::polygonErase(int fromId, int toId) { + for (int i = 0; i < ARRAYSIZE(_polygons); i++) { + if (_polygons[i].id >= fromId && _polygons[i].id <= toId) + memset(&_polygons[i], 0, sizeof(WizPolygon)); + } +} + +int Wiz::polygonHit(int id, int x, int y) { + for (int i = 0; i < ARRAYSIZE(_polygons); i++) { + if ((id == 0 || _polygons[i].id == id) && _polygons[i].bound.contains(x, y)) { + if (polygonContains(_polygons[i], x, y)) { + return _polygons[i].id; + } + } + } + return 0; +} + +bool Wiz::polygonDefined(int id) { + for (int i = 0; i < ARRAYSIZE(_polygons); i++) + if (_polygons[i].id == id) + return true; + return false; +} + +bool Wiz::polygonContains(const WizPolygon &pol, int x, int y) { + int pi = pol.numVerts - 1; + bool diry = (y < pol.vert[pi].y); + bool curdir; + bool r = false; + + for (int i = 0; i < pol.numVerts; i++) { + curdir = (y <= pol.vert[i].y); + + if (curdir != diry) { + if (((pol.vert[pi].y - pol.vert[i].y) * (pol.vert[i].x - x) <= + (pol.vert[pi].x - pol.vert[i].x) * (pol.vert[i].y - y)) == diry) + r = !r; + } + + pi = i; + diry = curdir; + } + + return r; +} + +void Wiz::copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch) { + Common::Rect dstRect(srcx, srcy, srcx + srcw, srcy + srch); + dstRect.clip(dstw, dsth); + + int rw = dstRect.width(); + int rh = dstRect.height(); + if (rh <= 0 || rw <= 0) + return; + + uint8 *dst1Ptr = dst1 + dstRect.left + dstRect.top * dstw; + uint8 *dst2Ptr = dst2 + dstRect.left + dstRect.top * dstw; + const uint8 *dataPtr = src; + + while (rh--) { + uint16 off = READ_LE_UINT16(dataPtr); dataPtr += 2; + const uint8 *dataPtrNext = off + dataPtr; + uint8 *dst1PtrNext = dst1Ptr + dstw; + uint8 *dst2PtrNext = dst2Ptr + dstw; + if (off != 0) { + int w = rw; + while (w > 0) { + uint8 code = *dataPtr++; + if (code & 1) { + code >>= 1; + dst1Ptr += code; + dst2Ptr += code; + w -= code; + } else if (code & 2) { + code = (code >> 2) + 1; + w -= code; + if (w >= 0) { + memset(dst1Ptr, *dataPtr++, code); + dst1Ptr += code; + dst2Ptr += code; + } else { + code += w; + memset(dst1Ptr, *dataPtr, code); + } + } else { + code = (code >> 2) + 1; + w -= code; + if (w >= 0) { + memcpy(dst1Ptr, dst2Ptr, code); + dst1Ptr += code; + dst2Ptr += code; + } else { + code += w; + memcpy(dst1Ptr, dst2Ptr, code); + } + } + } + } + dataPtr = dataPtrNext; + dst1Ptr = dst1PtrNext; + dst2Ptr = dst2PtrNext; + } +} + +static bool calcClipRects(int dst_w, int dst_h, int src_x, int src_y, int src_w, int src_h, const Common::Rect *rect, Common::Rect &srcRect, Common::Rect &dstRect) { + Common::Rect r3; + if (rect) { + r3 = *rect; + Common::Rect r4(dst_w, dst_h); + if (r3.intersects(r4)) { + r3.clip(r4); + } else { + return false; + } + } else { + r3 = Common::Rect(dst_w, dst_h); + } + dstRect = Common::Rect(src_x, src_y, src_x + src_w, src_y + src_h); + dstRect.clip(r3); + srcRect = dstRect; + srcRect.moveTo(0, 0); + return srcRect.isValidRect() && dstRect.isValidRect(); +} + +void Wiz::copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect) { + Common::Rect r1, r2; + if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { + dst += r2.left + r2.top * dstw; + decompressWizImage(dst, dstw, r2, src, r1); + } +} + +void Wiz::copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor) { + Common::Rect r1, r2; + if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { + if (flags & 0x400) { + int l = r1.left; + int r = r1.right; + r1.left = srcw - r; + r1.right = srcw - l; + } + if (flags & 0x800) { + int t = r1.top; + int b = r1.bottom; + r1.top = srch - b; + r1.bottom = srch - t; + } + byte imagePal[256]; + if (!palPtr) { + for (int i = 0; i < 256; i++) { + imagePal[i] = i; + } + palPtr = imagePal; + } + int h = r1.height(); + int w = r1.width(); + dst += r2.left + r2.top * dstw; + while (h--) { + for (int i = 0; i < w; ++i) { + uint8 col = *src++; + if (transColor == -1 || transColor != col) { + dst[i] = palPtr[col]; + } + } + dst += dstw; + } + } +} + +void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const Common::Rect &dstRect, const uint8 *src, const Common::Rect &srcRect, const uint8 *imagePal) { + const uint8 *dataPtr, *dataPtrNext; + uint8 *dstPtr, *dstPtrNext; + uint32 code; + uint8 databit; + int h, w, xoff; + uint16 off; + + dstPtr = dst; + dataPtr = src; + + // Skip over the first 'srcRect->top' lines in the data + h = srcRect.top; + while (h--) { + dataPtr += READ_LE_UINT16(dataPtr) + 2; + } + h = srcRect.height(); + w = srcRect.width(); + if (h <= 0 || w <= 0) + return; + + while (h--) { + xoff = srcRect.left; + off = READ_LE_UINT16(dataPtr); + w = srcRect.right - srcRect.left; + dstPtrNext = dstPitch + dstPtr; + dataPtrNext = off + 2 + dataPtr; + dataPtr += 2; + if (off == 0) + goto dec_next; + + // Skip over the leftmost 'srcRect->left' pixels. + // TODO: This code could be merged (at a loss of efficency) with the + // loop below which does the actual drawing. + while (xoff > 0) { + code = *dataPtr++; + databit = code & 1; + code >>= 1; + if (databit) { + xoff -= code; + if (xoff < 0) { + code = -xoff; + goto dec_sub1; + } + } else { + databit = code & 1; + code = (code >> 1) + 1; + if (databit) { + ++dataPtr; + xoff -= code; + if (xoff < 0) { + code = -xoff; + --dataPtr; + goto dec_sub2; + } + } else { + dataPtr += code; + xoff -= code; + if (xoff < 0) { + dataPtr += xoff; + code = -xoff; + goto dec_sub3; + } + } + } + } + + while (w > 0) { + code = *dataPtr++; + databit = code & 1; + code >>= 1; + if (databit) { +dec_sub1: dstPtr += code; + w -= code; + } else { + databit = code & 1; + code = (code >> 1) + 1; + if (databit) { +dec_sub2: w -= code; + if (w < 0) { + code += w; + } + uint8 color = *dataPtr++; + if (imagePal) { + color = imagePal[color]; + } + memset(dstPtr, color, code); + dstPtr += code; + } else { +dec_sub3: w -= code; + if (w < 0) { + code += w; + } + if (imagePal) { + while (code--) { + *dstPtr++ = imagePal[*dataPtr++]; + } + } else { + memcpy(dstPtr, dataPtr, code); + dstPtr += code; + dataPtr += code; + } + } + } + } +dec_next: + dataPtr = dataPtrNext; + dstPtr = dstPtrNext; + } +} + +int Wiz::isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h) { + int ret = 0; + while (y != 0) { + data += READ_LE_UINT16(data) + 2; + --y; + } + uint16 off = READ_LE_UINT16(data); data += 2; + if (off != 0) { + if (x == 0) { + ret = (~*data) & 1; + } else { + do { + uint8 code = *data++; + if (code & 1) { + code >>= 1; + if (code > x) { + ret = 0; + break; + } + x -= code; + } else if (code & 2) { + code = (code >> 2) + 1; + if (code > x) { + ret = 1; + break; + } + x -= code; + ++data; + } else { + code = (code >> 2) + 1; + if (code > x) { + ret = 1; + break; + } + x -= code; + data += code; + } + } while (x > 0); + } + } + return ret; +} + +uint8 Wiz::getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color) { + uint8 c = color; + if (x >= 0 && x < w && y >= 0 && y < h) { + while (y != 0) { + data += READ_LE_UINT16(data) + 2; + --y; + } + uint16 off = READ_LE_UINT16(data); data += 2; + if (off != 0) { + if (x == 0) { + c = (*data & 1) ? color : *data; + } else { + do { + uint8 code = *data++; + if (code & 1) { + code >>= 1; + if (code > x) { + c = color; + break; + } + x -= code; + } else if (code & 2) { + code = (code >> 2) + 1; + if (code > x) { + c = *data; + break; + } + x -= code; + ++data; + } else { + code = (code >> 2) + 1; + if (code > x) { + c = *(data + x); + break; + } + x -= code; + data += code; + } + } while (x > 0); + } + } + } + return c; +} + +uint8 Wiz::getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color) { + uint8 c; + if (x >= 0 && x < w && y >= 0 && y < h) { + c = data[y * w + x]; + } else { + c = color; + } + return c; +} + +void Wiz::computeWizHistogram(uint32 *histogram, const uint8 *data, const Common::Rect *srcRect) { + int y = srcRect->top; + while (y != 0) { + data += READ_LE_UINT16(data) + 2; + --y; + } + int ih = srcRect->height(); + while (ih--) { + uint16 off = READ_LE_UINT16(data); data += 2; + if (off != 0) { + const uint8 *p = data; + int x1 = srcRect->left; + int x2 = srcRect->right; + uint8 code; + while (x1 > 0) { + code = *p++; + if (code & 1) { + code >>= 1; + if (code > x1) { + code -= x1; + x2 -= code; + break; + } + x1 -= code; + } else if (code & 2) { + code = (code >> 2) + 1; + if (code > x1) { + code -= x1; + goto dec_sub2; + } + x1 -= code; + ++p; + } else { + code = (code >> 2) + 1; + if (code > x1) { + code -= x1; + p += x1; + goto dec_sub3; + } + x1 -= code; + p += code; + } + } + while (x2 > 0) { + code = *p++; + if (code & 1) { + code >>= 1; + x2 -= code; + } else if (code & 2) { + code = (code >> 2) + 1; +dec_sub2: x2 -= code; + if (x2 < 0) { + code += x2; + } + histogram[*p++] += code; + } else { + code = (code >> 2) + 1; +dec_sub3: x2 -= code; + if (x2 < 0) { + code += x2; + } + int n = code; + while (n--) { + ++histogram[*p++]; + } + } + } + data += off; + } + } +} + +void Wiz::computeRawWizHistogram(uint32 *histogram, const uint8 *data, int srcPitch, const Common::Rect *srcRect) { + data += srcRect->top * srcPitch + srcRect->left; + int iw = srcRect->width(); + int ih = srcRect->height(); + while (ih--) { + for (int i = 0; i < iw; ++i) { + ++histogram[data[i]]; + } + data += srcPitch; + } +} + +struct wizPackCtx { + uint32 len; + uint8 saveCode; + uint8 saveBuf[0x100]; +}; + +static void wizPackType1Helper1(uint8 *&dst, int len, byte newColor, byte prevColor, wizPackCtx *ctx) { + assert(len > 0); + if (newColor == prevColor) { + do { + int blockLen = MIN(len, 0x7F); + len -= blockLen; + if (dst) { + *dst++ = (blockLen * 2) | 1; + } + ++ctx->len; + } while (len > 0); + } else { + do { + int blockLen = MIN(len, 0x40); + len -= blockLen; + if (dst) { + *dst++ = ((blockLen - 1) * 4) | 2; + } + ++ctx->len; + if (dst) { + *dst++ = newColor; + } + ++ctx->len; + } while (len > 0); + } +} + +static void wizPackType1Helper2(uint8 *&dst, int len, wizPackCtx *ctx) { + assert(len > 0); + const uint8 *src = ctx->saveBuf; + do { + int blockLen = MIN(len, 0x40); + len -= blockLen; + if (dst) { + *dst++ = (blockLen - 1) * 4; + } + ++ctx->len; + while (blockLen--) { + if (dst) { + *dst++ = *src++; + } + ++ctx->len; + } + } while (len > 0); +} + +static int wizPackType1(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt, uint8 tColor) { + debug(1, "wizPackType1(%d, [%d,%d,%d,%d])", tColor, rCapt.left, rCapt.top, rCapt.right, rCapt.bottom); + wizPackCtx ctx; + memset(&ctx, 0, sizeof(ctx)); + + src += rCapt.top * srcPitch + rCapt.left; + int w = rCapt.width(); + int h = rCapt.height(); + + uint8 *nextDstPtr, *curDstPtr; + uint8 curColor, prevColor; + int saveBufPos; + + nextDstPtr = curDstPtr = 0; + + int dataSize = 0; + while (h--) { + if (dst) { + curDstPtr = dst; + nextDstPtr = dst; + dst += 2; + } + dataSize += 2; + int numBytes = 0; + + int i, code; + for (i = 0; i < w; ++i) { + if (src[i] != tColor) + break; + } + if (i != w) { + curDstPtr = dst; + ctx.len = 0; + prevColor = ctx.saveBuf[0] = *src; + const uint8 *curSrcPtr = src + 1; + saveBufPos = 1; + code = (tColor - ctx.saveBuf[0] == 0) ? 1 : 0; + int curw = w; + while (curw--) { + ctx.saveBuf[saveBufPos] = curColor = *curSrcPtr++; + ++saveBufPos; + if (code == 0) { + if (curColor == tColor) { + --saveBufPos; + wizPackType1Helper2(curDstPtr, saveBufPos, &ctx); + code = saveBufPos = 1; + ctx.saveBuf[0] = curColor; + numBytes = 0; + prevColor = curColor; + continue; + } + if (saveBufPos > 0x80) { + --saveBufPos; + wizPackType1Helper2(curDstPtr, saveBufPos, &ctx); + saveBufPos = 1; + ctx.saveBuf[0] = curColor; + numBytes = 0; + prevColor = curColor; + continue; + } + if (prevColor != curColor) { + numBytes = saveBufPos - 1; + prevColor = curColor; + continue; + } + code = 1; + if (numBytes != 0) { + if (saveBufPos - numBytes < 3) { + code = 0; + } else { + wizPackType1Helper2(curDstPtr, numBytes, &ctx); + } + } + } + if (prevColor != curColor || saveBufPos - numBytes > 0x80) { + saveBufPos -= numBytes; + --saveBufPos; + wizPackType1Helper1(curDstPtr, saveBufPos, prevColor, tColor, &ctx); + saveBufPos = 1; + numBytes = 0; + ctx.saveBuf[0] = curColor; + code = (tColor - ctx.saveBuf[0] == 0) ? 1 : 0; + } + prevColor = curColor; + } + if (code == 0) { + wizPackType1Helper2(curDstPtr, saveBufPos, &ctx); + } else { + saveBufPos -= numBytes; + wizPackType1Helper1(curDstPtr, saveBufPos, prevColor, tColor, &ctx); + } + dataSize += ctx.len; + src += srcPitch; + if (dst) { + dst += ctx.len; + *(uint16 *)nextDstPtr = TO_LE_16(ctx.len); + } + } + } + return dataSize; +} + +static int wizPackType0(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt, uint8 tColor) { + int w = rCapt.width(); + int h = rCapt.height(); + int size = w * h; + if (dst) { + src += rCapt.top * srcPitch + rCapt.left; + while (h--) { + memcpy(dst, src, w); + dst += w; + src += srcPitch; + } + } + return size; +} + +void ScummEngine_v72he::captureWizImage(int resType, int resNum, const Common::Rect& r, bool frontBuffer, int compType) { + debug(1, "ScummEngine_v72he::captureWizImage(%d, %d, %d, [%d,%d,%d,%d])", resType, resNum, compType, r.left, r.top, r.right, r.bottom); + uint8 *src = NULL; + VirtScreen *pvs = &virtscr[kMainVirtScreen]; + if (frontBuffer) { + src = pvs->getPixels(0, 0); + } else { + src = pvs->getBackPixels(0, 0); + } + Common::Rect rCapt(0, 0, pvs->w, pvs->h); + if (rCapt.intersects(r)) { + rCapt.clip(r); + const uint8 *palPtr = _currentPalette; + + int w = rCapt.width(); + int h = rCapt.height(); + int tColor = (VAR_WIZ_TCOLOR != 0xFF) ? VAR(VAR_WIZ_TCOLOR) : 5; + + // compute compressed size + int dataSize = 0; + int headerSize = palPtr ? 1080 : 36; + switch (compType) { + case 1: + dataSize = wizPackType1(0, src, pvs->pitch, rCapt, tColor); + break; + case 0: + dataSize = wizPackType0(0, src, pvs->pitch, rCapt, tColor); + break; + default: + warning("unhandled compression type %d", compType); + break; + } + + // alignment + dataSize = (dataSize + 1) & ~1; + int wizSize = headerSize + dataSize; + // write header + uint8 *wizImg = createResource(resType, resNum, dataSize + headerSize); + *(uint32 *)(wizImg + 0x00) = MKID('AWIZ'); + *(uint32 *)(wizImg + 0x04) = TO_BE_32(wizSize); + *(uint32 *)(wizImg + 0x08) = MKID('WIZH'); + *(uint32 *)(wizImg + 0x0C) = TO_BE_32(0x14); + *(uint32 *)(wizImg + 0x10) = TO_LE_32(compType); + *(uint32 *)(wizImg + 0x14) = TO_LE_32(w); + *(uint32 *)(wizImg + 0x18) = TO_LE_32(h); + int curSize = 0x1C; + if (palPtr) { + *(uint32 *)(wizImg + 0x1C) = MKID('RGBS'); + *(uint32 *)(wizImg + 0x20) = TO_BE_32(0x308); + memcpy(wizImg + 0x24, palPtr, 0x300); + *(uint32 *)(wizImg + 0x324) = MKID('RMAP'); + *(uint32 *)(wizImg + 0x328) = TO_BE_32(0x10C); + *(uint32 *)(wizImg + 0x32C) = 0; + curSize = 0x330; + for (int i = 0; i < 256; ++i) { + wizImg[curSize] = i; + ++curSize; + } + } + *(uint32 *)(wizImg + curSize + 0x0) = MKID('WIZD'); + *(uint32 *)(wizImg + curSize + 0x4) = TO_BE_32(dataSize + 8); + curSize += 8; + + // write compressed data + switch (compType) { + case 1: + wizPackType1(wizImg + headerSize, src, pvs->pitch, rCapt, tColor); + break; + case 0: + wizPackType0(wizImg + headerSize, src, pvs->pitch, rCapt, tColor); + break; + default: + break; + } + } +} + +void ScummEngine_v72he::displayWizImage(const WizImage *pwi) { + if (_fullRedraw) { + assert(_wiz._imagesNum < ARRAYSIZE(_wiz._images)); + memcpy(&_wiz._images[_wiz._imagesNum], pwi, sizeof(WizImage)); + ++_wiz._imagesNum; + } else if (pwi->flags & 0x40) { + drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags); + } else { + drawWizImage(rtImage, pwi); + } +} + +void ScummEngine_v72he::getWizImageDim(int resnum, int state, int32 &w, int32 &h) { + const uint8 *dataPtr = getResourceAddress(rtImage, resnum); + if (dataPtr) { + const uint8 *wizh = findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); + w = READ_LE_UINT32(wizh + 0x4); + h = READ_LE_UINT32(wizh + 0x8); + } else { + w = 0; + h = 0; + } +} + +uint8 *ScummEngine_v72he::drawWizImage(int restype, const WizImage *pwi) { + debug(1, "drawWizImage(%d, %d, %d, %d, 0x%X)", restype, pwi->resNum, pwi->x1, pwi->y1, pwi->flags); + uint8 *dst = NULL; + const uint8 *dataPtr = getResourceAddress(restype, pwi->resNum); + if (dataPtr) { + const uint8 *rmap = NULL; + const uint8 *xmap = findWrappedBlock(MKID('XMAP'), dataPtr, pwi->state, 0); + + const uint8 *wizh = findWrappedBlock(MKID('WIZH'), dataPtr, pwi->state, 0); + assert(wizh); + uint32 comp = READ_LE_UINT32(wizh + 0x0); + uint32 width = READ_LE_UINT32(wizh + 0x4); + uint32 height = READ_LE_UINT32(wizh + 0x8); + assert(comp == 0 || comp == 1 || comp == 2 || comp == 3 || comp == 10 || comp == 11); + + const uint8 *wizd = findWrappedBlock(MKID('WIZD'), dataPtr, pwi->state, 0); + assert(wizd); + if (pwi->flags & 1) { + const uint8 *pal = findWrappedBlock(MKID('RGBS'), dataPtr, pwi->state, 0); + assert(pal); + setPaletteFromPtr(pal, 256); + } + if (pwi->flags & 2) { + rmap = findWrappedBlock(MKID('RMAP'), dataPtr, pwi->state, 0); + assert(rmap); + const uint8 *rgbs = findWrappedBlock(MKID('RGBS'), dataPtr, pwi->state, 0); + assert(rgbs); + warning("drawWizImage() unhandled flag 0x2"); + // XXX modify 'RMAP' buffer + } + if (pwi->flags & 4) { + warning("WizImage printing is unimplemented"); + return NULL; + } + uint32 cw, ch; + if (pwi->flags & 0x20) { + dst = (uint8 *)malloc(width * height); + int color = 255; // FIXME: should be (VAR_WIZ_TCOLOR != 0xFF) ? VAR(VAR_WIZ_TCOLOR) : 5; + memset(dst, color, width * height); + cw = width; + ch = height; + } else { + VirtScreen *pvs = &virtscr[kMainVirtScreen]; + if (pwi->flags & 0x10) { + dst = pvs->getPixels(0, pvs->topline); + } else { + dst = pvs->getBackPixels(0, pvs->topline); + } + cw = pvs->w; + ch = pvs->h; + } + Common::Rect rScreen(cw, ch); + // XXX handle 'XMAP' / 'RMAP' data + if (comp == 1) { + if (pwi->flags & 0x80) { + warning("drawWizImage() unhandled flag 0x80"); + } else if (pwi->flags & 0x100) { + warning("drawWizImage() unhandled flag 0x100"); + } else { + _wiz.copyWizImage(dst, wizd, cw, ch, pwi->x1, pwi->y1, width, height, &rScreen); + } + } else if (comp == 0 || comp == 2 || comp == 3) { + const uint8 *trns = findWrappedBlock(MKID('TRNS'), dataPtr, pwi->state, 0); + int color = (trns == NULL) ? VAR(VAR_WIZ_TCOLOR) : -1; + const uint8 *pal = xmap; + if (pwi->flags & 2) { + pal = rmap + 4; + } + _wiz.copyRawWizImage(dst, wizd, cw, ch, pwi->x1, pwi->y1, width, height, &rScreen, pwi->flags, pal, color); + } else { + warning("unhandled wiz compression type %d", comp); + } + + if (!(pwi->flags & 0x20)) { + Common::Rect rImage(pwi->x1, pwi->y1, pwi->x1 + width, pwi->y1 + height); + if (rImage.intersects(rScreen)) { + rImage.clip(rScreen); + if (!(pwi->flags & 8) && pwi->flags & 0x18) { + ++rImage.bottom; + markRectAsDirty(kMainVirtScreen, rImage); + } else { + gdi.copyVirtScreenBuffers(rImage); + } + } + } + } + return dst; +} + +struct PolygonDrawData { + struct InterArea { + bool valid; + int32 xmin; + int32 xmax; + int32 x1; + int32 y1; + int32 x2; + int32 y2; + }; + Common::Point pto; + InterArea *ia; + int areasNum; + + PolygonDrawData(int n) { + areasNum = n; + ia = new InterArea[areasNum]; + memset(ia, 0, sizeof(InterArea) * areasNum); + } + + ~PolygonDrawData() { + delete[] ia; + } + + void calcIntersection(const Common::Point *p1, const Common::Point *p2, const Common::Point *p3, const Common::Point *p4) { + int32 x1_acc = p1->x << 0x10; + int32 x3_acc = p3->x << 0x10; + int32 y3_acc = p3->y << 0x10; + uint16 dy = ABS(p2->y - p1->y) + 1; + int32 x1_step = ((p2->x - p1->x) << 0x10) / dy; + int32 x3_step = ((p4->x - p3->x) << 0x10) / dy; + int32 y3_step = ((p4->y - p3->y) << 0x10) / dy; + + int iaidx = p1->y - pto.y; + while (dy--) { + assert(iaidx >= 0 && iaidx < areasNum); + InterArea *pia = &ia[iaidx]; + int32 tx1 = x1_acc >> 0x10; + int32 tx3 = x3_acc >> 0x10; + int32 ty3 = y3_acc >> 0x10; + + if (!pia->valid || pia->xmin > tx1) { + pia->xmin = tx1; + pia->x1 = tx3; + pia->y1 = ty3; + } + if (!pia->valid || pia->xmax < tx1) { + pia->xmax = tx1; + pia->x2 = tx3; + pia->y2 = ty3; + } + pia->valid = true; + + x1_acc += x1_step; + x3_acc += x3_step; + y3_acc += y3_step; + + if (p2->y <= p1->y) { + --iaidx; + } else { + ++iaidx; + } + } + } +}; + +void ScummEngine_v72he::drawWizPolygon(int resnum, int state, int id, int flags) { + int i; + WizPolygon *wp = NULL; + for (i = 0; i < ARRAYSIZE(_wiz._polygons); ++i) { + if (_wiz._polygons[i].id == id) { + wp = &_wiz._polygons[i]; + break; + } + } + if (!wp) { + error("Polygon %d is not defined", id); + } + if (wp->numVerts != 5) { + error("Invalid point count %d for Polygon %d", wp->numVerts, id); + } + WizImage wi; + wi.resNum = resnum; + wi.state = state; + wi.x1 = wi.y1 = 0; + wi.flags = 0x20; + uint8 *srcWizBuf = drawWizImage(rtImage, &wi); + if (srcWizBuf) { + uint8 *dst; + VirtScreen *pvs = &virtscr[kMainVirtScreen]; + if (flags & 0x10) { + dst = pvs->getPixels(0, 0); + } else { + dst = pvs->getBackPixels(0, 0); + } + if (wp->bound.left < 0 || wp->bound.top < 0 || wp->bound.right >= pvs->w || wp->bound.bottom >= pvs->h) { + error("Invalid coords polygon %d", wp->id); + } + + int32 wizW, wizH; + getWizImageDim(resnum, state, wizW, wizH); + Common::Point bbox[4]; + bbox[0].x = 0; + bbox[0].y = 0; + bbox[1].x = wizW - 1; + bbox[1].y = 0; + bbox[2].x = wizW - 1; + bbox[2].y = wizH - 1; + bbox[3].x = 0; + bbox[3].y = wizH - 1; + + int16 xmin_p, xmax_p, ymin_p, ymax_p; + xmin_p = xmax_p = wp->vert[0].x; + ymin_p = ymax_p = wp->vert[0].y; + for (i = 1; i < 4; ++i) { + xmin_p = MIN(wp->vert[i].x, xmin_p); + xmax_p = MAX(wp->vert[i].x, xmax_p); + ymin_p = MIN(wp->vert[i].y, ymin_p); + ymax_p = MAX(wp->vert[i].y, ymax_p); + } + + int16 xmin_b, xmax_b, ymin_b, ymax_b; + xmin_b = 0; + xmax_b = wizW - 1; + ymin_b = 0; + ymax_b = wizH - 1; + + PolygonDrawData pdd(ymax_p - ymin_p + 1); + pdd.pto.x = xmin_p; + pdd.pto.y = ymin_p; + + for (i = 0; i < 3; ++i) { + pdd.calcIntersection(&wp->vert[i], &wp->vert[i + 1], &bbox[i], &bbox[i + 1]); + } + pdd.calcIntersection(&wp->vert[3], &wp->vert[0], &bbox[3], &bbox[0]); + + uint yoff = pdd.pto.y * pvs->w; + for (i = 0; i < pdd.areasNum; ++i) { + PolygonDrawData::InterArea *pia = &pdd.ia[i]; + uint16 dx = pia->xmax - pia->xmin + 1; + uint8 *dstPtr = dst + pia->xmin + yoff; + int32 x_acc = pia->x1 << 0x10; + int32 y_acc = pia->y1 << 0x10; + int32 x_step = ((pia->x2 - pia->x1) << 0x10) / dx; + int32 y_step = ((pia->y2 - pia->y1) << 0x10) / dx; + while (dx--) { + uint srcWizOff = (y_acc >> 0x10) * wizW + (x_acc >> 0x10); + assert(srcWizOff < (uint32)(wizW * wizH)); + x_acc += x_step; + y_acc += y_step; + *dstPtr++ = srcWizBuf[srcWizOff]; + } + yoff += pvs->pitch; + } + + if (flags & 0x10) { + markRectAsDirty(kMainVirtScreen, wp->bound); + } else { + gdi.copyVirtScreenBuffers(wp->bound); + } + + free(srcWizBuf); + } +} + +void ScummEngine_v72he::flushWizBuffer() { + for (int i = 0; i < _wiz._imagesNum; ++i) { + WizImage *pwi = &_wiz._images[i]; + if (pwi->flags & 0x40) { + drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags); + } else { + drawWizImage(rtImage, pwi); + } + } + _wiz._imagesNum = 0; +} + +void ScummEngine_v80he::loadImgSpot(int resId, int state, int16 &x, int16 &y) { + const uint8 *dataPtr = getResourceAddress(rtImage, resId); + if (!dataPtr) { + warning("loadImgSpot: unknown Image %d", resId); + x = y = 0; + return; + } + + const uint8 *spotPtr = findWrappedBlock(MKID('SPOT'), dataPtr, state, 0); + if (spotPtr) { + x = (int16)READ_LE_UINT32(spotPtr + 0); + y = (int16)READ_LE_UINT32(spotPtr + 4); + } else { + x = 0; + y = 0; + } +} + +void ScummEngine_v80he::loadWizCursor(int resId, int resType, bool state) { + int16 x, y; + loadImgSpot(resId, 0, x, y); + if (x < 0) { + x = 0; + } else if (x > 32) { + x = 32; + } + if (y < 0) { + y = 0; + } else if (y > 32) { + y = 32; + } + + WizImage wi; + wi.resNum = resId; + wi.x1 = wi.y1 = 0; + wi.state = 0; + wi.flags = 0x20; + uint8 *cursor = drawWizImage(rtImage, &wi); + int32 cw, ch; + getWizImageDim(resId, 0, cw, ch); + setCursorFromBuffer(cursor, cw, ch, cw); + setCursorHotspot(x, y); + free(cursor); +} + +void ScummEngine_v90he::drawWizComplexPolygon(int resnum, int state, int po_x, int po_y, int arg14, int angle, int zoom, const Common::Rect *r) { + Common::Point pts[4]; + int32 w, h; + getWizImageDim(resnum, state, w, h); + + pts[1].x = pts[2].x = w / 2 - 1; + pts[0].x = pts[0].y = pts[1].y = pts[3].x = -w / 2; + pts[2].y = pts[3].y = h / 2 - 1; + + // transform points + if (zoom != 256) { + for (int i = 0; i < 4; ++i) { + pts[i].x = pts[i].x * zoom / 256; + pts[i].y = pts[i].y * zoom / 256; + } + } + if (angle != 0) { + double alpha = angle * PI / 180.; + double cos_alpha = cos(alpha); + double sin_alpha = sin(alpha); + for (int i = 0; i < 4; ++i) { + int16 x = pts[i].x; + int16 y = pts[i].y; + pts[i].x = (int16)(x * cos_alpha - y * sin_alpha); + pts[i].y = (int16)(y * cos_alpha + x * sin_alpha); + } + } + for (int i = 0; i < 4; ++i) { + pts[i].x += po_x; + pts[i].y += po_y; + } + // XXX drawWizPolygonPoints(resnum, state, pts, r, VAR(117)); + warning("ScummEngine_v90he::drawWizComplexPolygon() partially implemented"); +} + +void ScummEngine_v90he::displayWizComplexImage(const WizParameters *params) { + // XXX merge with ScummEngine_v72he::displayWizImage + int zoom = 256; + if (params->processFlags & 0x8) { + zoom = params->zoom; + } + int rotationAngle = 0; + if (params->processFlags & 0x10) { + rotationAngle = params->angle; + } + int state = 0; + if (params->processFlags & 0x400) { + state = params->img.state; + } + int flags = 0; + if (params->processFlags & 0x20) { + flags = params->img.flags; + } + int po_x = 0; + int po_y = 0; + if (params->processFlags & 0x1) { + po_x = params->img.x1; + po_y = params->img.y1; + } + int unk = 0; + if (params->processFlags & 0x4) { + unk = params->unk_15C; + } + const Common::Rect *r = NULL; + if (params->processFlags & 0x200) { + r = ¶ms->box; + } + + if (_fullRedraw) { + assert(_wiz._imagesNum < ARRAYSIZE(_wiz._images)); + WizImage *pwi = &_wiz._images[_wiz._imagesNum]; + pwi->resNum = params->img.resNum; + pwi->x1 = po_x; + pwi->y1 = po_y; + pwi->state = state; + pwi->flags = flags; + pwi->unk = unk; + ++_wiz._imagesNum; + } else if (params->processFlags & 0x18) { + drawWizComplexPolygon(params->img.resNum, state, po_x, po_y, unk, rotationAngle, zoom, r); + } else if (flags & 0x40) { + drawWizPolygon(params->img.resNum, state, po_x, flags); // XXX , VAR(117)); + } else { + if ((flags & 0x200) || (flags & 0x24)) { + warning("ScummEngine_v90he::displayWizComplexImage() unhandled flags = 0x%X", flags); + } + // XXX flags 0x200, 0x24 + WizImage wi; + wi.resNum = params->img.resNum; + wi.x1 = po_x; + wi.y1 = po_y; + wi.state = state; + wi.flags = flags; + wi.unk = unk; + drawWizImage(rtImage, &wi); + } +} + +void ScummEngine_v90he::processWizImage(const WizParameters *params) { + debug(1, "ScummEngine_v90he::processWizImage()"); + switch (params->processMode) { + case 1: + displayWizComplexImage(params); + break; + case 2: + captureWizImage(rtImage, params->img.resNum, params->box, (params->img.flags & 8) == 8, params->compType); + break; + case 3: + if (params->processFlags & 0x800) { + File f; + if (!f.open((const char *)params->filename, File::kFileReadMode)) { + warning("Unable to open for read '%s'", params->filename); + } else { + uint32 id = f.readUint32BE(); + if (id != MKID('AWIZ') && id != MKID('MULT')) { + VAR(VAR_GAME_LOADED) = -1; + } else { + uint32 size = f.readUint32BE(); + f.seek(0, SEEK_SET); + byte *p = createResource(rtImage, params->img.resNum, size); + if (f.read(p, size) != size) { + nukeResource(rtImage, params->img.resNum); + warning("i/o error when reading '%s'", params->filename); + VAR(VAR_GAME_LOADED) = -2; + } else { + VAR(VAR_GAME_LOADED) = 0; + } + } + f.close(); + } + } + break; + case 4: + if (params->processFlags & 0x800) { + if (params->unk_14C != 0) { + VAR(119) = -1; + } else { + File f; + if (!f.open((const char *)params->filename, File::kFileWriteMode)) { + warning("Unable to open for write '%s'", params->filename); + VAR(119) = -3; + } else { + byte *p = getResourceAddress(rtImage, params->img.resNum); + uint32 size = READ_BE_UINT32(p + 4); + if (f.write(p, size) != size) { + warning("i/o error when writing '%s'", params->filename); + VAR(119) = -2; + } else { + VAR(119) = 0; + } + f.close(); + } + } + } + break; + case 6: + // HE 99+ + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + warning("unhandled processWizImage mode %d", params->processMode); + break; + default: + warning("invalid processWizImage mode %d", params->processMode); + } +} + +int ScummEngine_v90he::getWizImageStates(int resnum) { + const uint8 *dataPtr = getResourceAddress(rtImage, resnum); + assert(dataPtr); + if (READ_UINT32(dataPtr) == MKID('MULT')) { + const byte *offs, *wrap; + + wrap = findResource(MKID('WRAP'), dataPtr); + if (wrap == NULL) + return 1; + + offs = findResourceData(MKID('OFFS'), wrap); + if (offs == NULL) + return 1; + + return getResourceDataSize(offs) / 4; + } else { + return 1; + } +} + +int ScummEngine_v90he::isWizPixelNonTransparent(int restype, int resnum, int state, int x, int y, int flags) { + int ret = 0; + const uint8 *data = getResourceAddress(restype, resnum); + assert(data); + const uint8 *wizh = findWrappedBlock(MKID('WIZH'), data, state, 0); + assert(wizh); + uint32 c = READ_LE_UINT32(wizh + 0x0); + int w = READ_LE_UINT32(wizh + 0x4); + int h = READ_LE_UINT32(wizh + 0x8); + const uint8 *wizd = findWrappedBlock(MKID('WIZD'), data, state, 0); + assert(wizd); + if (x >= 0 && x < w && y >= 0 && y < h) { + if (flags & 0x400) { + x = w - x - 1; + } + if (flags & 0x800) { + y = h - y - 1; + } + if (c == 1) { + ret = _wiz.isWizPixelNonTransparent(wizd, x, y, w, h); + } else if (c == 0 || c == 2 || c == 3) { + ret = _wiz.getRawWizPixelColor(wizd, x, y, w, h, VAR(VAR_WIZ_TCOLOR)) != VAR(VAR_WIZ_TCOLOR) ? 1 : 0; + } + } + return ret; +} + +uint8 ScummEngine_v90he::getWizPixelColor(int restype, int resnum, int state, int x, int y, int flags) { + uint8 color; + const uint8 *data = getResourceAddress(restype, resnum); + assert(data); + const uint8 *wizh = findWrappedBlock(MKID('WIZH'), data, state, 0); + assert(wizh); + uint32 c = READ_LE_UINT32(wizh + 0x0); + uint32 w = READ_LE_UINT32(wizh + 0x4); + uint32 h = READ_LE_UINT32(wizh + 0x8); + const uint8 *wizd = findWrappedBlock(MKID('WIZD'), data, state, 0); + assert(wizd); + if (c == 1) { + color = _wiz.getWizPixelColor(wizd, x, y, w, h, VAR(VAR_WIZ_TCOLOR)); + } else if (c == 0 || c == 2 || c == 3) { + color = _wiz.getRawWizPixelColor(wizd, x, y, w, h, VAR(VAR_WIZ_TCOLOR)); + } else { + color = VAR(VAR_WIZ_TCOLOR); + } + return color; +} + +int ScummEngine_v90he::computeWizHistogram(int resnum, int state, int x, int y, int w, int h) { + writeVar(0, 0); + defineArray(0, kDwordArray, 0, 0, 0, 255); + if (readVar(0) != 0) { + const uint8 *data = getResourceAddress(rtImage, resnum); + assert(data); + const uint8 *wizh = findWrappedBlock(MKID('WIZH'), data, state, 0); + assert(wizh); + uint32 ic = READ_LE_UINT32(wizh + 0x0); + uint32 iw = READ_LE_UINT32(wizh + 0x4); + uint32 ih = READ_LE_UINT32(wizh + 0x8); + const uint8 *wizd = findWrappedBlock(MKID('WIZD'), data, state, 0); + assert(wizd); + Common::Rect rWiz(iw, ih); + Common::Rect rCap(x, y, w + 1, h + 1); + if (rCap.intersects(rWiz)) { + rCap.clip(rWiz); + uint32 histogram[0x100]; + memset(histogram, 0, sizeof(histogram)); + if (ic == 1) { + _wiz.computeWizHistogram(histogram, wizd, &rCap); + } else if (ic == 0 || ic == 2 || ic == 3) { + _wiz.computeRawWizHistogram(histogram, wizd, w, &rCap); + } else { + warning("Unable to return histogram for type %d", ic); + } + for (int i = 0; i < 0x100; ++i) { + writeArray(0, 0, i, histogram[i]); + } + } + } + return readVar(0); +} + +} // End of namespace Scumm diff --git a/scumm/wiz_he.h b/scumm/wiz_he.h new file mode 100644 index 0000000000..277d0d1498 --- /dev/null +++ b/scumm/wiz_he.h @@ -0,0 +1,111 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2004 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef WIZ_HE_H +#define WIZ_HE_H + +#include "common/rect.h" + +namespace Scumm { + +struct WizPolygon { + Common::Point vert[5]; + Common::Rect bound; + int id; + int numVerts; + bool flag; +}; + +struct WizImage { + int resNum; + int x1; + int y1; + int flags; + int state; + int unk; +}; + +struct WizParameters { + byte filename[260]; + Common::Rect box; + int processFlags; + int processMode; + int unk_11C; + int unk_120; + int unk_124; + int unk_128; + int unk_12C; + int unk_130; + int unk_134; + int unk_138; + int compType; + int unk_14C; + int angle; + int zoom; + int unk_15C; + int unk_160; + uint8 remapColor[256]; + uint8 remapIndex[256]; + int remapNum; + WizImage img; +}; + +struct Wiz { + enum { + FW_PRINT = 0x4, + FW_MEM = 0x20, + FW_POLYGON = 0x40, + FW_XFLIP = 0x400, + FW_YFLIP = 0x800 + }; + + enum { + NUM_POLYGONS = 200, + NUM_IMAGES = 255 + }; + + WizImage _images[NUM_IMAGES]; + uint16 _imagesNum; + WizPolygon _polygons[NUM_POLYGONS]; + + Wiz(); + + void polygonStore(int id, bool flag, int vert1x, int vert1y, int vert2x, int vert2y, int vert3x, int vert3y, int vert4x, int vert4y); + void polygonErase(int fromId, int toId); + int polygonHit(int id, int x, int y); + bool polygonDefined(int id); + bool polygonContains(const WizPolygon &pol, int x, int y); + + void copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch); + void copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect); + void copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor); + void decompressWizImage(uint8 *dst, int dstPitch, const Common::Rect &dstRect, const uint8 *src, const Common::Rect &srcRect, const uint8 *imagePal = NULL); + int isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h); + uint8 getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color); + uint8 getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color); + void computeWizHistogram(uint32 *histogram, const uint8 *data, const Common::Rect *srcRect); + void computeRawWizHistogram(uint32 *histogram, const uint8 *data, int srcPitch, const Common::Rect *srcRect); +}; + +} // End of namespace Scumm + +#endif -- cgit v1.2.3