aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorBenjamin Haisch2008-09-16 07:14:07 +0000
committerWillem Jan Palenstijn2011-11-20 22:43:06 +0100
commitd09fbbabe66b583d06482a5b25f46b2eebf63d1e (patch)
treed77954c81653299884655fa52731e206d10502a3 /engines
parent20d60e6286fdaa1ffd62bcc5deae3b69e281047d (diff)
downloadscummvm-rg350-d09fbbabe66b583d06482a5b25f46b2eebf63d1e.tar.gz
scummvm-rg350-d09fbbabe66b583d06482a5b25f46b2eebf63d1e.tar.bz2
scummvm-rg350-d09fbbabe66b583d06482a5b25f46b2eebf63d1e.zip
TOLTECS: - Added menu system prototype (may change later)
- Added movie player (still incomplete, sound is not yet implemented) Both are not yet hooked to the engine. - Added code for microtile arrays (from the SEL - Simple DirectMedia Layer Extension Library project), under the LGPL This will be used as dirty rectangle "manager". This is experimental for now, it may be removed later.
Diffstat (limited to 'engines')
-rw-r--r--engines/toltecs/menu.cpp250
-rw-r--r--engines/toltecs/menu.h140
-rw-r--r--engines/toltecs/microtiles.cpp797
-rw-r--r--engines/toltecs/microtiles.h105
-rw-r--r--engines/toltecs/module.mk3
-rw-r--r--engines/toltecs/movie.cpp179
-rw-r--r--engines/toltecs/movie.h65
7 files changed, 1539 insertions, 0 deletions
diff --git a/engines/toltecs/menu.cpp b/engines/toltecs/menu.cpp
new file mode 100644
index 0000000000..9061ff5ddf
--- /dev/null
+++ b/engines/toltecs/menu.cpp
@@ -0,0 +1,250 @@
+/* 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 "sound/mixer.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/menu.h"
+#include "toltecs/resource.h"
+#include "toltecs/screen.h"
+
+namespace Toltecs {
+
+// This code is very experimental.
+
+Widget::Widget(ToltecsEngine *vm, int x, int y) : _vm(vm) {
+ _rect.left = x;
+ _rect.top = y;
+}
+
+Widget::~Widget() {
+}
+
+void Widget::redraw() {
+}
+
+Widget *Widget::getHoveredWidget(int mouseX, int mouseY) {
+ if (_rect.contains(mouseX, mouseY))
+ return this;
+ else
+ return NULL;
+}
+
+void Widget::calcDimensions() {
+}
+
+void Widget::setRect(Common::Rect rect) {
+ _rect = rect;
+}
+
+void Widget::onMouseEnter() {
+}
+
+void Widget::onMouseLeave() {
+}
+
+void Widget::onMouseMove(int mouseX, int mouseY) {
+}
+
+LabelWidget::LabelWidget(ToltecsEngine *vm, int x, int y, Common::String caption, uint flags) :
+ Widget(vm, x, y), _caption(caption), _flags(flags), _fontColor(kFontColorMenuDefault) {
+
+ calcDimensions();
+
+}
+
+LabelWidget::~LabelWidget() {
+}
+
+void LabelWidget::redraw() {
+ _vm->_screen->drawString(_rect.left, _rect.top, _fontColor, 14, (byte*)_caption.c_str(), -1, NULL, true);
+}
+
+void LabelWidget::calcDimensions() {
+ Font font(_vm->_res->load(14));
+ _rect.setWidth(font.getTextWidth((byte*)_caption.c_str()));
+ _rect.setHeight(font.getHeight());
+}
+
+void LabelWidget::setCaption(Common::String caption) {
+ _caption = caption;
+ calcDimensions();
+}
+
+void LabelWidget::setFontColor(byte fontColor) {
+ _fontColor = fontColor;
+}
+
+void LabelWidget::onMouseEnter() {
+ setFontColor(kFontColorMenuActive);
+}
+
+void LabelWidget::onMouseLeave() {
+ setFontColor(kFontColorMenuDefault);
+}
+
+
+VolumeControlWidget::VolumeControlWidget(ToltecsEngine *vm, int x, int y, Common::String caption, uint flags) :
+ Widget(_vm, x, y), _activeWidget(NULL) {
+
+ _label = new LabelWidget(vm, x, y, caption, flags);
+ _up = new LabelWidget(vm, x + 350, y + 4, "[", flags);
+ _down = new LabelWidget(vm, x + 350 + 24, y + 4, "]", flags);
+ _indicator = new LabelWidget(vm, x + 350 + 24 + 24 + 8, y, "||||||||||", flags);
+
+ _rect.setWidth(350 + 24 + 24 + 8 + 50);
+ _rect.setHeight(20);
+
+}
+
+VolumeControlWidget::~VolumeControlWidget() {
+ delete _label;
+ delete _up;
+ delete _down;
+ delete _indicator;
+}
+
+void VolumeControlWidget::redraw() {
+ _label->redraw();
+ _up->redraw();
+ _down->redraw();
+ _indicator->redraw();
+}
+
+Widget *VolumeControlWidget::getHoveredWidget(int mouseX, int mouseY) {
+ return Widget::getHoveredWidget(mouseX, mouseY);
+}
+
+void VolumeControlWidget::calcDimensions() {
+}
+
+void VolumeControlWidget::onMouseEnter() {
+ _label->setFontColor(kFontColorMenuActive);
+ _indicator->setFontColor(kFontColorMenuActive);
+ _activeWidget = NULL;
+}
+
+void VolumeControlWidget::onMouseLeave() {
+ _label->setFontColor(kFontColorMenuDefault);
+ _up->setFontColor(kFontColorMenuDefault);
+ _down->setFontColor(kFontColorMenuDefault);
+ _indicator->setFontColor(kFontColorMenuDefault);
+}
+
+void VolumeControlWidget::onMouseMove(int mouseX, int mouseY) {
+
+ Widget *hoveredWidget = NULL;
+
+ hoveredWidget = _up->getHoveredWidget(mouseX, mouseY);
+ if (!hoveredWidget)
+ hoveredWidget = _down->getHoveredWidget(mouseX, mouseY);
+
+ if (_activeWidget != hoveredWidget) {
+ _activeWidget = hoveredWidget;
+ if (!_activeWidget) {
+ _up->setFontColor(kFontColorMenuDefault);
+ _down->setFontColor(kFontColorMenuDefault);
+ } else if (_activeWidget == _up) {
+ _up->setFontColor(kFontColorMenuActive);
+ _down->setFontColor(kFontColorMenuDefault);
+ } else if (_activeWidget == _down) {
+ _up->setFontColor(kFontColorMenuDefault);
+ _down->setFontColor(kFontColorMenuActive);
+ }
+ }
+
+}
+
+MenuPage::MenuPage(Common::String caption) {
+}
+
+MenuPage::~MenuPage() {
+ // TODO: Delete widgets
+}
+
+void MenuPage::addWidget(Widget *widget) {
+ _widgets.push_back(widget);
+}
+
+void MenuPage::redraw() {
+ for (WidgetArray::iterator iter = _widgets.begin(); iter != _widgets.end(); iter++) {
+ (*iter)->redraw();
+ }
+}
+
+Widget *MenuPage::getHoveredWidget(int mouseX, int mouseY) {
+ Widget *hoveredWidget = NULL;
+ for (WidgetArray::iterator iter = _widgets.begin(); iter != _widgets.end() && !hoveredWidget; iter++) {
+ hoveredWidget = (*iter)->getHoveredWidget(mouseX, mouseY);
+ }
+ return hoveredWidget;
+}
+
+MenuSystem::MenuSystem(ToltecsEngine *vm) : _vm(vm), _activeWidget(NULL), _oldMouseX(-1), _oldMouseY(-1) {
+ _page = new MenuPage("Welcome");
+ _page->addWidget(new LabelWidget(_vm, 10, 10, "Load game", 0));
+ _page->addWidget(new LabelWidget(_vm, 10, 35, "Save game", 0));
+ _page->addWidget(new VolumeControlWidget(_vm, 10, 60, "Master volume", 0));
+ _page->addWidget(new VolumeControlWidget(_vm, 10, 90, "Some other volume", 0));
+}
+
+MenuSystem::~MenuSystem() {
+ delete _page;
+}
+
+void MenuSystem::update() {
+
+ _page->redraw();
+
+ if (_vm->_mouseX != _oldMouseX || _vm->_mouseY != _oldMouseY) {
+
+ _oldMouseX = _vm->_mouseX;
+ _oldMouseY = _vm->_mouseY;
+
+ Widget *hoveredWidget = _page->getHoveredWidget(_vm->_mouseX, _vm->_mouseY);
+ if (_activeWidget != hoveredWidget) {
+ if (_activeWidget)
+ _activeWidget->onMouseLeave();
+ if (hoveredWidget)
+ hoveredWidget->onMouseEnter();
+ _activeWidget = hoveredWidget;
+ }
+
+ if (_activeWidget) {
+ _activeWidget->onMouseMove(_vm->_mouseX, _vm->_mouseY);
+ }
+
+ }
+
+}
+
+} // End of namespace Toltecs
diff --git a/engines/toltecs/menu.h b/engines/toltecs/menu.h
new file mode 100644
index 0000000000..15b73b78f7
--- /dev/null
+++ b/engines/toltecs/menu.h
@@ -0,0 +1,140 @@
+/* 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_MENU_H
+#define TOLTECS_MENU_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/array.h"
+#include "common/rect.h"
+#include "common/str.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/voc.h"
+#include "sound/audiocd.h"
+
+#include "engines/engine.h"
+
+namespace Toltecs {
+
+const byte kFontColorMenuDefault = 229;
+const byte kFontColorMenuActive = 255;
+
+class Widget {
+public:
+ Widget(ToltecsEngine *vm, int x, int y);
+ virtual ~Widget();
+ virtual void redraw();
+ virtual Widget *getHoveredWidget(int mouseX, int mouseY);
+ virtual void calcDimensions();
+ void setRect(Common::Rect rect);
+ //virtual void setHilighted(bool active);
+ virtual void onMouseEnter();
+ virtual void onMouseLeave();
+ virtual void onMouseMove(int mouseX, int mouseY);
+protected:
+ ToltecsEngine *_vm;
+ Common::Rect _rect;
+ //bool _hilighted;
+};
+
+const int kLabelCentered = 1 << 1;
+const int kLabelHideOnMovie = 1 << 2;
+
+class LabelWidget : public Widget {
+public:
+ LabelWidget(ToltecsEngine *vm, int x, int y, Common::String caption, uint flags);
+ ~LabelWidget();
+ void redraw();
+ void calcDimensions();
+ void setCaption(Common::String caption);
+ void setFontColor(byte fontColor);
+ void onMouseEnter();
+ void onMouseLeave();
+protected:
+ Common::String _caption;
+ uint _flags;
+ byte _fontColor;
+};
+
+class VolumeControlWidget : public Widget {
+public:
+ VolumeControlWidget(ToltecsEngine *vm, int x, int y, Common::String caption, uint flags);
+ ~VolumeControlWidget();
+ void redraw();
+ Widget *getHoveredWidget(int mouseX, int mouseY);
+ void calcDimensions();
+ //void setHilighted(bool active);
+ void onMouseEnter();
+ void onMouseLeave();
+ void onMouseMove(int mouseX, int mouseY);
+protected:
+ uint _flags;
+ LabelWidget *_label, *_up, *_down, *_indicator;
+ Widget *_activeWidget;
+};
+
+class MenuPage {
+public:
+ MenuPage(Common::String caption);
+ ~MenuPage();
+ void addWidget(Widget *widget);
+ void redraw();
+ Widget *getHoveredWidget(int mouseX, int mouseY);
+protected:
+ typedef Common::Array<Widget*> WidgetArray;
+ Common::String _caption;
+ WidgetArray _widgets;
+};
+
+class MenuSystem {
+
+public:
+ MenuSystem(ToltecsEngine *vm);
+ ~MenuSystem();
+
+ void update();
+
+protected:
+ ToltecsEngine *_vm;
+
+ //LabelWidget *label1, *label2;
+ MenuPage *_page;
+
+ Widget *_activeWidget;
+ int16 _oldMouseX, _oldMouseY;
+
+};
+
+} // End of namespace Toltecs
+
+#endif /* TOLTECS_MENU_H */
diff --git a/engines/toltecs/microtiles.cpp b/engines/toltecs/microtiles.cpp
new file mode 100644
index 0000000000..3cd5facfa6
--- /dev/null
+++ b/engines/toltecs/microtiles.cpp
@@ -0,0 +1,797 @@
+/*
+ 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);
+}
+
+static void gem_uta_free (GemUta *uta) {
+ if (uta) {
+ if (uta->tiles)
+ free (uta->tiles);
+ free(uta);
+ }
+}
+
+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);
+
+ if (x0 > x1 || y0 > y1)
+ return;
+
+ _b1 = & (uta1->tiles [(y0 - uta1->y) * uta1->width + (x0 - uta1->x)]);
+ _b2 = & (uta2->tiles [(y0 - uta2->y) * uta2->width + (x0 - uta2->x)]);
+
+ for (y = y0; y <= y1; ++y)
+ {
+ GemUtaBBox *b1 = _b1;
+ const GemUtaBBox *b2 = _b2;
+
+ for (x = x0; x <= x1; ++x)
+ {
+ GEM_UTILE_UNION (*b1, *b2);
+
+ b1 ++;
+ b2 ++;
+ }
+ _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);
+
+ /* done. */
+}
+
+#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)) )
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+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));
+}
+
+#define GEM_UTILE_INTERSECTS(b1, b2) \
+ gem_utile_intersects (b1, b2)
+/*
+ * Return if the uta contains the rectangle.
+ */
+
+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;
+ }
+ }
+
+ 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;
+ }
+ }
+
+ /* 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;
+}
+
+
+#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
+
+
+ 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 *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;
+
+ b = uta->tiles [i];
+
+ if (TILE == GEM_UTILE_EMPTY)
+ goto next;
+
+ 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);
+
+ start = i;
+
+ if (GEM_UTA_BBOX_X1 (TILE) != GEM_UTILE_SIZE || x == uta->width - 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)
+ {
+ --x;
+ --i;
+ finish = 1;
+ }
+ }
+
+ 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)
+ {
+ rects [glom [start]].y1 = y1;
+ if (y != uta->height - 1) {
+ glom [start + uta->width] = 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;
+ }
+ n_rects ++;
+ }
+ 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)
+{
+}
+
+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");
+}
+
+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
+
diff --git a/engines/toltecs/microtiles.h b/engines/toltecs/microtiles.h
new file mode 100644
index 0000000000..21dd5a9fcf
--- /dev/null
+++ b/engines/toltecs/microtiles.h
@@ -0,0 +1,105 @@
+/*
+ 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/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();
+
+ //! Create a new microtile array with given coordinates.
+ MicroTileArray(int x, int y, int w, int h);
+
+ //! Destroy the microtile array.
+ ~MicroTileArray();
+
+ //! Clear the microtile array.
+ 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
+
+} // namespace Toltecs
+
+
+#endif // TOLTECS_MICROTILES_H
diff --git a/engines/toltecs/module.mk b/engines/toltecs/module.mk
index 541bf6be70..0d658f6095 100644
--- a/engines/toltecs/module.mk
+++ b/engines/toltecs/module.mk
@@ -3,6 +3,9 @@ MODULE := engines/toltecs
MODULE_OBJS = \
animation.o \
detection.o \
+ menu.o \
+ microtiles.o \
+ movie.o \
palette.o \
toltecs.o \
resource.o \
diff --git a/engines/toltecs/movie.cpp b/engines/toltecs/movie.cpp
new file mode 100644
index 0000000000..ef280fa508
--- /dev/null
+++ b/engines/toltecs/movie.cpp
@@ -0,0 +1,179 @@
+/* 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 "sound/mixer.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/movie.h"
+#include "toltecs/palette.h"
+#include "toltecs/resource.h"
+#include "toltecs/screen.h"
+#include "toltecs/script.h"
+
+namespace Toltecs {
+
+MoviePlayer::MoviePlayer(ToltecsEngine *vm) : _vm(vm) {
+}
+
+MoviePlayer::~MoviePlayer() {
+}
+
+void MoviePlayer::playMovie(uint resIndex) {
+
+ uint32 chunkCount, frameCount, subtitleSlot;
+ byte moviePalette[768];
+
+ memset(moviePalette, 0, sizeof(moviePalette));
+
+ _vm->_screen->finishTextDrawItems();
+ _vm->_screen->clearSprites();
+
+ _vm->_arc->openResource(resIndex);
+
+ frameCount = _vm->_arc->readUint32LE();
+ chunkCount = _vm->_arc->readUint32LE();
+ subtitleSlot = kMaxScriptSlots - 1;
+
+ // TODO: Read/figure out rest of the header
+ _vm->_arc->seek(0x10, SEEK_CUR);
+ _vm->_sceneWidth = 640;
+ _vm->_sceneHeight = 400;
+ _vm->_cameraHeight = 400;
+ _vm->_cameraX = 0;
+ _vm->_cameraY = 0;
+
+ while (chunkCount--) {
+
+ byte chunkType;
+ uint32 chunkSize;
+ byte *chunkBuffer;
+ uint32 movieOffset;
+
+ chunkType = _vm->_arc->readByte();
+ chunkSize = _vm->_arc->readUint32LE();
+
+ debug(0, "chunkType = %d; chunkSize = %d", chunkType, chunkSize);
+
+ chunkBuffer = new byte[chunkSize];
+ _vm->_arc->read(chunkBuffer, chunkSize);
+
+ movieOffset = _vm->_arc->pos();
+
+ switch (chunkType) {
+ case 0: // image data
+ case 1:
+ unpackRle(chunkBuffer, _vm->_screen->_backScreen);
+ // TODO: Rework this
+ _vm->_screen->updateShakeScreen();
+ _vm->updateInput();
+ _vm->updateScreen();
+ g_system->delayMillis(80);
+ break;
+ case 2: // palette data
+ unpackPalette(chunkBuffer, moviePalette, 256, 3);
+ _vm->_palette->setFullPalette(moviePalette);
+ break;
+ //case 3: -- what is this type
+ case 4: // audio data
+ // TODO: Handle audio data
+ break;
+ case 5:
+ // TODO: Check if the text is a subtitle (last character == 0xFE).
+ // If so, don't show it if text display is disabled.
+ memcpy(_vm->_script->getSlotData(subtitleSlot), chunkBuffer, chunkSize);
+ _vm->_screen->updateTalkText(subtitleSlot, 0);
+ break;
+ case 6: // start/stop shakescreen effect
+ if (chunkBuffer[0] == 0xFF)
+ _vm->_screen->stopShakeScreen();
+ else
+ _vm->_screen->startShakeScreen(chunkBuffer[0]);
+ break;
+ case 7: // setup subtitle parameters
+ _vm->_screen->_talkTextY = READ_LE_UINT16(&chunkBuffer[0]);
+ _vm->_screen->_talkTextX = READ_LE_UINT16(&chunkBuffer[2]);
+ _vm->_screen->_talkTextFontColor = chunkBuffer[4];
+ debug(0, "_talkTextX = %d; _talkTextY = %d; _talkTextFontColor = %d",
+ _vm->_screen->_talkTextX, _vm->_screen->_talkTextY, _vm->_screen->_talkTextFontColor);
+ break;
+ case 8: // stop subtitles
+ _vm->_script->getSlotData(subtitleSlot)[0] = 0xFF;
+ _vm->_screen->finishTextDrawItems();
+ break;
+ default:
+ error("Unknown chunk type %d at %08X", chunkType, _vm->_arc->pos() - 5 - chunkSize);
+ }
+
+ delete[] chunkBuffer;
+
+ _vm->_arc->seek(movieOffset, SEEK_SET);
+
+ }
+
+ _vm->_arc->closeResource();
+
+}
+
+void MoviePlayer::unpackPalette(byte *source, byte *dest, int elemCount, int elemSize) {
+ int ofs = 0, size = elemCount * elemSize;
+ while (ofs < size) {
+ byte len;
+ len = *source++;
+ if (len == 0) {
+ len = *source++;
+ } else {
+ byte value = *source++;
+ memset(dest, value, len);
+ }
+ ofs += len;
+ dest += len;
+ }
+}
+
+void MoviePlayer::unpackRle(byte *source, byte *dest) {
+ int size = 256000;
+ while (size > 0) {
+ byte a = *source++;
+ byte b = *source++;
+ if (a == 0) {
+ dest += b;
+ size -= b;
+ } else {
+ memset(dest, b, a);
+ dest += a;
+ size -= a;
+ }
+ }
+}
+
+
+} // End of namespace Toltecs
diff --git a/engines/toltecs/movie.h b/engines/toltecs/movie.h
new file mode 100644
index 0000000000..9ab5435121
--- /dev/null
+++ b/engines/toltecs/movie.h
@@ -0,0 +1,65 @@
+/* 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_MOVIE_H
+#define TOLTECS_MOVIE_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/array.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/voc.h"
+#include "sound/audiocd.h"
+
+#include "engines/engine.h"
+
+namespace Toltecs {
+
+class MoviePlayer {
+
+public:
+ MoviePlayer(ToltecsEngine *vm);
+ ~MoviePlayer();
+
+ void playMovie(uint resIndex);
+
+protected:
+ ToltecsEngine *_vm;
+
+ void unpackPalette(byte *source, byte *dest, int elemCount, int elemSize);
+ void unpackRle(byte *source, byte *dest);
+
+};
+
+} // End of namespace Toltecs
+
+#endif /* TOLTECS_MOVIE_H */