roo_display
API Documentation for roo_display
Loading...
Searching...
No Matches
shadow.cpp
Go to the documentation of this file.
2
3namespace roo_display {
4
5namespace {
6
7inline uint16_t isqrt32(uint32_t x) {
8 uint32_t r = 0, r2 = 0;
9 for (int p = 15; p >= 0; --p) {
10 uint32_t tr2 = r2 + (r << (p + 1)) + ((uint32_t)1u << (p + p));
11 if (tr2 <= x) {
12 r2 = tr2;
13 r |= ((uint32_t)1u << p);
14 }
15 }
16 return r;
17}
18
19// Returns the diffusion of the shadow at the specified (x, y) pixel within a
20// shadow given by the spec. Returned value is from 0 (no diffusion) to 16 *
21// extents.
22inline uint16_t calcShadowDiffusion(const RoundRectShadow::Spec& spec,
23 int16_t x, int16_t y) {
24 x -= spec.x;
25 y -= spec.y;
26
27 // We need to consider 9 cases:
28 //
29 // 123
30 // 456
31 // 789
32 //
33 // We will fold them to
34 //
35 // 12
36 // 34
37 if (x >= spec.w - spec.radius) {
38 x += spec.radius - spec.w + 1;
39 } else {
40 x = spec.radius - x;
41 }
42 if (y >= spec.h - spec.radius) {
43 y += spec.radius - spec.h + 1;
44 } else {
45 y = spec.radius - y;
46 }
47 if (x <= 0) {
48 if (y > 0) return 16 * y; // Case 2.
49 return 0; // Case 4.
50 }
51 if (y <= 0) return 16 * x; // Case 3.
52 // Now what's left is Case 1.
53 return isqrt32(256 * (x * x + y * y));
54}
55
56// Calculates alpha component of the specified (x, y) point within a shadow
57// given by the spec.
58inline uint8_t calcShadowAlpha(const RoundRectShadow::Spec& spec, int16_t x,
59 int16_t y) {
60 uint16_t d = calcShadowDiffusion(spec, x, y);
61 if (d > spec.border * 16) {
62 if (d > spec.radius * 16) {
63 return 0;
64 } else {
65 return spec.alpha_start -
66 ((uint32_t)((d - spec.border * 16) * spec.alpha_step) / 256 / 16);
67 }
68 }
69 return spec.alpha_start;
70}
71
72} // namespace
73
77 : object_extents_(extents), corner_radius_(corner_radius), color_(color) {
79 spec_.x = extents.xMin() - blur_radius + dx;
80 spec_.y = extents.yMin() - blur_radius + dy;
81 spec_.w = extents.width() + 2 * blur_radius;
82 spec_.h = extents.height() + 2 * blur_radius;
83 spec_.alpha_start = color_.a();
84 spec_.alpha_step =
85 (blur_radius == 0) ? 0 : 256 * spec_.alpha_start / blur_radius;
86 spec_.border = corner_radius;
87
88 shadow_extents_ =
89 Box(spec_.x, spec_.y, spec_.x + spec_.w - 1, spec_.y + spec_.h - 1);
90}
91
93 uint32_t count, Color* result) const {
94 while (count-- > 0) {
95 *result++ = color_.withA(calcShadowAlpha(spec_, *x++, *y++));
96 }
97}
98
100 int16_t yMax,
101 roo_display::Color* result) const {
102 if (xMin >= object_extents_.xMin() + corner_radius_ &&
103 xMax <= object_extents_.xMax() - corner_radius_) {
104 if (yMin >= object_extents_.yMin() && yMax <= object_extents_.yMax()) {
105 // Interior of the shadow.
106 *result = color_;
107 return true;
108 }
109 // Pixel color in this range does not depend on the specific x value at
110 // all, so we can compute only one vertical stripe and replicate it.
111 for (int16_t y = yMin; y <= yMax; ++y) {
112 Color c = color_.withA(calcShadowAlpha(spec_, xMin, y));
113 for (int16_t x = xMin; x <= xMax; ++x) {
114 *result++ = c;
115 }
116 }
117 return false;
118 } else if (yMin >= object_extents_.yMin() + corner_radius_ &&
119 yMax <= object_extents_.yMax() - corner_radius_) {
120 // Pixel color in this range does not depend on the specific y value
121 // at all, so we can compute only one horizontal stripe and replicate it.
122 for (int16_t x = xMin; x <= xMax; ++x) {
123 Color c = color_.withA(calcShadowAlpha(spec_, x, yMin));
124 Color* ptr = result++;
125 int16_t stride = (xMax - xMin + 1);
126 for (int16_t y = yMin; y <= yMax; ++y) {
127 *ptr = c;
128 ptr += stride;
129 }
130 }
131 return false;
132 }
133 for (int16_t y = yMin; y <= yMax; ++y) {
134 for (int16_t x = xMin; x <= xMax; ++x) {
135 *result++ = color_.withA(calcShadowAlpha(spec_, x, y));
136 }
137 }
138 return false;
139}
140
141} // namespace roo_display
Axis-aligned integer rectangle.
Definition box.h:12
int16_t width() const
Width in pixels (inclusive coordinates).
Definition box.h:77
int16_t xMin() const
Minimum x (inclusive).
Definition box.h:65
int16_t xMax() const
Maximum x (inclusive).
Definition box.h:71
int16_t height() const
Height in pixels (inclusive coordinates).
Definition box.h:80
int16_t yMax() const
Maximum y (inclusive).
Definition box.h:74
int16_t yMin() const
Minimum y (inclusive).
Definition box.h:68
ARGB8888 color stored as a 32-bit unsigned integer.
Definition color.h:16
constexpr uint8_t a() const
Alpha channel.
Definition color.h:36
constexpr Color withA(uint8_t a) const
Return a copy with the specified alpha channel.
Definition color.h:69
void readColors(const int16_t *x, const int16_t *y, uint32_t count, Color *result) const override
Read colors for the given points.
Definition shadow.cpp:92
Box extents() const override
Return the bounding box encompassing all pixels that need to be drawn.
Definition shadow.h:37
bool readColorRect(int16_t xMin, int16_t yMin, int16_t xMax, int16_t yMax, roo_display::Color *result) const override
Read colors for a rectangle.
Definition shadow.cpp:99
RoundRectShadow(roo_display::Box extents, Color color, uint8_t blur_radius, uint8_t dx, uint8_t dy, uint8_t corner_radius)
Construct a rounded-rect shadow.
Definition shadow.cpp:74
Defines 140 opaque HTML named colors.
float r
Definition smooth.cpp:474