Changed WaveformViewer from wxPanel to wxGLCanvas.

This commit is contained in:
apoorv569 2021-10-26 18:49:01 +05:30
parent 7174e52c48
commit b349486eef
7 changed files with 211 additions and 66 deletions

View File

@ -202,7 +202,7 @@ if wx_found
sources: src, sources: src,
cpp_args: [wx_cxx_flags], cpp_args: [wx_cxx_flags],
link_args: [wx_libs], link_args: [wx_libs],
dependencies: [wx, taglib, sqlite3, yaml, snd], dependencies: [wx, taglib, sqlite3, yaml, snd, glew],
install: true, install: true,
install_rpath: prefix / 'lib') install_rpath: prefix / 'lib')
else else

View File

@ -2,12 +2,36 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <signal.h>
#include "GL.hpp" #include "GL.hpp"
#include <GL/glew.h> #include <GL/glew.h>
#include <wx/event.h> #include <wx/event.h>
#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) static std::string ParseShader(const std::string& filepath)
{ {
std::string source; std::string source;
@ -36,18 +60,18 @@ static unsigned int CompileShader(unsigned int type, const std::string& source)
{ {
unsigned int id = glCreateShader(type); unsigned int id = glCreateShader(type);
const char* src = source.c_str(); const char* src = source.c_str();
glShaderSource(id, 1, &src , nullptr); GLCall(glShaderSource(id, 1, &src , nullptr));
glCompileShader(id); GLCall(glCompileShader(id));
int result; int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result); GLCall(glGetShaderiv(id, GL_COMPILE_STATUS, &result));
if (result == GL_FALSE) if (result == GL_FALSE)
{ {
int length; int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length); GLCall(glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length));
char message[length]; char message[length];
glGetShaderInfoLog(id, length, &length, message); GLCall(glGetShaderInfoLog(id, length, &length, message));
std::cout << "Failed to compile " std::cout << "Failed to compile "
<< (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << (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; std::cout << message << std::endl;
glDeleteShader(id); GLCall(glDeleteShader(id));
return 0; return 0;
} }
@ -63,35 +87,103 @@ static unsigned int CompileShader(unsigned int type, const std::string& source)
return id; 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); GLCall(glAttachShader(program, vs));
glLinkProgram(program); GLCall(glAttachShader(program, fs));
glValidateProgram(program); GLCall(glLinkProgram(program));
GLCall(glValidateProgram(program));
glDeleteShader(shader); GLCall(glDeleteShader(vs));
GLCall(glDeleteShader(fs));
return program; return program;
} }
bool GLHelper::InitGlew() 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() void GLHelper::Render()
{ {
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // float positions[] =
glClear(GL_COLOR_BUFFER_BIT); // {
// -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));
} }

View File

@ -5,5 +5,5 @@ class GLHelper
public: public:
bool InitGlew(); bool InitGlew();
void Render(); void Render();
void SetSize(int w, int h); void SetViewport(int x, int y, int width, int height);
}; };

View File

@ -404,7 +404,18 @@ MainFrame::MainFrame()
m_Database->CreateTableSamples(); m_Database->CreateTableSamples();
m_Database->CreateTableHives(); 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); m_ConfigFilepath, m_DatabaseFilepath);
// Binding events. // Binding events.

View File

@ -183,7 +183,9 @@ class MainFrame : public wxFrame
wxLongLong m_LoopA, m_LoopB; wxLongLong m_LoopA, m_LoopB;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
#if wxCHECK_VERSION(3, 1, 0)
wxSystemAppearance m_Theme = wxSystemSettings::GetAppearance(); wxSystemAppearance m_Theme = wxSystemSettings::GetAppearance();
#endif
private: private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------

View File

