diff --git a/meson.build b/meson.build index 5bbc419..cbcbb14 100755 --- a/meson.build +++ b/meson.build @@ -202,7 +202,7 @@ if wx_found sources: src, cpp_args: [wx_cxx_flags], link_args: [wx_libs], - dependencies: [wx, taglib, sqlite3, yaml, snd], + dependencies: [wx, taglib, sqlite3, yaml, snd, glew], install: true, install_rpath: prefix / 'lib') else diff --git a/src/GL.cpp b/src/GL.cpp index 19fad5d..5c6de42 100644 --- a/src/GL.cpp +++ b/src/GL.cpp @@ -2,12 +2,36 @@ #include #include +#include + #include "GL.hpp" #include #include +#define ASSERT(x) if (!(x)) raise(SIGTRAP); +#define GLCall(x) GLClearError(); \ + x;\ + ASSERT(GLLogCall(__FUNCTION__, __FILE__, __LINE__)) + +static void GLClearError() +{ + while (glGetError() != GL_NO_ERROR); +} + +static bool GLLogCall(const char* function, const char* file, int line) +{ + while (GLenum error = glGetError()) + { + std::cout << "[OpenGL Error] (" << error << "): " << function + << " " << file << ":" << line << std::endl; + return false; + } + + return true; +} + static std::string ParseShader(const std::string& filepath) { std::string source; @@ -36,18 +60,18 @@ static unsigned int CompileShader(unsigned int type, const std::string& source) { unsigned int id = glCreateShader(type); const char* src = source.c_str(); - glShaderSource(id, 1, &src , nullptr); - glCompileShader(id); + GLCall(glShaderSource(id, 1, &src , nullptr)); + GLCall(glCompileShader(id)); int result; - glGetShaderiv(id, GL_COMPILE_STATUS, &result); + GLCall(glGetShaderiv(id, GL_COMPILE_STATUS, &result)); if (result == GL_FALSE) { int length; - glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length); + GLCall(glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length)); char message[length]; - glGetShaderInfoLog(id, length, &length, message); + GLCall(glGetShaderInfoLog(id, length, &length, message)); std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") @@ -55,7 +79,7 @@ static unsigned int CompileShader(unsigned int type, const std::string& source) std::cout << message << std::endl; - glDeleteShader(id); + GLCall(glDeleteShader(id)); return 0; } @@ -63,35 +87,103 @@ static unsigned int CompileShader(unsigned int type, const std::string& source) return id; } -static unsigned int CreateShader(unsigned int type, const std::string& source) +static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader) { - unsigned int program = glCreateProgram(); + GLCall(unsigned int program = glCreateProgram()); - unsigned int shader = CompileShader(type, source); + unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader); + unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader); - glAttachShader(program, shader); - glLinkProgram(program); - glValidateProgram(program); + GLCall(glAttachShader(program, vs)); + GLCall(glAttachShader(program, fs)); + GLCall(glLinkProgram(program)); + GLCall(glValidateProgram(program)); - glDeleteShader(shader); + GLCall(glDeleteShader(vs)); + GLCall(glDeleteShader(fs)); return program; } bool GLHelper::InitGlew() { - GLenum initStatus = glewInit(); + // GLCall(glewExperimental = GL_TRUE); - return initStatus == GLEW_OK; + GLCall(GLenum init_status = glewInit()); + + if (init_status != GLEW_OK) + { + GLCall(const GLubyte* error = glewGetErrorString(init_status)); + + std::cout << "GLEW Error: " << error << std::endl; + return false; + } + else + return true; } void GLHelper::Render() { - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + // float positions[] = + // { + // -0.5f, -0.5f, // 0 + // 0.5f, -0.5f, // 1 + // 0.5f, 0.5f, // 2 + // -0.5f, 0.5f // 3 + // }; + + // unsigned int indices[] = + // { + // 0, 1, 2, + // 2, 3, 0 + // }; + + // unsigned int vertex_array_object; + // GLCall(glGenVertexArrays(1, &vertex_array_object)); + // GLCall(glBindVertexArray(vertex_array_object)); + + // unsigned int vertex_buffer; + // glGenBuffers(1, &vertex_buffer); + // glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + // glBufferData(GL_ARRAY_BUFFER, 4 * 2 * sizeof(float), positions, GL_STATIC_DRAW); + + // glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0); + // glEnableVertexAttribArray(0); + + // unsigned int index_buffer; + // glGenBuffers(1, &index_buffer); + // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); + // glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned int), indices, GL_STATIC_DRAW); + + // std::string vertexShader = ParseShader("../res/shaders/basic.vert"); + // std::string fragmentShader = ParseShader("../res/shaders/basic.frag"); + + // unsigned int shader = CreateShader(vertexShader, fragmentShader); + + // int location = glGetUniformLocation(shader, "u_Color"); + // float r = 0.0f, g = 0.0f, b = 0.0f, a =1.0f, inc = 0.01f; + + // glUseProgram(0); + // glBindBuffer(GL_ARRAY_BUFFER, 0); + // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + // glUseProgram(shader); + + // /* Set the shader color */ + // glUniform4f(location, r, 0.3f, 0.02f, a); + + // glBindVertexArray(vertex_array_object); + // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); + + // /* Draw call */ + // glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); + + + GLCall(glClearColor(0.4f, 0.2f, 0.8f, 1.0f)); + GLCall(glClear(GL_COLOR_BUFFER_BIT)); } -void GLHelper::SetSize(int width, int height) +void GLHelper::SetViewport(int x, int y, int width, int height) { - glViewport(0, 0, width, height); + GLCall(glViewport(x, y, width, height)); } diff --git a/src/GL.hpp b/src/GL.hpp index 46e4e05..9b3929d 100644 --- a/src/GL.hpp +++ b/src/GL.hpp @@ -5,5 +5,5 @@ class GLHelper public: bool InitGlew(); void Render(); - void SetSize(int w, int h); + void SetViewport(int x, int y, int width, int height); }; diff --git a/src/MainFrame.cpp b/src/MainFrame.cpp index 2a5f014..060d17a 100644 --- a/src/MainFrame.cpp +++ b/src/MainFrame.cpp @@ -404,7 +404,18 @@ MainFrame::MainFrame() m_Database->CreateTableSamples(); m_Database->CreateTableHives(); - m_TopWaveformPanel = new WaveformViewer(this, m_TopPanel, *m_Library, *m_MediaCtrl, *m_Database, + wxGLAttributes display_attributes; + display_attributes.PlatformDefaults().RGBA().DoubleBuffer().EndList(); + + // int display_attributes[] = + // { WX_GL_RGBA, + // WX_GL_DOUBLEBUFFER, + // WX_GL_CORE_PROFILE, + // WX_GL_MAJOR_VERSION ,3, + // WX_GL_MINOR_VERSION, 3, + // 0 }; + + m_TopWaveformPanel = new WaveformViewer(this, m_TopPanel, display_attributes, *m_Library, *m_MediaCtrl, *m_Database, m_ConfigFilepath, m_DatabaseFilepath); // Binding events. diff --git a/src/MainFrame.hpp b/src/MainFrame.hpp index 94273d8..f992ef4 100644 --- a/src/MainFrame.hpp +++ b/src/MainFrame.hpp @@ -183,7 +183,9 @@ class MainFrame : public wxFrame wxLongLong m_LoopA, m_LoopB; // ------------------------------------------------------------------- - wxSystemAppearance m_Theme = wxSystemSettings::GetAppearance(); + #if wxCHECK_VERSION(3, 1, 0) + wxSystemAppearance m_Theme = wxSystemSettings::GetAppearance(); + #endif private: // ------------------------------------------------------------------- diff --git a/src/WaveformViewer.cpp b/src/WaveformViewer.cpp index f704030..de78339 100644 --- a/src/WaveformViewer.cpp +++ b/src/WaveformViewer.cpp @@ -38,24 +38,27 @@ #include -WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataViewListCtrl& library, - wxMediaCtrl& mediaCtrl, Database& database, +// WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, int* attrs, +WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, const wxGLAttributes& attrs, + wxDataViewListCtrl& library, wxMediaCtrl& mediaCtrl, Database& database, const std::string& configFilepath, const std::string& databaseFilepath) - : wxPanel(window, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER | wxFULL_REPAINT_ON_RESIZE), + : wxGLCanvas(window, attrs), + // : wxGLCanvas(window, wxID_ANY, attrs), + // : wxPanel(window, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER | wxFULL_REPAINT_ON_RESIZE), m_ParentFrame(parentFrame), m_Window(window), m_Database(database), m_Library(library), m_MediaCtrl(mediaCtrl), m_ConfigFilepath(configFilepath), m_DatabaseFilepath(databaseFilepath) { // Create the canvas and context. #if wxCHECK_VERSION(3, 1, 0) // These settings should work with any GPU from the last 10 years. - wxGLAttributes display_attributes; - display_attributes.PlatformDefaults().RGBA().DoubleBuffer().EndList(); + // wxGLAttributes display_attributes; + // display_attributes.PlatformDefaults().RGBA().DoubleBuffer().EndList(); wxGLContextAttrs context_attributes; context_attributes.PlatformDefaults().CoreProfile().OGLVersion(3, 3).EndList(); - m_Canvas = new wxGLCanvas(this, display_attributes); - m_Context = new wxGLContext(m_Canvas, NULL, &context_attributes); + // this = new wxGLCanvas(this, display_attributes); + m_Context = new wxGLContext(this, NULL, &context_attributes); if (!m_Context->IsOK()) { @@ -63,16 +66,16 @@ WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataVi return; } #else - int display_attributes[] = - { WX_GL_RGBA, - WX_GL_DOUBLEBUFFER, - WX_GL_CORE_PROFILE, - WX_GL_MAJOR_VERSION ,3, - WX_GL_MINOR_VERSION, 3, - 0 }; + // int display_attributes[] = + // { WX_GL_RGBA, + // WX_GL_DOUBLEBUFFER, + // WX_GL_CORE_PROFILE, + // WX_GL_MAJOR_VERSION ,3, + // WX_GL_MINOR_VERSION, 3, + // 0 }; - m_Canvas = new wxGLCanvas(this, wxID_ANY, display_attributes); - m_Context = new wxGLContext(m_Canvas, NULL); + // this = new wxGLCanvas(this, wxID_ANY, display_attributes); + m_Context = new wxGLContext(this, NULL); // Unfortunately, there doesn't seem to be any way to check if the // context is ok prior to wxWidgets 3.1.0. @@ -80,15 +83,17 @@ WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataVi // On Linux, we must delay delay initialization until the canvas has // been fully created. On windows, we can finish now. - #ifdef __WXMSW__ - InitGL(); - #elif defined(__WXGTK__) - m_Canvas->Bind(wxEVT_CREATE, [this](wxWindowCreateEvent&){ InitGL(); }); - #endif // defined + // #ifdef __WXMSW__ + // InitGL(); + // #elif defined(__WXGTK__) + // this->Bind(wxEVT_CREATE, [this](wxWindowCreateEvent&){ InitGL(); }); + // #endif // defined - this->SetDoubleBuffered(true); + // this->SetDoubleBuffered(true); - // Bind(wxEVT_PAINT, &WaveformViewer::OnPaint, this); + Bind(wxEVT_SIZE, &WaveformViewer::OnSize, this); + + Bind(wxEVT_PAINT, &WaveformViewer::OnPaint, this); Bind(wxEVT_MOTION, &WaveformViewer::OnMouseMotion, this); Bind(wxEVT_LEFT_DOWN, &WaveformViewer::OnMouseLeftButtonDown, this); Bind(wxEVT_LEFT_UP, &WaveformViewer::OnMouseLeftButtonUp, this); @@ -101,42 +106,75 @@ WaveformViewer::~WaveformViewer() delete m_Context; } -void WaveformViewer::InitGL() +bool WaveformViewer::InitGL() { + if (!m_Context) + return false; + + // The current context must be set before we get OGL pointers + if (!IsShownOnScreen()) + return false; + // else + // SetCurrent(*m_Context); + // First call SetCurrent or GL initialization will fail. - m_Context->SetCurrent(*m_Canvas); + if (!m_Context->SetCurrent(*this)) + { + wxLogDebug("Error! Unable to set the context"); + return false; + } // Initialize GLEW. - bool glewInialized = m_Helper.InitGlew(); - - if (!glewInialized) + if (!m_GLHelper.InitGlew()) { - wxLogDebug("Failed to initialize GLEW."); - return; + wxLogDebug("Error %s()! Failed to initialize GLEW.", __FUNCTION__); + return false; } wxLogDebug("Context and GLEW initialized."); // Bind event handlers for the canvas. Binding was delayed until OpenGL was // initialized because these handlers will need to call OpenGL functions. - m_Canvas->Bind(wxEVT_SIZE, &WaveformViewer::OnSize, this); - m_Canvas->Bind(wxEVT_PAINT, &WaveformViewer::OnPaint, this); + // this->Bind(wxEVT_SIZE, &WaveformViewer::OnSize, this); + // this->Bind(wxEVT_PAINT, &WaveformViewer::OnPaint, this); + + return true; } void WaveformViewer::OnSize(wxSizeEvent &event) { - wxSize sz = event.GetSize(); - m_Helper.SetSize(sz.GetWidth(), sz.GetHeight()); - event.Skip(); + + // First call SetCurrent or GL initialization will fail. + // if (!m_Context->SetCurrent(*this)) + // wxLogDebug("Error from %s! Unable to set the context", __FUNCTION__); + + // if (!InitGL()) + // wxLogDebug("Failed to initialize GL"); + // else + // wxLogDebug("Canvas ready, initializing GL.."); + + // PostSizeEvent(); + + InitGL(); + + wxSize size = event.GetSize() * GetContentScaleFactor(); + m_GLHelper.SetViewport(0, 0, size.x, size.y); + + // Refresh(false); } void WaveformViewer::OnPaint(wxPaintEvent& event) { - wxPaintDC dc(m_Canvas); + wxPaintDC dc(this); - m_Helper.Render(); - m_Canvas->SwapBuffers(); + // First call SetCurrent or GL initialization will fail. + if (!m_Context->SetCurrent(*this)) + wxLogDebug("Error from %s! Unable to set the context", __FUNCTION__); + + m_GLHelper.Render(); + + this->SwapBuffers(); // wxPaintDC dc(this); diff --git a/src/WaveformViewer.hpp b/src/WaveformViewer.hpp index e70071e..00ea16e 100644 --- a/src/WaveformViewer.hpp +++ b/src/WaveformViewer.hpp @@ -37,11 +37,13 @@ #include #include -class WaveformViewer : public wxPanel +class WaveformViewer : public wxGLCanvas { public: - WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataViewListCtrl& library, - wxMediaCtrl& mediaCtrl, Database& database, + // WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataViewListCtrl& library, + // WaveformViewer(wxWindow* parentFrame, wxWindow* window, int* attrs, + WaveformViewer(wxWindow* parentFrame, wxWindow* window, const wxGLAttributes& attrs, + wxDataViewListCtrl& library, wxMediaCtrl& mediaCtrl, Database& database, const std::string& configFilepath, const std::string& databaseFilepath); ~WaveformViewer(); @@ -74,7 +76,7 @@ class WaveformViewer : public wxPanel // ------------------------------------------------------------------- wxGLCanvas* m_Canvas; wxGLContext* m_Context; - GLHelper m_Helper; + GLHelper m_GLHelper; private: // ------------------------------------------------------------------- @@ -85,7 +87,7 @@ class WaveformViewer : public wxPanel private: // ------------------------------------------------------------------- - void InitGL(); + bool InitGL(); // ------------------------------------------------------------------- void OnSize(wxSizeEvent& event);