diff --git a/external/cubicvr2/math/mat4.h b/external/cubicvr2/math/mat4.h index 0059cd8..b847d26 100644 --- a/external/cubicvr2/math/mat4.h +++ b/external/cubicvr2/math/mat4.h @@ -74,13 +74,24 @@ namespace CubicVR { return mOut; } - - static mat4 perspective(__float fovy, __float aspect, __float znear, __float zfar) { + static mat4 frustum(__float left, __float right, __float bottom, __float top, __float zNear, __float zFar) { + __float A = (right + left) / (right - left); + __float B = (top + bottom) / (top - bottom); + __float C = - (zFar + zNear) / (zFar - zNear); + __float D = - (-2.0 * zFar * zNear) / (zFar - zNear); + + + return mat4((2.0 * zNear) / (right - left), 0, A, 0, + 0, (2.0 * zNear) / (top - bottom), B, 0, + 0, 0, C, D, + 0, 0, -1, 0); + }; + static mat4 perspective(__float fovy, __float aspect, __float zNear, __float zFar) { __float yFac = tan(fovy * (float)M_PI / 360.0f); __float xFac = yFac * aspect; - return mat4( - 1.0f / xFac, 0, 0, 0, 0, 1.0f / yFac, 0, 0, 0, 0, -(zfar + znear) / (zfar - znear), -1, 0, 0, -(2.0f * zfar * znear) / (zfar - znear), 0); + return mat4::frustum(-xFac, xFac, -yFac, yFac, zNear, zFar); + }; static mat4 ortho(__float left,__float right,__float bottom,__float top,__float znear,__float zfar) { return mat4(2.0f / (right - left), 0, 0, 0, 0, 2.0f / (top - bottom), 0, 0, 0, 0, -2.0f / (zfar - znear), 0, -(left + right) / (right - left), -(top + bottom) / (top - bottom), -(zfar + znear) / (zfar - znear), 1); @@ -300,8 +311,18 @@ namespace CubicVR { return mat4::translate(-eyex,-eyey,-eyez) * mat4( side[0], up[0], -forward[0], 0, side[1], up[1], -forward[1], 0, side[2], up[2], -forward[2], 0, 0, 0, 0, 1); }; + + static vec3 unProject(mat4 pMatrix, mat4 mvMatrix, float width, float height, float winx, float winy, float winz) { + vec4 p(((winx / width) * 2.0) - 1.0, -(((winy / height) * 2.0) - 1.0), 1.0, 1.0); + + vec4 invp = mat4::vec4_multiply(mat4::vec4_multiply(p, mat4::inverse(pMatrix)), mat4::inverse(mvMatrix)); + + vec3 result(invp[0] / invp[3], invp[1] / invp[3], invp[2] / invp[3]); + + return result; + }; }; - -} + } + #endif /* defined(__CubicVR2__mat4__) */ diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index e843109..f85d2b2 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -153,11 +153,12 @@ AppFrame::AppFrame() : waterfallCanvas->setup(2048, 512); waterfallDataThread = new FFTVisualDataThread(); - t_FFTData = new std::thread(&FFTVisualDataThread::threadMain, waterfallDataThread); waterfallDataThread->setInputQueue("IQDataInput", wxGetApp().getWaterfallVisualQueue()); waterfallDataThread->setOutputQueue("FFTDataOutput", waterfallCanvas->getVisualDataQueue()); - + + t_FFTData = new std::thread(&FFTVisualDataThread::threadMain, waterfallDataThread); + waterfallSpeedMeter = new MeterCanvas(this, attribList); waterfallSpeedMeter->setHelpTip("Waterfall speed, click or drag to adjust (max 1024 lines per second)"); waterfallSpeedMeter->setMax(sqrt(1024)); diff --git a/src/panel/ScopePanel.cpp b/src/panel/ScopePanel.cpp index c50fa08..f72a14c 100644 --- a/src/panel/ScopePanel.cpp +++ b/src/panel/ScopePanel.cpp @@ -2,6 +2,7 @@ #include "ColorTheme.h" ScopePanel::ScopePanel() : GLPanel(), scopeMode(SCOPE_MODE_Y) { + setFill(GLPanelFillType::GLPANEL_FILL_NONE); bgPanel.setFill(GLPanelFillType::GLPANEL_FILL_GRAD_BAR_Y); bgPanelStereo[0].setFill(GLPanelFillType::GLPANEL_FILL_GRAD_BAR_Y); bgPanelStereo[0].setPosition(0, 0.5); @@ -21,14 +22,13 @@ void ScopePanel::setPoints(std::vector &points) { } void ScopePanel::drawPanelContents() { - - glLineWidth(1.0); if (scopeMode == SCOPE_MODE_Y) { bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground, ThemeMgr::mgr.currentTheme->scopeBackground * 2.0); bgPanel.calcTransform(transform); bgPanel.draw(); - + glLineWidth(1.0); + glEnable(GL_LINE_SMOOTH); glLoadMatrixf(transform); glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r * 0.35, ThemeMgr::mgr.currentTheme->scopeLine.g * 0.35, ThemeMgr::mgr.currentTheme->scopeLine.b * 0.35); @@ -45,8 +45,10 @@ void ScopePanel::drawPanelContents() { bgPanelStereo[1].calcTransform(transform); bgPanelStereo[1].draw(); + glLineWidth(1.0); glLoadMatrixf(transform); glColor3f(ThemeMgr::mgr.currentTheme->scopeLine.r, ThemeMgr::mgr.currentTheme->scopeLine.g, ThemeMgr::mgr.currentTheme->scopeLine.b); + glEnable(GL_LINE_SMOOTH); glBegin (GL_LINES); glVertex2f(-1.0, 0.0); glVertex2f(1.0, 0.0); diff --git a/src/ui/GLPanel.cpp b/src/ui/GLPanel.cpp index 00fa2be..7d06c81 100644 --- a/src/ui/GLPanel.cpp +++ b/src/ui/GLPanel.cpp @@ -8,6 +8,9 @@ using namespace CubicVR; GLPanel::GLPanel() : fillType(GLPANEL_FILL_SOLID), contentsVisible(true), transform(mat4::identity()) { pos[0] = 0.0f; pos[1] = 0.0f; + rot[0] = 0.0f; + rot[1] = 0.0f; + rot[2] = 0.0f; size[0] = 1.0f; size[1] = 1.0f; fill[0] = RGBA4f(0.5,0.5,0.5); @@ -241,6 +244,11 @@ void GLPanel::drawPanelContents() { void GLPanel::calcTransform(mat4 transform_in) { // compute local transform localTransform = mat4::translate(pos[0], pos[1], 0) * mat4::scale(size[0], size[1], 1); + + if (rot[0] || rot[1] || rot[2]) { + localTransform *= mat4::rotate(rot[0], rot[1], rot[2]); + } + // compute global transform transform = transform_in * localTransform; diff --git a/src/ui/GLPanel.h b/src/ui/GLPanel.h index b87bac2..0f3e3b6 100644 --- a/src/ui/GLPanel.h +++ b/src/ui/GLPanel.h @@ -36,6 +36,7 @@ public: typedef enum GLPanelFillType { GLPANEL_FILL_NONE, GLPANEL_FILL_SOLID, GLPANEL_FILL_GRAD_X, GLPANEL_FILL_GRAD_Y, GLPANEL_FILL_GRAD_BAR_X, GLPANEL_FILL_GRAD_BAR_Y } GLPanelFillType; typedef enum GLPanelCoordinateSystem { GLPANEL_Y_DOWN_ZERO_ONE, GLPANEL_Y_UP_ZERO_ONE, GLPANEL_Y_UP, GLPANEL_Y_DOWN } GLPanelCoordinateSystem; float pos[2]; + float rot[3]; float size[2]; float view[2]; GLPanelFillType fillType; diff --git a/src/util/ThreadQueue.h b/src/util/ThreadQueue.h index 8ba5e0a..a2d693e 100644 --- a/src/util/ThreadQueue.h +++ b/src/util/ThreadQueue.h @@ -49,6 +49,8 @@ public: * \param[in] item An item. */ void set_max_num_items(unsigned int max_num_items) { + std::lock_guard < std::mutex > lock(m_mutex); + m_max_num_items = max_num_items; } diff --git a/src/visual/ScopeCanvas.cpp b/src/visual/ScopeCanvas.cpp index a4cd4be..220997f 100644 --- a/src/visual/ScopeCanvas.cpp +++ b/src/visual/ScopeCanvas.cpp @@ -14,18 +14,28 @@ #include "CubicSDRDefs.h" #include "AppFrame.h" #include +#include wxBEGIN_EVENT_TABLE(ScopeCanvas, wxGLCanvas) EVT_PAINT(ScopeCanvas::OnPaint) EVT_IDLE(ScopeCanvas::OnIdle) +EVT_MOTION(ScopeCanvas::OnMouseMoved) +EVT_LEFT_DOWN(ScopeCanvas::OnMouseDown) +EVT_LEFT_UP(ScopeCanvas::OnMouseReleased) +EVT_RIGHT_DOWN(ScopeCanvas::OnMouseRightDown) +EVT_RIGHT_UP(ScopeCanvas::OnMouseRightReleased) +EVT_LEAVE_WINDOW(ScopeCanvas::OnMouseLeftWindow) +EVT_ENTER_WINDOW(ScopeCanvas::OnMouseEnterWindow) wxEND_EVENT_TABLE() -ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) : - wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, - wxFULL_REPAINT_ON_RESIZE), stereo(false), ppmMode(false) { +ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) : InteractiveCanvas(parent, attribList), stereo(false), ppmMode(false), ctr(0), ctrTarget(0), dragAccel(0) { glContext = new ScopeContext(this, &wxGetApp().GetContext(this)); inputData.set_max_num_items(1); + bgPanel.setFill(GLPanel::GLPANEL_FILL_GRAD_Y); + bgPanel.setSize(1.0, 0.5); + bgPanel.setPosition(0.0, -0.5); + panelSpacing = 0.2; } ScopeCanvas::~ScopeCanvas() { @@ -71,21 +81,74 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { initGLExtensions(); glViewport(0, 0, ClientSize.x, ClientSize.y); - + glContext->DrawBegin(); + + bgPanel.setFillColor(ThemeMgr::mgr.currentTheme->scopeBackground * 3.0, RGBA4f(0,0,0,0)); + bgPanel.calcTransform(CubicVR::mat4::identity()); + bgPanel.draw(); + scopePanel.setMode(stereo?ScopePanel::SCOPE_MODE_2Y:ScopePanel::SCOPE_MODE_Y); - scopePanel.calcTransform(CubicVR::mat4::identity()); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glLoadMatrixf(CubicVR::mat4::perspective(45.0, 1.0, 1.0, 1000.0)); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + CubicVR::mat4 modelView = CubicVR::mat4::lookat(0, 0, -1.2, 0, 0, 0, 0, -1, 0); + + float panelWidth = 1.0; + float panelInterval = (panelWidth * 2.0 + panelSpacing); + + if (!mouseTracker.mouseDown()) { + if (!dragAccel) { + ctrTarget = round(ctr / panelInterval); + if (ctrTarget < -1.0) { + ctrTarget = -1.0; + } else if (ctrTarget > 0.0) { + ctrTarget = 0.0; + } + ctrTarget *= panelInterval; + if (ctr != ctrTarget) { + ctr += (ctrTarget-ctr)*0.2; + } + } else { + dragAccel -= dragAccel * 0.01; + if (abs(dragAccel) < 0.1 || ctr < ctrTarget-panelInterval/2.0 || ctr > ctrTarget+panelInterval/2.0 ) { + dragAccel = 0; + } else { + ctr += dragAccel; + } + } + } + + scopePanel.setPosition(ctr, 0); + float roty = atan2(scopePanel.pos[0],1.2); + scopePanel.rot[1] = -(roty * (180.0 / M_PI)); + scopePanel.calcTransform(modelView); scopePanel.draw(); + + scopePanel.setPosition(panelInterval+ctr, 0); + roty = atan2(scopePanel.pos[0],1.2); + scopePanel.rot[1] = -(roty * (180.0 / M_PI)); + scopePanel.calcTransform(modelView); + scopePanel.draw(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); glContext->DrawTunerTitles(ppmMode); if (!deviceName.empty()) { glContext->DrawDeviceName(deviceName); } glContext->DrawEnd(); - SwapBuffers(); } + void ScopeCanvas::OnIdle(wxIdleEvent &event) { Refresh(); event.RequestMore(); @@ -94,3 +157,36 @@ void ScopeCanvas::OnIdle(wxIdleEvent &event) { ScopeRenderDataQueue *ScopeCanvas::getInputQueue() { return &inputData; } + +void ScopeCanvas::OnMouseMoved(wxMouseEvent& event) { + InteractiveCanvas::OnMouseMoved(event); + if (mouseTracker.mouseDown()) { + dragAccel = 4.0*mouseTracker.getDeltaMouseX(); + ctr += dragAccel; + } +} + +void ScopeCanvas::OnMouseWheelMoved(wxMouseEvent& event) { + +} + +void ScopeCanvas::OnMouseDown(wxMouseEvent& event) { + InteractiveCanvas::OnMouseDown(event); + +} + +void ScopeCanvas::OnMouseReleased(wxMouseEvent& event) { + InteractiveCanvas::OnMouseReleased(event); + +} + +void ScopeCanvas::OnMouseEnterWindow(wxMouseEvent& event) { + InteractiveCanvas::OnMouseEnterWindow(event); + +} + +void ScopeCanvas::OnMouseLeftWindow(wxMouseEvent& event) { + InteractiveCanvas::OnMouseLeftWindow(event); + +} + diff --git a/src/visual/ScopeCanvas.h b/src/visual/ScopeCanvas.h index 6cdff03..d5bfba5 100644 --- a/src/visual/ScopeCanvas.h +++ b/src/visual/ScopeCanvas.h @@ -10,8 +10,9 @@ #include "ScopeVisualProcessor.h" #include "ScopePanel.h" #include "fftw3.h" +#include "InteractiveCanvas.h" -class ScopeCanvas: public wxGLCanvas { +class ScopeCanvas: public InteractiveCanvas { public: ScopeCanvas(wxWindow *parent, int *attribList = NULL); ~ScopeCanvas(); @@ -26,13 +27,24 @@ public: private: void OnPaint(wxPaintEvent& event); void OnIdle(wxIdleEvent &event); + void OnMouseMoved(wxMouseEvent& event); + void OnMouseWheelMoved(wxMouseEvent& event); + void OnMouseDown(wxMouseEvent& event); + void OnMouseReleased(wxMouseEvent& event); + void OnMouseEnterWindow(wxMouseEvent& event); + void OnMouseLeftWindow(wxMouseEvent& event); ScopeRenderDataQueue inputData; ScopePanel scopePanel; + GLPanel bgPanel; ScopeContext *glContext; std::string deviceName; bool stereo; bool ppmMode; + float panelSpacing; + float ctr; + float ctrTarget; + float dragAccel; // event table wxDECLARE_EVENT_TABLE(); };