|
|
|
@ -11,19 +11,38 @@
|
|
|
|
|
#define BITMAP_TYPE_HPP
|
|
|
|
|
|
|
|
|
|
#include "tilearea_type.h"
|
|
|
|
|
#include "core/bitmath_func.hpp"
|
|
|
|
|
#include "core/geometry_type.hpp"
|
|
|
|
|
#include "core/math_func.hpp"
|
|
|
|
|
#include <limits>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
/** Represents a tile area containing containing individually set tiles.
|
|
|
|
|
* Each tile must be contained within the preallocated area.
|
|
|
|
|
* A std::vector<bool> is used to mark which tiles are contained.
|
|
|
|
|
* A std::vector is used to mark which tiles are contained.
|
|
|
|
|
*/
|
|
|
|
|
class BitmapTileArea : public TileArea {
|
|
|
|
|
friend struct BitmapTileIterator;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
std::vector<bool> data;
|
|
|
|
|
using BlockT = uint32_t;
|
|
|
|
|
static constexpr uint BLOCK_BITS = std::numeric_limits<BlockT>::digits;
|
|
|
|
|
|
|
|
|
|
inline uint Index(uint x, uint y) const { return y * this->w + x; }
|
|
|
|
|
std::vector<BlockT> data;
|
|
|
|
|
|
|
|
|
|
inline uint Index(TileIndex tile) const { return Index(TileX(tile) - TileX(this->tile), TileY(tile) - TileY(this->tile)); }
|
|
|
|
|
inline uint RowPitch() const { return CeilDivT<uint>(this->w, BLOCK_BITS); }
|
|
|
|
|
|
|
|
|
|
inline void ResetData()
|
|
|
|
|
{
|
|
|
|
|
this->data.assign(this->h * this->RowPitch(), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline std::pair<uint, uint> Index(uint x, uint y) const
|
|
|
|
|
{
|
|
|
|
|
return { (y * this->RowPitch()) + (x / BLOCK_BITS), x % BLOCK_BITS };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline std::pair<uint, uint> Index(TileIndex tile) const { return this->Index(TileX(tile) - TileX(this->tile), TileY(tile) - TileY(this->tile)); }
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
BitmapTileArea()
|
|
|
|
@ -38,7 +57,7 @@ public:
|
|
|
|
|
this->tile = ta.tile;
|
|
|
|
|
this->w = ta.w;
|
|
|
|
|
this->h = ta.h;
|
|
|
|
|
this->data.resize(Index(this->w, this->h));
|
|
|
|
|
this->ResetData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -61,8 +80,7 @@ public:
|
|
|
|
|
this->tile = TileXY(r.left, r.top);
|
|
|
|
|
this->w = r.Width();
|
|
|
|
|
this->h = r.Height();
|
|
|
|
|
this->data.clear();
|
|
|
|
|
this->data.resize(Index(w, h));
|
|
|
|
|
this->ResetData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Initialize(const TileArea &ta)
|
|
|
|
@ -70,8 +88,7 @@ public:
|
|
|
|
|
this->tile = ta.tile;
|
|
|
|
|
this->w = ta.w;
|
|
|
|
|
this->h = ta.h;
|
|
|
|
|
this->data.clear();
|
|
|
|
|
this->data.resize(Index(w, h));
|
|
|
|
|
this->ResetData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -81,7 +98,8 @@ public:
|
|
|
|
|
inline void SetTile(TileIndex tile)
|
|
|
|
|
{
|
|
|
|
|
assert(this->Contains(tile));
|
|
|
|
|
this->data[Index(tile)] = true;
|
|
|
|
|
auto pos = this->Index(tile);
|
|
|
|
|
SetBit(this->data[pos.first], pos.second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -91,16 +109,21 @@ public:
|
|
|
|
|
inline void ClrTile(TileIndex tile)
|
|
|
|
|
{
|
|
|
|
|
assert(this->Contains(tile));
|
|
|
|
|
this->data[Index(tile)] = false;
|
|
|
|
|
auto pos = this->Index(tile);
|
|
|
|
|
ClrBit(this->data[pos.first], pos.second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetTiles(const TileArea &area);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test if a tile is part of the tile area.
|
|
|
|
|
* @param tile Tile to check
|
|
|
|
|
*/
|
|
|
|
|
inline bool HasTile(TileIndex tile) const
|
|
|
|
|
{
|
|
|
|
|
return this->Contains(tile) && this->data[Index(tile)];
|
|
|
|
|
if (!this->Contains(tile)) return false;
|
|
|
|
|
auto pos = this->Index(tile);
|
|
|
|
|
return HasBit(this->data[pos.first], pos.second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool operator==(const BitmapTileArea &other) const
|
|
|
|
@ -110,25 +133,62 @@ public:
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** Iterator to iterate over all tiles belonging to a bitmaptilearea. */
|
|
|
|
|
class BitmapTileIterator : public OrthogonalTileIterator {
|
|
|
|
|
class BitmapTileIterator : public TileIterator {
|
|
|
|
|
protected:
|
|
|
|
|
const BitmapTileArea *bitmap;
|
|
|
|
|
BitmapTileArea::BlockT block; ///< Current block data.
|
|
|
|
|
const BitmapTileArea::BlockT *next; ///< Next block pointer.
|
|
|
|
|
uint block_x; ///< The current 'x' position in the block iteration.
|
|
|
|
|
uint y; ///< The current 'y' position in the rectangle.
|
|
|
|
|
TileIndex row_start; ///< Row start tile.
|
|
|
|
|
uint pitch; ///< The row pitch.
|
|
|
|
|
|
|
|
|
|
void advance()
|
|
|
|
|
{
|
|
|
|
|
while (this->block == 0) {
|
|
|
|
|
this->block_x++;
|
|
|
|
|
if (this->block_x == this->pitch) {
|
|
|
|
|
/* Next row */
|
|
|
|
|
this->y--;
|
|
|
|
|
if (this->y == 0) {
|
|
|
|
|
/* End */
|
|
|
|
|
this->tile = INVALID_TILE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this->block_x = 0;
|
|
|
|
|
this->row_start += MapSizeX();
|
|
|
|
|
}
|
|
|
|
|
/* Read next block and advance next pointer */
|
|
|
|
|
this->block = *this->next;
|
|
|
|
|
this->next++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t bit = FindFirstBit(this->block);
|
|
|
|
|
this->block = KillFirstBit(this->block);
|
|
|
|
|
this->tile = this->row_start + (this->block_x * BitmapTileArea::BLOCK_BITS) + bit;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* Construct the iterator.
|
|
|
|
|
* @param bitmap BitmapTileArea to iterate.
|
|
|
|
|
*/
|
|
|
|
|
BitmapTileIterator(const BitmapTileArea &bitmap) : OrthogonalTileIterator(bitmap), bitmap(&bitmap)
|
|
|
|
|
BitmapTileIterator(const BitmapTileArea &bitmap) : TileIterator(), block_x(0), y(bitmap.h), row_start(bitmap.tile), pitch(bitmap.RowPitch())
|
|
|
|
|
{
|
|
|
|
|
if (!this->bitmap->HasTile(TileIndex(this->tile))) ++(*this);
|
|
|
|
|
if (!bitmap.data.empty()) {
|
|
|
|
|
this->block = bitmap.data[0];
|
|
|
|
|
this->next = bitmap.data.data() + 1;
|
|
|
|
|
this->advance();
|
|
|
|
|
} else {
|
|
|
|
|
this->block = 0;
|
|
|
|
|
this->next = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline TileIterator& operator ++() override
|
|
|
|
|
{
|
|
|
|
|
(*this).OrthogonalTileIterator::operator++();
|
|
|
|
|
while (this->tile != INVALID_TILE && !this->bitmap->HasTile(TileIndex(this->tile))) {
|
|
|
|
|
(*this).OrthogonalTileIterator::operator++();
|
|
|
|
|
}
|
|
|
|
|
assert(this->tile != INVALID_TILE);
|
|
|
|
|
this->advance();
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|