Trying out OpenGL to render waveform.
This commit is contained in:
parent
0ecf694997
commit
7174e52c48
13
meson.build
13
meson.build
|
|
@ -121,6 +121,7 @@ src = [
|
||||||
'src/Serialize.cpp',
|
'src/Serialize.cpp',
|
||||||
'src/Tags.cpp',
|
'src/Tags.cpp',
|
||||||
'src/WaveformViewer.cpp',
|
'src/WaveformViewer.cpp',
|
||||||
|
'src/GL.cpp',
|
||||||
'src/SH_Event.cpp',
|
'src/SH_Event.cpp',
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
@ -137,12 +138,14 @@ if not wx.found()
|
||||||
wx_base = wx_subproject.dependency('wxbase')
|
wx_base = wx_subproject.dependency('wxbase')
|
||||||
wx_core = wx_subproject.dependency('wxcore')
|
wx_core = wx_subproject.dependency('wxcore')
|
||||||
wx_media = wx_subproject.dependency('wxmedia')
|
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
|
else
|
||||||
wx_found = true
|
wx_found = true
|
||||||
|
|
||||||
wxconfig = find_program(['wx-config-gtk3', 'wx-config'])
|
wxconfig = find_program(['wx-config', 'wx-config-gtk3', 'wx-config-3.1'])
|
||||||
wx_modules = ['media', 'std']
|
wx_modules = ['gl', 'media', 'std']
|
||||||
wx_cxx_flags = []
|
wx_cxx_flags = []
|
||||||
wx_libs = []
|
wx_libs = []
|
||||||
|
|
||||||
|
|
@ -183,6 +186,8 @@ if not snd.found()
|
||||||
snd = snd_subproject.dependency('sndfile')
|
snd = snd_subproject.dependency('sndfile')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
glew = dependency('glew')
|
||||||
|
|
||||||
# Create samplehive-config.h based on configuration
|
# Create samplehive-config.h based on configuration
|
||||||
config_h = configure_file(output: 'SampleHiveConfig.hpp',
|
config_h = configure_file(output: 'SampleHiveConfig.hpp',
|
||||||
configuration: config_data,)
|
configuration: config_data,)
|
||||||
|
|
@ -203,7 +208,7 @@ if wx_found
|
||||||
else
|
else
|
||||||
executable('SampleHive',
|
executable('SampleHive',
|
||||||
sources: src,
|
sources: src,
|
||||||
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')
|
||||||
endif
|
endif
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class GLHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool InitGlew();
|
||||||
|
void Render();
|
||||||
|
void SetSize(int w, int h);
|
||||||
|
};
|
||||||
|
|
@ -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_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.
|
||||||
|
#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);
|
this->SetDoubleBuffered(true);
|
||||||
|
|
||||||
Bind(wxEVT_PAINT, &WaveformViewer::OnPaint, 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);
|
||||||
|
|
@ -57,55 +98,90 @@ WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, wxDataVi
|
||||||
|
|
||||||
WaveformViewer::~WaveformViewer()
|
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)
|
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()
|
// wxPaintDC dc(this);
|
||||||
|| m_WaveformBitmap.GetWidth() != size.x
|
|
||||||
|| m_WaveformBitmap.GetHeight() != size.y
|
|
||||||
|| bBitmapDirty)
|
|
||||||
{
|
|
||||||
wxLogDebug("Updating waveform bitmap..");
|
|
||||||
|
|
||||||
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
|
// dc.DrawBitmap(m_WaveformBitmap, 0, 0, false);
|
||||||
if (bSelectRange)
|
|
||||||
{
|
|
||||||
wxRect rect(m_CurrentPoint, m_AnchorPoint);
|
|
||||||
|
|
||||||
dc.SetPen(wxPen(wxColour(200, 200, 200), 2, wxPENSTYLE_SOLID));
|
// RenderPlayhead(dc);
|
||||||
dc.SetBrush(wxBrush(wxColour(200, 200, 200, 80), wxBRUSHSTYLE_SOLID));
|
|
||||||
dc.DrawRectangle(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw selected area
|
// // Draw selection range
|
||||||
if (!bSelectRange && bDrawSelectedArea && !bBitmapDirty)
|
// if (bSelectRange)
|
||||||
{
|
// {
|
||||||
dc.SetPen(wxPen(wxColour(200, 200, 200, 255), 4, wxPENSTYLE_SOLID));
|
// wxRect rect(m_CurrentPoint, m_AnchorPoint);
|
||||||
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;
|
// dc.SetPen(wxPen(wxColour(200, 200, 200), 2, wxPENSTYLE_SOLID));
|
||||||
SendLoopPoints();
|
// dc.SetBrush(wxBrush(wxColour(200, 200, 200, 80), wxBRUSHSTYLE_SOLID));
|
||||||
}
|
// dc.DrawRectangle(rect);
|
||||||
else
|
// }
|
||||||
bAreaSelected = false;
|
|
||||||
|
// // 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)
|
void WaveformViewer::RenderPlayhead(wxDC& dc)
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Database.hpp"
|
#include "Database.hpp"
|
||||||
|
#include "GL.hpp"
|
||||||
|
|
||||||
#include <wx/dataview.h>
|
#include <wx/dataview.h>
|
||||||
#include <wx/bitmap.h>
|
#include <wx/bitmap.h>
|
||||||
#include <wx/colour.h>
|
#include <wx/colour.h>
|
||||||
#include <wx/dc.h>
|
#include <wx/dc.h>
|
||||||
#include <wx/event.h>
|
#include <wx/event.h>
|
||||||
|
#include <wx/glcanvas.h>
|
||||||
#include <wx/infobar.h>
|
#include <wx/infobar.h>
|
||||||
#include <wx/mediactrl.h>
|
#include <wx/mediactrl.h>
|
||||||
#include <wx/panel.h>
|
#include <wx/panel.h>
|
||||||
|
|
@ -48,10 +50,12 @@ class WaveformViewer : public wxPanel
|
||||||
wxWindow* m_ParentFrame;
|
wxWindow* m_ParentFrame;
|
||||||
wxWindow* m_Window;
|
wxWindow* m_Window;
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
Database& m_Database;
|
Database& m_Database;
|
||||||
wxDataViewListCtrl& m_Library;
|
wxDataViewListCtrl& m_Library;
|
||||||
wxMediaCtrl& m_MediaCtrl;
|
wxMediaCtrl& m_MediaCtrl;
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
const std::string& m_ConfigFilepath;
|
const std::string& m_ConfigFilepath;
|
||||||
const std::string& m_DatabaseFilepath;
|
const std::string& m_DatabaseFilepath;
|
||||||
|
|
||||||
|
|
@ -66,6 +70,12 @@ class WaveformViewer : public wxPanel
|
||||||
wxPoint m_AnchorPoint;
|
wxPoint m_AnchorPoint;
|
||||||
wxPoint m_CurrentPoint;
|
wxPoint m_CurrentPoint;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
wxGLCanvas* m_Canvas;
|
||||||
|
wxGLContext* m_Context;
|
||||||
|
GLHelper m_Helper;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
bool bBitmapDirty = false;
|
bool bBitmapDirty = false;
|
||||||
|
|
@ -75,6 +85,10 @@ class WaveformViewer : public wxPanel
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
void InitGL();
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
void OnSize(wxSizeEvent& event);
|
||||||
void OnPaint(wxPaintEvent& event);
|
void OnPaint(wxPaintEvent& event);
|
||||||
void RenderPlayhead(wxDC& dc);
|
void RenderPlayhead(wxDC& dc);
|
||||||
void UpdateWaveformBitmap();
|
void UpdateWaveformBitmap();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue