mirror of
https://github.com/luanti-org/luanti.git
synced 2025-08-21 18:11:11 +00:00
Extract bitmap class
This commit is contained in:
parent
f2eb5e7a93
commit
e835673c5e
2 changed files with 95 additions and 44 deletions
|
@ -4,54 +4,12 @@
|
||||||
|
|
||||||
#include "imagefilters.h"
|
#include "imagefilters.h"
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
|
#include "util/bitmap.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <IVideoDriver.h>
|
#include <IVideoDriver.h>
|
||||||
|
|
||||||
// Simple 2D bitmap class with just the functionality needed here
|
|
||||||
class Bitmap {
|
|
||||||
u32 linesize, lines;
|
|
||||||
std::vector<u8> data;
|
|
||||||
|
|
||||||
static inline u32 bytepos(u32 index) { return index >> 3; }
|
|
||||||
static inline u8 bitpos(u32 index) { return index & 7; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
Bitmap(u32 width, u32 height) : linesize(width), lines(height),
|
|
||||||
data(bytepos(width * height) + 1) {}
|
|
||||||
|
|
||||||
inline bool get(u32 x, u32 y) const {
|
|
||||||
u32 index = y * linesize + x;
|
|
||||||
return data[bytepos(index)] & (1 << bitpos(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void set(u32 x, u32 y) {
|
|
||||||
u32 index = y * linesize + x;
|
|
||||||
data[bytepos(index)] |= 1 << bitpos(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool all() const {
|
|
||||||
for (u32 i = 0; i < data.size() - 1; i++) {
|
|
||||||
if (data[i] != 0xff)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// last byte not entirely filled
|
|
||||||
for (u8 i = 0; i < bitpos(linesize * lines); i++) {
|
|
||||||
bool value_of_bit = data.back() & (1 << i);
|
|
||||||
if (!value_of_bit)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void copy(Bitmap &to) const {
|
|
||||||
assert(to.linesize == linesize && to.lines == lines);
|
|
||||||
to.data = data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <bool IS_A8R8G8B8>
|
template <bool IS_A8R8G8B8>
|
||||||
static void imageCleanTransparentWithInlining(video::IImage *src, u32 threshold)
|
static void imageCleanTransparentWithInlining(video::IImage *src, u32 threshold)
|
||||||
{
|
{
|
||||||
|
@ -143,7 +101,7 @@ static void imageCleanTransparentWithInlining(video::IImage *src, u32 threshold)
|
||||||
|
|
||||||
// Apply changes to bitmap for next run. This is done so we don't introduce
|
// Apply changes to bitmap for next run. This is done so we don't introduce
|
||||||
// a bias in color propagation in the direction pixels are processed.
|
// a bias in color propagation in the direction pixels are processed.
|
||||||
newmap.copy(bitmap);
|
bitmap = newmap;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
93
src/util/bitmap.h
Normal file
93
src/util/bitmap.h
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
// Luanti
|
||||||
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
// Copyright (C) 2021-2025 sfan5
|
||||||
|
|
||||||
|
#include "irrlichttypes.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rudimentary header-only 2D bitmap class.
|
||||||
|
* @warning not thread-safe
|
||||||
|
*/
|
||||||
|
class Bitmap {
|
||||||
|
u32 linesize, lines;
|
||||||
|
std::vector<u8> data;
|
||||||
|
|
||||||
|
static inline u32 bytepos(u32 index) { return index >> 3; }
|
||||||
|
static inline u8 bitpos(u32 index) { return index & 7; }
|
||||||
|
|
||||||
|
template<bool set, bool toggle, bool clear>
|
||||||
|
bool modify_(u32 x, u32 y)
|
||||||
|
{
|
||||||
|
u32 index = y * linesize + x;
|
||||||
|
u8 mask = 1 << bitpos(index);
|
||||||
|
u8 byte = data[bytepos(index)];
|
||||||
|
if constexpr (set)
|
||||||
|
byte |= mask;
|
||||||
|
else if constexpr (toggle)
|
||||||
|
byte ^= mask;
|
||||||
|
else if constexpr (clear)
|
||||||
|
byte &= ~mask;
|
||||||
|
data[bytepos(index)] = byte;
|
||||||
|
return byte & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// @brief Create an empty bitmap
|
||||||
|
Bitmap() : linesize(0), lines(0) {}
|
||||||
|
|
||||||
|
/// @brief Create a new zero-filled bitmap
|
||||||
|
Bitmap(u32 width, u32 height)
|
||||||
|
{
|
||||||
|
resize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 width() const { return linesize; }
|
||||||
|
inline u32 height() const { return lines; }
|
||||||
|
|
||||||
|
inline void resize(u32 width, u32 height, bool initial_value=false)
|
||||||
|
{
|
||||||
|
assert(width <= 65534 && height <= 65534); // index would overflow
|
||||||
|
linesize = width;
|
||||||
|
lines = height;
|
||||||
|
data.clear(); // make sure to discard all data
|
||||||
|
if (width && height)
|
||||||
|
data.resize(bytepos(width * height) + 1, static_cast<u8>(initial_value ? 0xff : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void reset(bool value)
|
||||||
|
{
|
||||||
|
std::fill(data.begin(), data.end(), value ? 0xff : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool get(u32 x, u32 y) const
|
||||||
|
{
|
||||||
|
u32 index = y * linesize + x;
|
||||||
|
return data[bytepos(index)] & (1 << bitpos(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set(u32 x, u32 y) { modify_<1, 0, 0>(x, y); }
|
||||||
|
inline void unset(u32 x, u32 y) { modify_<0, 0, 1>(x, y); }
|
||||||
|
inline bool toggle(u32 x, u32 y) { return modify_<0, 1, 0>(x, y); }
|
||||||
|
|
||||||
|
/// @brief Returns true if all bits in the bitmap are set
|
||||||
|
inline bool all() const
|
||||||
|
{
|
||||||
|
if (!linesize || !lines)
|
||||||
|
return (assert(0), true);
|
||||||
|
for (u32 i = 0; i < data.size() - 1; i++) {
|
||||||
|
if (data[i] != 0xff)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
u8 last_byte = data.back(); // not used entirely
|
||||||
|
for (u8 i = 0; i < bitpos(linesize * lines); i++) {
|
||||||
|
if (!(last_byte & (1 << i)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Note: a 3D class could be written based on the 2D one. Or maybe the other way?
|
Loading…
Add table
Add a link
Reference in a new issue