Prepare rendering in smaller batches (per screen frame)

This commit is contained in:
Gitea
2019-09-21 09:38:39 +02:00
parent 1481a33326
commit f7cb80007f
2 changed files with 57 additions and 26 deletions

View File

@@ -9,10 +9,17 @@
// system includes
#include <cmath>
OsciWidget::OsciWidget(QWidget *parent) :
QOpenGLWidget{parent},
m_redrawTimerId(startTimer(1000/m_fps))
qint32 framesForDuration(qint64 duration){
return qint32(44100 * duration / 1000000LL);
}
OsciWidget::OsciWidget(QWidget *parent)
: QOpenGLWidget{parent}
, m_redrawTimerId(startTimer(1000/m_fps, Qt::PreciseTimer))
, m_lastFrame{0}
{
m_bufferTimer.start();
m_statsTimer.start();
}
@@ -27,16 +34,18 @@ void OsciWidget::setFps(int fps)
m_fps = fps;
m_redrawTimerId = startTimer(1000/m_fps);
m_redrawTimerId = startTimer(1000/m_fps, Qt::PreciseTimer);
}
void OsciWidget::setAfterglow(float afterglow){
void OsciWidget::setAfterglow(float afterglow)
{
m_afterglow = afterglow;
// percentage of the image that should be visible after one second
// i.e. factor^fps=afterglow -> factor = afterglow^(1/fps)
}
void OsciWidget::setLightspeed(int lightspeed) {
void OsciWidget::setLightspeed(int lightspeed)
{
const auto temp = (float(lightspeed)/20.f);
m_lightspeed = temp*temp*temp;
qDebug() << m_lightspeed;
@@ -49,6 +58,8 @@ void OsciWidget::renderSamples(const SamplePair *begin, const SamplePair *end)
m_samplesCounter += std::distance(begin, end);
m_buffer.insert(m_buffer.end(), begin, end);
//m_bufferTimer.restart();
//qDebug() << m_statsTimer.elapsed();
}
void OsciWidget::paintEvent(QPaintEvent *event)
@@ -69,10 +80,21 @@ void OsciWidget::paintEvent(QPaintEvent *event)
painter.drawPixmap(0, 0, m_pixmap);
}
void OsciWidget::updateFrameBuffer()
void OsciWidget::darkenFrame()
{
QPainter painter(&m_pixmap);
painter.setCompositionMode(QPainter::CompositionMode_Multiply);
painter.setPen({});
auto afterglowColor = 255 * pow(m_afterglow, 1.0/m_fps);
painter.setBrush(QColor(afterglowColor, afterglowColor, afterglowColor));
painter.drawRect(m_pixmap.rect());
}
void OsciWidget::updateDrawBuffer()
{
// Workaround for flickering (do not update, when there is no new data)
if(m_buffer.empty()) return;
//if(m_buffer.empty()) return;
if (m_pixmap.size() != size())
{
@@ -80,19 +102,11 @@ void OsciWidget::updateFrameBuffer()
m_pixmap.fill(Qt::black);
}
darkenFrame();
QPainter painter(&m_pixmap);
// darkening last frame
painter.setCompositionMode(QPainter::CompositionMode_Multiply);
painter.setPen({});
auto afterglowColor = 255 * pow(m_afterglow, 1.0/m_fps);
painter.setBrush(QColor(afterglowColor, afterglowColor, afterglowColor));
painter.drawRect(m_pixmap.rect());
// drawing new lines ontop
painter.translate(m_pixmap.width()/2, m_pixmap.height()/2);
painter.scale(m_factor * m_pixmap.width() / 2.0, m_factor * m_pixmap.height() / 2.0);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
QPen pen;
pen.setCosmetic(true); // let pen be scale invariant
@@ -100,30 +114,44 @@ void OsciWidget::updateFrameBuffer()
pen.setColor(QColor(0, 255, 0));
painter.setPen(pen);
for (const auto &i : m_buffer)
qint64 samplesUsed = 0;
double timeConstant = log(m_afterglow);
auto duration = m_bufferTimer.elapsed()*1000;
qint32 framesCnt = framesForDuration(duration);
//qDebug() << framesCnt << duration;
for (size_t idx = 0; idx < framesCnt && idx < m_buffer.size(); ++idx)
{
const auto &frame = m_buffer[idx];
double time = (m_buffer.size() - samplesUsed) / 44100.0;
const QPointF p{
float(i.first) / std::numeric_limits<qint16>::max(),
float(-i.second) / std::numeric_limits<qint16>::max()
float(frame.first) / std::numeric_limits<qint16>::max(),
float(-frame.second) / std::numeric_limits<qint16>::max()
};
const QLineF line(m_lastPoint, p);
auto beamOpacity = std::min(1.0, 1. / ((line.length() * m_lightspeed) + 1));
auto beamDecay = exp(time*timeConstant);
//qDebug() << time << beamDecay;
painter.setOpacity(std::min(1.0, 1. / ((line.length() * m_lightspeed) + 1)));
painter.setOpacity(beamDecay*beamOpacity);
painter.drawLine(m_lastPoint, p);
m_lastPoint = p;
++samplesUsed;
}
m_buffer.clear();
//m_buffer.clear();
}
void OsciWidget::timerEvent(QTimerEvent *event)
{
QWidget::timerEvent(event);
if (event->timerId() == m_redrawTimerId){
updateFrameBuffer();
updateDrawBuffer();
repaint();
}
}

View File

@@ -40,20 +40,23 @@ protected:
void timerEvent(QTimerEvent *event) override;
private:
void updateFrameBuffer();
void updateDrawBuffer();
private:
float m_factor{1.f};
int m_fps{30};
float m_afterglow{0.2};
float m_afterglow{0.01};
float m_lightspeed{35.f};
std::vector<SamplePair> m_buffer;
int m_frameCounter{0}, m_callbacksCounter{0}, m_samplesCounter{0};
QElapsedTimer m_statsTimer;
QElapsedTimer m_bufferTimer;
int m_redrawTimerId;
QPointF m_lastPoint;
size_t m_lastFrame;
QPixmap m_pixmap;
void darkenFrame();
};