diff --git a/sdrbase/gui/glscopeng.cpp b/sdrbase/gui/glscopeng.cpp index 3903d78d0..e88495db3 100644 --- a/sdrbase/gui/glscopeng.cpp +++ b/sdrbase/gui/glscopeng.cpp @@ -346,7 +346,7 @@ void GLScopeNG::paintGL() m_glShaderSimple.drawSegments(mat, color, q3, 2); } // display trace } // trace length > 0 - } // Display X only + } // Display X if ((m_displayMode == DisplayY) || (m_displayMode == DisplayXYV) || (m_displayMode == DisplayXYH)) // display traces #1..n { @@ -458,17 +458,17 @@ void GLScopeNG::paintGL() // paint traces #1..n if (m_traceSize > 0) { + int start = (m_timeOfsProMill/1000.0) * m_traceSize; + int end = std::min(start + m_traceSize/m_timeBase, m_traceSize); + + if(end - start < 2) + start--; + for (int i = 1; i < m_traces->size(); i++) { const float *trace = (*m_traces)[i]; const ScopeVisNG::TraceData& traceData = (*m_tracesData)[i]; - int start = (m_timeOfsProMill/1000.0) * m_traceSize; - int end = std::min(start + m_traceSize/m_timeBase, m_traceSize); - - if(end - start < 2) - start--; - float rectX = m_glScopeRect2.x(); float rectY = m_glScopeRect2.y() + m_glScopeRect2.height() / 2.0f; float rectW = m_glScopeRect2.width() * (float)m_timeBase / (float)(m_traceSize - 1); @@ -509,7 +509,233 @@ void GLScopeNG::paintGL() } } // one trace display } // trace length > 0 - } // Display Y only + } // Display Y + + if (m_displayMode == DisplayPol) + { + // paint left display: mixed XY + + // draw rect around + { + GLfloat q3[] { + 1, 1, + 0, 1, + 0, 0, + 1, 0 + }; + + QVector4D color(1.0f, 1.0f, 1.0f, 0.5f); + m_glShaderSimple.drawContour(m_glScopeMatrix1, color, q3, 4); + + } + + // paint grid + const ScaleEngine::TickList* tickList; + const ScaleEngine::Tick* tick; + + // Horizontal Y1 + tickList = &m_y1Scale.getTickList(); + { + GLfloat q3[4*tickList->count()]; + int effectiveTicks = 0; + + for (int i= 0; i < tickList->count(); i++) + { + tick = &(*tickList)[i]; + + if (tick->major) + { + if (tick->textSize > 0) + { + float y = 1 - (tick->pos / m_y1Scale.getSize()); + q3[4*effectiveTicks] = 0; + q3[4*effectiveTicks+1] = y; + q3[4*effectiveTicks+2] = 1; + q3[4*effectiveTicks+3] = y; + effectiveTicks++; + } + } + } + + QVector4D color(1.0f, 1.0f, 0.25f, (float) m_displayGridIntensity / 100.0f); + m_glShaderSimple.drawSegments(m_glScopeMatrix1, color, q3, 2*effectiveTicks); + } + + // Vertical X1 + tickList = &m_x1Scale.getTickList(); + { + GLfloat q3[4*tickList->count()]; + int effectiveTicks = 0; + for(int i= 0; i < tickList->count(); i++) { + tick = &(*tickList)[i]; + if(tick->major) { + if(tick->textSize > 0) { + float x = tick->pos / m_x1Scale.getSize(); + q3[4*effectiveTicks] = x; + q3[4*effectiveTicks+1] = 0; + q3[4*effectiveTicks+2] = x; + q3[4*effectiveTicks+3] = 1; + effectiveTicks++; + } + } + } + + QVector4D color(1.0f, 1.0f, 1.0f, (float) m_displayGridIntensity / 100.0f); + m_glShaderSimple.drawSegments(m_glScopeMatrix1, color, q3, 2*effectiveTicks); + } + + // paint left #1 scale + { + GLfloat vtx1[] = { + 0, 1, + 1, 1, + 1, 0, + 0, 0 + }; + GLfloat tex1[] = { + 0, 1, + 1, 1, + 1, 0, + 0, 0 + }; + + m_glShaderLeft1Scale.drawSurface(m_glLeft1ScaleMatrix, tex1, vtx1, 4); + } + + // paint bottom #1 scale + { + GLfloat vtx1[] = { + 0, 1, + 1, 1, + 1, 0, + 0, 0 + }; + GLfloat tex1[] = { + 0, 1, + 1, 1, + 1, 0, + 0, 0 + }; + + m_glShaderBottom1Scale.drawSurface(m_glBot1ScaleMatrix, tex1, vtx1, 4); + } + + // Paint secondary grid + + // Horizontal Y2 + tickList = &m_y2Scale.getTickList(); + { + GLfloat q3[4*tickList->count()]; + int effectiveTicks = 0; + for(int i= 0; i < tickList->count(); i++) { + tick = &(*tickList)[i]; + if(tick->major) { + if(tick->textSize > 0) { + float y = 1 - (tick->pos / m_y2Scale.getSize()); + q3[4*effectiveTicks] = 0; + q3[4*effectiveTicks+1] = y; + q3[4*effectiveTicks+2] = 1; + q3[4*effectiveTicks+3] = y; + effectiveTicks++; + } + } + } + + QVector4D color(0.25f, 1.0f, 1.0f, (float) m_displayGridIntensity / 100.0f); + m_glShaderSimple.drawSegments(m_glScopeMatrix1, color, q3, 2*effectiveTicks); + } + + // Paint secondary scale + { + GLfloat vtx1[] = { + 0, 1, + 1, 1, + 1, 0, + 0, 0 + }; + GLfloat tex1[] = { + 0, 1, + 1, 1, + 1, 0, + 0, 0 + }; + + m_glShaderLeft2Scale.drawSurface(m_glRight1ScaleMatrix, tex1, vtx1, 4); + } + + // paint all traces + if (m_traceSize > 0) + { + int start = (m_timeOfsProMill/1000.0) * m_traceSize; + int end = std::min(start + m_traceSize/m_timeBase, m_traceSize); + + if(end - start < 2) + start--; + + for (int i = 0; i < m_traces->size(); i++) + { + const float *trace = (*m_traces)[i]; + const ScopeVisNG::TraceData& traceData = (*m_tracesData)[i]; + + float rectX = m_glScopeRect1.x(); + float rectY = m_glScopeRect1.y() + m_glScopeRect1.height() / 2.0f; + float rectW = m_glScopeRect1.width() * (float)m_timeBase / (float)(m_traceSize - 1); + //float rectH = -(m_glScopeRect1.height() / 2.0f) * traceData.m_amp; + float rectH = -m_glScopeRect1.height() / 2.0f; + + //QVector4D color(1.0f, 1.0f, 0.25f, m_displayTraceIntensity / 100.0f); + QVector4D color(traceData.m_traceColorR, traceData.m_traceColorG, traceData.m_traceColorB, m_displayTraceIntensity / 100.0f); + QMatrix4x4 mat; + mat.setToIdentity(); + mat.translate(-1.0f + 2.0f * rectX, 1.0f - 2.0f * rectY); + mat.scale(2.0f * rectW, -2.0f * rectH); + m_glShaderSimple.drawPolyline(mat, color, (GLfloat *) &trace[2*start], end - start); + + // Paint trigger level if any + if ((traceData.m_triggerDisplayLevel > -1.0f) && (traceData.m_triggerDisplayLevel < 1.0f)) + { + GLfloat q3[] { + 0, traceData.m_triggerDisplayLevel, + 1, traceData.m_triggerDisplayLevel + }; + + float rectX = m_glScopeRect1.x(); + float rectY = m_glScopeRect1.y() + m_glScopeRect1.height() / 2.0f; + float rectW = m_glScopeRect1.width(); + float rectH = -m_glScopeRect1.height() / 2.0f; + + QVector4D color( + m_focusedTriggerData.m_triggerColorR, + m_focusedTriggerData.m_triggerColorG, + m_focusedTriggerData.m_triggerColorB, + 0.4f); + QMatrix4x4 mat; + mat.setToIdentity(); + mat.translate(-1.0f + 2.0f * rectX, 1.0f - 2.0f * rectY); + mat.scale(2.0f * rectW, -2.0f * rectH); + m_glShaderSimple.drawSegments(mat, color, q3, 2); + } + } // all traces display + } // trace length > 0 + + // paint right display: polar XY + + if (m_traceSize > 0) + { + int start = (m_timeOfsProMill/1000.0) * m_traceSize; + int end = std::min(start + m_traceSize/m_timeBase, m_traceSize); + + if(end - start < 2) + start--; + + for (int i = 0; i < m_traces->size(); i++) + { + const float *trace = (*m_traces)[i]; + const ScopeVisNG::TraceData& traceData = (*m_tracesData)[i]; + + } // XY polar display + } // trace length > 0 + } // XY mixed + polar display m_mutex.unlock(); } @@ -615,7 +841,7 @@ void GLScopeNG::applyConfig() } else if (m_displayMode == DisplayPol) // horizontal arrangement: XY stacked on left and polar on right { - + setPolarDisplays(); } } @@ -1222,6 +1448,217 @@ void GLScopeNG::setHorizontalDisplays() } // Y vertical scale (Y2) } +void GLScopeNG::setPolarDisplays() +{ + QFontMetrics fm(font()); + int M = fm.width("-"); + int scopeHeight = height() - m_topMargin - m_botMargin; + int scopeWidth = (width() - m_rightMargin)/2 - m_leftMargin; + int scopeDim = std::min(scopeWidth, scopeHeight); + + // Mixed XY display (left) + + m_glScopeRect1 = QRectF( + (float) m_leftMargin / (float) width(), + (float) m_topMargin / (float) height(), + (float) (scopeWidth-m_leftMargin) / (float) width(), + (float) scopeHeight / (float) height() + ); + m_glScopeMatrix1.setToIdentity(); + m_glScopeMatrix1.translate ( + -1.0f + ((float) 2*m_leftMargin / (float) width()), + 1.0f - ((float) 2*m_topMargin / (float) height()) + ); + m_glScopeMatrix1.scale ( + (float) 2*(scopeWidth-m_leftMargin) / (float) width(), + (float) -2*scopeHeight / (float) height() + ); + + m_glBot1ScaleMatrix.setToIdentity(); + m_glBot1ScaleMatrix.translate ( + -1.0f + ((float) 2*m_leftMargin / (float) width()), + 1.0f - ((float) 2*(scopeHeight + m_topMargin + 1) / (float) height()) + ); + m_glBot1ScaleMatrix.scale ( + (float) 2*(scopeWidth-m_leftMargin) / (float) width(), + (float) -2*(m_botMargin - 1) / (float) height() + ); + + m_glLeft1ScaleMatrix.setToIdentity(); + m_glLeft1ScaleMatrix.translate ( + -1.0f, + 1.0f - ((float) 2*m_topMargin / (float) height()) + ); + m_glLeft1ScaleMatrix.scale ( + (float) 2*(m_leftMargin-1) / (float) width(), + (float) -2*scopeHeight / (float) height() + ); + + m_glRight1ScaleMatrix.setToIdentity(); + m_glRight1ScaleMatrix.translate ( + -1.0f + ((float) 2*scopeWidth / (float) width()), + 1.0f - ((float) 2*m_topMargin / (float) height()) + ); + m_glRight1ScaleMatrix.scale ( + (float) 2*(m_leftMargin-1) / (float) width(), + (float) -2*scopeHeight / (float) height() + ); + + // Polar XY display (right) + + m_glScopeRect2 = QRectF( + (float)(m_leftMargin + scopeWidth + m_leftMargin) / (float)width(), + (float)m_topMargin / (float)height(), + (float) scopeDim / (float)width(), + (float)(height() - m_topMargin - m_botMargin) / (float)height() + ); + m_glScopeMatrix2.setToIdentity(); + m_glScopeMatrix2.translate ( + -1.0f + ((float) 2*(m_leftMargin + scopeWidth + m_leftMargin) / (float) width()), + 1.0f - ((float) 2*m_topMargin / (float) height()) + ); + m_glScopeMatrix2.scale ( + (float) 2*scopeDim / (float) width(), + (float) -2*(height() - m_topMargin - m_botMargin) / (float) height() + ); + + m_glBot2ScaleMatrix.setToIdentity(); + m_glBot2ScaleMatrix.translate ( + -1.0f + ((float) 2*(m_leftMargin + m_leftMargin + scopeWidth) / (float) width()), + 1.0f - ((float) 2*(scopeHeight + m_topMargin + 1) / (float) height()) + ); + m_glBot2ScaleMatrix.scale ( + (float) 2*scopeDim / (float) width(), + (float) -2*(m_botMargin - 1) / (float) height() + ); + + m_glLeft2ScaleMatrix.setToIdentity(); + m_glLeft2ScaleMatrix.translate ( + -1.0f + (float) 2*(m_leftMargin + scopeWidth) / (float) width(), + 1.0f - ((float) 2*m_topMargin / (float) height()) + ); + m_glLeft2ScaleMatrix.scale ( + (float) 2*(m_leftMargin-1) / (float) width(), + (float) -2*scopeHeight / (float) height() + ); + + { // Mixed XY horizontal scale (X1) + m_x1Scale.setSize(scopeWidth); + + m_bot1ScalePixmap = QPixmap( + scopeWidth, + m_botMargin - 1 + ); + + const ScaleEngine::TickList* tickList; + const ScaleEngine::Tick* tick; + + m_bot1ScalePixmap.fill(Qt::black); + QPainter painter(&m_bot1ScalePixmap); + painter.setPen(QColor(0xf0, 0xf0, 0xff)); + painter.setFont(font()); + tickList = &m_x1Scale.getTickList(); + + for(int i = 0; i < tickList->count(); i++) { + tick = &(*tickList)[i]; + if(tick->major) { + if(tick->textSize > 0) { + painter.drawText(QPointF(tick->textPos, fm.height() - 1), tick->text); + } + } + } + + m_glShaderBottom1Scale.initTexture(m_bot1ScalePixmap.toImage()); + } // Mixed XY horizontal scale (X1) + + { // Polar XY horizontal scale (X2) + m_x2Scale.setSize(scopeDim); + m_bot2ScalePixmap = QPixmap( + scopeDim, + m_botMargin - 1 + ); + + const ScaleEngine::TickList* tickList; + const ScaleEngine::Tick* tick; + + m_bot2ScalePixmap.fill(Qt::black); + QPainter painter(&m_bot2ScalePixmap); + painter.setPen(QColor(0xf0, 0xf0, 0xff)); + painter.setFont(font()); + tickList = &m_x2Scale.getTickList(); + + for(int i = 0; i < tickList->count(); i++) { + tick = &(*tickList)[i]; + if(tick->major) { + if(tick->textSize > 0) { + painter.drawText(QPointF(tick->textPos, fm.height() - 1), tick->text); + } + } + } + + m_glShaderBottom2Scale.initTexture(m_bot2ScalePixmap.toImage()); + } // Polar XY horizontal scale (X2) + + { // Mixed XY vertical scale (Y1) + m_y1Scale.setSize(scopeHeight); + + m_left1ScalePixmap = QPixmap( + m_leftMargin - 1, + scopeHeight + ); + + const ScaleEngine::TickList* tickList; + const ScaleEngine::Tick* tick; + + m_left1ScalePixmap.fill(Qt::black); + QPainter painter(&m_left1ScalePixmap); + painter.setPen(QColor(0xf0, 0xf0, 0xff)); + painter.setFont(font()); + tickList = &m_y1Scale.getTickList(); + + for(int i = 0; i < tickList->count(); i++) { + tick = &(*tickList)[i]; + if(tick->major) { + if(tick->textSize > 0) { + painter.drawText(QPointF(m_leftMargin - M - tick->textSize, m_topMargin + scopeHeight - tick->textPos - fm.ascent()/2), tick->text); + } + } + } + + m_glShaderLeft1Scale.initTexture(m_left1ScalePixmap.toImage()); + + } // Mixed XY vertical scale (Y1) + + { // Polar XY vertical scale (Y2) + m_y2Scale.setSize(scopeHeight); + + m_left2ScalePixmap = QPixmap( + m_leftMargin - 1, + scopeHeight + ); + + const ScaleEngine::TickList* tickList; + const ScaleEngine::Tick* tick; + + m_left2ScalePixmap.fill(Qt::black); + QPainter painter(&m_left2ScalePixmap); + painter.setPen(QColor(0xf0, 0xf0, 0xff)); + painter.setFont(font()); + tickList = &m_y2Scale.getTickList(); + + for(int i = 0; i < tickList->count(); i++) { + tick = &(*tickList)[i]; + if(tick->major) { + if(tick->textSize > 0) { + painter.drawText(QPointF(m_leftMargin - M - tick->textSize, m_topMargin + scopeHeight - tick->textPos - fm.ascent()/2), tick->text); + } + } + } + + m_glShaderLeft2Scale.initTexture(m_left2ScalePixmap.toImage()); + } // Polar XY vertical scale (Y2) +} + void GLScopeNG::setYScale(ScaleEngine& scale, uint32_t highlightedTraceIndex) { ScopeVisNG::TraceData& traceData = (*m_tracesData)[highlightedTraceIndex]; diff --git a/sdrbase/gui/glscopeng.h b/sdrbase/gui/glscopeng.h index 9d207d051..c23104816 100644 --- a/sdrbase/gui/glscopeng.h +++ b/sdrbase/gui/glscopeng.h @@ -142,6 +142,7 @@ private: void setUniqueDisplays(); //!< Arrange displays when X and Y are unique on screen void setVerticalDisplays(); //!< Arrange displays when X and Y are stacked vertically void setHorizontalDisplays(); //!< Arrange displays when X and Y are stacked horizontally + void setPolarDisplays(); //!< Arrange displays when X and Y are stacked over on the left and polar display is on the right protected slots: void cleanup(); diff --git a/sdrbase/gui/glscopenggui.cpp b/sdrbase/gui/glscopenggui.cpp index 4dde12de5..874f9c11a 100644 --- a/sdrbase/gui/glscopenggui.cpp +++ b/sdrbase/gui/glscopenggui.cpp @@ -297,9 +297,9 @@ void GLScopeNGGUI::on_traceAdd_clicked(bool checked) if (ui->trace->value() == 0) { ui->onlyY->setEnabled(true); - ui->horizontalXY->setEnabled(true); // TODO: re-activate when these displays become active + ui->horizontalXY->setEnabled(true); ui->verticalXY->setEnabled(true); -// ui->polar->setEnabled(true); + ui->polar->setEnabled(true); } ScopeVisNG::TraceData traceData;