Trying out OpenGL to render waveform.

This commit is contained in:
apoorv569 2021-10-17 13:38:50 +05:30
parent 0ecf694997
commit 7174e52c48
5 changed files with 239 additions and 38 deletions

View File

@ -121,6 +121,7 @@ src = [
'src/Serialize.cpp',
'src/Tags.cpp',
'src/WaveformViewer.cpp',
'src/GL.cpp',
'src/SH_Event.cpp',
]
@ -137,12 +138,14 @@ if not wx.found()
wx_base = wx_subproject.dependency('wxbase')
wx_core = wx_subproject.dependency('wxcore')
wx_media = wx_subproject.dependency('wxmedia')
wx = [wx_core, wx_base, wx_media]
wx_gl = wx_subproject.dependency('wxgl')
wx = [wx_core, wx_base, wx_media, wx_gl]
else
wx_found = true
wxconfig = find_program(['wx-config-gtk3', 'wx-config'])
wx_modules = ['media', 'std']
wxconfig = find_program(['wx-config', 'wx-config-gtk3', 'wx-config-3.1'])
wx_modules = ['gl', 'media', 'std']
wx_cxx_flags = []
wx_libs = []
@ -183,6 +186,8 @@ if not snd.found()
snd = snd_subproject.dependency('sndfile')
endif
glew = dependency('glew')
# Create samplehive-config.h based on configuration
config_h = configure_file(output: 'SampleHiveConfig.hpp',
configuration: config_data,)
@ -203,7 +208,7 @@ if wx_found
else
executable('SampleHive',
sources: src,
dependencies: [wx, taglib, sqlite3, yaml, snd],
dependencies: [wx, taglib, sqlite3, yaml, snd, glew],
install: true,
install_rpath: prefix / 'lib')
endif

97
src/GL.cpp Normal file
View File

@ -0,0 +1,97 @@
#include <fstream>
#include <iostream>
#include <sstream>
#include "GL.hpp"
#include <GL/glew.h>
#include <wx/event.h>
static std::string ParseShader(const std::string& filepath)
{
std::string source;
std::ifstream stream(filepath);
std::stringstream shader_stream;
stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
shader_stream << stream.rdbuf();
stream.close();
source = shader_stream.str();
}
catch(std::ifstream::failure e)
{
std::cout << "Error! Could not parse shader file." << e.code() << e.what() << std::endl;
}
return source;
}
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);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char message[length];
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile "
<< (type == GL_VERTEX_SHADER ? "vertex" : "fragment")
<< "shader" << std::endl;
std::cout << message << std::endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int CreateShader(unsigned int type, const std::string& source)
{
unsigned int program = glCreateProgram();
unsigned int shader = CompileShader(type, source);
glAttachShader(program, shader);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(shader);
return program;
}
bool GLHelper::InitGlew()
{
GLenum initStatus = glewInit();
return initStatus == GLEW_OK;
}
void GLHelper::Render()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
void GLHelper::SetSize(int width, int height)
{
glViewport(0, 0, width, height);
}

9
src/GL.hpp Normal file
View File

@ -0,0 +1,9 @@
#pragma once
class GLHelper
{
public:
bool InitGlew();
void Render();
void SetSize(int w, int h);
};

View File

