diff options
-rw-r--r-- | engines/toltecs/animation.cpp | 1 | ||||
-rw-r--r-- | engines/toltecs/microtiles.cpp | 844 | ||||
-rw-r--r-- | engines/toltecs/microtiles.h | 113 | ||||
-rw-r--r-- | engines/toltecs/module.mk | 1 | ||||
-rw-r--r-- | engines/toltecs/render.cpp | 320 | ||||
-rw-r--r-- | engines/toltecs/render.h | 119 | ||||
-rw-r--r-- | engines/toltecs/saveload.cpp | 1 | ||||
-rw-r--r-- | engines/toltecs/screen.cpp | 74 | ||||
-rw-r--r-- | engines/toltecs/screen.h | 23 | ||||
-rw-r--r-- | engines/toltecs/segmap.cpp | 74 | ||||
-rw-r--r-- | engines/toltecs/segmap.h | 19 | ||||
-rw-r--r-- | engines/toltecs/sprite.cpp | 79 | ||||
-rw-r--r-- | engines/toltecs/toltecs.cpp | 78 | ||||
-rw-r--r-- | engines/toltecs/toltecs.h | 3 |
14 files changed, 740 insertions, 1009 deletions
diff --git a/engines/toltecs/animation.cpp b/engines/toltecs/animation.cpp index 34a18489be..3175bf67fe 100644 --- a/engines/toltecs/animation.cpp +++ b/engines/toltecs/animation.cpp @@ -138,6 +138,7 @@ int16 AnimationPlayer::getStatus() { void AnimationPlayer::unpackFrame() { _vm->_screen->unpackRle(_animBuffer, _vm->_screen->_frontScreen, _width, _height); _vm->_screen->unpackRle(_animBuffer, _vm->_screen->_backScreen, _width, _height); + _vm->_screen->_fullRefresh = true; } void AnimationPlayer::saveState(Common::WriteStream *out) { diff --git a/engines/toltecs/microtiles.cpp b/engines/toltecs/microtiles.cpp index 3cd5facfa6..7c82505c21 100644 --- a/engines/toltecs/microtiles.cpp +++ b/engines/toltecs/microtiles.cpp @@ -1,614 +1,135 @@ -/* - SEL - Simple DirectMedia Layer Extension Library - Copyright (C) 2002 Matej Knopp <knopp@users.sf.net> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* microtile arrays implementation */ - -/* - * This is a microtile array implementation similiar to the one - * from LibArt_LGPL. First, I wanted to use that one but unfortunately - * I fount out that it suffered from a bad design and simply didn't meet - * my requirements so I decided to write the implementation on my own. - */ - #include "toltecs/microtiles.h" -#include "common/scummsys.h" -#include "common/endian.h" -#include "common/util.h" namespace Toltecs { -typedef struct _GemUta GemUta; -typedef struct _GemRect GemRect; - -typedef uint32 GemUtaBBox; - -#define GEM_UTA_BBOX_CONS(x0, y0, x1, y1) (((x0) << 24) | ((y0) << 16) | \ - ((x1) << 8) | (y1)) - -#define GEM_UTILE_EMPTY 0x00000000 -#define GEM_UTILE_FULL 0x01012020 - -#define GEM_UTA_BBOX_X0(ub) ((ub) >> 24) -#define GEM_UTA_BBOX_Y0(ub) (((ub) >> 16) & 0xff) -#define GEM_UTA_BBOX_X1(ub) (((ub) >> 8) & 0xff) -#define GEM_UTA_BBOX_Y1(ub) ((ub) & 0xff) - -#define GEM_UTILE_SHIFT 5 -#define GEM_UTILE_SIZE (1 << GEM_UTILE_SHIFT) - -#define GEM_MIN(a,b) ((a) < (b) ? (a) : (b)) -#define GEM_MAX(a,b) ((a) > (b) ? (a) : (b)) - -struct _GemUta { - int x; - int y; - int width; /* number of tiles in one line */ - int height; /* number of tiles in one row */ - GemUtaBBox *tiles; -}; - -struct _GemRect { - int x0; - int x1; - int y0; - int y1; -}; - - -static GemUta * gem_uta_new (int x, int y, int width, int height); -static GemUta * gem_uta_new_coords (int x, int y, int width, int height); -static void gem_uta_free (GemUta *uta); -static void gem_uta_union (GemUta *uta1, const GemUta *uta2); -static void gem_uta_add_rect (GemUta *uta, const GemRect * rect); - -#define GEM_UTA_QUERY_CONTAIN 0 -#define GEM_UTA_QUERY_INTERSECT 1 - -static int gem_uta_query_rect (const GemUta *uta, const GemRect * rect, int query); - -static Common::Rect * gem_uta_get_rects (const GemUta *uta, int * num_rects, - int min_x, int min_y, int max_x, int max_y); - -/************** UTA IMPLEMENTATION **************/ - -#define GEM_UTILE_UNION(b1, b2) \ - { \ - if (b1 == GEM_UTILE_FULL || b2 == GEM_UTILE_EMPTY) \ - { } \ - else if (b1 == GEM_UTILE_EMPTY || b2 == GEM_UTILE_FULL) \ - { b1 = b2; } \ - else { \ - b1 = GEM_UTA_BBOX_CONS ( \ - GEM_MIN(GEM_UTA_BBOX_X0(b1), \ - GEM_UTA_BBOX_X0(b2)), \ - GEM_MIN(GEM_UTA_BBOX_Y0(b1), \ - GEM_UTA_BBOX_Y0(b2)), \ - GEM_MAX(GEM_UTA_BBOX_X1(b1), \ - GEM_UTA_BBOX_X1(b2)), \ - GEM_MAX(GEM_UTA_BBOX_Y1(b1), \ - GEM_UTA_BBOX_Y1(b2))); \ - } \ - } - -static GemUta * gem_uta_new (int x, int y, int width, int height) { - GemUta *uta; - - uta = (GemUta *) malloc (sizeof (GemUta)); - uta->x = x; - uta->y = y; - uta->width = width; - uta->height = height; - - uta->tiles = (GemUtaBBox *) - malloc (sizeof (GemUtaBBox) * width * height); - - memset (uta->tiles, 0, sizeof (GemUtaBBox) * width * height); - - return uta; -} - -static GemUta * gem_uta_new_coords (int x, int y, int width, int height) { - return gem_uta_new (x >> GEM_UTILE_SHIFT, y >> GEM_UTILE_SHIFT, - (width >> GEM_UTILE_SHIFT) + 1, - (height >> GEM_UTILE_SHIFT) + 1); +MicroTileArray::MicroTileArray(int16 width, int16 height) { + _tilesW = (width / TileSize) + ((width % TileSize) > 0 ? 1 : 0); + _tilesH = (height / TileSize) + ((height % TileSize) > 0 ? 1 : 0); + _tiles = new BoundingBox[_tilesW * _tilesH]; + clear(); } -static void gem_uta_free (GemUta *uta) { - if (uta) { - if (uta->tiles) - free (uta->tiles); - free(uta); - } +MicroTileArray::~MicroTileArray() { + delete[] _tiles; } -static void gem_uta_union (GemUta *uta1, const GemUta *uta2) { - int32 x0, y0, x1, y1; - int x, y; - GemUtaBBox *_b1; - const GemUtaBBox *_b2; - - if (!uta1 || !uta2) - return; - - x0 = GEM_MAX (uta1->x, uta2->x); - y0 = GEM_MAX (uta2->y, uta2->y); - x1 = GEM_MIN (uta1->x + uta1->width - 1, - uta2->x + uta2->width - 1); - y1 = GEM_MIN (uta1->y + uta1->height - 1, - uta2->y + uta2->height - 1); +void MicroTileArray::addRect(Common::Rect r) { - if (x0 > x1 || y0 > y1) - return; + int ux0, uy0, ux1, uy1; + int tx0, ty0, tx1, ty1; + int ix0, iy0, ix1, iy1; - _b1 = & (uta1->tiles [(y0 - uta1->y) * uta1->width + (x0 - uta1->x)]); - _b2 = & (uta2->tiles [(y0 - uta2->y) * uta2->width + (x0 - uta2->x)]); + r.clip(Common::Rect(0, 0, 639, 399)); - for (y = y0; y <= y1; ++y) - { - GemUtaBBox *b1 = _b1; - const GemUtaBBox *b2 = _b2; + ux0 = r.left / TileSize; + uy0 = r.top / TileSize; + ux1 = r.right / TileSize; + uy1 = r.bottom / TileSize; - for (x = x0; x <= x1; ++x) - { - GEM_UTILE_UNION (*b1, *b2); + tx0 = r.left % TileSize; + ty0 = r.top % TileSize; + tx1 = r.right % TileSize; + ty1 = r.bottom % TileSize; - b1 ++; - b2 ++; + for (int yc = uy0; yc <= uy1; yc++) { + for (int xc = ux0; xc <= ux1; xc++) { + ix0 = (xc == ux0) ? tx0 : 0; + ix1 = (xc == ux1) ? tx1 : TileSize - 1; + iy0 = (yc == uy0) ? ty0 : 0; + iy1 = (yc == uy1) ? ty1 : TileSize - 1; + updateBoundingBox(_tiles[xc + yc * _tilesW], ix0, iy0, ix1, iy1); } - _b1 += uta1->width; - _b2 += uta2->width; } -} - -/* - * Add a rectangle to the microtile array. - * The coordinates of the rectangle are considered absolute. - */ -static void gem_uta_add_rect (GemUta *uta, const GemRect * _rect) { - int xf0, xf1, yf0, yf1; - int width, height; - int x0, y0, x1, y1; - int x, y; - GemUtaBBox *_b; - GemUtaBBox *b; - GemUtaBBox bbox; - GemRect rect; - - if (!uta || !_rect) - return; - - rect = *_rect; - - rect.x0 -= uta->x << GEM_UTILE_SHIFT; - rect.y0 -= uta->y << GEM_UTILE_SHIFT; - rect.x1 -= uta->x << GEM_UTILE_SHIFT; - rect.y1 -= uta->y << GEM_UTILE_SHIFT; - - if (rect.x0 < 0) - rect.x0 = 0; - if (rect.y0 < 0) - rect.y0 = 0; - if (rect.x1 > (uta->width << GEM_UTILE_SHIFT)) - rect.x1 = (uta->width << GEM_UTILE_SHIFT); - if (rect.y1 > (uta->height << GEM_UTILE_SHIFT)) - rect.y1 = (uta->height << GEM_UTILE_SHIFT); - - if (rect.x0 > rect.x1 || rect.y0 > rect.y1) - return; - - width = ((rect.x1 + GEM_UTILE_SIZE) >> GEM_UTILE_SHIFT) - - (rect.x0 >> GEM_UTILE_SHIFT); - height = ((rect.y1 + GEM_UTILE_SIZE) >> GEM_UTILE_SHIFT) - - (rect.y0 >> GEM_UTILE_SHIFT); - - xf0 = rect.x0 % (GEM_UTILE_SIZE); - yf0 = rect.y0 % (GEM_UTILE_SIZE); - xf1 = rect.x1 % (GEM_UTILE_SIZE); - yf1 = rect.y1 % (GEM_UTILE_SIZE); - - x0 = rect.x0 >> GEM_UTILE_SHIFT; - y0 = rect.y0 >> GEM_UTILE_SHIFT; - x1 = rect.x1 >> GEM_UTILE_SHIFT; - y1 = rect.y1 >> GEM_UTILE_SHIFT; - - _b = & (uta->tiles [(y0 * uta->width) + x0]); - - if (width == 1 && height == 1) { - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, yf0 + 1, xf1 + 1, yf1 + 1); - GEM_UTILE_UNION (*_b, bbox); - return; - } - if (width == 1) { - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, yf0 + 1, xf1 + 1, - GEM_UTILE_SIZE); - GEM_UTILE_UNION (*_b, bbox); - _b += uta->width; - if (height > 2) { - for (y = y0 + 1; y <= (y1 - 1); ++y) { - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, 1, xf1 + 1, GEM_UTILE_SIZE); - GEM_UTILE_UNION (*_b, bbox); - _b += uta->width; - } - } - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, 1, xf1 + 1, yf1 + 1); - GEM_UTILE_UNION (*_b, bbox); - return; - } else if (height == 1) { - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, yf0 + 1, GEM_UTILE_SIZE, yf1 + 1); - GEM_UTILE_UNION (*_b, bbox); - ++_b; - if (width > 2) { - for (x = x0 + 1; x <= (x1 - 1); ++x) { - bbox = GEM_UTA_BBOX_CONS (1, yf0 + 1, GEM_UTILE_SIZE, xf1 + 1); - GEM_UTILE_UNION (*_b, bbox); - ++_b; - } - } - bbox = GEM_UTA_BBOX_CONS (1, yf0 + 1, xf1 + 1, yf1 + 1); - GEM_UTILE_UNION (*_b, bbox); - return; - } - - b = _b; - - /* top-left corner */ - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, yf0 + 1, GEM_UTILE_SIZE, GEM_UTILE_SIZE); - GEM_UTILE_UNION (*b, bbox); - ++b; - - /* top edge */ - if (width > 2) { - for (x = x0 + 1; x <= (x1 - 1); ++x) { - bbox = GEM_UTA_BBOX_CONS (1, yf0 + 1, GEM_UTILE_SIZE, GEM_UTILE_SIZE); - GEM_UTILE_UNION (*b, bbox); - ++b; - } - } - - /* top-right corner */ - bbox = GEM_UTA_BBOX_CONS (1, yf0 + 1, xf1 + 1, GEM_UTILE_SIZE); - GEM_UTILE_UNION (*b, bbox); - - _b += uta->width; - - /* left edge, content, right edge */ - if (height > 2) { - for (y = y0 + 1; y <= (y1 - 1); ++y) { - b = _b; - - /* left edge */ - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, 1, GEM_UTILE_SIZE, GEM_UTILE_SIZE); - GEM_UTILE_UNION (*b, bbox); - ++b; - - /* content */ - if (width > 2) { - for (x = x0 + 1; x <= (x1 - 1); ++x) { - *b = GEM_UTILE_FULL; - ++b; - } - } - - /* right edge */ - bbox = GEM_UTA_BBOX_CONS (1, 1, xf1 + 1, GEM_UTILE_SIZE); - GEM_UTILE_UNION (*b, bbox); - - _b += uta->width; - } - } +} - b = _b; - - /* bottom-left corner */ - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, 1, GEM_UTILE_SIZE, yf1 + 1); - GEM_UTILE_UNION (*b, bbox); - ++b; - - /* bottom edge */ - if (width > 2) { - for (x = x0 + 1; x <= (x1 - 1); ++x) { - bbox = GEM_UTA_BBOX_CONS (1, 1, GEM_UTILE_SIZE, yf1 + 1); - GEM_UTILE_UNION (*b, bbox); - ++b; - } - } - - /* bottom-left corner */ - bbox = GEM_UTA_BBOX_CONS (1, 1, xf1 + 1, yf1 + 1); - GEM_UTILE_UNION (*b, bbox); +void MicroTileArray::clear() { + memset(_tiles, 0, _tilesW * _tilesH * sizeof(BoundingBox)); +} - /* done. */ +byte MicroTileArray::TileX0(const BoundingBox &boundingBox) { + return (boundingBox >> 24) & 0xFF; } -#define GEM_UTILE_CONTAINS(b1, b2) \ - ( !(GEM_UTA_BBOX_X0 (b1) > GEM_UTA_BBOX_X0 (b2) || \ - GEM_UTA_BBOX_Y0 (b1) > GEM_UTA_BBOX_Y0 (b2) || \ - GEM_UTA_BBOX_X1 (b1) < GEM_UTA_BBOX_X1 (b2) || \ - GEM_UTA_BBOX_Y1 (b1) < GEM_UTA_BBOX_Y1 (b2)) ) +byte MicroTileArray::TileY0(const BoundingBox &boundingBox) { + return (boundingBox >> 16) & 0xFF; +} -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif +byte MicroTileArray::TileX1(const BoundingBox &boundingBox) { + return (boundingBox >> 8) & 0xFF; +} -#ifndef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif +byte MicroTileArray::TileY1(const BoundingBox &boundingBox) { + return boundingBox & 0xFF; +} -static inline int gem_utile_intersects (GemUtaBBox b1, GemUtaBBox b2) { - GemUtaBBox b3; - b3 = GEM_UTA_BBOX_CONS ( - MAX (GEM_UTA_BBOX_X0 (b1), GEM_UTA_BBOX_X0 (b2)), - MAX (GEM_UTA_BBOX_Y0 (b1), GEM_UTA_BBOX_Y0 (b2)), - MIN (GEM_UTA_BBOX_X1 (b1), GEM_UTA_BBOX_X1 (b2)), - MIN (GEM_UTA_BBOX_Y1 (b1), GEM_UTA_BBOX_Y1 (b2)) - ); - return (GEM_UTA_BBOX_X0 (b3) <= GEM_UTA_BBOX_X1 (b3) && - GEM_UTA_BBOX_Y0 (b3) <= GEM_UTA_BBOX_Y1 (b3)); +bool MicroTileArray::isBoundingBoxEmpty(const BoundingBox &boundingBox) { + return boundingBox == EmptyBoundingBox; } -#define GEM_UTILE_INTERSECTS(b1, b2) \ - gem_utile_intersects (b1, b2) -/* - * Return if the uta contains the rectangle. - */ +bool MicroTileArray::isBoundingBoxFull(const BoundingBox &boundingBox) { + return boundingBox == FullBoundingBox; +} -static int gem_uta_query_rect (const GemUta *uta, const GemRect * _rect, int query) { - int xf0, xf1, yf0, yf1; - int width, height; - int x0, y0, x1, y1; - int x, y; - GemUtaBBox *_b; - GemUtaBBox *b; - GemUtaBBox bbox; - GemRect rect; - - if (!uta || !_rect) - return 0; - - rect = *_rect; - - rect.x0 -= uta->x << GEM_UTILE_SHIFT; - rect.y0 -= uta->y << GEM_UTILE_SHIFT; - rect.x1 -= uta->x << GEM_UTILE_SHIFT; - rect.y1 -= uta->y << GEM_UTILE_SHIFT; - - if (rect.x0 < 0) - rect.x0 = 0; - if (rect.y0 < 0) - rect.y0 = 0; - if (rect.x1 > (uta->width << GEM_UTILE_SHIFT)) - rect.x1 = (uta->width << GEM_UTILE_SHIFT); - if (rect.y1 > (uta->height << GEM_UTILE_SHIFT)) - rect.y1 = (uta->height << GEM_UTILE_SHIFT); - - if (rect.x0 > rect.x1 || rect.y0 > rect.y1) - return 0; - - width = ((rect.x1 + GEM_UTILE_SIZE) >> GEM_UTILE_SHIFT) - - (rect.x0 >> GEM_UTILE_SHIFT); - height = ((rect.y1 + GEM_UTILE_SIZE) >> GEM_UTILE_SHIFT) - - (rect.y0 >> GEM_UTILE_SHIFT); - - xf0 = rect.x0 % (GEM_UTILE_SIZE); - yf0 = rect.y0 % (GEM_UTILE_SIZE); - xf1 = rect.x1 % (GEM_UTILE_SIZE); - yf1 = rect.y1 % (GEM_UTILE_SIZE); - - x0 = rect.x0 >> GEM_UTILE_SHIFT; - y0 = rect.y0 >> GEM_UTILE_SHIFT; - x1 = rect.x1 >> GEM_UTILE_SHIFT; - y1 = rect.y1 >> GEM_UTILE_SHIFT; - - _b = & (uta->tiles [(y0 * uta->width) + x0]); - - if (width == 1 && height == 1) { - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, yf0 + 1, xf1 + 1, yf1 + 1); - if (query == GEM_UTA_QUERY_INTERSECT && - GEM_UTILE_INTERSECTS (*_b, bbox)) - return 1; - else if (query == GEM_UTA_QUERY_CONTAIN && - GEM_UTILE_CONTAINS (*_b, bbox)) - return 1; - return 0; - - } -#define CHECK(b1,b2) \ - { \ - if (query == GEM_UTA_QUERY_INTERSECT && \ - GEM_UTILE_INTERSECTS (b1, b2)) \ - return 1; \ - else if (query == GEM_UTA_QUERY_CONTAIN && \ - !(GEM_UTILE_CONTAINS (b1, b2))) \ - return 0; \ - } - if (width == 1) { - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, yf0 + 1, xf1 + 1, GEM_UTILE_SIZE); - CHECK (*_b, bbox); - _b += uta->width; - if (height > 2) { - for (y = y0 + 1; y <= (y1 - 1); ++y) { - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, 1, xf1 + 1, GEM_UTILE_SIZE); - CHECK (*_b, bbox); - _b += uta->width; - } - } - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, 1, xf1 + 1, yf1 + 1); - CHECK (*_b, bbox); - if (query == GEM_UTA_QUERY_INTERSECT) - return 0; - else if (query == GEM_UTA_QUERY_CONTAIN) - return 1; - } else if (height == 1) { - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, yf0 + 1, GEM_UTILE_SIZE, yf1 + 1); - CHECK (*_b, bbox); - ++_b; - if (width > 2) { - for (x = x0 + 1; x <= (x1 - 1); ++x) { - bbox = GEM_UTA_BBOX_CONS (1, yf0 + 1, GEM_UTILE_SIZE, xf1 + 1); - CHECK (*_b, bbox); - ++_b; - } - } - bbox = GEM_UTA_BBOX_CONS (1, yf0 + 1, xf1 + 1, yf1 + 1); - CHECK (*_b, bbox); - if (query == GEM_UTA_QUERY_INTERSECT) - return 0; - else if (query == GEM_UTA_QUERY_CONTAIN) - return 1; - } - - b = _b; - - /* top-left corner */ - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, yf0 + 1, GEM_UTILE_SIZE, GEM_UTILE_SIZE); - CHECK (*b, bbox); - ++b; - - /* top edge */ - if (width > 2) { - for (x = x0 + 1; x <= (x1 - 1); ++x) { - bbox = GEM_UTA_BBOX_CONS (1, yf0 + 1, GEM_UTILE_SIZE, GEM_UTILE_SIZE); - CHECK (*b, bbox); - ++b; - } - } - - /* top-right corner */ - bbox = GEM_UTA_BBOX_CONS (1, yf0 + 1, xf1 + 1, GEM_UTILE_SIZE); - CHECK (*b, bbox); - - _b += uta->width; - - /* left edge, content, right edge */ - if (height > 2) { - for (y = y0 + 1; y <= (y1 - 1); ++y) { - b = _b; - - /* left edge */ - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, 1, GEM_UTILE_SIZE, GEM_UTILE_SIZE); - CHECK (*b, bbox); - ++b; - - /* content */ - if (width > 2) { - for (x = x0 + 1; x <= (x1 - 1); ++x) { - CHECK (*b, GEM_UTILE_FULL); - ++b; - } - } - - /* right edge */ - bbox = GEM_UTA_BBOX_CONS (1, 1, xf1 + 1, GEM_UTILE_SIZE); - CHECK (*b, bbox); - - _b += uta->width; - } - } +void MicroTileArray::setBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1) { + boundingBox = (x0 << 24) | (y0 << 16) | (x1 << 8) | y1; +} - b = _b; - - /* bottom-left corner */ - bbox = GEM_UTA_BBOX_CONS (xf0 + 1, 1, GEM_UTILE_SIZE, yf1 + 1); - CHECK (*b, bbox); - ++b; - - /* bottom edge */ - if (width > 2) { - for (x = x0 + 1; x <= (x1 - 1); ++x) { - bbox = GEM_UTA_BBOX_CONS (1, 1, GEM_UTILE_SIZE, yf1 + 1); - CHECK (*b, bbox); - ++b; - } +void MicroTileArray::updateBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1) { + if (!isBoundingBoxEmpty(boundingBox)) { + x0 = MIN(TileX0(boundingBox), x0); + y0 = MIN(TileY0(boundingBox), y0); + x1 = MAX(TileX1(boundingBox), x1); + y1 = MAX(TileY1(boundingBox), y1); } - - /* bottom-left corner */ - bbox = GEM_UTA_BBOX_CONS (1, 1, xf1 + 1, yf1 + 1); - CHECK (*b, bbox); - -#undef CHECK - - /* done. */ - if (query == GEM_UTA_QUERY_CONTAIN) - return 1; - return 0; + setBoundingBox(boundingBox, x0, y0, x1, y1); } +Common::Rect * MicroTileArray::getRectangles(int *num_rects, int min_x, int min_y, int max_x, int max_y) { -#undef CLAMP -#define CLAMP(a,min,max) (a = (a < min ? min : (a > max ? max : a))) - -static Common::Rect * gem_uta_get_rects (const GemUta *uta, int * num_rects, - int min_x, int min_y, int max_x, int max_y) { - -#if 1 - + Common::Rect *rects = new Common::Rect[_tilesW * _tilesH]; - GemRect *rects = new GemRect[uta->width * uta->height]; - Common::Rect *result = NULL; int n_rects = 0; int x, y; int x0, y0, x1, y1; + int i = 0; + + for (y = 0; y < _tilesH; ++y) { + for (x = 0; x < _tilesW; ++x) { - int *glom = new int[uta->width * uta->height]; - int i; /* current */ - - for (i = 0; i < uta->width * uta->height; ++i) - glom [i] = -1; - - i = 0; - - for (y = 0; y < uta->height; ++y) { - for (x = 0; x < uta->width; ++x) { -#define TILE uta->tiles [i] int start; int finish = 0; - GemUtaBBox b; + BoundingBox boundingBox; + + boundingBox = _tiles[i]; + + if (isBoundingBoxEmpty(boundingBox)) + goto next; - b = uta->tiles [i]; + x0 = (x * TileSize) + TileX0(boundingBox); + y0 = (y * TileSize) + TileY0(boundingBox); + y1 = (y * TileSize) + TileY1(boundingBox); - if (TILE == GEM_UTILE_EMPTY) - goto next; + x0 = CLIP (x0, min_x, max_x); + y0 = CLIP (y0, min_y, max_y); + y1 = CLIP (y1, min_y, max_y); - x0 = ((uta->x + x) << GEM_UTILE_SHIFT) + GEM_UTA_BBOX_X0 (TILE) - 1; - y0 = ((uta->y + y) << GEM_UTILE_SHIFT) + GEM_UTA_BBOX_Y0 (TILE) - 1; - y1 = ((uta->y + y) << GEM_UTILE_SHIFT) + GEM_UTA_BBOX_Y1 (TILE) - 1; - - CLAMP (x0, min_x, max_x); - CLAMP (y0, min_y, max_y); - CLAMP (y1, min_y, max_y); - +#if 1 start = i; - - if (GEM_UTA_BBOX_X1 (TILE) != GEM_UTILE_SIZE || x == uta->width - 1) { + + if (TileX1(boundingBox) != TileSize - 1 || x == _tilesW - 1) { /* the tile does not continue */ goto done; } - + while (!finish) { ++x; ++i; - - if (x == uta->width || - GEM_UTA_BBOX_Y0 (TILE) != GEM_UTA_BBOX_Y0 (b) || - GEM_UTA_BBOX_Y1 (TILE) != GEM_UTA_BBOX_Y1 (b) || - GEM_UTA_BBOX_X0 (TILE) != 1) + + if (x == _tilesW || i >= _tilesW * _tilesH || + TileY0(_tiles[i]) != TileY0(boundingBox) || + TileY1(_tiles[i]) != TileY1(boundingBox) || + TileX0(_tiles[i]) != 0) { --x; --i; @@ -617,181 +138,56 @@ static Common::Rect * gem_uta_get_rects (const GemUta *uta, int * num_rects, } done: - x1 = ((uta->x + x) << GEM_UTILE_SHIFT) + GEM_UTA_BBOX_X1 (TILE) - 1; - - CLAMP (x1, min_x, max_x); - - if (glom [start] != -1 && /* try to glom */ - rects [glom [start]].x0 == x0 && - rects [glom [start]].x1 == x1 && - rects [glom [start]].y1 == y0 - 1) +#endif + x1 = (x * TileSize) + TileX1(_tiles[i]); + + x1 = CLIP (x1, min_x, max_x); + + #if 1 + + rects[n_rects].left = x0; + rects[n_rects].top = y0; + rects[n_rects].right = x1 + 1; + rects[n_rects].bottom = y1 + 1; + n_rects++; + fflush(stdout); + + #else + + if (glom [start] != -1 && /* try to glom */ + rects [glom [start]].left == x0 && + rects [glom [start]].right == x1 && + rects [glom [start]].bottom == y0 - 1) { - rects [glom [start]].y1 = y1; - if (y != uta->height - 1) { - glom [start + uta->width] = glom [start]; + rects [glom [start]].bottom = y1; + if (y != tilesH - 1) { + glom [start + tilesW] = glom [start]; } } else { - rects [n_rects].x0 = x0; - rects [n_rects].y0 = y0; - rects [n_rects].x1 = x1; - rects [n_rects].y1 = y1; - if (y != uta->height - 1) { - glom [start + uta->width] = n_rects; + rects[n_rects].left = x0; + rects[n_rects].top = y0; + rects[n_rects].right = x1; + rects[n_rects].bottom = y1; + if (y != tilesH - 1) { + glom [start + tilesW] = n_rects; } n_rects ++; } + + #endif + next: ++i; -#undef TILE + } } - - result = new Common::Rect[n_rects]; - - for (i = 0; i < n_rects; ++i) { - result[i].left = rects [i].x0; - result[i].top = rects [i].y0; - result[i].right = rects[i].x1; // CHECK - result[i].bottom = rects[i].y1; // CHECK - } *num_rects = n_rects; - - delete rects; - delete glom; - - return result; - -#else - return NULL; -#endif - -} -MicroTileArray::MicroTileArray() - : m_uta (NULL) -{ -} + //delete glom; -MicroTileArray::MicroTileArray(int x, int y, int w, int h) - : m_x (x), m_y (y), m_w (w), m_h (h) -{ - m_uta = gem_uta_new_coords (x, y, w, h); - if (!m_uta) - error("MicroTileArray::MicroTileArray() Out of memory"); -} + return rects; -MicroTileArray::~MicroTileArray() { - if (m_uta) - gem_uta_free (m_uta); } -void MicroTileArray::clear() { - if (!m_uta) - return; - - memset (m_uta->tiles, 0, m_uta->width * m_uta->height * sizeof(GemUtaBBox)); -} - -void MicroTileArray::init(int x, int y, int w, int h) { - if (m_uta) - gem_uta_free (m_uta); - m_uta = gem_uta_new_coords (x, y, w, h); - m_x = x; - m_y = y; - m_w = w; - m_h = h; - if (!m_uta) - error("Out of memory"); -} - -int MicroTileArray::getRectangles(Common::Rect * & rects, int min_x, int max_x, int min_y, int max_y) const { - if (!m_uta) - return 0; - - int n_rects; - - rects = gem_uta_get_rects (m_uta, &n_rects, min_x, max_x, min_y, max_y); - - return n_rects; -} - -int MicroTileArray::getRectangles(Common::Rect * & rects) const { - if (!m_uta) - return 0; - - int n_rects; - - rects = gem_uta_get_rects (m_uta, &n_rects, - m_x, m_y, m_x + m_w - 1, m_y + m_h - 1); - - return n_rects; -} - -bool MicroTileArray::contains(const Common::Rect & rect) const { - if (!m_uta) - return false; - - GemRect r; - r.x0 = rect.left; - r.y0 = rect.top; - r.x1 = rect.right; // CHECK - r.y1 = rect.bottom; // CHECK - - return gem_uta_query_rect (m_uta, &r, GEM_UTA_QUERY_CONTAIN); -} - -bool MicroTileArray::intersects(const Common::Rect & rect) const { - if (!m_uta) - return false; - - GemRect r; - r.x0 = rect.left; - r.y0 = rect.top; - r.x1 = rect.right; // CHECK - r.y1 = rect.bottom; // CHECK - - return gem_uta_query_rect (m_uta, &r, GEM_UTA_QUERY_INTERSECT); -} - -void MicroTileArray::unite(const Common::Rect & rect) { - if (!m_uta || rect.width() == 0 || rect.height() == 0) - return; - - GemRect r; - r.x0 = rect.left; - r.y0 = rect.top; - r.x1 = rect.right; // CHECK - r.y1 = rect.bottom; // CHECK - - gem_uta_add_rect (m_uta, &r); -} - -MicroTileArray & MicroTileArray::operator += (const Common::Rect & rect) { - if (!m_uta || rect.width() == 0 || rect.height() == 0) - return *this; - - GemRect r; - r.x0 = rect.left; - r.y0 = rect.top; - r.x1 = rect.right; // CHECK - r.y1 = rect.bottom; // CHECK - - gem_uta_add_rect (m_uta, &r); - - return *this; -} - -void MicroTileArray::unite (const MicroTileArray & uta) { - if (m_uta) - gem_uta_union (m_uta, uta.m_uta); -} - -MicroTileArray & MicroTileArray::operator += (const MicroTileArray & uta) { - if (m_uta) - gem_uta_union (m_uta, uta.m_uta); - return *this; -} - -} // namespace Toltecs - +} // End of namespace Toltecs diff --git a/engines/toltecs/microtiles.h b/engines/toltecs/microtiles.h index 21dd5a9fcf..2135addf1d 100644 --- a/engines/toltecs/microtiles.h +++ b/engines/toltecs/microtiles.h @@ -1,105 +1,38 @@ -/* - SEL - Simple DirectMedia Layer Extension Library - Copyright (C) 2002 Matej Knopp <knopp@users.sf.net> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - #ifndef TOLTECS_MICROTILES_H #define TOLTECS_MICROTILES_H +#include "common/scummsys.h" +#include "common/util.h" #include "common/rect.h" namespace Toltecs { -//! Class that represents a microtile array. -/*! - Microtile array is an efficient method of representing regions that - need to be redrawn. For more information about the microtile arrays - in general visit the LibArt homepage at - http://www.levien.com/libart/uta.html . - - Note that this implementation is not the one of LibArt and - differs from it. - */ -class MicroTileArray { -public: - //! Create an empty unitialized uta. - /* - \note You must initialize the class using - Uta::init() before doing anything with it. - */ - MicroTileArray(); +typedef uint32 BoundingBox; - //! Create a new microtile array with given coordinates. - MicroTileArray(int x, int y, int w, int h); +const BoundingBox FullBoundingBox = 0x00001F1F; +const BoundingBox EmptyBoundingBox = 0x00000000; +const int TileSize = 32; - //! Destroy the microtile array. +class MicroTileArray { +public: + MicroTileArray(int16 width, int16 height); ~MicroTileArray(); - - //! Clear the microtile array. + void addRect(Common::Rect r); void clear(); - - //! Initialize the array. - /* - You can use this funtion to resize the array as well, - but you should be aware that the content of the array - will be cleared. - */ - void init(int x, int y, int w, int h); - - //! Return the microtile array as rectangles. - /*! - The \a rects array should be freed when no longer needed. - \return The number of rectangles in \a rects. - */ - int getRectangles(Common::Rect * & rects, - int min_x, int max_x, int min_y, int max_y) const; - - //! Return the microtile array as rectangles. - /*! - The \a rects array should be freed when no longer needed. - \return The number of rectangles in \a rects. - */ - int getRectangles(Common::Rect * & rects) const; - - //! Whether the microtile array contains given rectangle. - bool contains(const Common::Rect &) const; - - //! Whether the microtile array intersects given rectangle. - bool intersects(const Common::Rect &) const; - - //! Unite the microtile array with a rectangle. - void unite(const Common::Rect &); - - //! Unite the microtile array with a rectangle. - MicroTileArray & operator+=(const Common::Rect &); - - //! Unite the array with another microtile array. - void unite(const MicroTileArray &); - - //! Unite the array with another microtile array. - MicroTileArray & operator+=(const MicroTileArray &); - -protected: - typedef struct _GemUta GemUta; - GemUta *m_uta; - int m_x, m_y, m_w, m_h; -}; // class Uta + Common::Rect *getRectangles(int *num_rects, int min_x, int min_y, int max_x, int max_y); +protected: + BoundingBox *_tiles; + int16 _tilesW, _tilesH; + byte TileX0(const BoundingBox &boundingBox); + byte TileY0(const BoundingBox &boundingBox); + byte TileX1(const BoundingBox &boundingBox); + byte TileY1(const BoundingBox &boundingBox); + bool isBoundingBoxEmpty(const BoundingBox &boundingBox); + bool isBoundingBoxFull(const BoundingBox &boundingBox); + void setBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1); + void updateBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1); +}; } // namespace Toltecs - #endif // TOLTECS_MICROTILES_H diff --git a/engines/toltecs/module.mk b/engines/toltecs/module.mk index 3cf88552ff..49d4e19f65 100644 --- a/engines/toltecs/module.mk +++ b/engines/toltecs/module.mk @@ -8,6 +8,7 @@ MODULE_OBJS = \ movie.o \ palette.o \ toltecs.o \ + render.o \ resource.o \ saveload.o \ screen.o \ diff --git a/engines/toltecs/render.cpp b/engines/toltecs/render.cpp new file mode 100644 index 0000000000..dd7dfc212f --- /dev/null +++ b/engines/toltecs/render.cpp @@ -0,0 +1,320 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * + */ + +#include "common/events.h" +#include "common/keyboard.h" +#include "common/file.h" +#include "common/savefile.h" +#include "common/config-manager.h" + +#include "base/plugins.h" +#include "base/version.h" + +#include "toltecs/toltecs.h" +#include "toltecs/render.h" +#include "toltecs/resource.h" + +namespace Toltecs { + +Common::Rect makeRect(int16 x, int16 y, int16 width, int16 height) { + Common::Rect rect; + rect.left = x; + rect.top = y; + rect.setWidth(width); + rect.setHeight(height); + return rect; +} + +RenderQueue::RenderQueue(ToltecsEngine *vm) : _vm(vm) { + _currQueue = new RenderQueueArray(); + _prevQueue = new RenderQueueArray(); + _updateUta = new MicroTileArray(640, 400); +} + +RenderQueue::~RenderQueue() { + delete _currQueue; + delete _prevQueue; + delete _updateUta; +} + +void RenderQueue::addSprite(SpriteDrawItem &sprite) { + + RenderQueueItem item; + item.type = kSprite; + item.flags = kRefresh; + item.rect = makeRect(sprite.x - _vm->_cameraX, sprite.y - _vm->_cameraY, sprite.width, sprite.height); + item.priority = sprite.priority; + + item.sprite = sprite; + item.sprite.x -= _vm->_cameraX; + item.sprite.y -= _vm->_cameraY; + + // Add sprite sorted by priority + RenderQueueArray::iterator iter = _currQueue->begin(); + while (iter != _currQueue->end() && (*iter).priority <= item.priority) { + iter++; + } + _currQueue->insert(iter, item); + +} + +void RenderQueue::addText(int16 x, int16 y, byte color, uint fontResIndex, byte *text, int len) { + + Font font(_vm->_res->load(fontResIndex)); + + RenderQueueItem item; + item.type = kText; + item.flags = kRefresh; + item.rect = makeRect(x, y, font.getTextWidth(text), font.getHeight()); + item.priority = 1000; + + item.text.color = color; + item.text.fontResIndex = fontResIndex; + item.text.text = text; + item.text.len = len; + + _currQueue->push_back(item); + +} + +void RenderQueue::addMask(SegmapMaskRect &mask) { + + RenderQueueItem item; + item.type = kMask; + item.flags = kRefresh; + item.rect = makeRect(mask.x - _vm->_cameraX, mask.y - _vm->_cameraY, mask.width, mask.height); + item.priority = mask.priority; + + item.mask = mask; + + // Only add the mask if a sprite intersects its rect + if (rectIntersectsItem(item.rect)) { + RenderQueueArray::iterator iter = _currQueue->begin(); + while (iter != _currQueue->end() && (*iter).priority <= item.priority) { + iter++; + } + _currQueue->insert(iter, item); + } + +} + +void RenderQueue::update() { + + bool doFullRefresh = _vm->_screen->_fullRefresh; + + _updateUta->clear(); + + if (!doFullRefresh) { + + for (RenderQueueArray::iterator iter = _currQueue->begin(); iter != _currQueue->end(); iter++) { + RenderQueueItem *item = &(*iter); + RenderQueueItem *prevItem = findItemInQueue(_prevQueue, *item); + if (prevItem) { + if (hasItemChanged(*prevItem, *item)) { + item->flags = kRefresh; + addDirtyRect(prevItem->rect); + } else { + item->flags = kUnchanged; + } + } else { + item->flags = kRefresh; + } + } + + for (RenderQueueArray::iterator iter = _prevQueue->begin(); iter != _prevQueue->end(); iter++) { + RenderQueueItem *prevItem = &(*iter); + RenderQueueItem *item = findItemInQueue(_currQueue, *prevItem); + if (!item) { + prevItem->flags = kRemoved; + addDirtyRect(prevItem->rect); + } + } + + restoreDirtyBackground(); + + for (RenderQueueArray::iterator iter = _currQueue->begin(); iter != _currQueue->end(); iter++) { + RenderQueueItem *item = &(*iter); + if (item->flags != kUnchanged) + invalidateItemsByRect(item->rect, item); + } + + } else { + byte *destp = _vm->_screen->_frontScreen; + byte *srcp = _vm->_screen->_backScreen + _vm->_cameraX + _vm->_cameraY * _vm->_sceneWidth; + int16 w = MIN<int16>(640, _vm->_sceneWidth); + int16 h = MIN<int16>(400, _vm->_cameraHeight); + while (h--) { + memcpy(destp, srcp, w); + destp += 640; + srcp += _vm->_sceneWidth; + } + _vm->_screen->_fullRefresh = false; + } + + for (RenderQueueArray::iterator iter = _currQueue->begin(); iter != _currQueue->end(); iter++) { + const RenderQueueItem *item = &(*iter); + + if (item->flags == kRefresh) { + + switch (item->type) { + case kSprite: + _vm->_screen->drawSprite(item->sprite); + break; + case kText: + _vm->_screen->drawString(item->rect.left, item->rect.top, item->text.color, item->text.fontResIndex, + item->text.text, item->text.len, NULL, true); + break; + case kMask: + _vm->_screen->drawSurface(item->rect.left, item->rect.top, item->mask.surface); + break; + default: + break; + } + + if (!doFullRefresh) + addDirtyRect(item->rect); + + } + + } + + if (doFullRefresh) { + clear(); + _vm->_system->copyRectToScreen((const byte *)_vm->_screen->_frontScreen, 640, 0, 0, 640, _vm->_cameraHeight); + } else { + updateDirtyRects(); + } + + SWAP(_currQueue, _prevQueue); + _currQueue->clear(); + +} + +void RenderQueue::clear() { + _prevQueue->clear(); + _currQueue->clear(); +} + +bool RenderQueue::rectIntersectsItem(const Common::Rect &rect) { + for (RenderQueueArray::iterator iter = _currQueue->begin(); iter != _currQueue->end(); iter++) { + const RenderQueueItem *item = &(*iter); + if (rect.intersects(item->rect)) + return true; + } + return false; +} + +RenderQueueItem *RenderQueue::findItemInQueue(RenderQueueArray *queue, const RenderQueueItem &item) { + /* This checks if the given item also exists in the previously drawn frame. + The state of the item (position, color etc) is handled elsewhere. + */ + for (RenderQueueArray::iterator iter = queue->begin(); iter != queue->end(); iter++) { + RenderQueueItem *prevItem = &(*iter); + if (prevItem->type == item.type) { + switch (item.type) { + case kSprite: + if (prevItem->sprite.resIndex == item.sprite.resIndex && + prevItem->sprite.frameNum == item.sprite.frameNum) + return prevItem; + break; + case kText: + if (prevItem->text.text == item.text.text && + prevItem->text.len == item.text.len) + return prevItem; + break; + case kMask: + if (prevItem->mask.surface == item.mask.surface) + return prevItem; + break; + } + } + } + return NULL; // Not found +} + +bool RenderQueue::hasItemChanged(const RenderQueueItem &item1, const RenderQueueItem &item2) { + + // TODO: Clean up. + + if (item1.type != item1.type) + return true; + + if (item1.rect.left != item2.rect.left || + item1.rect.top != item2.rect.top || + item1.rect.right != item2.rect.right || + item1.rect.bottom != item2.rect.bottom) + return true; + + if (item1.type == kText && item1.text.color != item2.text.color) + return true; + + return false; +} + +void RenderQueue::invalidateItemsByRect(const Common::Rect &rect, const RenderQueueItem *item) { + for (RenderQueueArray::iterator iter = _currQueue->begin(); iter != _currQueue->end(); iter++) { + RenderQueueItem *subItem = &(*iter); + if (item != subItem && + subItem->flags == kUnchanged && + rect.intersects(subItem->rect)) { + + subItem->flags = kRefresh; + invalidateItemsByRect(subItem->rect, subItem); + } + } +} + +void RenderQueue::addDirtyRect(const Common::Rect &rect) { + _updateUta->addRect(rect); +} + +void RenderQueue::restoreDirtyBackground() { + int n_rects = 0; + Common::Rect *rects = _updateUta->getRectangles(&n_rects, 0, 0, 639, _vm->_cameraHeight - 1); + for (int i = 0; i < n_rects; i++) { + byte *destp = _vm->_screen->_frontScreen + rects[i].left + rects[i].top * 640; + byte *srcp = _vm->_screen->_backScreen + (_vm->_cameraX + rects[i].left) + (_vm->_cameraY + rects[i].top) * _vm->_sceneWidth; + int16 w = rects[i].width(); + int16 h = rects[i].height(); + while (h--) { + memcpy(destp, srcp, w); + destp += 640; + srcp += _vm->_sceneWidth; + } + invalidateItemsByRect(rects[i], NULL); + } + delete[] rects; +} + +void RenderQueue::updateDirtyRects() { + int n_rects = 0; + Common::Rect *rects = _updateUta->getRectangles(&n_rects, 0, 0, 639, _vm->_cameraHeight - 1); + for (int i = 0; i < n_rects; i++) { + _vm->_system->copyRectToScreen((const byte *)_vm->_screen->_frontScreen + rects[i].left + rects[i].top * 640, + 640, rects[i].left, rects[i].top, rects[i].width(), rects[i].height()); + } + delete[] rects; +} + + +} // End of namespace Toltecs diff --git a/engines/toltecs/render.h b/engines/toltecs/render.h new file mode 100644 index 0000000000..0f5554b127 --- /dev/null +++ b/engines/toltecs/render.h @@ -0,0 +1,119 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * + */ + +#ifndef TOLTECS_RENDER_H +#define TOLTECS_RENDER_H + +#include "common/scummsys.h" +#include "common/endian.h" +#include "common/util.h" +#include "common/file.h" +#include "common/savefile.h" +#include "common/system.h" +#include "common/hash-str.h" +#include "common/events.h" +#include "common/keyboard.h" +#include "common/list.h" +#include "common/array.h" +#include "common/rect.h" + +#include "graphics/surface.h" + +#include "sound/audiostream.h" +#include "sound/mixer.h" +#include "sound/voc.h" +#include "sound/audiocd.h" + +#include "engines/engine.h" + +#include "toltecs/segmap.h" +#include "toltecs/screen.h" +#include "toltecs/microtiles.h" + +namespace Toltecs { + +enum RenderType { + kSprite, + kText, + kMask +}; + +enum RenderFlags { + kNone = 1 << 0, + kRefresh = 1 << 1, + kRemoved = 1 << 2, + kMoved = 1 << 3, + kUnchanged = 1 << 4 +}; + +struct RenderTextItem { + byte color; + uint fontResIndex; + byte *text; + int len; +}; + +struct RenderQueueItem { + RenderType type; + uint flags; + Common::Rect rect; + int16 priority; + union { + SpriteDrawItem sprite; + RenderTextItem text; + SegmapMaskRect mask; + }; +}; + +class RenderQueue { +public: + RenderQueue(ToltecsEngine *vm); + ~RenderQueue(); + + void addSprite(SpriteDrawItem &sprite); + void addText(int16 x, int16 y, byte color, uint fontResIndex, byte *text, int len); + void addMask(SegmapMaskRect &mask); + void update(); + void clear(); + +protected: + typedef Common::List<RenderQueueItem> RenderQueueArray; + + ToltecsEngine *_vm; + RenderQueueArray *_currQueue, *_prevQueue; + MicroTileArray *_updateUta; + + bool rectIntersectsItem(const Common::Rect &rect); + RenderQueueItem *findItemInQueue(RenderQueueArray *queue, const RenderQueueItem &item); + bool hasItemChanged(const RenderQueueItem &item1, const RenderQueueItem &item2); + void invalidateItemsByRect(const Common::Rect &rect, const RenderQueueItem *item); + + void addDirtyRect(const Common::Rect &rect); + void restoreDirtyBackground(); + void updateDirtyRects(); + +}; + +} // End of namespace Toltecs + +#endif /* TOLTECS_RENDER_H */ diff --git a/engines/toltecs/saveload.cpp b/engines/toltecs/saveload.cpp index 99bbc0519c..b631b1d529 100644 --- a/engines/toltecs/saveload.cpp +++ b/engines/toltecs/saveload.cpp @@ -139,7 +139,6 @@ void ToltecsEngine::loadgame(const char *filename) { delete in; loadScene(_sceneResIndex); - _screen->clearSprites(); _newCameraX = _cameraX; _newCameraY = _cameraY; diff --git a/engines/toltecs/screen.cpp b/engines/toltecs/screen.cpp index fc981db511..8951c1eb6a 100644 --- a/engines/toltecs/screen.cpp +++ b/engines/toltecs/screen.cpp @@ -36,6 +36,7 @@ #include "toltecs/toltecs.h" #include "toltecs/palette.h" +#include "toltecs/render.h" #include "toltecs/resource.h" #include "toltecs/screen.h" #include "toltecs/script.h" @@ -74,12 +75,18 @@ Screen::Screen(ToltecsEngine *vm) : _vm(vm) { _talkTextFontColor = 0; _talkTextMaxWidth = 520; + _renderQueue = new RenderQueue(_vm); + _fullRefresh = false; + _guiRefresh = false; + } Screen::~Screen() { delete[] _frontScreen; delete[] _backScreen; + + delete _renderQueue; } @@ -155,7 +162,9 @@ void Screen::drawGuiImage(int16 x, int16 y, uint resIndex) { } } } - + + _guiRefresh = true; + } void Screen::startShakeScreen(int16 shakeCounter) { @@ -261,9 +270,6 @@ void Screen::addAnimatedSprite(int16 x, int16 y, int16 fragmentId, byte *data, i void Screen::clearSprites() { - _spriteDrawList.clear(); - // TODO - } void Screen::updateVerbLine(int16 slotIndex, int16 slotOffset) { @@ -336,6 +342,8 @@ void Screen::updateVerbLine(int16 slotIndex, int16 slotOffset) { drawGuiText(_verbLineX - 1 - (wrapState.width / 2), y, 0xF9, 0xFF, _fontResIndexArray[0], wrapState); + _guiRefresh = true; + } void Screen::updateTalkText(int16 slotIndex, int16 slotOffset) { @@ -461,7 +469,7 @@ void Screen::addTalkTextRect(Font &font, int16 x, int16 &y, int16 length, int16 } -void Screen::drawTalkTextItems() { +void Screen::addTalkTextItemsToRenderQueue() { for (int16 i = 0; i <= _talkTextItemNum; i++) { TalkTextItem *item = &_talkTextItems[i]; @@ -475,8 +483,8 @@ void Screen::drawTalkTextItems() { item->duration = 0; for (byte j = 0; j < item->lineCount; j++) { - drawString(item->lines[j].x, item->lines[j].y, item->color, _fontResIndexArray[item->fontNum], - text, item->lines[j].length, NULL, true); + _renderQueue->addText(item->lines[j].x, item->lines[j].y, item->color, _fontResIndexArray[item->fontNum], + text, item->lines[j].length); text += item->lines[j].length; } @@ -535,6 +543,8 @@ void Screen::drawGuiTextMulti(byte *textData) { } while (*wrapState.sourceString != 0xFF); + _guiRefresh = true; + } int16 Screen::wrapGuiText(uint fontResIndex, int maxWidth, GuiTextWrapState &wrapState) { @@ -634,6 +644,55 @@ void Screen::drawChar(const Font &font, byte *dest, int16 x, int16 y, byte ch, b } +void Screen::drawSurface(int16 x, int16 y, Graphics::Surface *surface) { + + int16 skipX = 0; + int16 width = surface->w; + int16 height = surface->h; + byte *surfacePixels = (byte*)surface->getBasePtr(0, 0); + byte *frontScreen; + + // Not on screen, skip + if (x + width < 0 || y + height < 0 || x >= 640 || y >= _vm->_cameraHeight) + return; + + if (x < 0) { + skipX = -x; + x = 0; + width -= skipX; + } + + if (y < 0) { + int16 skipY = -y; + surfacePixels += surface->w * skipY; + y = 0; + height -= skipY; + } + + if (x + width >= 640) { + width -= x + width - 640; + } + + if (y + height >= _vm->_cameraHeight) { + height -= y + height - _vm->_cameraHeight; + } + + frontScreen = _vm->_screen->_frontScreen + x + (y * 640); + + for (int16 h = 0; h < height; h++) { + surfacePixels += skipX; + for (int16 w = 0; w < width; w++) { + if (*surfacePixels != 0xFF) + *frontScreen = *surfacePixels; + frontScreen++; + surfacePixels++; + } + frontScreen += 640 - width; + surfacePixels += surface->w - width - skipX; + } + +} + void Screen::saveState(Common::WriteStream *out) { // Save verb line @@ -726,6 +785,7 @@ void Screen::loadState(Common::ReadStream *in) { in->read(gui, 640); gui += 640; } + _guiRefresh = true; } // Load fonts diff --git a/engines/toltecs/screen.h b/engines/toltecs/screen.h index e8866317e6..752d5a4c7c 100644 --- a/engines/toltecs/screen.h +++ b/engines/toltecs/screen.h @@ -59,7 +59,7 @@ struct SpriteDrawItem { int16 x, y; int16 width, height; int16 origWidth, origHeight; - int16 resIndex; + int16 resIndex, frameNum; uint32 offset; int16 xdelta, ydelta; uint16 flags; @@ -133,11 +133,11 @@ enum SpriteReaderStatus { class SpriteFilter { public: - SpriteFilter(SpriteDrawItem *sprite) : _sprite(sprite) { + SpriteFilter(const SpriteDrawItem &sprite) : _sprite(&sprite) { } virtual SpriteReaderStatus readPacket(PixelPacket &packet) = 0; protected: - SpriteDrawItem *_sprite; + const SpriteDrawItem *_sprite; }; struct TextRect { @@ -163,6 +163,8 @@ struct GuiTextWrapState { byte textBuffer[100]; }; +class RenderQueue; + class Screen { public: Screen(ToltecsEngine *vm); @@ -184,9 +186,8 @@ public: void clearSprites(); // Sprite drawing - void drawSprite(SpriteDrawItem *sprite); - void drawSpriteCore(byte *dest, SpriteFilter &reader, SpriteDrawItem *sprite); - void drawSprites(); + void drawSprite(const SpriteDrawItem &sprite); + void drawSpriteCore(byte *dest, SpriteFilter &reader, const SpriteDrawItem &sprite); // Verb line void updateVerbLine(int16 slotIndex, int16 slotOffset); @@ -194,7 +195,7 @@ public: // Talk text void updateTalkText(int16 slotIndex, int16 slotOffset); void addTalkTextRect(Font &font, int16 x, int16 &y, int16 length, int16 width, TalkTextItem *item); - void drawTalkTextItems(); + void addTalkTextItemsToRenderQueue(); int16 getTalkTextDuration(); void finishTextDrawItems(); @@ -207,6 +208,8 @@ public: int16 drawString(int16 x, int16 y, byte color, uint fontResIndex, byte *text, int len = -1, int16 *ywobble = NULL, bool outline = false); void drawChar(const Font &font, byte *dest, int16 x, int16 y, byte ch, byte color, bool outline); + void drawSurface(int16 x, int16 y, Graphics::Surface *surface); + void saveState(Common::WriteStream *out); void loadState(Common::ReadStream *in); @@ -226,8 +229,6 @@ public: byte *_frontScreen, *_backScreen; - Common::List<SpriteDrawItem> _spriteDrawList; - uint _fontResIndexArray[10]; byte _fontColor1, _fontColor2; @@ -249,6 +250,10 @@ public: int16 _talkTextItemNum; TalkTextItem _talkTextItems[5]; + RenderQueue *_renderQueue; + bool _fullRefresh; + bool _guiRefresh; + void addDrawRequest(const DrawRequest &drawRequest); }; diff --git a/engines/toltecs/segmap.cpp b/engines/toltecs/segmap.cpp index 6a3f849d4a..ec9d021260 100644 --- a/engines/toltecs/segmap.cpp +++ b/engines/toltecs/segmap.cpp @@ -36,6 +36,7 @@ #include "sound/mixer.h" #include "toltecs/toltecs.h" +#include "toltecs/render.h" #include "toltecs/resource.h" #include "toltecs/screen.h" #include "toltecs/segmap.h" @@ -421,78 +422,9 @@ void SegmentMap::freeSegmapMaskRectSurfaces() { } } -void SegmentMap::restoreMasksBySprite(SpriteDrawItem *sprite) { - // TODO: This needs more optimization +void SegmentMap::addMasksToRenderQueue() { for (uint i = 0; i < _maskRects.size(); i++) { - if (sprite->priority <= _maskRects[i].priority) { - restoreMask(i); - } - } -} - -void SegmentMap::restoreMask(int16 index) { - - // TODO: This needs more optimization - SegmapMaskRect *maskRect = &_maskRects[index]; - - int16 skipX = 0; - int16 x = maskRect->x - _vm->_cameraX; - int16 y = maskRect->y - _vm->_cameraY; - int16 width = maskRect->width; - int16 height = maskRect->height; - byte *maskSurface = (byte*)maskRect->surface->getBasePtr(0, 0); - byte *frontScreen; - - debug(0, "SegmentMap::restoreMask() screenX = %d; screenY = %d; maskX = %d; maskY = %d", - x, y, maskRect->x, maskRect->y); - - // Not on screen, skip - if (x + width < 0 || y + height < 0 || x >= 640 || y >= _vm->_cameraHeight) - return; - - if (x < 0) { - skipX = -x; - x = 0; - width -= skipX; - } - - if (y < 0) { - int16 skipY = -y; - maskSurface += maskRect->width * skipY; - y = 0; - height -= skipY; - } - - if (x + width >= 640) { - width -= x + width - 640; - } - - if (y + height >= _vm->_cameraHeight) { - height -= y + height - _vm->_cameraHeight; - } - - frontScreen = _vm->_screen->_frontScreen + x + (y * 640); - - for (int16 h = 0; h < height; h++) { - maskSurface += skipX; - for (int16 w = 0; w < width; w++) { - if (*maskSurface != 0xFF) - *frontScreen = *maskSurface; - frontScreen++; - maskSurface++; - } - frontScreen += 640 - width; - maskSurface += maskRect->width - width - skipX; - } - -} - -void SegmentMap::debugDrawRects(Graphics::Surface *surf) { - for (uint16 i = 0; i < _pathRects.size(); i++) { - SegmapPathRect pathRect = _pathRects[i]; - surf->frameRect( - Common::Rect(pathRect.x1, pathRect.y1, pathRect.x2, pathRect.y2), - 255); + _vm->_screen->_renderQueue->addMask(_maskRects[i]); } } diff --git a/engines/toltecs/segmap.h b/engines/toltecs/segmap.h index 6c20eac431..77ab247c72 100644 --- a/engines/toltecs/segmap.h +++ b/engines/toltecs/segmap.h @@ -56,6 +56,13 @@ struct ScriptWalk { int16 scaling; }; +struct SegmapMaskRect { + int16 x, y; + int16 width, height; + int16 priority; + Graphics::Surface *surface; +}; + class SegmentMap { public: SegmentMap(ToltecsEngine *vm); @@ -71,21 +78,11 @@ public: int8 getScalingAtPoint(int16 x, int16 y); void getRgbModifiertAtPoint(int16 x, int16 y, int16 id, byte &r, byte &g, byte &b); - void restoreMasksBySprite(SpriteDrawItem *sprite); - void restoreMask(int16 index); - - void debugDrawRects(Graphics::Surface *surf); + void addMasksToRenderQueue(); //protected: public: // for debugging purposes - struct SegmapMaskRect { - int16 x, y; - int16 width, height; - int16 priority; - Graphics::Surface *surface; - }; - struct SegmapPathRect { int16 x1, y1, x2, y2; }; diff --git a/engines/toltecs/sprite.cpp b/engines/toltecs/sprite.cpp index 3327f04bdd..4e5af5f293 100644 --- a/engines/toltecs/sprite.cpp +++ b/engines/toltecs/sprite.cpp @@ -36,6 +36,7 @@ #include "toltecs/toltecs.h" #include "toltecs/palette.h" +#include "toltecs/render.h" #include "toltecs/resource.h" #include "toltecs/screen.h" #include "toltecs/script.h" @@ -45,7 +46,7 @@ namespace Toltecs { class SpriteReader : public SpriteFilter { public: - SpriteReader(byte *source, SpriteDrawItem *sprite) : SpriteFilter(sprite), _source(source) { + SpriteReader(byte *source, const SpriteDrawItem &sprite) : SpriteFilter(sprite), _source(source) { _curWidth = _sprite->origWidth; _curHeight = _sprite->origHeight; } @@ -95,7 +96,7 @@ protected: class SpriteFilterScaleDown : public SpriteFilter { public: - SpriteFilterScaleDown(SpriteDrawItem *sprite, SpriteReader *reader) : SpriteFilter(sprite), _reader(reader) { + SpriteFilterScaleDown(const SpriteDrawItem &sprite, SpriteReader *reader) : SpriteFilter(sprite), _reader(reader) { _height = _sprite->height; _yerror = _sprite->yerror; _origHeight = _sprite->origHeight; @@ -146,7 +147,7 @@ protected: class SpriteFilterScaleUp : public SpriteFilter { public: - SpriteFilterScaleUp(SpriteDrawItem *sprite, SpriteReader *reader) : SpriteFilter(sprite), _reader(reader) { + SpriteFilterScaleUp(const SpriteDrawItem &sprite, SpriteReader *reader) : SpriteFilter(sprite), _reader(reader) { _height = _sprite->height; _yerror = _sprite->yerror; _origHeight = _sprite->origHeight; @@ -205,12 +206,15 @@ void Screen::addDrawRequest(const DrawRequest &drawRequest) { if (drawRequest.flags == 0xFFFF) return; + frameNum = drawRequest.flags & 0x0FFF; + sprite.flags = 0; sprite.baseColor = drawRequest.baseColor; sprite.x = drawRequest.x; sprite.y = drawRequest.y; sprite.priority = drawRequest.y; sprite.resIndex = drawRequest.resIndex; + sprite.frameNum = frameNum; spriteData = _vm->_res->load(drawRequest.resIndex); @@ -226,8 +230,6 @@ void Screen::addDrawRequest(const DrawRequest &drawRequest) { sprite.flags |= 0x40; } - frameNum = drawRequest.flags & 0x0FFF; - // First initialize the sprite item with the values from the sprite resource SpriteFrameEntry spriteFrameEntry(spriteData + frameNum * 12); @@ -391,48 +393,43 @@ void Screen::addDrawRequest(const DrawRequest &drawRequest) { if (sprite.width <= 0) return; - // Add sprite sorted by priority - Common::List<SpriteDrawItem>::iterator iter = _spriteDrawList.begin(); - while (iter != _spriteDrawList.end() && (*iter).priority <= sprite.priority) { - iter++; - } - _spriteDrawList.insert(iter, sprite); + _renderQueue->addSprite(sprite); } -void Screen::drawSprite(SpriteDrawItem *sprite) { +void Screen::drawSprite(const SpriteDrawItem &sprite) { debug(0, "Screen::drawSprite() x = %d; y = %d; flags = %04X; resIndex = %d; offset = %08X; drawX = %d; drawY = %d", - sprite->x, sprite->y, sprite->flags, sprite->resIndex, sprite->offset, - sprite->x - _vm->_cameraX, sprite->y - _vm->_cameraY); + sprite.x, sprite.y, sprite.flags, sprite.resIndex, sprite.offset, + sprite.x - _vm->_cameraX, sprite.y - _vm->_cameraY); debug(0, "Screen::drawSprite() width = %d; height = %d; origWidth = %d; origHeight = %d", - sprite->width, sprite->height, sprite->origWidth, sprite->origHeight); + sprite.width, sprite.height, sprite.origWidth, sprite.origHeight); - byte *source = _vm->_res->load(sprite->resIndex) + sprite->offset; - byte *dest = _frontScreen + (sprite->x - _vm->_cameraX) + (sprite->y - _vm->_cameraY) * 640; + byte *source = _vm->_res->load(sprite.resIndex) + sprite.offset; + byte *dest = _frontScreen + sprite.x + sprite.y * 640; SpriteReader spriteReader(source, sprite); - if (sprite->flags & 0x40) { + if (sprite.flags & 0x40) { // Shadow sprites - if (sprite->flags & 1) { + if (sprite.flags & 1) { SpriteFilterScaleDown spriteScaler(sprite, &spriteReader); drawSpriteCore(dest, spriteScaler, sprite); - } else if (sprite->flags & 2) { + } else if (sprite.flags & 2) { SpriteFilterScaleUp spriteScaler(sprite, &spriteReader); drawSpriteCore(dest, spriteScaler, sprite); } else { drawSpriteCore(dest, spriteReader, sprite); } - } else if (sprite->flags & 0x10) { + } else if (sprite.flags & 0x10) { // 256 color sprite drawSpriteCore(dest, spriteReader, sprite); } else { // 16 color sprite - if (sprite->flags & 1) { + if (sprite.flags & 1) { SpriteFilterScaleDown spriteScaler(sprite, &spriteReader); drawSpriteCore(dest, spriteScaler, sprite); - } else if (sprite->flags & 2) { + } else if (sprite.flags & 2) { SpriteFilterScaleUp spriteScaler(sprite, &spriteReader); drawSpriteCore(dest, spriteScaler, sprite); } else { @@ -444,13 +441,13 @@ void Screen::drawSprite(SpriteDrawItem *sprite) { } -void Screen::drawSpriteCore(byte *dest, SpriteFilter &reader, SpriteDrawItem *sprite) { +void Screen::drawSpriteCore(byte *dest, SpriteFilter &reader, const SpriteDrawItem &sprite) { int16 destInc; - if (sprite->flags & 4) { + if (sprite.flags & 4) { destInc = -1; - dest += sprite->width; + dest += sprite.width; } else { destInc = 1; } @@ -459,10 +456,10 @@ void Screen::drawSpriteCore(byte *dest, SpriteFilter &reader, SpriteDrawItem *sp PixelPacket packet; byte *destp = dest; - int16 skipX = sprite->skipX; + int16 skipX = sprite.skipX; - int16 w = sprite->width; - int16 h = sprite->height; + int16 w = sprite.width; + int16 h = sprite.height; do { status = reader.readPacket(packet); @@ -483,20 +480,20 @@ void Screen::drawSpriteCore(byte *dest, SpriteFilter &reader, SpriteDrawItem *sp w -= packet.count; - if (((sprite->flags & 0x40) && (packet.pixel != 0)) || - ((sprite->flags & 0x10) && (packet.pixel != 0xFF)) || - !(sprite->flags & 0x10) && (packet.pixel != 0)) + if (((sprite.flags & 0x40) && (packet.pixel != 0)) || + ((sprite.flags & 0x10) && (packet.pixel != 0xFF)) || + !(sprite.flags & 0x10) && (packet.pixel != 0)) { - if (sprite->flags & 0x40) { + if (sprite.flags & 0x40) { while (packet.count--) { *dest = _vm->_palette->getColorTransPixel(*dest); dest += destInc; } } else { - if (sprite->flags & 0x10) { + if (sprite.flags & 0x10) { packet.pixel = ((packet.pixel << 4) & 0xF0) | ((packet.pixel >> 4) & 0x0F); } else { - packet.pixel += sprite->baseColor - 1; + packet.pixel += sprite.baseColor - 1; } while (packet.count--) { *dest = packet.pixel; @@ -515,8 +512,8 @@ void Screen::drawSpriteCore(byte *dest, SpriteFilter &reader, SpriteDrawItem *sp } dest = destp + 640; destp = dest; - skipX = sprite->skipX; - w = sprite->width; + skipX = sprite.skipX; + w = sprite.width; h--; } @@ -524,12 +521,4 @@ void Screen::drawSpriteCore(byte *dest, SpriteFilter &reader, SpriteDrawItem *sp } -void Screen::drawSprites() { - for (Common::List<SpriteDrawItem>::iterator iter = _spriteDrawList.begin(); iter != _spriteDrawList.end(); iter++) { - SpriteDrawItem *sprite = &(*iter); - drawSprite(sprite); - _vm->_segmap->restoreMasksBySprite(sprite); - } -} - } // End of namespace Toltecs diff --git a/engines/toltecs/toltecs.cpp b/engines/toltecs/toltecs.cpp index f9ebb416c6..3c9f1dbda9 100644 --- a/engines/toltecs/toltecs.cpp +++ b/engines/toltecs/toltecs.cpp @@ -42,11 +42,11 @@ #include "toltecs/menu.h" #include "toltecs/movie.h" #include "toltecs/palette.h" +#include "toltecs/render.h" #include "toltecs/resource.h" #include "toltecs/script.h" #include "toltecs/screen.h" #include "toltecs/segmap.h" - #include "toltecs/microtiles.h" namespace Toltecs { @@ -89,8 +89,6 @@ int ToltecsEngine::init() { int ToltecsEngine::go() { - _system->setFeatureState(OSystem::kFeatureAutoComputeDirtyRects, true); - _quitGame = false; _counter01 = 0; _counter02 = 0; @@ -162,23 +160,6 @@ int ToltecsEngine::go() { } #endif -//#define TEST_MICROTILES -#ifdef TEST_MICROTILES - MicroTileArray *uta = new MicroTileArray(0, 0, 640, 480); - uta->unite(Common::Rect(10, 10, 50, 50)); - uta->unite(Common::Rect(45, 45, 60, 60)); - Common::Rect *rects; - int n_rects; - n_rects = uta->getRectangles(rects); - printf("n_rects = %d\n", n_rects); fflush(stdout); - for (int i = 0; i < n_rects; i++) { - printf("%d, %d, %d, %d\n", rects[i].left, rects[i].top, rects[i].right, rects[i].bottom); - fflush(stdout); - } - _system->quit(); - delete uta; -#endif - #if 1 _script->loadScript(0, 0); _script->runScript(0); @@ -231,6 +212,9 @@ void ToltecsEngine::loadScene(uint resIndex) { // Load scene segmap _segmap->load(scene + imageSize + 4); + _screen->_fullRefresh = true; + _screen->_renderQueue->clear(); + } void ToltecsEngine::updateScreen() { @@ -238,21 +222,19 @@ void ToltecsEngine::updateScreen() { // FIXME: Quick hack, sometimes cameraY was negative (the code in updateCamera was at fault) if (_cameraY < 0) _cameraY = 0; - // TODO: Optimize redraw by using dirty rectangles - byte *destp = _screen->_frontScreen; - byte *srcp = _screen->_backScreen + _cameraX + _cameraY * _sceneWidth; - for (uint y = 0; y < MIN<uint>(_cameraHeight, 400); y++) { - memcpy(destp, srcp, MIN<uint>(_sceneWidth, 640)); - destp += 640; - srcp += _sceneWidth; - } + _segmap->addMasksToRenderQueue(); + _screen->addTalkTextItemsToRenderQueue(); - _screen->drawSprites(); - _screen->clearSprites(); + _screen->_renderQueue->update(); + + //printf("_guiHeight = %d\n", _guiHeight); fflush(stdout); - _screen->drawTalkTextItems(); + if (_screen->_guiRefresh && _guiHeight > 0 && _cameraHeight > 0) { + _system->copyRectToScreen((const byte *)_screen->_frontScreen + _cameraHeight * 640, + 640, 0, _cameraHeight, 640, _guiHeight); + _screen->_guiRefresh = false; + } - _system->copyRectToScreen((const byte *)_screen->_frontScreen, 640, 0, 0, 640, 400); _system->updateScreen(); updateCamera(); @@ -268,7 +250,7 @@ void ToltecsEngine::updateInput() { // FIXME: This is just for debugging switch (event.kbd.keycode) { - case Common::KEYCODE_F5: + case Common::KEYCODE_F7: savegame("toltecs.001"); break; case Common::KEYCODE_F9: @@ -342,6 +324,15 @@ void ToltecsEngine::updateInput() { } +void ToltecsEngine::setGuiHeight(int16 guiHeight) { + if (guiHeight != _guiHeight) { + _guiHeight = guiHeight; + _cameraHeight = 400 - _guiHeight; + debug(0, "ToltecsEngine::setGuiHeight() _guiHeight = %d; _cameraHeight = %d", _guiHeight, _cameraHeight); + // TODO: clearScreen(); + } +} + void ToltecsEngine::setCamera(int16 x, int16 y) { _screen->finishTextDrawItems(); @@ -356,8 +347,6 @@ void ToltecsEngine::setCamera(int16 x, int16 y) { y = _sceneHeight - _cameraHeight; */ - // TODO DirtyRect clearing stuff - _screen->clearSprites(); _cameraX = x; @@ -366,17 +355,6 @@ void ToltecsEngine::setCamera(int16 x, int16 y) { _cameraY = y; _newCameraY = y; - // TODO More DirtyRect clearing stuff - -} - -void ToltecsEngine::setGuiHeight(int16 guiHeight) { - if (guiHeight != _guiHeight) { - _guiHeight = guiHeight; - _cameraHeight = 400 - _guiHeight; - debug(0, "ToltecsEngine::setGuiHeight() _guiHeight = %d; _cameraHeight = %d", _guiHeight, _cameraHeight); - // TODO: clearScreen(); - } } void ToltecsEngine::scrollCameraUp(int16 delta) { @@ -385,7 +363,6 @@ void ToltecsEngine::scrollCameraUp(int16 delta) { _newCameraY = 0; else _newCameraY -= delta; - _screen->finishTextDrawItems(); } } @@ -396,7 +373,6 @@ void ToltecsEngine::scrollCameraDown(int16 delta) { delta += (_sceneHeight - _cameraHeight) - (delta + _newCameraY); _newCameraY += delta; debug(0, "ToltecsEngine::scrollCameraDown() _newCameraY = %d; delta = %d", _newCameraY, delta); - _screen->finishTextDrawItems(); } } @@ -406,7 +382,6 @@ void ToltecsEngine::scrollCameraLeft(int16 delta) { _newCameraX = 0; else _newCameraX -= delta; - _screen->finishTextDrawItems(); } } @@ -417,7 +392,6 @@ void ToltecsEngine::scrollCameraRight(int16 delta) { delta += (_sceneWidth - 640) - (delta + _newCameraX); _newCameraX += delta; debug(0, "ToltecsEngine::scrollCameraRight() _newCameraX = %d; delta = %d", _newCameraY, delta); - _screen->finishTextDrawItems(); } } @@ -426,11 +400,15 @@ void ToltecsEngine::updateCamera() { if (_cameraX != _newCameraX) { //dirtyFullRefresh = -1; _cameraX = _newCameraX; + _screen->_fullRefresh = true; + _screen->finishTextDrawItems(); } if (_cameraY != _newCameraY) { //dirtyFullRefresh = -1; _cameraY = _newCameraY; + _screen->_fullRefresh = true; + _screen->finishTextDrawItems(); } debug(0, "ToltecsEngine::updateCamera() _cameraX = %d; _cameraY = %d", _cameraX, _cameraY); diff --git a/engines/toltecs/toltecs.h b/engines/toltecs/toltecs.h index 7c7e3ea435..e0d64bda36 100644 --- a/engines/toltecs/toltecs.h +++ b/engines/toltecs/toltecs.h @@ -82,8 +82,9 @@ public: void updateScreen(); void updateInput(); - void setCamera(int16 x, int16 y); void setGuiHeight(int16 guiHeight); + + void setCamera(int16 x, int16 y); void scrollCameraUp(int16 delta); void scrollCameraDown(int16 delta); void scrollCameraLeft(int16 delta); |