diff --git a/src/etc-internal.h b/src/etc-internal.h index 6b010b3..4cbc704 100644 --- a/src/etc-internal.h +++ b/src/etc-internal.h @@ -136,6 +136,11 @@ struct Vec2i return Vec2i(x % value, y % value); } + Vec2i operator&(unsigned value) const + { + return Vec2i(x & value, y & value); + } + Vec2i operator-() const { return Vec2i(-x, -y); diff --git a/src/tilemap-common.h b/src/tilemap-common.h index 45ee91c..76dcf15 100644 --- a/src/tilemap-common.h +++ b/src/tilemap-common.h @@ -46,6 +46,13 @@ wrap(int value, int range) return res < 0 ? res + range : res; } +static inline Vec2i +wrap(const Vec2i &value, int range) +{ + return Vec2i(wrap(value.x, range), + wrap(value.y, range)); +} + static inline int16_t tableGetWrapped(const Table &t, int x, int y, int z = 0) { diff --git a/src/tilemapvx.cpp b/src/tilemapvx.cpp index 57abe26..5773110 100644 --- a/src/tilemapvx.cpp +++ b/src/tilemapvx.cpp @@ -57,12 +57,12 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader Table *mapData; Table *flags; - Vec2i offset; + Vec2i origin; - Vec2i dispPos; - /* Map viewport position */ + /* Subregion of the map that is drawn to screen (map viewport) */ IntRect mapViewp; - Vec2i sceneOffset; + /* Position on screen the map subregion is drawn at */ + Vec2i dispPos; Scene::Geometry sceneGeo; std::vector groundVert; @@ -179,48 +179,29 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader TileAtlasVX::build(atlas, bitmaps); } - void updatePosition() - { - dispPos = -(offset - mapViewp.pos() * 32) + sceneOffset; - } - void updateMapViewport() { - int tileOX, tileOY; + IntRect newMvp; - Vec2i offs = offset + sceneGeo.orig; + const Vec2i combOrigin = origin + sceneGeo.orig; + const Vec2i geoSize = sceneGeo.rect.size(); - if (offs.x >= 0) - tileOX = offs.x / 32; - else - tileOX = -(-(offs.x-31) / 32); + /* Round the combined origin (which is in pixels) down to the nearest + * top left tile boundary, by masking off the lower 5 bits (2^5 = 32) */ + newMvp.setPos((combOrigin & ~(32-1)) / 32); - if (offs.y >= 0) - tileOY = offs.y / 32; - else - tileOY = -(-(offs.y-31) / 32); + /* Ensure that the size is big enough to cover the whole viewport, + * and add one tile row/column as a buffer for scrolling */ + newMvp.setSize((geoSize / 32) + !!(geoSize % 32) + Vec2i(1)); - bool dirty = false; - - if (tileOX < mapViewp.x || tileOX > mapViewp.x) - { - mapViewp.x = tileOX; - dirty = true; - } - - if (tileOY < mapViewp.y || tileOY > mapViewp.y) - { - mapViewp.y = tileOY; - dirty = true; - } - - if (dirty) + if (newMvp != mapViewp) { + mapViewp = newMvp; + flashMap.setViewport(newMvp); buffersDirty = true; } - updatePosition(); - flashMap.setViewport(mapViewp); + dispPos = sceneGeo.rect.pos() - wrap(combOrigin, 32); } static size_t quadBytes(size_t quads) @@ -365,10 +346,6 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader void onGeometryChange(const Scene::Geometry &geo) { - const Vec2i geoSize = geo.rect.size(); - mapViewp.setSize((geoSize / 32) + !!(geoSize % 32) + Vec2i(1)); - - sceneOffset = geo.offset(); sceneGeo = geo; buffersDirty = true; @@ -379,7 +356,7 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader /* TileAtlasVX::Reader */ void onQuads(const FloatRect *t, const FloatRect *p, - size_t n, bool overPlayer) + size_t n, bool overPlayer) { SVertex *vert = allocVert(overPlayer ? aboveVert : groundVert, n*4); @@ -466,8 +443,8 @@ TilemapVX::BitmapArray &TilemapVX::getBitmapArray() DEF_ATTR_RD_SIMPLE(TilemapVX, MapData, Table*, p->mapData) DEF_ATTR_RD_SIMPLE(TilemapVX, FlashData, Table*, p->flashMap.getData()) DEF_ATTR_RD_SIMPLE(TilemapVX, Flags, Table*, p->flags) -DEF_ATTR_RD_SIMPLE(TilemapVX, OX, int, p->offset.x) -DEF_ATTR_RD_SIMPLE(TilemapVX, OY, int, p->offset.y) +DEF_ATTR_RD_SIMPLE(TilemapVX, OX, int, p->origin.x) +DEF_ATTR_RD_SIMPLE(TilemapVX, OY, int, p->origin.y) Viewport *TilemapVX::getViewport() const { @@ -540,10 +517,10 @@ void TilemapVX::setOX(int value) { guardDisposed(); - if (p->offset.x == value) + if (p->origin.x == value) return; - p->offset.x = value; + p->origin.x = value; p->mapViewportDirty = true; } @@ -551,10 +528,10 @@ void TilemapVX::setOY(int value) { guardDisposed(); - if (p->offset.y == value) + if (p->origin.y == value) return; - p->offset.y = value; + p->origin.y = value; p->mapViewportDirty = true; }