]> git.sesse.net Git - nageru/blobdiff - analyzer.cpp
Upgrade bmusb.
[nageru] / analyzer.cpp
index 578d17a78498aa6c87aa2590b0a8726a8c7fb139..e61e4885b57631dbc99400cff4c64f1f536b2809 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <QDialogButtonBox>
 #include <QMouseEvent>
+#include <QPen>
 #include <QSurface>
 
 #include <movit/resource_pool.h>
 #include "mixer.h"
 #include "ui_analyzer.h"
 
+// QCustomPlot includes qopenglfunctions.h, which #undefs all of the epoxy
+// definitions (ugh) and doesn't put back any others (ugh). Add the ones we
+// need back.
+
+#define glBindBuffer epoxy_glBindBuffer
+#define glBindFramebuffer epoxy_glBindFramebuffer
+#define glBufferData epoxy_glBufferData
+#define glDeleteBuffers epoxy_glDeleteBuffers
+#define glDisable epoxy_glDisable
+#define glGenBuffers epoxy_glGenBuffers
+#define glGetError epoxy_glGetError
+#define glReadPixels epoxy_glReadPixels
+#define glUnmapBuffer epoxy_glUnmapBuffer
+#define glWaitSync epoxy_glWaitSync
+
 using namespace std;
 
 Analyzer::Analyzer()
@@ -47,10 +63,30 @@ Analyzer::Analyzer()
         glGenBuffers(1, &pbo);
         glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
         glBufferData(GL_PIXEL_PACK_BUFFER_ARB, global_flags.width * global_flags.height * 4, NULL, GL_STREAM_READ);
+
+       ui->histogram->xAxis->setVisible(true);
+       ui->histogram->yAxis->setVisible(false);
+       ui->histogram->xAxis->setRange(0, 255);
 }
 
 Analyzer::~Analyzer()
 {
+       delete_context(context);
+       delete surface;
+}
+
+void Analyzer::update_channel_name(Mixer::Output output, const string &name)
+{
+       if (output >= Mixer::OUTPUT_INPUT0) {
+               int index = (output - Mixer::OUTPUT_INPUT0) + 2;
+               ui->input_box->setItemText(index, QString::fromStdString(name));
+       }
+}
+
+void Analyzer::mixer_shutting_down()
+{
+       ui->display->shutdown();
+
        if (!make_current(context, surface)) {
                printf("oops\n");
                exit(1);
@@ -60,8 +96,6 @@ Analyzer::~Analyzer()
        if (resource_pool != nullptr) {
                resource_pool->clean_context();
        }
-       delete_context(context);
-       delete surface;
 }
 
 void Analyzer::grab_clicked()
@@ -145,15 +179,38 @@ void Analyzer::grab_clicked()
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        check_error();
 
-       printf("R hist:");
-       for (unsigned i = 0; i < 256; ++i) { printf(" %d", r_hist[i]); }
-       printf("\n");
-       printf("G hist:");
-       for (unsigned i = 0; i < 256; ++i) { printf(" %d", g_hist[i]); }
-       printf("\n");
-       printf("B hist:");
-       for (unsigned i = 0; i < 256; ++i) { printf(" %d", b_hist[i]); }
-       printf("\n");
+       QVector<double> r_vec(256), g_vec(256), b_vec(256), x_vec(256);
+       double max = 0.0;
+       for (unsigned i = 0; i < 256; ++i) {
+               x_vec[i] = i;
+               r_vec[i] = log(r_hist[i] + 1.0);
+               g_vec[i] = log(g_hist[i] + 1.0);
+               b_vec[i] = log(b_hist[i] + 1.0);
+
+               max = std::max(max, r_vec[i]);
+               max = std::max(max, g_vec[i]);
+               max = std::max(max, b_vec[i]);
+       }
+
+       ui->histogram->clearGraphs();
+       ui->histogram->addGraph();
+       ui->histogram->graph(0)->setData(x_vec, r_vec);
+       ui->histogram->graph(0)->setPen(QPen(Qt::red));
+       ui->histogram->graph(0)->setBrush(QBrush(QColor(255, 127, 127, 80)));
+       ui->histogram->addGraph();
+       ui->histogram->graph(1)->setData(x_vec, g_vec);
+       ui->histogram->graph(1)->setPen(QPen(Qt::green));
+       ui->histogram->graph(1)->setBrush(QBrush(QColor(127, 255, 127, 80)));
+       ui->histogram->addGraph();
+       ui->histogram->graph(2)->setData(x_vec, b_vec);
+       ui->histogram->graph(2)->setPen(QPen(Qt::blue));
+       ui->histogram->graph(2)->setBrush(QBrush(QColor(127, 127, 255, 80)));
+
+       ui->histogram->xAxis->setVisible(true);
+       ui->histogram->yAxis->setVisible(false);
+       ui->histogram->xAxis->setRange(0, 255);
+       ui->histogram->yAxis->setRange(0, max);
+       ui->histogram->replot();
 
        resource_pool->release_2d_texture(fbo_tex);
        check_error();
@@ -178,15 +235,116 @@ bool Analyzer::eventFilter(QObject *watched, QEvent *event)
                        int y = lrint(mouse_event->y() * double(pixmap->height()) / ui->grabbed_frame_label->height());
                        x = std::min(x, pixmap->width() - 1);
                        y = std::min(y, pixmap->height() - 1);
+
+                       char buf[256];
+                       snprintf(buf, sizeof(buf), "Selected coordinate (x,y): (%d,%d)", x, y);
+                       ui->coord_label->setText(buf);
+
                        QRgb pixel = grabbed_image.pixel(x, y);
                        ui->red_label->setText(QString::fromStdString(to_string(qRed(pixel))));
                        ui->green_label->setText(QString::fromStdString(to_string(qGreen(pixel))));
                        ui->blue_label->setText(QString::fromStdString(to_string(qBlue(pixel))));
 
-                       char buf[256];
                        snprintf(buf, sizeof(buf), "#%02x%02x%02x", qRed(pixel), qGreen(pixel), qBlue(pixel));
                        ui->hex_label->setText(buf);
                }
         }
         return false;
 }
