From 49a4df3c8c3e51d88c03b8f6745c787fb0f6a47e Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 15 Aug 2009 11:50:59 +0000 Subject: Added Dirty Rect handling functionality svn-id: r43406 --- engines/cruise/background.cpp | 3 ++ engines/cruise/background.h | 1 + engines/cruise/backgroundIncrust.cpp | 6 +++ engines/cruise/cell.cpp | 5 +++ engines/cruise/detection.cpp | 2 +- engines/cruise/function.cpp | 8 +++- engines/cruise/gfxModule.cpp | 72 +++++++++++++++++++++++++++++++++++- engines/cruise/gfxModule.h | 1 + engines/cruise/mainDraw.cpp | 11 ++++++ 9 files changed, 106 insertions(+), 3 deletions(-) diff --git a/engines/cruise/background.cpp b/engines/cruise/background.cpp index 6635a8d621..587c790554 100644 --- a/engines/cruise/background.cpp +++ b/engines/cruise/background.cpp @@ -30,6 +30,7 @@ namespace Cruise { uint8 colorMode = 0; uint8 *backgroundScreens[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; // wasn't initialized in original, but it's probably better +bool backgroundChanged[8] = { false, false, false, false, false, false, false, false }; backgroundTableStruct backgroundTable[8]; char hwPage[64000]; @@ -101,6 +102,8 @@ int loadBackground(const char *name, int idx) { return (-2); } + backgroundChanged[idx] = true; + ptrToFree = gfxModuleData.pPage10; if (loadFileSub1(&ptrToFree, name, NULL) < 0) { if (ptrToFree != gfxModuleData.pPage10) diff --git a/engines/cruise/background.h b/engines/cruise/background.h index 711e89a34a..6f9b89d3f0 100644 --- a/engines/cruise/background.h +++ b/engines/cruise/background.h @@ -36,6 +36,7 @@ struct backgroundTableStruct { extern short int cvtPalette[0x20]; extern int CVTLoaded; extern uint8 *backgroundScreens[8]; +extern bool backgroundChanged[8]; extern backgroundTableStruct backgroundTable[8]; int loadBackground(const char *name, int idx); diff --git a/engines/cruise/backgroundIncrust.cpp b/engines/cruise/backgroundIncrust.cpp index 03ed552018..78cf49c653 100644 --- a/engines/cruise/backgroundIncrust.cpp +++ b/engines/cruise/backgroundIncrust.cpp @@ -71,6 +71,8 @@ void restoreBackground(backgroundIncrustStruct *pIncrust) { if (pBackground == NULL) return; + backgroundChanged[pIncrust->backgroundIdx] = true; + int X = pIncrust->savedX; int Y = pIncrust->savedY; int width = pIncrust->saveWidth; @@ -108,6 +110,8 @@ backgroundIncrustStruct *addBackgroundIncrust(int16 overlayIdx, int16 objectIdx, backgroundPtr = backgroundScreens[backgroundIdx]; + backgroundChanged[backgroundIdx] = true; + assert(backgroundPtr != NULL); currentHead = pHead; @@ -218,6 +222,8 @@ void regenerateBackgroundIncrust(backgroundIncrustStruct *pHead) { // Poly addBackgroundIncrustSub1(frame, pl->X, pl->Y, NULL, pl->scale, (char*)backgroundScreens[pl->backgroundIdx], (char *)filesDatabase[frame].subData.ptr); } + + backgroundChanged[pl->backgroundIdx] = true; } pl = pl2; diff --git a/engines/cruise/cell.cpp b/engines/cruise/cell.cpp index 7966d5ea12..aeafed4f7a 100644 --- a/engines/cruise/cell.cpp +++ b/engines/cruise/cell.cpp @@ -176,6 +176,11 @@ void createTextObject(cellStruct *pObject, int overlayIdx, int messageIdx, int x if (ax) { pNewElement->gfxPtr = renderText(width, ax); } + + // WORKAROUND: This is needed for the new dirty rect handling so as to properly refresh the screen + // when the copy protection screen is being shown + if ((messageIdx == 0) && !strcmp(overlayTable[overlayIdx].overlayName, "XX2")) + backgroundChanged[0] = true; } void removeCell(cellStruct *objPtr, int ovlNumber, int objectIdx, int objType, int backgroundPlane) { diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp index 879fad0210..d7c1b1c22d 100644 --- a/engines/cruise/detection.cpp +++ b/engines/cruise/detection.cpp @@ -26,7 +26,7 @@ #include "base/plugins.h" - +#include "common/savefile.h" #include "engines/advancedDetector.h" #include "cruise/cruise.h" diff --git a/engines/cruise/function.cpp b/engines/cruise/function.cpp index 6fe82f76d4..53549bff9e 100644 --- a/engines/cruise/function.cpp +++ b/engines/cruise/function.cpp @@ -510,6 +510,8 @@ int16 Op_LoadBackground(void) { gfxModuleData_gfxWaitVSync(); result = loadBackground(bgName, bgIdx); + + gfxModuleData_addDirtyRect(Common::Rect(0, 0, 320, 200)); } changeCursor(CURSOR_NORMAL); @@ -788,6 +790,7 @@ int16 Op_ClearScreen(void) { if ((bgIdx >= 0) && (bgIdx < NBSCREENS) && (backgroundScreens[bgIdx])) { memset(backgroundScreens[bgIdx], 0, 320 * 200); + backgroundChanged[bgIdx] = true; strcpy(backgroundTable[0].name, ""); } @@ -922,6 +925,7 @@ int16 Op_SetActiveBackground(void) { if (newPlane >= 0 && newPlane < NBSCREENS) { if (backgroundScreens[newPlane]) { masterScreen = newPlane; + backgroundChanged[newPlane] = true; switchPal = 1; } } @@ -936,8 +940,10 @@ int16 Op_RemoveBackground(void) { if (backgroundScreens[backgroundIdx]) free(backgroundScreens[backgroundIdx]); - if (masterScreen == backgroundIdx) + if (masterScreen == backgroundIdx) { masterScreen = 0; + backgroundChanged[0] = true; + } strcpy(backgroundTable[backgroundIdx].name, ""); } else { diff --git a/engines/cruise/gfxModule.cpp b/engines/cruise/gfxModule.cpp index 003a335e42..b3ac68edae 100644 --- a/engines/cruise/gfxModule.cpp +++ b/engines/cruise/gfxModule.cpp @@ -26,6 +26,8 @@ #include "common/system.h" #include "common/endian.h" +#include "common/list.h" +#include "common/rect.h" #include "cruise/cruise.h" #include "cruise/cruise_main.h" @@ -41,6 +43,12 @@ palEntry lpalette[256]; int palDirtyMin = 256; int palDirtyMax = -1; +typedef Common::List RectList; +RectList _dirtyRects; +RectList _priorFrameRects; + +bool _dirtyRectScreen = false; + gfxModuleDataStruct gfxModuleData = { 0, // use Tandy 0, // use EGA @@ -229,7 +237,47 @@ void gfxModuleData_flipScreen(void) { flip(); } +void gfxModuleData_addDirtyRect(const Common::Rect &r) { + _dirtyRects.push_back(Common::Rect( MAX(r.left, (int16)0), MAX(r.top, (int16)0), + MIN(r.right, (int16)320), MIN(r.bottom, (int16)200))); +} + +/** + * Creates the union of two rectangles. + */ +static bool unionRectangle(Common::Rect &pDest, const Common::Rect &pSrc1, const Common::Rect &pSrc2) { + pDest.left = MIN(pSrc1.left, pSrc2.left); + pDest.top = MIN(pSrc1.top, pSrc2.top); + pDest.right = MAX(pSrc1.right, pSrc2.right); + pDest.bottom = MAX(pSrc1.bottom, pSrc2.bottom); + + return !pDest.isEmpty(); +} + +static void mergeClipRects() { + RectList::iterator rOuter, rInner; + + for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) { + rInner = rOuter; + while (++rInner != _dirtyRects.end()) { + + if ((*rOuter).intersects(*rInner)) { + // these two rectangles overlap, so translate it to a bigger rectangle + // that contains both of them + unionRectangle(*rOuter, *rOuter, *rInner); + + // remove the inner rect from the list + _dirtyRects.erase(rInner); + + // move back to beginning of list + rInner = rOuter; + } + } + } +} + void flip() { + RectList::iterator dr; int i; byte paletteRGBA[256 * 4]; @@ -245,7 +293,29 @@ void flip() { palDirtyMax = -1; } - g_system->copyRectToScreen(globalScreen, 320, 0, 0, 320, 200); + // Make a copy of the prior frame's dirty rects, and then backup the current frame's rects + RectList tempList = _priorFrameRects; + _priorFrameRects = _dirtyRects; + + // Merge the prior frame's dirty rects into the current frame's list + for (dr = tempList.begin(); dr != tempList.end(); ++dr) { + Common::Rect &r = *dr; + _dirtyRects.push_back(Common::Rect(r.left, r.top, r.right, r.bottom)); + } + + // Merge any overlapping rects to simplify the drawing process + mergeClipRects(); + + // Copy any modified areas + for (dr = _dirtyRects.begin(); dr != _dirtyRects.end(); ++dr) { + Common::Rect &r = *dr; + g_system->copyRectToScreen(globalScreen + 320 * r.top + r.left, 320, + r.left, r.top, r.width(), r.height()); + } + + _dirtyRects.clear(); + + // Allow the screen to update g_system->updateScreen(); } diff --git a/engines/cruise/gfxModule.h b/engines/cruise/gfxModule.h index dc085d8b0d..308b96ab64 100644 --- a/engines/cruise/gfxModule.h +++ b/engines/cruise/gfxModule.h @@ -62,6 +62,7 @@ void gfxModuleData_flipScreen(void); void gfxModuleData_convertOldPalColor(uint16 oldColor, uint8 *pOutput); void gfxModuleData_setPalEntries(const byte *ptr, int start, int num); void gfxModuleData_setPal256(const byte *ptr); +void gfxModuleData_addDirtyRect(const Common::Rect &r); void flip(void); void drawSolidBox(int32 x1, int32 y1, int32 x2, int32 y2, uint8 colour); void resetBitmap(uint8 *dataPtr, int32 dataSize); diff --git a/engines/cruise/mainDraw.cpp b/engines/cruise/mainDraw.cpp index 047f00ee90..61e8f8d85c 100644 --- a/engines/cruise/mainDraw.cpp +++ b/engines/cruise/mainDraw.cpp @@ -1121,6 +1121,8 @@ void mainDrawPolygons(int fileIndex, cellStruct *plWork, int X, int scale, int Y if (spriteY1 == spriteY2) return; + gfxModuleData_addDirtyRect(Common::Rect(spriteX2, spriteY2, spriteX1, spriteY1)); + var_8 = 0; memset(polygonMask, 0xFF, (320*200) / 8); @@ -1177,6 +1179,8 @@ void drawMessage(const gfxEntryStruct *pGfxPtr, int globalX, int globalY, int wi globalY = 198 - pGfxPtr->height; } + gfxModuleData_addDirtyRect(Common::Rect(globalX, globalY, globalX + width, globalY + height)); + initialOuput = ouputPtr + (globalY * 320) + globalX; for (yp = 0; yp < height; yp++) { @@ -1206,6 +1210,9 @@ void drawSprite(int width, int height, cellStruct *currentObjPtr, const uint8 *d int x = 0; int y = 0; + // Flag the given area as having been changed + gfxModuleData_addDirtyRect(Common::Rect(xs, ys, xs + width - 1, ys + height - 1)); + cellStruct* plWork = currentObjPtr; int workBufferSize = height * (width / 8); @@ -1406,6 +1413,10 @@ void mainDraw(int16 param) { if (bgPtr) { gfxModuleData_gfxCopyScreen(bgPtr, gfxModuleData.pPage10); + if (backgroundChanged[masterScreen]) { + backgroundChanged[masterScreen] = false; + gfxModuleData_addDirtyRect(Common::Rect(0, 0, 320, 200)); + } } autoCellHead.next = NULL; -- cgit v1.2.3