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,
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

View File

@ -2,12 +2,36 @@
#include <iostream>
#include <sstream>
#include <signal.h>
#include "GL.hpp"
#include <GL/glew.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)
{
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));
}

View File

@ -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);
};

View File

@ -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.

View File

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

View File

@ -38,24 +38,27 @@
#include <sndfile.hh>
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);

View File

@ -37,11 +37,13 @@
#include <wx/timer.h>
#include <wx/window.h>
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);