aboutsummaryrefslogtreecommitdiff
path: root/engines/cryomni3d/sprites.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/cryomni3d/sprites.cpp')
-rw-r--r--engines/cryomni3d/sprites.cpp218
1 files changed, 218 insertions, 0 deletions
diff --git a/engines/cryomni3d/sprites.cpp b/engines/cryomni3d/sprites.cpp
new file mode 100644
index 0000000000..b1c5f95b0e
--- /dev/null
+++ b/engines/cryomni3d/sprites.cpp
@@ -0,0 +1,218 @@
+/* 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/debug.h"
+#include "common/file.h"
+#include "graphics/surface.h"
+
+#include "engines/cryomni3d/sprites.h"
+
+// #define SPRTIES_DEBUG
+
+namespace CryOmni3D {
+
+#define MAP_ID(id) \
+ do { \
+ if (_map) { \
+ id = (*_map)[id]; \
+ } \
+ } while(false)
+
+Sprites::Sprites() : _map(nullptr) {
+ _surface = new Graphics::Surface();
+}
+
+Sprites::~Sprites() {
+ for (Common::Array<CryoCursor *>::iterator it = _cursors.begin(); it != _cursors.end(); it++) {
+ if ((*it)->refCnt > 1) {
+ (*it)->refCnt--;
+ } else {
+ delete *it;
+ }
+ }
+ delete _map;
+ delete _surface;
+}
+
+void Sprites::loadSprites(Common::ReadStream &spr_fl) {
+ byte magic[4];
+
+ while (true) {
+ if (spr_fl.read(magic, sizeof(magic)) == 0) {
+ break;
+ }
+ if (memcmp(magic, "SPRI", sizeof(magic))) {
+ error("Invalid sprite magic");
+ }
+
+ // 2 unknown uint32
+ spr_fl.readUint32BE();
+ spr_fl.readUint32BE();
+
+ CryoCursor *cursor = new CryoCursor();
+
+ uint16 w = spr_fl.readUint16BE();
+ uint16 h = spr_fl.readUint16BE();
+ unsigned int sz = cursor->setup(w, h);
+ cursor->_offX = spr_fl.readUint32BE();
+ cursor->_offY = spr_fl.readUint32BE();
+
+ spr_fl.read(cursor->_data, sz);
+ _cursors.push_back(cursor);
+ }
+}
+
+void Sprites::setupMapTable(const unsigned int *table, unsigned int size) {
+ delete _map;
+ _map = nullptr;
+ // Reset the reverse mapping
+ for (Common::Array<CryoCursor *>::iterator it = _cursors.begin(); it != _cursors.end(); it++) {
+ (*it)->_constantId = -1;
+ }
+ if (table) {
+ _map = new Common::Array<unsigned int>(table, size);
+
+ // Sweep all the mapping and set its reverse values
+ unsigned int i = 0;
+ for (Common::Array<unsigned int>::const_iterator it = _map->begin(); it != _map->end(); it++, i++) {
+ _cursors[*it]->_constantId = i;
+ }
+
+#ifdef SPRITES_DEBUG
+ // Normally we don't have any unreachable sprties from constants,
+ // as it could be time consuming, this should be fixed in the static map
+ // Count unswept values
+ unsigned int unswept = 0;
+ for (Common::Array<CryoCursor *>::iterator it = _cursors.begin(); it != _cursors.end(); it++) {
+ if ((*it)->_constantId == -1u) {
+ unswept++;
+ }
+ }
+
+ if (unswept) {
+ warning("We got %d unreachable sprites from map table. This should not happen."
+ " Fixing it for now", unswept);
+ // Enlarge the map to hold new indexes
+ _map->reserve(_map->size() + unswept);
+
+ // Set new indexes to unswept sprites
+ i = 0;
+ for (Common::Array<CryoCursor *>::iterator it = _cursors.begin(); it != _cursors.end(); it++, i++) {
+ if ((*it)->_constantId == -1u) {
+ warning("Fixing sprite the %d sprite", i);
+ (*it)->_constantId = _map->size();
+ _map->push_back(i);
+ }
+ }
+ }
+#endif
+ }
+}
+
+void Sprites::setSpriteHotspot(unsigned int spriteId, unsigned int x, unsigned int y) {
+ MAP_ID(spriteId);
+ _cursors[spriteId]->_offX = x;
+ _cursors[spriteId]->_offY = y;
+}
+
+void Sprites::replaceSprite(unsigned int oldSpriteId, unsigned int newSpriteId) {
+ MAP_ID(oldSpriteId);
+ MAP_ID(newSpriteId);
+ if (_cursors[oldSpriteId]->refCnt > 1) {
+ _cursors[oldSpriteId]->refCnt--;
+ } else {
+ delete _cursors[oldSpriteId];
+ }
+ _cursors[oldSpriteId] = _cursors[newSpriteId];
+ _cursors[oldSpriteId]->refCnt++;
+}
+
+unsigned int Sprites::getSpritesCount() const {
+ if (_map) {
+ return _map->size();
+ } else {
+ return _cursors.size();
+ }
+}
+
+unsigned int Sprites::revMapSpriteId(unsigned int id) const {
+ if (_map) {
+ if (id >= _cursors.size()) {
+ error("revMapSpriteId is out of bounds: %d/%d", id, _cursors.size());
+ }
+ id = _cursors[id]->_constantId;
+ }
+
+ return id;
+}
+
+unsigned int Sprites::calculateSpriteId(unsigned int baseId, unsigned int offset) const {
+ if (_map) {
+ MAP_ID(baseId);
+ baseId += offset;
+ if (baseId >= _cursors.size()) {
+ error("Calculate sprite is out of bounds: %d/%d", baseId, _cursors.size());
+ }
+ unsigned int spriteId = _cursors[baseId]->_constantId;
+ if (spriteId == -1u) {
+ error("Sprite %d is unreachable", baseId);
+ }
+ return spriteId;
+ } else {
+ return baseId + offset;
+ }
+}
+
+const Graphics::Surface &Sprites::getSurface(unsigned int spriteId) const {
+ MAP_ID(spriteId);
+
+ CryoCursor *cursor = _cursors[spriteId];
+
+ _surface->init(cursor->_width, cursor->_height, cursor->_width, cursor->_data,
+ Graphics::PixelFormat::createFormatCLUT8());
+ return *_surface;
+}
+
+const Graphics::Cursor &Sprites::getCursor(unsigned int spriteId) const {
+ MAP_ID(spriteId);
+
+ return *_cursors[spriteId];
+}
+
+Sprites::CryoCursor::CryoCursor() : _width(0), _height(0), _offX(0), _offY(0), _data(nullptr),
+ refCnt(1) {
+}
+
+Sprites::CryoCursor::~CryoCursor() {
+ assert(refCnt == 1);
+ delete[] _data;
+}
+
+unsigned int Sprites::CryoCursor::setup(uint16 width, uint16 height) {
+ _width = width;
+ _height = height;
+ unsigned int sz = _width * _height;
+ _data = new byte[sz];
+ return sz;
+}
+
+} // End of namespace CryOmni3D