summaryrefslogtreecommitdiff
path: root/src/resources
diff options
context:
space:
mode:
authorAndrei Karas <akaras@inbox.ru>2016-12-31 05:04:16 +0300
committerAndrei Karas <akaras@inbox.ru>2016-12-31 17:30:48 +0300
commit537085e221d25f710ed7162e1fc8add8ffe4a72f (patch)
treed1abf9cdb898005099eb741a1f6ed79417b331fb /src/resources
parent496e74aa95984380e4a36fe8d55d0839002d6f8f (diff)
downloadmv-537085e221d25f710ed7162e1fc8add8ffe4a72f.tar.gz
mv-537085e221d25f710ed7162e1fc8add8ffe4a72f.tar.bz2
mv-537085e221d25f710ed7162e1fc8add8ffe4a72f.tar.xz
mv-537085e221d25f710ed7162e1fc8add8ffe4a72f.zip
Improve fringe map layers drawing.
Pre cache next tile position with image.
Diffstat (limited to 'src/resources')
-rw-r--r--src/resources/image/image.cpp30
-rw-r--r--src/resources/image/image.h5
-rw-r--r--src/resources/map/maplayer.cpp55
-rw-r--r--src/resources/map/maplayer.h16
-rw-r--r--src/resources/map/maplayer_unittest.cc451
-rw-r--r--src/resources/map/tileinfo.h7
6 files changed, 549 insertions, 15 deletions
diff --git a/src/resources/image/image.cpp b/src/resources/image/image.cpp
index 379a1c074..a3bb1b0ce 100644
--- a/src/resources/image/image.cpp
+++ b/src/resources/image/image.cpp
@@ -45,6 +45,36 @@
#include "debug.h"
+#ifdef UNITTESTS
+Image::Image(const int width,
+ const int height) :
+ Resource(),
+#ifdef USE_OPENGL
+ mGLImage(0),
+ mTexWidth(0),
+ mTexHeight(0),
+#endif // USE_OPENGL
+ mBounds(),
+ mAlpha(1.0F),
+ mSDLSurface(nullptr),
+#ifdef USE_SDL2
+ mTexture(nullptr),
+#endif // USE_SDL2
+ mAlphaChannel(nullptr),
+ mAlphaCache(),
+ mLoaded(false),
+ mHasAlphaChannel(false),
+ mUseAlphaCache(false),
+ mIsAlphaVisible(true),
+ mIsAlphaCalculated(false)
+{
+ mBounds.x = 0;
+ mBounds.y = 0;
+ mBounds.w = width;
+ mBounds.h = height;
+}
+#endif // UNITTESTS
+
#ifdef USE_SDL2
Image::Image(SDL_Texture *restrict const image,
const int width, const int height) :
diff --git a/src/resources/image/image.h b/src/resources/image/image.h
index ca5a8a12e..0a6060fef 100644
--- a/src/resources/image/image.h
+++ b/src/resources/image/image.h
@@ -81,6 +81,11 @@ class Image notfinal : public Resource
#endif // USE_OPENGL
public:
+#ifdef UNITTESTS
+ Image(const int width,
+ const int height);
+#endif // UNITTESTS
+
A_DELETE_COPY(Image)
/**
diff --git a/src/resources/map/maplayer.cpp b/src/resources/map/maplayer.cpp
index b795db243..ad9fc69e6 100644
--- a/src/resources/map/maplayer.cpp
+++ b/src/resources/map/maplayer.cpp
@@ -562,7 +562,7 @@ void MapLayer::drawFringe(Graphics *const graphics,
img->mBounds.h);
}
}
-// logger->log("ok tiles3: (%d,%d) to %d, +%d", x, y, endX, tilePtr->count);
+// logger->log("ok tiles3: (%d,%d) to %d, +%d, %d", x, y, endX, tilePtr->count, tilePtr->nextTile);
}
else
{
@@ -570,7 +570,7 @@ void MapLayer::drawFringe(Graphics *const graphics,
// for now special layer can be not drawed
if (x + tilePtr->count + 1 >= endX)
break;
-// logger->log("error tiles3: (%d,%d) to %d, +%d", x, y, endX, tilePtr->count);
+// logger->log("error tiles3: (%d,%d) to %d, +%d, %d", x, y, endX, tilePtr->count, tilePtr->nextTile);
c = tilePtr->count;
x += c;
tilePtr += c;
@@ -612,8 +612,9 @@ void MapLayer::drawFringe(Graphics *const graphics,
}
}
}
- x += c;
- tilePtr += c;
+ const int nextTile = tilePtr->nextTile;
+ x += nextTile;
+ tilePtr += nextTile;
}
}
@@ -652,13 +653,13 @@ void MapLayer::drawFringe(Graphics *const graphics,
{
if (x + tilePtr->count + 1 >= endX)
break;
-// logger->log("error tiles4: (%d,%d) to %d, +%d", x, y, endX, tilePtr->count);
+// logger->log("error tiles4: (%d,%d) to %d, +%d, %d", x, y, endX, tilePtr->count, tilePtr->nextTile);
const int c = tilePtr->count;
x += c;
tilePtr += c;
continue;
}
-// logger->log("ok tiles4: (%d,%d) to %d, +%d", x, y, endX, tilePtr->count);
+// logger->log("ok tiles4: (%d,%d) to %d, +%d, %d", x, y, endX, tilePtr->count, tilePtr->nextTile);
const int x32 = x * mapTileSize;
const Image *const img = tilePtr->image;
const int px = x32 + dx;
@@ -679,10 +680,11 @@ void MapLayer::drawFringe(Graphics *const graphics,
py,
tilePtr->width,
img->mBounds.h);
- x += c;
- tilePtr += c;
}
}
+ const int nextTile = tilePtr->nextTile;
+ x += nextTile;
+ tilePtr += nextTile;
}
}
} // !flag
@@ -734,7 +736,8 @@ void MapLayer::drawFringe(Graphics *const graphics,
int MapLayer::getTileDrawWidth(const TileInfo *restrict tilePtr,
const int endX,
- int &width)
+ int &restrict width,
+ int &restrict nextTile)
{
BLOCK_START("MapLayer::getTileDrawWidth")
const Image *const img1 = tilePtr->image;
@@ -744,17 +747,37 @@ int MapLayer::getTileDrawWidth(const TileInfo *restrict tilePtr,
{
tilePtr ++;
const Image *const img = tilePtr->image;
- if (img != img1 || !tilePtr->isEnabled)
+ if (img == nullptr || !tilePtr->isEnabled)
+ {
break;
+ }
+ if (img != img1)
+ {
+ nextTile = c;
+ BLOCK_END("MapLayer::getTileDrawWidth")
+ return c;
+ }
c ++;
width += img->mBounds.w;
}
+ int c2 = c;
+ for (int x2 = c2 + 1; x2 < endX; x2++)
+ {
+ if (tilePtr->image != nullptr)
+ {
+ break;
+ }
+ c2 ++;
+ tilePtr ++;
+ }
+ nextTile = c2;
BLOCK_END("MapLayer::getTileDrawWidth")
return c;
}
int MapLayer::getEmptyTileDrawWidth(const TileInfo *restrict tilePtr,
- const int endX)
+ const int endX,
+ int &restrict nextTile)
{
BLOCK_START("MapLayer::getEmptyTileDrawWidth")
int c = 0;
@@ -767,6 +790,8 @@ int MapLayer::getEmptyTileDrawWidth(const TileInfo *restrict tilePtr,
c ++;
}
BLOCK_END("MapLayer::getEmptyTileDrawWidth")
+
+ nextTile = c;
return c;
}
@@ -817,20 +842,24 @@ void MapLayer::updateCache(const int width,
TileInfo *tilePtr = mTiles + y * mWidth;
for (int x = mX; x < width1; x ++, tilePtr ++)
{
+ int nextTile = 0;
if (tilePtr->image == nullptr)
{
tilePtr->isEnabled = false;
tilePtr->count = getEmptyTileDrawWidth(tilePtr,
- width1 - x);
+ width1 - x,
+ nextTile);
}
else
{
int tileWidth = 0;
tilePtr->count = getTileDrawWidth(tilePtr,
width1 - x,
- tileWidth);
+ tileWidth,
+ nextTile);
tilePtr->width = tileWidth;
}
+ tilePtr->nextTile = nextTile;
}
}
}
diff --git a/src/resources/map/maplayer.h b/src/resources/map/maplayer.h
index 19f213ecc..10be2d3aa 100644
--- a/src/resources/map/maplayer.h
+++ b/src/resources/map/maplayer.h
@@ -164,13 +164,25 @@ class MapLayer final: public MemoryCounter, public ConfigListener
std::string getCounterName() const override final
{ return mName; }
+#ifdef UNITTESTS
+ TileInfo *getTiles() const
+ {
+ return mTiles;
+ }
+
+#endif // UNITTESTS
+
+#ifndef UNITTESTS
protected:
+#endif // UNITTESTS
static int getTileDrawWidth(const TileInfo *restrict img,
const int endX,
- int &width) A_WARN_UNUSED A_NONNULL(1);
+ int &restrict width,
+ int &restrict nextTile) A_WARN_UNUSED A_NONNULL(1);
static int getEmptyTileDrawWidth(const TileInfo *restrict img,
- const int endX)
+ const int endX,
+ int &restrict nextTile)
A_WARN_UNUSED A_NONNULL(1);
void updateConditionTiles(MetaTile *restrict const metaTiles,
diff --git a/src/resources/map/maplayer_unittest.cc b/src/resources/map/maplayer_unittest.cc
new file mode 100644
index 000000000..90f34ce0e
--- /dev/null
+++ b/src/resources/map/maplayer_unittest.cc
@@ -0,0 +1,451 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2016 The ManaPlus Developers
+ *
+ * This file is part of The ManaPlus Client.
+ *
+ * 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
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "catch.hpp"
+
+#include "logger.h"
+
+#include "resources/image/image.h"
+
+#include "resources/map/maplayer.h"
+
+#include "debug.h"
+
+TEST_CASE("MapLayer getTileDrawWidth")
+{
+ Image *const img1 = new Image(32, 32);
+ Image *const img2 = new Image(32, 32);
+ Image *const img3 = new Image(32, 32);
+ MapLayer *layer = nullptr;
+ int width;
+ int nextTile;
+
+ SECTION("simple 1")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 1, 1,
+ false,
+ 0,
+ 0);
+ layer->setTile(0, 0, img1);
+ TileInfo *const tiles = layer->getTiles();
+ REQUIRE(layer->getTileDrawWidth(tiles,
+ 1,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 0);
+ }
+
+ SECTION("simple 2")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 2, 1,
+ false,
+ 0,
+ 0);
+ layer->setTile(0, 0, img1);
+ TileInfo *const tiles = layer->getTiles();
+ REQUIRE(layer->getTileDrawWidth(tiles,
+ 2,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 1);
+ }
+
+ SECTION("simple 3")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 2, 1,
+ false,
+ 0,
+ 0);
+ layer->setTile(0, 0, img1);
+ layer->setTile(1, 0, img2);
+ TileInfo *const tiles = layer->getTiles();
+ REQUIRE(layer->getTileDrawWidth(tiles,
+ 1,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 0);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 1,
+ 1,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 0);
+ }
+
+ SECTION("simple 4")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 2, 1,
+ false,
+ 0,
+ 0);
+ layer->setTile(0, 0, img1);
+ layer->setTile(1, 0, img1);
+ TileInfo *const tiles = layer->getTiles();
+ REQUIRE(layer->getTileDrawWidth(tiles,
+ 2,
+ width,
+ nextTile) == 1);
+ REQUIRE(width == 64);
+ REQUIRE(nextTile == 1);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 1,
+ 1,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 0);
+ }
+
+ SECTION("simple 4")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 3, 1,
+ false,
+ 0,
+ 0);
+ layer->setTile(0, 0, img1);
+ layer->setTile(2, 0, img1);
+ TileInfo *const tiles = layer->getTiles();
+ REQUIRE(layer->getTileDrawWidth(tiles,
+ 3,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 1);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 2,
+ 1,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 0);
+ }
+
+ SECTION("simple 5")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 3, 1,
+ false,
+ 0,
+ 0);
+ layer->setTile(0, 0, img1);
+ layer->setTile(1, 0, img1);
+ TileInfo *const tiles = layer->getTiles();
+ REQUIRE(layer->getTileDrawWidth(tiles,
+ 3,
+ width,
+ nextTile) == 1);
+ REQUIRE(width == 64);
+ REQUIRE(nextTile == 2);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 1,
+ 2,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 1);
+ }
+
+ SECTION("simple 6")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 3, 1,
+ false,
+ 0,
+ 0);
+ layer->setTile(0, 0, img1);
+ layer->setTile(1, 0, img1);
+ layer->setTile(2, 0, img2);
+ TileInfo *const tiles = layer->getTiles();
+ REQUIRE(layer->getTileDrawWidth(tiles,
+ 3,
+ width,
+ nextTile) == 1);
+ REQUIRE(width == 64);
+ REQUIRE(nextTile == 1);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 1,
+ 2,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 0);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 2,
+ 1,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 0);
+ }
+
+ SECTION("normal 1")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 100, 100,
+ false,
+ 0,
+ 0);
+ layer->setTile(1, 10, img1);
+ layer->setTile(2, 10, img1);
+ layer->setTile(3, 10, img1);
+ layer->setTile(4, 10, img2);
+ layer->setTile(5, 10, nullptr);
+ layer->setTile(6, 10, img2);
+ layer->setTile(7, 10, nullptr);
+ layer->setTile(8, 10, nullptr);
+ layer->setTile(9, 10, img2);
+ layer->setTile(10, 10, img2);
+ layer->setTile(11, 10, img3);
+ layer->setTile(12, 10, nullptr);
+ layer->setTile(13, 10, nullptr);
+ layer->setTile(14, 10, nullptr);
+ layer->setTile(15, 10, img1);
+ layer->setTile(16, 10, img1);
+ layer->setTile(17, 10, img1);
+ TileInfo *const tiles = layer->getTiles();
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 1,
+ 100 - 1,
+ width,
+ nextTile) == 2);
+ REQUIRE(width == 96);
+ REQUIRE(nextTile == 2);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 2,
+ 100 - 2,
+ width,
+ nextTile) == 1);
+ REQUIRE(width == 64);
+ REQUIRE(nextTile == 1);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 3,
+ 100 - 3,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 0);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 4,
+ 100 - 4,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 1);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 6,
+ 100 - 6,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 2);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 9,
+ 100 - 9,
+ width,
+ nextTile) == 1);
+ REQUIRE(width == 64);
+ REQUIRE(nextTile == 1);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 10,
+ 100 - 10,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 0);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 11,
+ 100 - 11,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 3);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 15,
+ 100 - 15,
+ width,
+ nextTile) == 2);
+ REQUIRE(width == 96);
+ REQUIRE(nextTile == 84);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 16,
+ 100 - 16,
+ width,
+ nextTile) == 1);
+ REQUIRE(width == 64);
+ REQUIRE(nextTile == 83);
+
+ REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 17,
+ 100 - 17,
+ width,
+ nextTile) == 0);
+ REQUIRE(width == 32);
+ REQUIRE(nextTile == 82);
+ }
+
+ delete layer;
+ delete img1;
+ delete img2;
+ delete img3;
+}
+
+
+TEST_CASE("MapLayer getEmptyTileDrawWidth")
+{
+ Image *const img1 = new Image(32, 32);
+ Image *const img2 = new Image(32, 32);
+ Image *const img3 = new Image(32, 32);
+ MapLayer *layer = nullptr;
+ int nextTile;
+
+ SECTION("simple 2")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 2, 1,
+ false,
+ 0,
+ 0);
+ layer->setTile(0, 0, img1);
+ TileInfo *const tiles = layer->getTiles();
+ REQUIRE(layer->getEmptyTileDrawWidth(tiles + 1,
+ 1,
+ nextTile) == 0);
+ REQUIRE(nextTile == 0);
+ }
+
+ SECTION("simple 4")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 3, 1,
+ false,
+ 0,
+ 0);
+ layer->setTile(0, 0, img1);
+ layer->setTile(2, 0, img1);
+ TileInfo *const tiles = layer->getTiles();
+ REQUIRE(layer->getEmptyTileDrawWidth(tiles + 1,
+ 2,
+ nextTile) == 0);
+ REQUIRE(nextTile == 0);
+ }
+
+ SECTION("simple 5")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 3, 1,
+ false,
+ 0,
+ 0);
+ layer->setTile(0, 0, img1);
+ layer->setTile(1, 0, img1);
+ TileInfo *const tiles = layer->getTiles();
+ REQUIRE(layer->getEmptyTileDrawWidth(tiles + 2,
+ 1,
+ nextTile) == 0);
+ REQUIRE(nextTile == 0);
+ }
+
+ SECTION("normal 1")
+ {
+ MapLayer *layer = new MapLayer("test",
+ 0, 0,
+ 100, 100,
+ false,
+ 0,
+ 0);
+ layer->setTile(1, 10, img1);
+ layer->setTile(2, 10, img1);
+ layer->setTile(3, 10, img1);
+ layer->setTile(4, 10, img2);
+ layer->setTile(5, 10, nullptr);
+ layer->setTile(6, 10, img2);
+ layer->setTile(7, 10, nullptr);
+ layer->setTile(8, 10, nullptr);
+ layer->setTile(9, 10, img2);
+ layer->setTile(10, 10, img2);
+ layer->setTile(11, 10, img3);
+ layer->setTile(12, 10, nullptr);
+ layer->setTile(13, 10, nullptr);
+ layer->setTile(14, 10, nullptr);
+ layer->setTile(15, 10, img1);
+ layer->setTile(16, 10, img1);
+ layer->setTile(17, 10, img1);
+ TileInfo *const tiles = layer->getTiles();
+
+ REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 0,
+ 100 - 0,
+ nextTile) == 0);
+ REQUIRE(nextTile == 0);
+
+ REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 5,
+ 100 - 5,
+ nextTile) == 0);
+ REQUIRE(nextTile == 0);
+
+ REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 7,
+ 100 - 7,
+ nextTile) == 1);
+ REQUIRE(nextTile == 1);
+
+ REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 8,
+ 100 - 8,
+ nextTile) == 0);
+ REQUIRE(nextTile == 0);
+
+ REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 12,
+ 100 - 12,
+ nextTile) == 2);
+ REQUIRE(nextTile == 2);
+
+ REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 13,
+ 100 - 13,
+ nextTile) == 1);
+ REQUIRE(nextTile == 1);
+
+ REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 14,
+ 100 - 14,
+ nextTile) == 0);
+ REQUIRE(nextTile == 0);
+ }
+
+ delete layer;
+ delete img1;
+ delete img2;
+ delete img3;
+}
diff --git a/src/resources/map/tileinfo.h b/src/resources/map/tileinfo.h
index 764df0fb4..a15a5dc01 100644
--- a/src/resources/map/tileinfo.h
+++ b/src/resources/map/tileinfo.h
@@ -31,13 +31,20 @@ struct TileInfo final
image(nullptr),
width(0),
count(1),
+ nextTile(1),
isEnabled(true)
{
}
+ /* tile image */
Image *image;
+ /* repeated tile width in pixels */
int width;
+ /* repeated tiles count - 1 */
int count;
+ /* number of tiles to get next tile */
+ int nextTile;
+ /* is tile enabled flag. if set to true, also mean image is non null */
bool isEnabled;
};