aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/toltecs/animation.cpp1
-rw-r--r--engines/toltecs/microtiles.cpp844
-rw-r--r--engines/toltecs/microtiles.h113
-rw-r--r--engines/toltecs/module.mk1
-rw-r--r--engines/toltecs/render.cpp320
-rw-r--r--engines/toltecs/render.h119
-rw-r--r--engines/toltecs/saveload.cpp1
-rw-r--r--engines/toltecs/screen.cpp74
-rw-r--r--engines/toltecs/screen.h23
-rw-r--r--engines/toltecs/segmap.cpp74
-rw-r--r--engines/toltecs/segmap.h19
-rw-r--r--engines/toltecs/sprite.cpp79
-rw-r--r--engines/toltecs/toltecs.cpp78
-rw-r--r--engines/toltecs/toltecs.h3
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);