@ -45,9 +45,50 @@ WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataVi
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();
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);
if (!m_Context->IsOK())
{
wxLogDebug("Failed to create context.");
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 };
m_Canvas = new wxGLCanvas(this, wxID_ANY, display_attributes);
m_Context = new wxGLContext(m_Canvas, NULL);
// Unfortunately, there doesn't seem to be any way to check if the
// context is ok prior to wxWidgets 3.1.0.
#endif // wxCHECK_VERSION
// 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
this->SetDoubleBuffered(true);
Bind(wxEVT_PAINT, &WaveformViewer::OnPaint, 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);
@ -57,55 +98,90 @@ WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataVi
WaveformViewer::~WaveformViewer()
{
delete m_Context;
}
void WaveformViewer::InitGL()
{
// First call SetCurrent or GL initialization will fail.
m_Context->SetCurrent(*m_Canvas);
// Initialize GLEW.
bool glewInialized = m_Helper.InitGlew();
if (!glewInialized)
{
wxLogDebug("Failed to initialize GLEW.");
return;
}
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);
}
void WaveformViewer::OnSize(wxSizeEvent &event)
{
wxSize sz = event.GetSize();
m_Helper.SetSize(sz.GetWidth(), sz.GetHeight());
event.Skip();
}
void WaveformViewer::OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
wxPaintDC dc(m_Canvas);
const wxSize& size = m_Window->GetClientSize();
m_Helper.Render();
m_Canvas->SwapBuffers();
if (!m_WaveformBitmap.IsOk()
|| m_WaveformBitmap.GetWidth() != size.x
|| m_WaveformBitmap.GetHeight() != size.y
|| bBitmapDirty)
{
wxLogDebug("Updating waveform bitmap..");
// wxPaintDC dc(this);
m_WaveformBitmap = wxBitmap(wxImage(size.x, size.y), 32);
// const wxSize& size = m_Window->GetClientSize();
UpdateWaveformBitmap();
// if (!m_WaveformBitmap.IsOk()
// || m_WaveformBitmap.GetWidth() != size.x
// || m_WaveformBitmap.GetHeight() != size.y
// || bBitmapDirty)
// {
// wxLogDebug("Updating waveform bitmap..");
bBitmapDirty = false;
}
// m_WaveformBitmap = wxBitmap(wxImage(size.x, size.y), 32);
dc.DrawBitmap(m_WaveformBitmap, 0, 0, false);
// UpdateWaveformBitmap();
RenderPlayhead(dc);
// bBitmapDirty = false;
// }
// Draw selection range
if (bSelectRange)
{
wxRect rect(m_CurrentPoint, m_AnchorPoint);
// dc.DrawBitmap(m_WaveformBitmap, 0, 0, false);
dc.SetPen(wxPen(wxColour(200, 200, 200), 2, wxPENSTYLE_SOLID));
dc.SetBrush(wxBrush(wxColour(200, 200, 200, 80), wxBRUSHSTYLE_SOLID));
dc.DrawRectangle(rect);
}
// RenderPlayhead(dc);
// Draw selected area
if (!bSelectRange && bDrawSelectedArea && !bBitmapDirty)
{
dc.SetPen(wxPen(wxColour(200, 200, 200, 255), 4, wxPENSTYLE_SOLID));
dc.SetBrush(wxBrush(wxColour(200, 200, 200, 80), wxBRUSHSTYLE_SOLID));
dc.DrawRectangle(wxRect(m_AnchorPoint.x, -2, m_CurrentPoint.x - m_AnchorPoint.x, this->GetSize().GetHeight() + 5));
// // Draw selection range
// if (bSelectRange)
// {
// wxRect rect(m_CurrentPoint, m_AnchorPoint);
bAreaSelected = true;
SendLoopPoints();
}
else
bAreaSelected = false;
// dc.SetPen(wxPen(wxColour(200, 200, 200), 2, wxPENSTYLE_SOLID));
// dc.SetBrush(wxBrush(wxColour(200, 200, 200, 80), wxBRUSHSTYLE_SOLID));
// dc.DrawRectangle(rect);
// }
// // Draw selected area
// if (!bSelectRange && bDrawSelectedArea && !bBitmapDirty)
// {
// dc.SetPen(wxPen(wxColour(200, 200, 200, 255), 4, wxPENSTYLE_SOLID));
// dc.SetBrush(wxBrush(wxColour(200, 200, 200, 80), wxBRUSHSTYLE_SOLID));
// dc.DrawRectangle(wxRect(m_AnchorPoint.x, -2, m_CurrentPoint.x - m_AnchorPoint.x, this->GetSize().GetHeight() + 5));
// bAreaSelected = true;
// SendLoopPoints();
// }
// else
// bAreaSelected = false;
}
void WaveformViewer::RenderPlayhead(wxDC& dc)

View File

@ -21,12 +21,14 @@
#pragma once
#include "Database.hpp"
#include "GL.hpp"
#include <wx/dataview.h>
#include <wx/bitmap.h>
#include <wx/colour.h>
#include <wx/dc.h>
#include <wx/event.h>
#include <wx/glcanvas.h>
#include <wx/infobar.h>
#include <wx/mediactrl.h>
#include <wx/panel.h>
@ -48,10 +50,12 @@ class WaveformViewer : public wxPanel
wxWindow* m_ParentFrame;
wxWindow* m_Window;
// -------------------------------------------------------------------
Database& m_Database;
wxDataViewListCtrl& m_Library;
wxMediaCtrl& m_MediaCtrl;
// -------------------------------------------------------------------
const std::string& m_ConfigFilepath;
const std::string& m_DatabaseFilepath;
@ -66,6 +70,12 @@ class WaveformViewer : public wxPanel
wxPoint m_AnchorPoint;
wxPoint m_CurrentPoint;
private:
// -------------------------------------------------------------------
wxGLCanvas* m_Canvas;
wxGLContext* m_Context;
GLHelper m_Helper;
private:
// -------------------------------------------------------------------
bool bBitmapDirty = false;
@ -75,6 +85,10 @@ class WaveformViewer : public wxPanel
private:
// -------------------------------------------------------------------
void InitGL();
// -------------------------------------------------------------------
void OnSize(wxSizeEvent& event);
void OnPaint(wxPaintEvent& event);
void RenderPlayhead(wxDC& dc);
void UpdateWaveformBitmap();