+
+void Analyzer::resizeEvent(QResizeEvent* event)
+{
+       QMainWindow::resizeEvent(event);
+
+       // Ask for a relayout, but only after the event loop is done doing relayout
+       // on everything else.
+       QMetaObject::invokeMethod(this, "relayout", Qt::QueuedConnection);
+}
+
+void Analyzer::relayout()
+{
+       double aspect = double(global_flags.width) / global_flags.height;
+
+       // Left pane (2/5 of the width).
+       {
+               int width = ui->left_pane->geometry().width();
+               int height = ui->left_pane->geometry().height();
+
+               // Figure out how much space everything that's non-responsive needs.
+               int remaining_height = height - ui->left_pane->spacing() * (ui->left_pane->count() - 1);
+
+               remaining_height -= ui->grab_btn->geometry().height();
+               ui->left_pane->setStretch(2, ui->grab_btn->geometry().height());
+
+               remaining_height -= ui->histogram_label->geometry().height();
+               ui->left_pane->setStretch(4, ui->histogram_label->geometry().height());
+
+               // The histogram's minimumHeight returns 0, so let's set a reasonable minimum for it.
+               int min_histogram_height = 50;
+               remaining_height -= min_histogram_height;
+
+               // Allocate so that the display is 16:9, if possible.
+               unsigned wanted_display_height = width / aspect;
+               unsigned display_height;
+               unsigned margin = 0;
+               if (remaining_height >= int(wanted_display_height)) {
+                       display_height = wanted_display_height;
+               } else {
+                       display_height = remaining_height;
+                       int display_width = lrint(display_height * aspect);
+                       margin = (width - display_width) / 2;
+               }
+               ui->left_pane->setStretch(1, display_height);
+               ui->display_left_spacer->changeSize(margin, 1);
+               ui->display_right_spacer->changeSize(margin, 1);
+
+               remaining_height -= display_height;
+
+               // Figure out if we can do the histogram at 16:9.
+               remaining_height += min_histogram_height;
+               unsigned histogram_height;
+               if (remaining_height >= int(wanted_display_height)) {
+                       histogram_height = wanted_display_height;
+               } else {
+                       histogram_height = remaining_height;
+               }
+               remaining_height -= histogram_height;
+               ui->left_pane->setStretch(3, histogram_height);
+
+               ui->left_pane->setStretch(0, remaining_height / 2);
+               ui->left_pane->setStretch(5, remaining_height / 2);
+       }
+
+       // Right pane (remaining 3/5 of the width).
+       {
+               int width = ui->right_pane->geometry().width();
+               int height = ui->right_pane->geometry().height();
+
+               // Figure out how much space everything that's non-responsive needs.
+               int remaining_height = height - ui->right_pane->spacing() * (ui->right_pane->count() - 1);
+               remaining_height -= ui->grabbed_frame_sublabel->geometry().height();
+               remaining_height -= ui->coord_label->geometry().height();
+               remaining_height -= ui->color_hbox->geometry().height();
+
+               // Allocate so that the display is 16:9, if possible.
+               unsigned wanted_display_height = width / aspect;
+               unsigned display_height;
+               unsigned margin = 0;
+               if (remaining_height >= int(wanted_display_height)) {
+                       display_height = wanted_display_height;
+               } else {
+                       display_height = remaining_height;
+                       int display_width = lrint(display_height * aspect);
+                       margin = (width - display_width) / 2;
+               }
+               ui->right_pane->setStretch(1, display_height);
+               ui->grabbed_frame_left_spacer->changeSize(margin, 1);
+               ui->grabbed_frame_right_spacer->changeSize(margin, 1);
+               remaining_height -= display_height;
+
+               if (remaining_height < 0) remaining_height = 0;
+
+               ui->right_pane->setStretch(0, remaining_height / 2);
+               ui->right_pane->setStretch(5, remaining_height / 2);
+       }
+}