+long ScreenBuffer[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
+boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
+
+int TEST_flag = 0;
+
+
+static void ScrollPlayfield(int dx, int dy)
+{
+ int x1 = mScrollX_last / TILEX - 2;
+ int y1 = mScrollY_last / TILEY - 2;
+ int x2 = mScrollX_last / TILEX + (SCR_FIELDX - 1) + 2;
+ int y2 = mScrollY_last / TILEY + (SCR_FIELDY - 1) + 2;
+ int x, y;
+
+ BlitBitmap(screenBitmap, screenBitmap,
+ TILEX * (dx == -1),
+ TILEY * (dy == -1),
+ (MAX_BUF_XSIZE * TILEX) - TILEX * (dx != 0),
+ (MAX_BUF_YSIZE * TILEY) - TILEY * (dy != 0),
+ TILEX * (dx == 1),
+ TILEY * (dy == 1));
+
+ /* when scrolling the whole playfield, do not redraw single tiles */
+ for (x = 0; x < MAX_BUF_XSIZE; x++)
+ for (y = 0; y < MAX_BUF_YSIZE; y++)
+ redraw[x][y] = FALSE;
+ redraw_tiles = 0;
+
+#if 1
+ DrawFrameIfNeeded();
+#endif
+
+ for (y = DisplayMinY; y <= DisplayMaxY; y++)
+ {
+ for (x = DisplayMinX; x <= DisplayMaxX; x++)
+ {
+ if (x >= x1 && x <= x2 && y >= y1 && y <= y2)
+ {
+ int sx = x - x1;
+ int sy = y - y1;
+ int tsi = GetSI(x, y);
+ long id = ((PlayField16[tsi]) |
+ (PlayField8[tsi] << 16) |
+ (DisPlayField[tsi] << 24));
+
+#if 0
+#if 1
+ printf("::: [%d] %d [%d, %d] [%d]\n", dx, sx, x, y, buf_xsize);
+#else
+ if (sx == 0 || sx == MAX_BUF_XSIZE - 1)
+ printf("::: %d, %d\n", dx, sx);
+#endif
+#endif
+
+ if ((dx == -1 && x == x2) ||
+ (dx == +1 && x == x1) ||
+ (dy == -1 && y == y2) ||
+ (dy == +1 && y == y1))
+ {
+#if 0
+ printf("::: %d, %d\n", sx, sy);
+#endif
+
+ TEST_flag = 1;
+
+ DrawFieldNoAnimated(x, y);
+ DrawFieldAnimated(x, y);
+
+ TEST_flag = 0;
+ }
+
+ ScreenBuffer[sx][sy] = id;
+ }
+ }
+ }
+}
+
+static void ScrollPlayfieldIfNeededExt(boolean reset)
+{
+ if (reset)
+ {
+ mScrollX_last = -1;
+ mScrollY_last = -1;
+
+ return;
+ }
+
+ if (mScrollX_last == -1 || mScrollY_last == -1)
+ {
+ mScrollX_last = mScrollX;
+ mScrollY_last = mScrollY;
+
+ return;
+ }
+
+#if 1
+
+ /* check if scrolling the playfield requires redrawing the viewport bitmap */
+ if ((mScrollX != mScrollX_last ||
+ mScrollY != mScrollY_last) &&
+ (ABS(mScrollX - mScrollX_last) >= TILEX ||
+ ABS(mScrollY - mScrollY_last) >= TILEY))
+ {
+ int dx = (ABS(mScrollX - mScrollX_last) < TILEX ? 0 :
+ mScrollX < mScrollX_last ? 1 : mScrollX > mScrollX_last ? -1 : 0);
+ int dy = (ABS(mScrollY - mScrollY_last) < TILEY ? 0 :
+ mScrollY < mScrollY_last ? 1 : mScrollY > mScrollY_last ? -1 : 0);
+
+ mScrollX_last -= dx * TILEX;
+ mScrollY_last -= dy * TILEY;
+
+ ScrollPlayfield(dx, dy);
+
+#if 0
+ printf("::: %ld, %ld\n", mScrollX, mScrollY);
+#endif
+ }
+
+#else
+
+ /* check if scrolling the playfield reached the destination tile position */
+ if ((mScrollX != mScrollX_last || mScrollY != mScrollY_last) &&
+ mScrollX % TILEX == 0 && mScrollY % TILEY == 0)
+ {
+ int dx = (mScrollX < mScrollX_last ? 1 : mScrollX > mScrollX_last ? -1 : 0);
+ int dy = (mScrollY < mScrollY_last ? 1 : mScrollY > mScrollY_last ? -1 : 0);
+
+ mScrollX_last = mScrollX;
+ mScrollY_last = mScrollY;
+
+ ScrollPlayfield(dx, dy);
+
+#if 0
+ printf("::: %ld, %ld\n", mScrollX, mScrollY);
+#endif
+ }
+
+#endif
+}
+
+static void ScrollPlayfieldIfNeeded()
+{
+ ScrollPlayfieldIfNeededExt(FALSE);
+}
+
+void InitScrollPlayfield()
+{
+ ScrollPlayfieldIfNeededExt(TRUE);
+}
+
+void UpdatePlayfield()
+{
+ int x, y;
+#if 1
+ int num_redrawn = 0;
+#endif
+
+ for (y = DisplayMinY; y <= DisplayMaxY; y++)
+ {
+ for (x = DisplayMinX; x <= DisplayMaxX; x++)
+ {
+ int element = LowByte(PlayField16[GetSI(x, y)]);
+ int graphic = GfxGraphic[x][y];
+ int sync_frame = GfxFrame[x][y];
+#if 1
+ boolean redraw = FALSE;
+#else
+ boolean redraw = TRUE; // !!! TEST ONLY -- ALWAYS REDRAW !!!
+#endif
+
+ if (graphic < 0)
+ continue;
+
+ if (element != GfxElementLast[x][y] &&
+ graphic == GfxGraphicLast[x][y])
+ {
+ /* element changed, but not graphic => disable updating graphic */
+
+ GfxElementLast[x][y] = element;
+ GfxGraphicLast[x][y] = GfxGraphic[x][y] = -1;
+
+ continue;
+ }
+
+ if (graphic != GfxGraphicLast[x][y]) // new graphic
+ {
+ redraw = TRUE;
+
+ GfxElementLast[x][y] = element;
+ GfxGraphicLast[x][y] = GfxGraphic[x][y];
+ sync_frame = GfxFrame[x][y] = 0;
+ }
+ else if (isNextAnimationFrame_SP(graphic, sync_frame)) // new frame
+ {
+ redraw = TRUE;
+ }
+
+ if (redraw)
+ {
+ int sx = x * StretchWidth;
+ int sy = y * StretchWidth;
+
+#if 0
+ printf("::: REDRAW (%d, %d): %d, %d\n", x, y, graphic, sync_frame);
+#endif
+
+ StretchedSprites.BltImg(sx, sy, graphic, sync_frame);
+
+#if 1
+ num_redrawn++;
+#endif
+ }
+ }
+ }
+
+#if 0
+ printf("::: FRAME %d: %d redrawn\n", FrameCounter, num_redrawn);
+#endif
+}
+
+void UpdatePlayfield_TMP()
+{
+ int x1 = mScrollX_last / TILEX - 2;
+ int y1 = mScrollY_last / TILEY - 2;
+ int x2 = mScrollX_last / TILEX + (SCR_FIELDX - 1) + 2;
+ int y2 = mScrollY_last / TILEY + (SCR_FIELDY - 1) + 2;
+ int x, y;
+
+ for (y = DisplayMinY; y <= DisplayMaxY; y++)
+ {
+ for (x = DisplayMinX; x <= DisplayMaxX; x++)
+ {
+ if (x >= x1 && x <= x2 && y >= y1 && y <= y2)
+ {
+ int sx = x - x1;
+ int sy = y - y1;
+ int tsi = GetSI(x, y);
+ long id = ((PlayField16[tsi]) |
+ (PlayField8[tsi] << 16) |
+ (DisPlayField[tsi] << 24));
+ boolean redraw_screen_tile = (ScreenBuffer[sx][sy] != id);
+
+#if 0
+ if (LowByte(PlayField16[tsi]) == fiMurphy)
+ continue;
+#endif
+
+ if (redraw_screen_tile)
+ {
+#if 0
+ DrawFieldNoAnimated(x, y);
+ DrawFieldAnimated(x, y);
+#endif
+
+ ScreenBuffer[sx][sy] = id;
+
+ redraw[sx][sy] = TRUE;
+ redraw_tiles++;
+ }
+ }
+ }
+ }
+}
+
+void OLD_UpdatePlayfield()
+{
+ int x, y;
+ int left = mScrollX / TILEX;
+ int top = mScrollY / TILEY;
+
+ for (y = top; y < top + MAX_BUF_YSIZE; y++)
+ {
+ for (x = left; x < left + MAX_BUF_XSIZE; x++)
+ {
+ int sx = x % MAX_BUF_XSIZE;
+ int sy = y % MAX_BUF_YSIZE;
+ int tsi = GetSI(x, y);
+ long id = ((PlayField16[tsi]) |
+ (PlayField8[tsi] << 16) |
+ (DisPlayField[tsi] << 24));
+ boolean redraw_screen_tile = (ScreenBuffer[sx][sy] != id);
+
+ if (redraw_screen_tile)
+ {
+ DrawFieldNoAnimated(x, y);
+ DrawFieldAnimated(x, y);
+
+ ScreenBuffer[sx][sy] = id;
+
+ redraw[sx][sy] = TRUE;
+ redraw_tiles++;
+ }
+ }
+ }
+}
+