From 537085e221d25f710ed7162e1fc8add8ffe4a72f Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Sat, 31 Dec 2016 05:04:16 +0300 Subject: Improve fringe map layers drawing. Pre cache next tile position with image. --- src/Makefile.am | 1 + src/resources/image/image.cpp | 30 +++ src/resources/image/image.h | 5 + src/resources/map/maplayer.cpp | 55 +++- src/resources/map/maplayer.h | 16 +- src/resources/map/maplayer_unittest.cc | 451 +++++++++++++++++++++++++++++++++ src/resources/map/tileinfo.h | 7 + 7 files changed, 550 insertions(+), 15 deletions(-) create mode 100644 src/resources/map/maplayer_unittest.cc diff --git a/src/Makefile.am b/src/Makefile.am index bd5515604..92a47e25f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1890,6 +1890,7 @@ manaplustests_SOURCES = ${manaplus_SOURCES} \ resources/dye/dyepalette_unittest.cc \ integrity_unittest.cc \ utils/chatutils_unittest.cc \ + resources/map/maplayer_unittest.cc \ resources/resourcemanager/resourcemanager_unittest.cc \ gui/windowmanager_unittest.cc endif 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 . + */ + +#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; }; -- cgit v1.2.3-70-g09d2