aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 */