From d27d91c1ef37290eb353b5577bcac0d58421621d Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Mon, 27 Oct 2014 21:22:29 -0400 Subject: [PATCH] Code re-factor / cleanup GL Window now ready to draw signal lines --- CMakeLists.txt | 10 +- src/AppFrame.cpp | 52 ++++++ src/AppFrame.h | 17 ++ src/CubicSDR.cpp | 384 +-------------------------------------- src/CubicSDR.h | 58 +----- src/PrimaryGLContext.cpp | 126 +++++++++++++ src/PrimaryGLContext.h | 28 +++ src/SDRThread.cpp | 139 +------------- 8 files changed, 249 insertions(+), 565 deletions(-) create mode 100644 src/AppFrame.cpp create mode 100644 src/AppFrame.h create mode 100644 src/PrimaryGLContext.cpp create mode 100644 src/PrimaryGLContext.h diff --git a/CMakeLists.txt b/CMakeLists.txt index be120c2..a53a478 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,8 +52,8 @@ set(wxWidgets_CONFIGURATION mswu) find_package(wxWidgets COMPONENTS gl core base REQUIRED) include(${wxWidgets_USE_FILE}) -include_directories ( ${PROJECT_SOURCE_DIR}/../CubicVR-2/build/include ) -link_directories ( ${PROJECT_SOURCE_DIR}/../CubicVR-2/build/lib ${OPENGL_INCLUDE_DIR}) +# include_directories ( ${PROJECT_SOURCE_DIR}/../CubicVR-2/build/include ) +# link_directories ( ${PROJECT_SOURCE_DIR}/../CubicVR-2/build/lib ${OPENGL_INCLUDE_DIR}) include_directories ( ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release ) link_directories ( ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/x32 ) @@ -61,18 +61,22 @@ link_directories ( ${PROJECT_SOURCE_DIR}/external/rtl-sdr-release/x32 ) SET (cubicsdr_sources src/CubicSDR.cpp src/SDRThread.cpp + src/PrimaryGLContext.cpp + src/AppFrame.cpp ) SET (cubicsdr_headers src/CubicSDR.h src/SDRThread.h + src/PrimaryGLContext.h + src/AppFrame.h ) #configure_files(${PROJECT_SOURCE_DIR}/shaders ${PROJECT_BINARY_DIR}/shaders COPYONLY) #configure_files(${PROJECT_SOURCE_DIR}/png ${PROJECT_BINARY_DIR}/png COPYONLY) add_executable(CubicSDR ${cubicsdr_sources} ${cubicsdr_headers}) -target_link_libraries(CubicSDR cubicvr2 rtlsdr ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES}) +target_link_libraries(CubicSDR rtlsdr ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES}) # cubicvr2 glfw ${GLFW_LIBRARIES} ${OPENAL_LIBRARY} diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp new file mode 100644 index 0000000..3a48577 --- /dev/null +++ b/src/AppFrame.cpp @@ -0,0 +1,52 @@ +#include "AppFrame.h" + +#include "wx/wxprec.h" + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#if !wxUSE_GLCANVAS +#error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library" +#endif + + +wxBEGIN_EVENT_TABLE(AppFrame, wxFrame) EVT_MENU(wxID_NEW, AppFrame::OnNewWindow) +EVT_MENU(wxID_CLOSE, AppFrame::OnClose) +wxEND_EVENT_TABLE() + +AppFrame::AppFrame() : + wxFrame(NULL, wxID_ANY, wxT("CubicSDR")) { + + new TestGLCanvas(this, NULL); + + SetIcon(wxICON(sample)); + + // Make a menubar + wxMenu *menu = new wxMenu; +// menu->Append(wxID_NEW); +// menu->AppendSeparator(); + menu->Append(wxID_CLOSE); + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(menu, wxT("&File")); + + SetMenuBar(menuBar); + + CreateStatusBar(); + + SetClientSize(400, 400); + Show(); + +// static const int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 }; +// wxLogStatus("Double-buffered display %s supported", wxGLCanvas::IsDisplaySupported(attribs) ? "is" : "not"); +// ShowFullScreen(true); +} + +void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) { + // true is to force the frame to close + Close(true); +} + +void AppFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event)) { + new AppFrame(); +} diff --git a/src/AppFrame.h b/src/AppFrame.h new file mode 100644 index 0000000..0abdac7 --- /dev/null +++ b/src/AppFrame.h @@ -0,0 +1,17 @@ +#pragma once + +#include "wx/frame.h" +#include "PrimaryGLContext.h" + +// Define a new frame type +class AppFrame : public wxFrame +{ +public: + AppFrame(); + +private: + void OnClose(wxCommandEvent& event); + void OnNewWindow(wxCommandEvent& event); + + wxDECLARE_EVENT_TABLE(); +}; diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 52d1b63..d4b905e 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -1,9 +1,5 @@ #define OPENGL -//WX_GL_CORE_PROFILE 1 -//WX_GL_MAJOR_VERSION 3 -//WX_GL_MINOR_VERSION 2 - #include "wx/wxprec.h" #ifndef WX_PRECOMP @@ -14,238 +10,14 @@ #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library" #endif + #include "CubicSDR.h" +#include "AppFrame.h" -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// control ids -enum { - SpinTimer = wxID_HIGHEST + 1 -}; - -// ---------------------------------------------------------------------------- -// helper functions -// ---------------------------------------------------------------------------- - -static void CheckGLError() { - GLenum errLast = GL_NO_ERROR; - - for (;;) { - GLenum err = glGetError(); - if (err == GL_NO_ERROR) - return; - - // normally the error is reset by the call to glGetError() but if - // glGetError() itself returns an error, we risk looping forever here - // so check that we get a different error than the last time - if (err == errLast) { - wxLogError - (wxT("OpenGL error state couldn't be reset.")); - return; - } - - errLast = err; - - wxLogError - (wxT("OpenGL error %d"), err); - } -} - -// function to draw the texture for cube faces -static wxImage DrawDice(int size, unsigned num) { - wxASSERT_MSG(num >= 1 && num <= 6, wxT("invalid dice index")); - - const int dot = size / 16; // radius of a single dot - const int gap = 5 * size / 32; // gap between dots - - wxBitmap bmp(size, size); - wxMemoryDC dc; - dc.SelectObject(bmp); - dc.SetBackground(*wxWHITE_BRUSH); - dc.Clear(); - dc.SetBrush(*wxBLACK_BRUSH); - - // the upper left and lower right points - if (num != 1) { - dc.DrawCircle(gap + dot, gap + dot, dot); - dc.DrawCircle(size - gap - dot, size - gap - dot, dot); - } - - // draw the central point for odd dices - if (num % 2) { - dc.DrawCircle(size / 2, size / 2, dot); - } - - // the upper right and lower left points - if (num > 3) { - dc.DrawCircle(size - gap - dot, gap + dot, dot); - dc.DrawCircle(gap + dot, size - gap - dot, dot); - } - - // finally those 2 are only for the last dice - if (num == 6) { - dc.DrawCircle(gap + dot, size / 2, dot); - dc.DrawCircle(size - gap - dot, size / 2, dot); - } - - dc.SelectObject(wxNullBitmap); - - return bmp.ConvertToImage(); -} - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// PrimaryGLContext -// ---------------------------------------------------------------------------- - -PrimaryGLContext::PrimaryGLContext(wxGLCanvas *canvas) : - wxGLContext(canvas) { - SetCurrent(*canvas); - - // set up the parameters we want to use - glEnable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_TEXTURE_2D); - - // add slightly more light, the default lighting is rather dark - GLfloat ambient[] = { 0.5, 0.5, 0.5, 0.5 }; - glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); - - // set viewing projection - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(-0.5f, 0.5f, -0.5f, 0.5f, 1.0f, 3.0f); - - // create the textures to use for cube sides: they will be reused by all - // canvases (which is probably not critical in the case of simple textures - // we use here but could be really important for a real application where - // each texture could take many megabytes) - glGenTextures(WXSIZEOF(m_textures), m_textures); - - for (unsigned i = 0; i < WXSIZEOF(m_textures); i++) { - glBindTexture(GL_TEXTURE_2D, m_textures[i]); - - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - const wxImage img(DrawDice(256, i + 1)); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, img.GetData()); - } - - CheckGLError(); -} - -void PrimaryGLContext::DrawRotatedCube(float xangle, float yangle) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.0f, 0.0f, -2.0f); - glRotatef(xangle, 1.0f, 0.0f, 0.0f); - glRotatef(yangle, 0.0f, 1.0f, 0.0f); - - // draw six faces of a cube of size 1 centered at (0, 0, 0) - glBindTexture(GL_TEXTURE_2D, m_textures[0]); - glBegin(GL_QUADS); - glNormal3f(0.0f, 0.0f, 1.0f); - glTexCoord2f(0, 0); - glVertex3f(0.5f, 0.5f, 0.5f); - glTexCoord2f(1, 0); - glVertex3f(-0.5f, 0.5f, 0.5f); - glTexCoord2f(1, 1); - glVertex3f(-0.5f, -0.5f, 0.5f); - glTexCoord2f(0, 1); - glVertex3f(0.5f, -0.5f, 0.5f); - glEnd(); - - glBindTexture(GL_TEXTURE_2D, m_textures[1]); - glBegin(GL_QUADS); - glNormal3f(0.0f, 0.0f, -1.0f); - glTexCoord2f(0, 0); - glVertex3f(-0.5f, -0.5f, -0.5f); - glTexCoord2f(1, 0); - glVertex3f(-0.5f, 0.5f, -0.5f); - glTexCoord2f(1, 1); - glVertex3f(0.5f, 0.5f, -0.5f); - glTexCoord2f(0, 1); - glVertex3f(0.5f, -0.5f, -0.5f); - glEnd(); - - glBindTexture(GL_TEXTURE_2D, m_textures[2]); - glBegin(GL_QUADS); - glNormal3f(0.0f, 1.0f, 0.0f); - glTexCoord2f(0, 0); - glVertex3f(0.5f, 0.5f, 0.5f); - glTexCoord2f(1, 0); - glVertex3f(0.5f, 0.5f, -0.5f); - glTexCoord2f(1, 1); - glVertex3f(-0.5f, 0.5f, -0.5f); - glTexCoord2f(0, 1); - glVertex3f(-0.5f, 0.5f, 0.5f); - glEnd(); - - glBindTexture(GL_TEXTURE_2D, m_textures[3]); - glBegin(GL_QUADS); - glNormal3f(0.0f, -1.0f, 0.0f); - glTexCoord2f(0, 0); - glVertex3f(-0.5f, -0.5f, -0.5f); - glTexCoord2f(1, 0); - glVertex3f(0.5f, -0.5f, -0.5f); - glTexCoord2f(1, 1); - glVertex3f(0.5f, -0.5f, 0.5f); - glTexCoord2f(0, 1); - glVertex3f(-0.5f, -0.5f, 0.5f); - glEnd(); - - glBindTexture(GL_TEXTURE_2D, m_textures[4]); - glBegin(GL_QUADS); - glNormal3f(1.0f, 0.0f, 0.0f); - glTexCoord2f(0, 0); - glVertex3f(0.5f, 0.5f, 0.5f); - glTexCoord2f(1, 0); - glVertex3f(0.5f, -0.5f, 0.5f); - glTexCoord2f(1, 1); - glVertex3f(0.5f, -0.5f, -0.5f); - glTexCoord2f(0, 1); - glVertex3f(0.5f, 0.5f, -0.5f); - glEnd(); - - glBindTexture(GL_TEXTURE_2D, m_textures[5]); - glBegin(GL_QUADS); - glNormal3f(-1.0f, 0.0f, 0.0f); - glTexCoord2f(0, 0); - glVertex3f(-0.5f, -0.5f, -0.5f); - glTexCoord2f(1, 0); - glVertex3f(-0.5f, -0.5f, 0.5f); - glTexCoord2f(1, 1); - glVertex3f(-0.5f, 0.5f, 0.5f); - glTexCoord2f(0, 1); - glVertex3f(-0.5f, 0.5f, -0.5f); - glEnd(); - - glFlush(); - - CheckGLError(); -} - -// ---------------------------------------------------------------------------- -// CubicSDR: the application object -// ---------------------------------------------------------------------------- IMPLEMENT_APP(CubicSDR) + bool CubicSDR::OnInit() { if (!wxApp::OnInit()) return false; @@ -292,8 +64,6 @@ int CubicSDR::OnExit() { PrimaryGLContext& CubicSDR::GetContext(wxGLCanvas *canvas) { PrimaryGLContext *glContext; if (!m_glContext) { - // Create the OpenGL context for the first mono window which needs it: - // subsequently created windows will all share the same context. m_glContext = new PrimaryGLContext(canvas); } glContext = m_glContext; @@ -303,151 +73,3 @@ PrimaryGLContext& CubicSDR::GetContext(wxGLCanvas *canvas) { return *glContext; } -// ---------------------------------------------------------------------------- -// TestGLCanvas -// ---------------------------------------------------------------------------- - -wxBEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas) EVT_PAINT(TestGLCanvas::OnPaint) -EVT_KEY_DOWN(TestGLCanvas::OnKeyDown) -EVT_TIMER(SpinTimer, TestGLCanvas::OnSpinTimer) -wxEND_EVENT_TABLE() - -TestGLCanvas::TestGLCanvas(wxWindow *parent, int *attribList) -// With perspective OpenGL graphics, the wxFULL_REPAINT_ON_RESIZE style -// flag should always be set, because even making the canvas smaller should -// be followed by a paint event that updates the entire canvas with new -// viewport settings. -: - wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, - wxFULL_REPAINT_ON_RESIZE), m_xangle(30.0), m_yangle(30.0), m_spinTimer(this, SpinTimer) { -// if ( attribList ) -// { -// int i = 0; -// while ( attribList[i] != 0 ) -// { -// ++i; -// } -// } -} - -void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { - // This is required even though dc is not used otherwise. - wxPaintDC dc(this); - - // Set the OpenGL viewport according to the client size of this canvas. - // This is done here rather than in a wxSizeEvent handler because our - // OpenGL rendering context (and thus viewport setting) is used with - // multiple canvases: If we updated the viewport in the wxSizeEvent - // handler, changing the size of one canvas causes a viewport setting that - // is wrong when next another canvas is repainted. - const wxSize ClientSize = GetClientSize(); - - PrimaryGLContext& canvas = wxGetApp().GetContext(this); - glViewport(0, 0, ClientSize.x, ClientSize.y); - - // Render the graphics and swap the buffers. - canvas.DrawRotatedCube(m_xangle, m_yangle); - - SwapBuffers(); -} - -void TestGLCanvas::Spin(float xSpin, float ySpin) { - m_xangle += xSpin; - m_yangle += ySpin; - - Refresh(false); -} - -void TestGLCanvas::OnKeyDown(wxKeyEvent& event) { - float angle = 5.0; - - switch (event.GetKeyCode()) { - case WXK_RIGHT: - Spin(0.0, -angle); - break; - - case WXK_LEFT: - Spin(0.0, angle); - break; - - case WXK_DOWN: - Spin(-angle, 0.0); - break; - - case WXK_UP: - Spin(angle, 0.0); - break; - - case WXK_SPACE: - if (m_spinTimer.IsRunning()) - m_spinTimer.Stop(); - else - m_spinTimer.Start(1); - break; - - default: - event.Skip(); - return; - } -} - -void TestGLCanvas::OnSpinTimer(wxTimerEvent& WXUNUSED(event)) { - Spin(0.0, 4.0); -} - -wxString glGetwxString(GLenum name) { - const GLubyte *v = glGetString(name); - if (v == 0) { - // The error is not important. It is GL_INVALID_ENUM. - // We just want to clear the error stack. - glGetError(); - - return wxString(); - } - - return wxString((const char*) v); -} - -// ---------------------------------------------------------------------------- -// AppFrame: main application window -// ---------------------------------------------------------------------------- - -wxBEGIN_EVENT_TABLE(AppFrame, wxFrame) EVT_MENU(wxID_NEW, AppFrame::OnNewWindow) -EVT_MENU(wxID_CLOSE, AppFrame::OnClose) -wxEND_EVENT_TABLE() - -AppFrame::AppFrame() : - wxFrame(NULL, wxID_ANY, wxT("CubicSDR")) { - - new TestGLCanvas(this, NULL); - - SetIcon(wxICON(sample)); - - // Make a menubar - wxMenu *menu = new wxMenu; - menu->Append(wxID_NEW); - menu->AppendSeparator(); - menu->Append(wxID_CLOSE); - wxMenuBar *menuBar = new wxMenuBar; - menuBar->Append(menu, wxT("&Cube")); - - SetMenuBar(menuBar); - - CreateStatusBar(); - - SetClientSize(400, 400); - Show(); - -// static const int attribs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 }; -// wxLogStatus("Double-buffered display %s supported", wxGLCanvas::IsDisplaySupported(attribs) ? "is" : "not"); -// ShowFullScreen(true); -} - -void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) { - // true is to force the frame to close - Close(true); -} - -void AppFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event)) { - new AppFrame(); -} diff --git a/src/CubicSDR.h b/src/CubicSDR.h index fb207b0..49e3d4b 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -4,30 +4,18 @@ //WX_GL_MAJOR_VERSION 3 //WX_GL_MINOR_VERSION 2 -#include "wx/glcanvas.h" + + #include "SDRThread.h" - -// the rendering context used by all GL canvases -class PrimaryGLContext : public wxGLContext -{ -public: - PrimaryGLContext(wxGLCanvas *canvas); - - // render the cube showing it at given angles - void DrawRotatedCube(float xangle, float yangle); - -private: - // textures for the cube faces - GLuint m_textures[6]; -}; - +#include "wx/glcanvas.h" +#include "PrimaryGLContext.h" class CubicSDR : public wxApp { public: - CubicSDR() { m_glContext = NULL; } + CubicSDR() { m_glContext = NULL; m_pThread = NULL; } - PrimaryGLContext& GetContext(wxGLCanvas *canvas); + PrimaryGLContext &GetContext(wxGLCanvas *canvas); virtual bool OnInit(); virtual int OnExit(); @@ -38,36 +26,4 @@ private: wxCriticalSection m_pThreadCS; }; -// Define a new frame type -class AppFrame : public wxFrame -{ -public: - AppFrame(); - -private: - void OnClose(wxCommandEvent& event); - void OnNewWindow(wxCommandEvent& event); - - wxDECLARE_EVENT_TABLE(); -}; - -class TestGLCanvas : public wxGLCanvas -{ -public: - TestGLCanvas(wxWindow *parent, int *attribList = NULL); - -private: - void OnPaint(wxPaintEvent& event); - void Spin(float xSpin, float ySpin); - void OnKeyDown(wxKeyEvent& event); - void OnSpinTimer(wxTimerEvent& WXUNUSED(event)); - - // angles of rotation around x- and y- axis - float m_xangle, - m_yangle; - - wxTimer m_spinTimer; - - wxDECLARE_EVENT_TABLE(); -}; - +DECLARE_APP(CubicSDR) diff --git a/src/PrimaryGLContext.cpp b/src/PrimaryGLContext.cpp new file mode 100644 index 0000000..a99603b --- /dev/null +++ b/src/PrimaryGLContext.cpp @@ -0,0 +1,126 @@ +#include "PrimaryGLContext.h" + +#include "wx/wxprec.h" + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#if !wxUSE_GLCANVAS +#error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library" +#endif + +#include "CubicSDR.h" + +wxString glGetwxString(GLenum name) { + const GLubyte *v = glGetString(name); + if (v == 0) { + // The error is not important. It is GL_INVALID_ENUM. + // We just want to clear the error stack. + glGetError(); + + return wxString(); + } + + return wxString((const char*) v); +} + +static void CheckGLError() { + GLenum errLast = GL_NO_ERROR; + + for (;;) { + GLenum err = glGetError(); + if (err == GL_NO_ERROR) + return; + + if (err == errLast) { + wxLogError + (wxT("OpenGL error state couldn't be reset.")); + return; + } + + errLast = err; + + wxLogError + (wxT("OpenGL error %d"), err); + } +} + +PrimaryGLContext::PrimaryGLContext(wxGLCanvas *canvas) : + wxGLContext(canvas) { + SetCurrent(*canvas); + + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + CheckGLError(); +} + +void PrimaryGLContext::PlotIQ() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glBegin(GL_LINE_STRIP); + glColor3f(1.0f, 1.0f, 1.0f); + glVertex3f(-1.0f, -0.5f, 0.0f); + glVertex3f(1.0f, -0.5f, 0.0f); + glEnd(); + + glBegin(GL_LINE_STRIP); + glColor3f(1.0f, 1.0f, 1.0f); + glVertex3f(-1.0f, 0.5f, 0.0f); + glVertex3f(1.0f, 0.5f, 0.0f); + glEnd(); + + glFlush(); + + CheckGLError(); +} + +wxBEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas) EVT_PAINT(TestGLCanvas::OnPaint) +EVT_KEY_DOWN(TestGLCanvas::OnKeyDown) +wxEND_EVENT_TABLE() + +TestGLCanvas::TestGLCanvas(wxWindow *parent, int *attribList) : + wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, + wxFULL_REPAINT_ON_RESIZE) { + +} + +void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { + wxPaintDC dc(this); + const wxSize ClientSize = GetClientSize(); + + PrimaryGLContext& canvas = wxGetApp().GetContext(this); + glViewport(0, 0, ClientSize.x, ClientSize.y); + + canvas.PlotIQ(); + + SwapBuffers(); +} + +void TestGLCanvas::OnKeyDown(wxKeyEvent& event) { + float angle = 5.0; + + switch (event.GetKeyCode()) { + case WXK_RIGHT: + break; + case WXK_LEFT: + break; + case WXK_DOWN: + break; + case WXK_UP: + break; + case WXK_SPACE: + break; + default: + event.Skip(); + return; + } +} + diff --git a/src/PrimaryGLContext.h b/src/PrimaryGLContext.h new file mode 100644 index 0000000..0a5d49c --- /dev/null +++ b/src/PrimaryGLContext.h @@ -0,0 +1,28 @@ +#pragma once + +#include "wx/glcanvas.h" +#include "wx/timer.h" + +class PrimaryGLContext : public wxGLContext +{ +public: + PrimaryGLContext(wxGLCanvas *canvas); + + void PlotIQ(); + +private: + // textures for the cube faces + GLuint m_textures[6]; +}; + +class TestGLCanvas : public wxGLCanvas +{ +public: + TestGLCanvas(wxWindow *parent, int *attribList = NULL); + +private: + void OnPaint(wxPaintEvent& event); + void OnKeyDown(wxKeyEvent& event); + + wxDECLARE_EVENT_TABLE(); +}; diff --git a/src/SDRThread.cpp b/src/SDRThread.cpp index 4aa146d..abbdf14 100644 --- a/src/SDRThread.cpp +++ b/src/SDRThread.cpp @@ -1,8 +1,7 @@ #include "SDRThread.h" -static void rtl_callback(unsigned char *buf, uint32_t len, void *ctx) { - std::cout << "Got buffer! length: " << len << std::endl; -} +#define BUF_SIZE (16 * 32 * 512) + SDRThread::SDRThread(wxApp *app) : wxThread(wxTHREAD_DETACHED) { @@ -15,14 +14,12 @@ SDRThread::~SDRThread() { void SDRThread::enumerate_rtl() { + char manufact[256], product[256], serial[256]; + unsigned int rtl_count = rtlsdr_get_device_count(); std::cout << "RTL Devices: " << rtl_count << std::endl; - char manufact[256]; - char product[256]; - char serial[256]; - for (int i = 0; i < rtl_count; i++) { std::cout << "Device #" << i << ": " << rtlsdr_get_device_name(i) << std::endl; if (rtlsdr_get_device_usb_strings(i, manufact, product, serial) == 0) { @@ -83,8 +80,6 @@ void SDRThread::enumerate_rtl() { } -#define BUF_SIZE 16 * 32 * 512 - wxThread::ExitCode SDRThread::Entry() { __int8 *buf = (__int8 *) malloc(BUF_SIZE); @@ -97,141 +92,25 @@ wxThread::ExitCode SDRThread::Entry() { int n_read; int i = 0; - // rtlsdr_read_async(dev, rtl_callback, NULL, 0, 0); std::cout << "Sampling.."; while (!TestDestroy()) { rtlsdr_read_sync(dev, buf, BUF_SIZE, &n_read); -// std::cout << "Got buffer! length: " << n_read << std::endl; - std::cout << "."; - if (i%50==0) { + std::cout << (n_read == BUF_SIZE) ? "." : "!"; + + if (i % 50 == 0) { std::cout << std::endl; } i++; - - //wxQueueEvent(app,new wxThreadEvent(wxEVT_COMMAND_SDRThread_UPDATE)); } std::cout << std::endl << "Done." << std::endl << std::endl; - // wxQueueEvent(m_pHandler,new wxThreadEvent(wxEVT_COMMAND_SDRThread_COMPLETED)); - free(buf); rtlsdr_close(dev); + free(buf); - return (wxThread::ExitCode) 0; // success + return (wxThread::ExitCode) 0; } -/* - class MyFrame: public wxFrame { - public: - ~MyFrame() { - // it's better to do any thread cleanup in the OnClose() - // event handler, rather than in the destructor. - // This is because the event loop for a top-level window is not - // active anymore when its destructor is called and if the thread - // sends events when ending, they won't be processed unless - // you ended the thread from OnClose. - // See @ref overview_windowdeletion for more info. - } - - void DoStartThread(); - void DoPauseThread(); - // a resume routine would be nearly identic to DoPauseThread() - void DoResumeThread() { - } - void OnThreadUpdate(wxThreadEvent&); - void OnThreadCompletion(wxThreadEvent&); - void OnClose(wxCloseEvent&); - protected: - SDRThread *m_pThread; - wxCriticalSection m_pThreadCS; // protects the m_pThread pointer - wxDECLARE_EVENT_TABLE(); - }; - wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_CLOSE(MyFrame::OnClose) - EVT_MENU(Minimal_Start, MyFrame::DoStartThread) - EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_SDRThread_UPDATE, MyFrame::OnThreadUpdate) - EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_SDRThread_COMPLETED, MyFrame::OnThreadCompletion) - wxEND_EVENT_TABLE() - wxDEFINE_EVENT(wxEVT_COMMAND_SDRThread_COMPLETED, wxThreadEvent)wxDEFINE_EVENT - (wxEVT_COMMAND_SDRThread_UPDATE, wxThreadEvent)void - MyFrame::DoStartThread() { - m_pThread = new SDRThread(this); - if (m_pThread->Run() != wxTHREAD_NO_ERROR) { - wxLogError - ("Can't create the thread!"); - delete m_pThread; - m_pThread = NULL; - } - // after the call to wxThread::Run(), the m_pThread pointer is "unsafe": - // at any moment the thread may cease to exist (because it completes its work). - // To avoid dangling pointers OnThreadExit() will set m_pThread - // to NULL when the thread dies. - } - wxThread::ExitCode SDRThread::Entry() { - while (!TestDestroy()) { - // ... do a bit of work... - wxQueueEvent(m_pHandler, - new wxThreadEvent(wxEVT_COMMAND_SDRThread_UPDATE)); - } - // signal the event handler that this thread is going to be destroyed - // NOTE: here we assume that using the m_pHandler pointer is safe, - // (in this case this is assured by the MyFrame destructor) - wxQueueEvent(m_pHandler, - new wxThreadEvent(wxEVT_COMMAND_SDRThread_COMPLETED)); - return (wxThread::ExitCode) 0; // success - } - SDRThread::~SDRThread() { - wxCriticalSectionLocker enter(m_pHandler->m_pThreadCS); - // the thread is being destroyed; make sure not to leave dangling pointers around - m_pHandler->m_pThread = NULL; - } - void MyFrame::OnThreadCompletion(wxThreadEvent&) { - wxMessageOutputDebug().Printf("MYFRAME: SDRThread exited!\n"); - } - void MyFrame::OnThreadUpdate(wxThreadEvent&) { - wxMessageOutputDebug().Printf("MYFRAME: SDRThread update...\n"); - } - void MyFrame::DoPauseThread() { - // anytime we access the m_pThread pointer we must ensure that it won't - // be modified in the meanwhile; since only a single thread may be - // inside a given critical section at a given time, the following code - // is safe: - wxCriticalSectionLocker enter(m_pThreadCS); - if (m_pThread) // does the thread still exist? - { - // without a critical section, once reached this point it may happen - // that the OS scheduler gives control to the SDRThread::Entry() function, - // which in turn may return (because it completes its work) making - // invalid the m_pThread pointer - if (m_pThread->Pause() != wxTHREAD_NO_ERROR) - wxLogError - ("Can't pause the thread!"); - } - } - void MyFrame::OnClose(wxCloseEvent&) { - { - wxCriticalSectionLocker enter(m_pThreadCS); - if (m_pThread) // does the thread still exist? - { - wxMessageOutputDebug().Printf("MYFRAME: deleting thread"); - if (m_pThread->Delete() != wxTHREAD_NO_ERROR) - wxLogError - ("Can't delete the thread!"); - } - } // exit from the critical section to give the thread - // the possibility to enter its destructor - // (which is guarded with m_pThreadCS critical section!) - while (1) { - { // was the ~SDRThread() function executed? - wxCriticalSectionLocker enter(m_pThreadCS); - if (!m_pThread) - break; - } - // wait for thread completion - wxThread::This()->Sleep(1); - } - Destroy(); - } - */