@ -38,24 +38,27 @@
#include <sndfile.hh> #include <sndfile.hh>
WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataViewListCtrl& library, // WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, int* attrs,
wxMediaCtrl& mediaCtrl, Database& database, WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, const wxGLAttributes& attrs,
wxDataViewListCtrl& library, wxMediaCtrl& mediaCtrl, Database& database,
const std::string& configFilepath, const std::string& databaseFilepath) 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_ParentFrame(parentFrame), m_Window(window), m_Database(database), m_Library(library), m_MediaCtrl(mediaCtrl),
m_ConfigFilepath(configFilepath), m_DatabaseFilepath(databaseFilepath) m_ConfigFilepath(configFilepath), m_DatabaseFilepath(databaseFilepath)
{ {
// Create the canvas and context. // Create the canvas and context.
#if wxCHECK_VERSION(3, 1, 0) #if wxCHECK_VERSION(3, 1, 0)
// These settings should work with any GPU from the last 10 years. // These settings should work with any GPU from the last 10 years.
wxGLAttributes display_attributes; // wxGLAttributes display_attributes;
display_attributes.PlatformDefaults().RGBA().DoubleBuffer().EndList(); // display_attributes.PlatformDefaults().RGBA().DoubleBuffer().EndList();
wxGLContextAttrs context_attributes; wxGLContextAttrs context_attributes;
context_attributes.PlatformDefaults().CoreProfile().OGLVersion(3, 3).EndList(); context_attributes.PlatformDefaults().CoreProfile().OGLVersion(3, 3).EndList();
m_Canvas = new wxGLCanvas(this, display_attributes); // this = new wxGLCanvas(this, display_attributes);
m_Context = new wxGLContext(m_Canvas, NULL, &context_attributes); m_Context = new wxGLContext(this, NULL, &context_attributes);
if (!m_Context->IsOK()) if (!m_Context->IsOK())
{ {
@ -63,16 +66,16 @@ WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataVi
return; return;
} }
#else #else
int display_attributes[] = // int display_attributes[] =
{ WX_GL_RGBA, // { WX_GL_RGBA,
WX_GL_DOUBLEBUFFER, // WX_GL_DOUBLEBUFFER,
WX_GL_CORE_PROFILE, // WX_GL_CORE_PROFILE,
WX_GL_MAJOR_VERSION ,3, // WX_GL_MAJOR_VERSION ,3,
WX_GL_MINOR_VERSION, 3, // WX_GL_MINOR_VERSION, 3,
0 }; // 0 };
m_Canvas = new wxGLCanvas(this, wxID_ANY, display_attributes); // this = new wxGLCanvas(this, wxID_ANY, display_attributes);
m_Context = new wxGLContext(m_Canvas, NULL); m_Context = new wxGLContext(this, NULL);
// Unfortunately, there doesn't seem to be any way to check if the // Unfortunately, there doesn't seem to be any way to check if the
// context is ok prior to wxWidgets 3.1.0. // 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 // On Linux, we must delay delay initialization until the canvas has
// been fully created. On windows, we can finish now. // been fully created. On windows, we can finish now.
#ifdef __WXMSW__ // #ifdef __WXMSW__
InitGL(); // InitGL();
#elif defined(__WXGTK__) // #elif defined(__WXGTK__)
m_Canvas->Bind(wxEVT_CREATE, [this](wxWindowCreateEvent&){ InitGL(); }); // this->Bind(wxEVT_CREATE, [this](wxWindowCreateEvent&){ InitGL(); });
#endif // defined // #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_MOTION, &WaveformViewer::OnMouseMotion, this);
Bind(wxEVT_LEFT_DOWN, &WaveformViewer::OnMouseLeftButtonDown, this); Bind(wxEVT_LEFT_DOWN, &WaveformViewer::OnMouseLeftButtonDown, this);
Bind(wxEVT_LEFT_UP, &WaveformViewer::OnMouseLeftButtonUp, this); Bind(wxEVT_LEFT_UP, &WaveformViewer::OnMouseLeftButtonUp, this);
@ -101,42 +106,75 @@ WaveformViewer::~WaveformViewer()
delete m_Context; 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. // 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. // Initialize GLEW.
bool glewInialized = m_Helper.InitGlew(); if (!m_GLHelper.InitGlew())
if (!glewInialized)
{ {
wxLogDebug("Failed to initialize GLEW."); wxLogDebug("Error %s()! Failed to initialize GLEW.", __FUNCTION__);
return; return false;
} }
wxLogDebug("Context and GLEW initialized."); wxLogDebug("Context and GLEW initialized.");
// Bind event handlers for the canvas. Binding was delayed until OpenGL was // Bind event handlers for the canvas. Binding was delayed until OpenGL was
// initialized because these handlers will need to call OpenGL functions. // initialized because these handlers will need to call OpenGL functions.
m_Canvas->Bind(wxEVT_SIZE, &WaveformViewer::OnSize, this); // this->Bind(wxEVT_SIZE, &WaveformViewer::OnSize, this);
m_Canvas->Bind(wxEVT_PAINT, &WaveformViewer::OnPaint, this); // this->Bind(wxEVT_PAINT, &WaveformViewer::OnPaint, this);
return true;
} }
void WaveformViewer::OnSize(wxSizeEvent &event) void WaveformViewer::OnSize(wxSizeEvent &event)
{ {
wxSize sz = event.GetSize();
m_Helper.SetSize(sz.GetWidth(), sz.GetHeight());
event.Skip(); 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) void WaveformViewer::OnPaint(wxPaintEvent& event)
{ {
wxPaintDC dc(m_Canvas); wxPaintDC dc(this);
m_Helper.Render(); // First call SetCurrent or GL initialization will fail.
m_Canvas->SwapBuffers(); if (!m_Context->SetCurrent(*this))
wxLogDebug("Error from %s! Unable to set the context", __FUNCTION__);
m_GLHelper.Render();
this->SwapBuffers();
// wxPaintDC dc(this); // wxPaintDC dc(this);

View File

@ -37,11 +37,13 @@
#include <wx/timer.h> #include <wx/timer.h>
#include <wx/window.h> #include <wx/window.h>
class WaveformViewer : public wxPanel class WaveformViewer : public wxGLCanvas
{ {
public: public:
WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataViewListCtrl& library, // WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataViewListCtrl& library,
wxMediaCtrl& mediaCtrl, Database& database, // 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); const std::string& configFilepath, const std::string& databaseFilepath);
~WaveformViewer(); ~WaveformViewer();
@ -74,7 +76,7 @@ class WaveformViewer : public wxPanel
// ------------------------------------------------------------------- // -------------------------------------------------------------------
wxGLCanvas* m_Canvas; wxGLCanvas* m_Canvas;
wxGLContext* m_Context; wxGLContext* m_Context;
GLHelper m_Helper; GLHelper m_GLHelper;
private: private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -85,7 +87,7 @@ class WaveformViewer : public wxPanel
private: private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
void InitGL(); bool InitGL();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
void OnSize(wxSizeEvent& event); void OnSize(wxSizeEvent& event);