A field of falling diagonal rain streaks, in the visual grammar of the Deluge logo.
More...
#include <rainfall.h>
|
| struct | Block |
| | A single square block of a streak. More...
|
| struct | Streak |
| | A streak's shape and position, without its motion. Exposed so the spacing rule can be unit-tested against hand-built cases. More...
|
| struct | Drop |
| struct | Logo |
| | The whole logo, as one object. More...
|
|
|
| Rainfall () |
| | Construct a field that is already populated, so the first rendered frame is not empty.
|
| void | scatter () |
| | Re-seed every drop across the panel.
|
|
void | advance () |
| | Advance every drop one frame, respawning any whose tail has left the panel.
|
| size_t | lengthOf (size_t drop) const |
| | Cells in a drop's streak.
|
| Block | cellAt (size_t drop, size_t cell) const |
| | One block of a drop's streak.
|
| float | speedOf (size_t drop) const |
| | Speed of a drop, px per frame. Exposed for tests.
|
|
| static constexpr float | minGapFor (int32_t size) |
| | Minimum distance allowed between two live drops of the same block size, px.
|
| static float | separationSquared (const Streak &a, const Streak &b) |
| | Squared distance between two streaks, px squared.
|
|
| static constexpr float | kLogoSmallScaleChance = 0.10f |
| | Chance a logo is emitted at the smallest cell scale.
|
Mirrors OLED_MAIN_WIDTH_PIXELS, OLED_MAIN_HEIGHT_PIXELS and OLED_MAIN_TOPMOST_PIXEL. screensaver.cpp static_asserts these against the real macros, so they cannot drift.
|
|
static constexpr int32_t | kWidth = 128 |
|
static constexpr int32_t | kHeight = 48 |
|
static constexpr int32_t | kTopmost = 5 |
|
static constexpr int32_t | kVisibleHeight = kHeight - kTopmost |
|
static constexpr size_t | kNumDrops = 34 |
| | Drops in the field at once.
|
|
static constexpr float | kSpeedFar = 0.5f |
| | Speed of the most distant drops, px per frame, applied to both axes. On the kSpeedStep grid.
|
| static constexpr float | kSpeedNear = 1.5f |
| | Speed of the nearest drops, px per frame, applied to both axes. On the kSpeedStep grid.
|
| static constexpr float | kSpeedStep = 0.25f |
| | Granularity every drop's speed is snapped to, px per frame.
|
| static constexpr float | kSpawnFromTop = static_cast<float>(kWidth) / static_cast<float>(kWidth + kVisibleHeight) |
| | Chance that a respawning drop enters through the top edge rather than the left.
|
|
static constexpr int32_t | kSpawnAttempts = 6 |
| | Candidate positions tried per spawn before settling for the roomiest one found.
|
|
| uint32_t | nextRandom () |
| | Step the linear congruential generator.
|
| float | nextRandomFloat () |
| | Step the linear congruential generator, mapped to [0, 1).
|
| void | roll (Drop &drop) |
| | Give a drop a fresh depth, and the size, speed and length that follow from it.
|
| void | place (Drop &drop, bool seeded) |
| | Position a drop, either scattered across the panel or entering an edge.
|
|
void | emitLogo () |
| | Start a logo falling, picking its scale, speed and entry edge.
|
|
void | advanceLogo () |
| | Move the live logo, retire it once clear, and run the emission countdown.
|
| int32_t | nextLogoInterval () |
| void | spawn (size_t index, bool seeded) |
| | Replace drops_[index], honouring the minimum-spacing rule.
|
|
| static constexpr float | reachOf (int32_t size, int32_t length) |
| | Distance a streak's tail trails behind its head, on each axis, in pixels.
|
| static Streak | streakOf (const Drop &drop) |
| | Extract a drop's shape and position as a Streak, for spacing checks.
|
|
Every few minutes one complete Deluge logo falls through the field and leaves. It is one object rather than seven drops: the bootloader's logo is exactly seven diagonal runs of three or four cells – the rain's own vocabulary, arranged – so its 25 cells sit at fixed offsets from a single origin.
|
|
static constexpr size_t | kLogoCells = 25 |
| | Cells in the logo's grid, and the width and height of that grid in cells.
|
|
static constexpr int32_t | kLogoGridWidth = 11 |
|
static constexpr int32_t | kLogoGridHeight = 10 |
| static constexpr int32_t | kLogoIntervalMinFrames = 2400 |
| | Shortest and longest wait between logo emissions, in frames.
|
|
static constexpr int32_t | kLogoIntervalMaxFrames = 7200 |
| bool | logoActive () const |
| Block | logoCellAt (size_t cell) const |
| | One cell of the logo.
|
| int32_t | logoScale () const |
| | Cell scale of the live logo, in pixels. Exposed for tests.
|
| float | logoSpeed () const |
| | Speed of the live logo, px per frame. Exposed for tests.
|
| void | forceLogo () |
| | Emit a logo on the next advance(), whatever the countdown says.
|
A field of falling diagonal rain streaks, in the visual grammar of the Deluge logo.
Each drop is a rigid streak of three or four square cells stepping down-right at 45 degrees, exactly as the streaks in the bootloader's logo do. Nothing ever draws the logo itself.
- Note
- Deliberately has no display dependency, so the motion maths is unit-testable on the host and the ASCII preview harness can drive it. That is why the panel dimensions below are repeated rather than included – cpu_specific.h is target-only.
◆ cellAt()
| Rainfall::Block deluge::hid::display::Rainfall::cellAt |
( |
size_t | drop, |
|
|
size_t | cell ) const |
|
nodiscard |
One block of a drop's streak.
- Parameters
-
| drop | Drop index, less than kNumDrops. |
| cell | Cell index, less than lengthOf(drop). Cell 0 leads, at the bottom-right. |
- Returns
- The block's unclipped position and pixel size.
◆ forceLogo()
| void deluge::hid::display::Rainfall::forceLogo |
( |
| ) |
|
|
inline |
Emit a logo on the next advance(), whatever the countdown says.
- Note
- For the preview harness: the interval is minutes long, so the animation would otherwise be uninspectable without waiting it out. Does nothing if one is already up.
◆ lengthOf()
| size_t deluge::hid::display::Rainfall::lengthOf |
( |
size_t | drop | ) |
const |
|
inlinenodiscard |
Cells in a drop's streak.
- Parameters
-
| drop | Drop index, less than kNumDrops. |
- Returns
- 3 or 4, matching the streak lengths in the bootloader's logo.
◆ logoActive()
| bool deluge::hid::display::Rainfall::logoActive |
( |
| ) |
const |
|
inlinenodiscard |
- Returns
- True while a logo is on or approaching the panel.
◆ logoCellAt()
| Rainfall::Block deluge::hid::display::Rainfall::logoCellAt |
( |
size_t | cell | ) |
const |
|
nodiscard |
One cell of the logo.
- Precondition
- logoActive() is true.
- Parameters
-
| cell | Cell index, less than kLogoCells. |
- Returns
- The cell's unclipped block position and pixel size.
◆ logoScale()
| int32_t deluge::hid::display::Rainfall::logoScale |
( |
| ) |
const |
|
inlinenodiscard |
Cell scale of the live logo, in pixels. Exposed for tests.
- Returns
- 1, 2 or 3; zero when no logo is active.
◆ logoSpeed()
| float deluge::hid::display::Rainfall::logoSpeed |
( |
| ) |
const |
|
inlinenodiscard |
Speed of the live logo, px per frame. Exposed for tests.
- Returns
- The logo's speed, always a multiple of kSpeedStep; zero when none is active.
◆ minGapFor()
| constexpr float deluge::hid::display::Rainfall::minGapFor |
( |
int32_t | size | ) |
|
|
inlinestaticnodiscardconstexpr |
Minimum distance allowed between two live drops of the same block size, px.
- Note
- Only same-size pairs are checked. A near streak passing over a far one is the parallax reading correctly, and preventing it would need per-frame work.
- Parameters
-
| size | Block size in pixels: 1, 2 or 3. |
- Returns
- The minimum permitted distance in pixels.
◆ nextLogoInterval()
| int32_t deluge::hid::display::Rainfall::nextLogoInterval |
( |
| ) |
|
|
private |
- Returns
- A fresh wait before the next emission, in frames.
◆ nextRandom()
| uint32_t deluge::hid::display::Rainfall::nextRandom |
( |
| ) |
|
|
private |
Step the linear congruential generator.
- Returns
- The new RNG state.
◆ nextRandomFloat()
| float deluge::hid::display::Rainfall::nextRandomFloat |
( |
| ) |
|
|
private |
Step the linear congruential generator, mapped to [0, 1).
- Returns
- The next LCG output, mapped to [0, 1).
◆ place()
| void deluge::hid::display::Rainfall::place |
( |
Drop & | drop, |
|
|
bool | seeded ) |
|
private |
Position a drop, either scattered across the panel or entering an edge.
- Parameters
-
| drop | The drop to position in place. |
| seeded | True to place it anywhere on the panel, false to enter the top or left edge. |
◆ reachOf()
| constexpr float deluge::hid::display::Rainfall::reachOf |
( |
int32_t | size, |
|
|
int32_t | length ) |
|
inlinestaticnodiscardconstexprprivate |
Distance a streak's tail trails behind its head, on each axis, in pixels.
- Parameters
-
| size | Block size in pixels: 1, 2 or 3. |
| length | Streak length in cells: 3 or 4. |
- Returns
- The tail's trailing distance, in pixels.
◆ roll()
| void deluge::hid::display::Rainfall::roll |
( |
Drop & | drop | ) |
|
|
private |
Give a drop a fresh depth, and the size, speed and length that follow from it.
- Parameters
-
| drop | The drop to roll and populate in place. |
◆ scatter()
| void deluge::hid::display::Rainfall::scatter |
( |
| ) |
|
Re-seed every drop across the panel.
- Note
- Does not reseed the LCG, so successive calls produce different fields.
◆ separationSquared()
| float deluge::hid::display::Rainfall::separationSquared |
( |
const Streak & | a, |
|
|
const Streak & | b ) |
|
staticnodiscard |
Squared distance between two streaks, px squared.
Both are parallel segments at 45 degrees, so this is closed-form: the offset across travel if the two overlap along travel, otherwise the hypotenuse of the across- and along-gaps.
- Note
- Squared, so the caller compares against a squared minimum and no sqrt is needed.
- Parameters
-
| a | One streak. |
| b | The other streak. |
- Returns
- The squared distance between them, in pixels squared.
◆ spawn()
| void deluge::hid::display::Rainfall::spawn |
( |
size_t | index, |
|
|
bool | seeded ) |
|
private |
Replace drops_[index], honouring the minimum-spacing rule.
- Parameters
-
| index | Slot in drops_ to replace. |
| seeded | Forwarded to place(): true to scatter anywhere, false to enter an edge. |
◆ speedOf()
| float deluge::hid::display::Rainfall::speedOf |
( |
size_t | drop | ) |
const |
|
inlinenodiscard |
Speed of a drop, px per frame. Exposed for tests.
- Parameters
-
| drop | Drop index, less than kNumDrops. |
- Returns
- The drop's speed, always a multiple of kSpeedStep.
◆ streakOf()
| Streak deluge::hid::display::Rainfall::streakOf |
( |
const Drop & | drop | ) |
|
|
inlinestaticnodiscardprivate |
Extract a drop's shape and position as a Streak, for spacing checks.
- Parameters
-
- Returns
- The equivalent Streak.
◆ kLogoIntervalMinFrames
| int32_t deluge::hid::display::Rainfall::kLogoIntervalMinFrames = 2400 |
|
staticconstexpr |
Shortest and longest wait between logo emissions, in frames.
- Note
- 2 to 6 minutes at the screensaver's 50ms tick. Deliberately long: a sighting should be a surprise, so a short idle period usually shows none at all.
◆ kLogoSmallScaleChance
| float deluge::hid::display::Rainfall::kLogoSmallScaleChance = 0.10f |
|
staticconstexpr |
Chance a logo is emitted at the smallest cell scale.
- Note
- Weighted away from scale 1: there the logo is single pixels moving at the far layer's own speed, so the surrounding drizzle camouflages it and it reads as a dense patch of rain rather than as the mark. Acceptable as the rare case, not as a third of them.
◆ kSpawnFromTop
| float deluge::hid::display::Rainfall::kSpawnFromTop = static_cast<float>(kWidth) / static_cast<float>(kWidth + kVisibleHeight) |
|
staticconstexpr |
Chance that a respawning drop enters through the top edge rather than the left.
The ratio of the two edge lengths, which is what makes the flux uniform across the panel. Spawning only along the top starves the lower-right: everything drifts right, so a drop seeded past x = kWidth - kVisibleHeight leaves the right edge before it reaches the bottom.
◆ kSpeedNear
| float deluge::hid::display::Rainfall::kSpeedNear = 1.5f |
|
staticconstexpr |
Speed of the nearest drops, px per frame, applied to both axes. On the kSpeedStep grid.
- Note
- Above 1 px/frame a drop is not drawn at every position it passes through, so it visibly skips: measured at 24.7% of frames at 1.25 px/frame and 49.8% at 1.5. That is accepted deliberately, in exchange for rain that moves at this pace. Capping here at 1.0 removes the skipping but makes the fastest drops a third slower, and shortening kFrameIntervalMS to compensate speeds the whole field up – both were tried and both were worse. Slower, smoother rain is a real option; it is just not the one chosen.
◆ kSpeedStep
| float deluge::hid::display::Rainfall::kSpeedStep = 0.25f |
|
staticconstexpr |
Granularity every drop's speed is snapped to, px per frame.
- Note
- Must stay a negative power of two, so that speeds and positions are exactly representable and a drop's step cadence cannot drift. See roll() for why a coarse, small-denominator speed is what keeps the motion smooth rather than juddery.
◆ logoCountdown_
Frames until the next emission. Only counts down while no logo is active, so two can never overlap and the gap is measured between sightings rather than between starts.
The documentation for this class was generated from the following files:
- src/deluge/hid/display/rainfall.h
- src/deluge/hid/display/rainfall.cpp