97 lines
2.5 KiB
C++
97 lines
2.5 KiB
C++
#include "fibonacci_line_pattern.h"
|
|
|
|
#include <utility>
|
|
|
|
namespace radiantwave
|
|
{
|
|
|
|
FibonacciLinePattern::FibonacciLinePattern(int peakWordCount, float maxWidthPixels,
|
|
float spaceWidth, WidthFunction widthFunction)
|
|
: maxWidthPixels_(maxWidthPixels),
|
|
spaceWidth_(spaceWidth),
|
|
widthFunction_(std::move(widthFunction))
|
|
{
|
|
// Build the Fibonacci numbers 1,1,2,3,5,8,... up to the peak, then cap the
|
|
// oscillation with the peak itself so the widest line fills the screen.
|
|
// E.g. peak 15 -> 1,1,2,3,5,8,13,15.
|
|
sequence_.push_back(1);
|
|
if (peakWordCount > 1)
|
|
{
|
|
sequence_.push_back(1);
|
|
}
|
|
int a = 1;
|
|
int b = 1;
|
|
while (true)
|
|
{
|
|
int next = a + b;
|
|
if (next > peakWordCount)
|
|
{
|
|
break;
|
|
}
|
|
sequence_.push_back(next);
|
|
a = b;
|
|
b = next;
|
|
}
|
|
if (sequence_.back() < peakWordCount)
|
|
{
|
|
sequence_.push_back(peakWordCount);
|
|
}
|
|
}
|
|
|
|
int FibonacciLinePattern::nextLine(const std::vector<std::string> &words,
|
|
std::vector<std::string> &out)
|
|
{
|
|
if (words.empty())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Wrap to the start of the word list at line boundaries only. Never wrap
|
|
// mid-line, so a line is always a contiguous slice of the source text and
|
|
// the scroll reads word-for-word like the proclamation itself.
|
|
if (wordIndex_ >= static_cast<int>(words.size()))
|
|
{
|
|
wordIndex_ = 0;
|
|
}
|
|
|
|
int target = sequence_[sequenceIndex_];
|
|
int placed = 0;
|
|
float width = 0.0f;
|
|
|
|
while (placed < target && wordIndex_ < static_cast<int>(words.size()))
|
|
{
|
|
const std::string &word = words[wordIndex_];
|
|
float wordWidth = widthFunction_(word);
|
|
float added = wordWidth + (width > 0.0f ? spaceWidth_ : 0.0f);
|
|
|
|
// Always place the first word even if it alone exceeds the cap.
|
|
if (placed > 0 && width + added > maxWidthPixels_)
|
|
{
|
|
break;
|
|
}
|
|
|
|
out.push_back(word);
|
|
width += added;
|
|
++placed;
|
|
++wordIndex_;
|
|
}
|
|
|
|
// Walk the oscillation up and down: ..., 3,2,1,1,2,3,...
|
|
const int size = static_cast<int>(sequence_.size());
|
|
sequenceIndex_ += direction_;
|
|
if (sequenceIndex_ >= size)
|
|
{
|
|
sequenceIndex_ = size >= 2 ? size - 2 : 0;
|
|
direction_ = -1;
|
|
}
|
|
else if (sequenceIndex_ < 0)
|
|
{
|
|
sequenceIndex_ = size >= 3 ? 2 : 0;
|
|
direction_ = 1;
|
|
}
|
|
|
|
return placed;
|
|
}
|
|
|
|
} // namespace radiantwave
|