Cache the last rainbow frame so it can be used again in the next frame. Makes the painting much kinder on the CPU, but has the side effect of requiring the line segments to have integer spacings.

This commit is contained in:
David Sansome 2011-06-23 20:36:38 +00:00
parent decc769ebb
commit 05e6ee8440
2 changed files with 56 additions and 14 deletions

View File

@ -37,7 +37,9 @@ NyanCatAnalyzer::NyanCatAnalyzer(QWidget* parent)
memset(history_, 0, sizeof(history_));
for (int i=0 ; i<kRainbowBands ; ++i) {
colors_[i] = QPen(QColor::fromHsv(i * 255 / kRainbowBands, 255, 255), kCatHeight/kRainbowBands);
colors_[i] = QPen(QColor::fromHsv(i * 255 / kRainbowBands, 255, 255),
kCatHeight/kRainbowBands,
Qt::SolidLine, Qt::FlatCap);
// pow constants computed so that
// | band_scale(0) | ~= .5 and | band_scale(5) | ~= 32
@ -57,6 +59,12 @@ void NyanCatAnalyzer::timerEvent(QTimerEvent* e) {
}
}
void NyanCatAnalyzer::resizeEvent(QResizeEvent* e) {
// Invalidate the buffer so it's recreated from scratch in the next paint
// event.
buffer_ = QPixmap();
}
void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_frame) {
// Discard the second half of the transform
const int scope_size = s.size() / 2;
@ -86,7 +94,7 @@ void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_fr
}
// Create polylines for the rainbows.
const float px_per_frame = float(width() - kCatWidth + kRainbowOverlap) / kHistorySize;
const int px_per_frame = float(width() - kCatWidth + kRainbowOverlap) / kHistorySize;
QPointF polyline[kRainbowBands * kHistorySize];
QPointF* dest = polyline;
float* source = history_;
@ -104,19 +112,45 @@ void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, bool new_fr
}
}
p.fillRect(rect(), background_brush_);
QTime t;
t.start();
// Draw the rainbows
p.setRenderHint(QPainter::Antialiasing);
for (int band=kRainbowBands-1 ; band>=0 ; --band) {
p.setPen(colors_[band]);
p.drawPolyline(&polyline[band*kHistorySize], kHistorySize);
// Do we have to draw the whole rainbow into the buffer?
if (buffer_.isNull()) {
buffer_ = QPixmap(size());
buffer_.fill(background_brush_.color());
QPainter buffer_painter(&buffer_);
buffer_painter.setRenderHint(QPainter::Antialiasing);
for (int band=kRainbowBands-1 ; band>=0 ; --band) {
buffer_painter.setPen(colors_[band]);
buffer_painter.drawPolyline(&polyline[band*kHistorySize], kHistorySize);
}
} else {
// We can just shuffle the buffer along a bit and draw the new frame's data.
QPainter buffer_painter(&buffer_);
buffer_painter.setRenderHint(QPainter::Antialiasing);
buffer_painter.drawPixmap(0, 0, buffer_,
px_per_frame, 0,
buffer_.width() - px_per_frame, -1);
buffer_painter.fillRect(buffer_.width() - px_per_frame, 0, px_per_frame, height(),
background_brush_);
for (int band=kRainbowBands-1 ; band>=0 ; --band) {
buffer_painter.setPen(colors_[band]);
buffer_painter.drawPolyline(&polyline[(band+1)*kHistorySize - 2], 2);
}
}
// Draw the buffer on to the widget
p.drawPixmap(0, 0, buffer_);
qLog(Debug) << t.elapsed();
// Draw nyan cat (he's been waiting for this for 50 lines).
// Nyan nyan nyan nyan.
QRect cat_dest(width() - kCatWidth, (height() - kCatHeight) / 2,
kCatWidth, kCatHeight);
p.drawPixmap(cat_dest, cat_, CatSourceRect());
}

View File

@ -30,12 +30,13 @@ public:
static const char* kName;
void timerEvent(QTimerEvent* e);
protected:
void transform(Scope&);
void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame);
void timerEvent(QTimerEvent* e);
void resizeEvent(QResizeEvent* e);
private:
static const int kCatHeight = 21;
static const int kCatWidth = 34;
@ -54,15 +55,22 @@ private:
}
private:
// "constants" that get initialised in the constructor
float band_scale_[kRainbowBands];
QPen colors_[kRainbowBands];
// Nyan cat!
QPixmap cat_;
float band_scale_[kRainbowBands];
// For the nyan cat animation
int timer_id_;
int frame_;
// The y positions of each point on the rainbow.
float history_[kHistorySize * kRainbowBands];
QPen colors_[kRainbowBands];
// A cache of the last frame's rainbow, so it can be used in the next frame.
QPixmap buffer_;
QBrush background_brush_;
};