Files
klubhaus-doorbell/libraries/FastLED/src/fl/tile2x2.cpp
2026-02-12 00:45:31 -08:00

170 lines
4.9 KiB
C++

#include "fl/tile2x2.h"
#include "crgb.h"
#include "fl/draw_visitor.h"
#include "fl/math_macros.h"
#include "fl/raster.h"
#include "fl/raster_sparse.h"
#include "fl/unused.h"
#include "fl/warn.h"
#include "fl/xymap.h"
#include "fl/vector.h"
namespace fl {
namespace {
static vec2<u16> wrap(const vec2<u16> &v, const vec2<u16> &size) {
// Wrap the vector v around the size
return vec2<u16>(v.x % size.x, v.y % size.y);
}
static vec2<u16> wrap_x(const vec2<u16> &v, const u16 width) {
// Wrap the x component of the vector v around the size
return vec2<u16>(v.x % width, v.y);
}
} // namespace
Tile2x2_u8_wrap::Tile2x2_u8_wrap() {
mData[0][0] = {vec2<u16>(0, 0), 0};
mData[0][1] = {vec2<u16>(0, 1), 0};
mData[1][0] = {vec2<u16>(1, 0), 0};
mData[1][1] = {vec2<u16>(1, 1), 0};
}
void Tile2x2_u8::Rasterize(const span<const Tile2x2_u8> &tiles,
XYRasterU8Sparse *out_raster) {
out_raster->rasterize(tiles);
}
void Tile2x2_u8::draw(const CRGB &color, const XYMap &xymap, CRGB *out) const {
XYDrawComposited visitor(color, xymap, out);
draw(xymap, visitor);
}
void Tile2x2_u8::scale(u8 scale) {
// scale the tile
if (scale == 255) {
return;
}
for (int x = 0; x < 2; ++x) {
for (int y = 0; y < 2; ++y) {
u16 value = at(x, y);
at(x, y) = (value * scale) >> 8;
}
}
}
Tile2x2_u8_wrap::Tile2x2_u8_wrap(const Tile2x2_u8 &from, u16 width) {
const vec2<u16> origin = from.origin();
at(0, 0) = {wrap_x(vec2<u16>(origin.x, origin.y), width), from.at(0, 0)};
at(0, 1) = {wrap_x(vec2<u16>(origin.x, origin.y + 1), width), from.at(0, 1)};
at(1, 0) = {wrap_x(vec2<u16>(origin.x + 1, origin.y), width), from.at(1, 0)};
at(1, 1) = {wrap_x(vec2<u16>(origin.x + 1, origin.y + 1), width),
from.at(1, 1)};
}
Tile2x2_u8_wrap::Entry &Tile2x2_u8_wrap::at(u16 x, u16 y) {
// Wrap around the edges
x = (x + 2) % 2;
y = (y + 2) % 2;
return mData[y][x];
}
Tile2x2_u8_wrap::Tile2x2_u8_wrap(const Data& data) {
mData[0][0] = data[0][0];
mData[0][1] = data[0][1];
mData[1][0] = data[1][0];
mData[1][1] = data[1][1];
}
const Tile2x2_u8_wrap::Entry &Tile2x2_u8_wrap::at(u16 x, u16 y) const {
// Wrap around the edges
x = (x + 2) % 2;
y = (y + 2) % 2;
return mData[y][x];
}
Tile2x2_u8_wrap::Tile2x2_u8_wrap(const Tile2x2_u8 &from, u16 width,
u16 height) {
const vec2<u16> origin = from.origin();
at(0, 0) = {wrap(vec2<u16>(origin.x, origin.y), vec2<u16>(width, height)),
from.at(0, 0)};
at(0, 1) = {wrap(vec2<u16>(origin.x, origin.y + 1), vec2<u16>(width, height)),
from.at(0, 1)};
at(1, 0) = {wrap(vec2<u16>(origin.x + 1, origin.y), vec2<u16>(width, height)),
from.at(1, 0)};
at(1,
1) = {wrap(vec2<u16>(origin.x + 1, origin.y + 1), vec2<u16>(width, height)),
from.at(1, 1)};
}
u8 Tile2x2_u8::maxValue() const {
u8 max = 0;
max = MAX(max, at(0, 0));
max = MAX(max, at(0, 1));
max = MAX(max, at(1, 0));
max = MAX(max, at(1, 1));
return max;
}
Tile2x2_u8 Tile2x2_u8::MaxTile(const Tile2x2_u8 &a, const Tile2x2_u8 &b) {
Tile2x2_u8 result;
for (int x = 0; x < 2; ++x) {
for (int y = 0; y < 2; ++y) {
result.at(x, y) = MAX(a.at(x, y), b.at(x, y));
}
}
return result;
}
rect<u16> Tile2x2_u8::bounds() const {
vec2<u16> min = mOrigin;
vec2<u16> max = mOrigin + vec2<u16>(2, 2);
return rect<u16>(min, max);
}
fl::vector_fixed<Tile2x2_u8_wrap, 2> Tile2x2_u8_wrap::Interpolate(const Tile2x2_u8_wrap& a, const Tile2x2_u8_wrap& b, float t) {
fl::vector_fixed<Tile2x2_u8_wrap, 2> result;
// Clamp t to [0, 1]
if (t <= 0.0f) {
result.push_back(a);
return result;
}
if (t >= 1.0f) {
result.push_back(b);
return result;
}
// Create interpolated tile
Tile2x2_u8_wrap interpolated;
// Interpolate each of the 4 positions
for (u16 x = 0; x < 2; ++x) {
for (u16 y = 0; y < 2; ++y) {
const auto& data_a = a.at(x, y);
const auto& data_b = b.at(x, y);
// For now, assume positions are the same or close enough
// Use position from 'a' as the base
vec2<u16> pos = data_a.first;
// Simple linear interpolation for alpha values
u8 alpha_a = data_a.second;
u8 alpha_b = data_b.second;
// Linear interpolation: a + t * (b - a)
float alpha_float = alpha_a + t * (alpha_b - alpha_a);
u8 interpolated_alpha = static_cast<u8>(alpha_float + 0.5f); // Round to nearest
interpolated.mData[y][x] = {pos, interpolated_alpha};
}
}
result.push_back(interpolated);
return result;
}
} // namespace fl