And this error as well,
Code: Select all
Error! Could not initialize GLEW.
zsh: segmentation fault (core dumped) ./wxGL
I have attacted the minimal app source code I made to test this.
Code: Select all
Error! Could not initialize GLEW.
zsh: segmentation fault (core dumped) ./wxGL
Ok I moved the GLContext code to OnSize(),doublemax wrote: ↑Thu Oct 14, 2021 9:25 am Please check the "opengl/pyramid" sample that come with wxWidgets. Under GTK you can't set the GL context before the underlying window is fully initialized. Therefore the samples initialize OGL in the OnSize event handler and don't draw inside the paint event handler until the window size is > 0.
Code: Select all
void MainFrame::OnSize(wxSizeEvent &event)
{
event.Skip();
if (!IsShownOnScreen())
return;
wxGLContext* context = new wxGLContext(m_Canvas);
context->SetCurrent(*m_Canvas);
Refresh(false);
}
Code: Select all
void MainFrame::OnPaint(wxPaintEvent &event)
{
if (this->GetSize().GetHeight() < 0 || this->GetSize().GetWidth() < 0)
{
std::cout << "Error! Window size not initalize properly" << std::endl;
return;
}
if (glewInit() != GLEW_OK)
std::cout << "Error! Could not initialize GLEW." << std::endl;
/* Print out the OpenGL version we are using */
std::cout << glGetString(GL_VERSION) << std::endl;
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;
glGenVertexArrays(1, &vertex_array_object);
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);
glUseProgram(shader);
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);
glViewport(0, 0, m_Panel->GetSize().GetHeight(), m_Panel->GetSize().GetWidth());
glClearColor(0.07f, 0.13f, 0.17f, 1.0f);
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
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);
if (r > 1.0f)
inc = -0.01f;
else if (r < 0.0f)
inc = 0.01f;
r += inc;
}
Code: Select all
#ifndef GLHELPER_H_INCLUDED
#define GLHELPER_H_INCLUDED
class GLHelper
{
public:
bool InitGlew();
void Render();
void SetSize(int w, int h);
};
#endif // GLHELPER_H_INCLUDED
Code: Select all
#include <GL/glew.h>
#ifdef __WXMSW__
#include <GL/wglew.h>
#elif defined(__WXGTK__)
#include <GL/glxew.h>
#endif // defined
#include "glhelper.h"
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);
}
Code: Select all
#include "wx/wx.h"
#include <wx/glcanvas.h>
#include "glhelper.h"
class wxGlewFrame: public wxFrame
{
public:
wxGlewFrame(wxWindow*);
~wxGlewFrame();
private:
void OnCanvasSize(wxSizeEvent&);
void OnCanvasPaint(wxPaintEvent&);
void InitGL();
wxGLCanvas* m_canvas;
wxGLContext* m_context;
GLHelper m_helper;
};
wxGlewFrame::wxGlewFrame(wxWindow* parent)
: wxFrame(parent, wxID_ANY, wxString())
{
// Create the canvas and context.
#if wxCHECK_VERSION(3,1,0)
// These settings should work with any GPU from the last 10 years.
wxGLAttributes dispAttrs;
dispAttrs.PlatformDefaults().RGBA().DoubleBuffer().EndList();
wxGLContextAttrs cxtAttrs;
cxtAttrs.PlatformDefaults().CoreProfile().OGLVersion(3, 3).EndList();
m_canvas = new wxGLCanvas(this, dispAttrs);
m_context = new wxGLContext(m_canvas, NULL, &cxtAttrs);
if ( !m_context->IsOK() )
{
SetTitle("Failed to create context.");
return;
}
#else
int dispAttrs[] = { 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, dispAttrs);
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 full created. On windows, we can finish now.
#ifdef __WXMSW__
InitGL();
#elif defined(__WXGTK__)
m_canvas->Bind(wxEVT_CREATE, [this](wxWindowCreateEvent&){InitGL();});
#endif // defined
}
wxGlewFrame::~wxGlewFrame()
{
delete m_context;
}
void wxGlewFrame::OnCanvasSize(wxSizeEvent& event)
{
wxSize sz = event.GetSize();
m_helper.SetSize(sz.GetWidth(), sz.GetHeight());
event.Skip();
}
void wxGlewFrame::OnCanvasPaint(wxPaintEvent&)
{
wxPaintDC dc(m_canvas);
m_helper.Render();
m_canvas->SwapBuffers();
}
void wxGlewFrame::InitGL()
{
// First call SetCurrent or GL initialization will fail.
m_context->SetCurrent(*m_canvas);
// Initialize GLEW.
bool glewInialized = m_helper.InitGlew();
if ( !glewInialized )
{
SetTitle("Failed it initialize GLEW.");
return;
}
SetTitle("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, &wxGlewFrame::OnCanvasSize, this);
m_canvas->Bind(wxEVT_PAINT, &wxGlewFrame::OnCanvasPaint, this);
}
class MyApp : public wxApp
{
public:
virtual bool OnInit()
{
wxGlewFrame* frame = new wxGlewFrame(NULL);
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(MyApp);
Thank you for the example code. Its working now. However I was not able to run the application if I set the parent of wxGLCanvas to a wxPanel instead of the top wxFrame. Is it not possible to use a panel for the canvas? Or is the problem was with using a sizer for panel, as I had a sizer for panel as well?New Pagodi wrote: ↑Thu Oct 14, 2021 6:11 pm If you want to use wxGLCanvas with an extension loader like glew, glad, libepoxy, etc, the easiest thing is to put a helper class in between the wxWidgets code and the GL code and keep all of the GL stuff bottled up in the cpp file for that helper class.
I only recently started learning opengl as you can probably tell by my example code I shared in original post. I found out about wxGL stuff and I wanted to use it in my application. So I started experimenting this as both a project and exercise for learning opengl.Manolo wrote: ↑Thu Oct 14, 2021 6:23 pm Are you starting to think OGL is a nightmare? Oh yeah. I know how you feel. Don't worry, it isn't that tricky.
First, take a look at this FAQ post: viewtopic.php?f=27&t=45552
And read wxWidgets docs: https://docs.wxwidgets.org/trunk/classw ... anvas.html, and the "see also" links.
Now, you can create a wxGLContext anywhere you like. But, because you must use later, at SetCurrent(), you'd better store it as a your-class member, and don't forget to delete it at class dtor.
In the code you posted you create it at OnSize() event handler. Good? No. As soon as the handler finishes the pointer you created by "new" is not stored (and not deleted, you have a memory leak), so no other code path can use this context.
And you need to create the context only once instead of every time the window changes its size.
As doublemax told you, in Unix the context must be set as current after the window has been realized. This condition becomes true when the windw has a valid size and it's shown too. That's why pyramid sample uses OnSize() handler, and checks IsShownOnScreen() before using SetCurrent(). Paint events can be handled before the window has a vlaid size, so, again, the sample checks this condition too.
Now, the glew thing. GLEW needs that the gl-context is set as current before trying to initializate its library. But if you haven't a var to store the context, how do you call SetCurrent(*mycontext)?
Be aware of using glewExperimental = GL_TRUE; before glewInit(). It was needed for finding pointers for OGL>2.1 . It was so as for glew 1.12, I don't know if newer versions still need it.
Finally, your OGL code. All shaders stuff and data binding may be executed once. I mean, when they change. Not at every paint-event handler. The GPU stores it all (unlike OGL<2.1) So the only commands really needed at pai nt-event are those that draw (glClear, glViewport if size changed, glDrawXXX,....). Again the pyramid sample splits these tasks and call them only when needed.
Go ahead!! You'll get it.
I tried changing the constructor to this and it still works for me.apoorv569 wrote: ↑Fri Oct 15, 2021 3:20 pm Thank you for the example code. Its working now. However I was not able to run the application if I set the parent of wxGLCanvas to a wxPanel instead of the top wxFrame. Is it not possible to use a panel for the canvas? Or is the problem was with using a sizer for panel, as I had a sizer for panel as well?
Code: Select all
wxGlewFrame::wxGlewFrame(wxWindow* parent)
: wxFrame(parent, wxID_ANY, wxString())
{
wxPanel* bg = new wxPanel(this,wxID_ANY);
// Create the canvas and context.
#if wxCHECK_VERSION(3,1,0)
// These settings should work with any GPU from the last 10 years.
wxGLAttributes dispAttrs;
dispAttrs.PlatformDefaults().RGBA().DoubleBuffer().EndList();
wxGLContextAttrs cxtAttrs;
cxtAttrs.PlatformDefaults().CoreProfile().OGLVersion(3, 3).EndList();
m_canvas = new wxGLCanvas(bg, dispAttrs);
m_context = new wxGLContext(m_canvas, NULL, &cxtAttrs);
if ( !m_context->IsOK() )
{
SetTitle("Failed to create context.");
return;
}
#else
int dispAttrs[] = { 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, dispAttrs);
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 full created. On windows, we can finish now.
#ifdef __WXMSW__
InitGL();
#elif defined(__WXGTK__)
m_canvas->Bind(wxEVT_CREATE, [this](wxWindowCreateEvent&){InitGL();});
#endif // defined
wxBoxSizer* szr = new wxBoxSizer(wxVERTICAL);
szr->Add(m_canvas, wxSizerFlags(1).Expand().Border(wxALL));
bg->SetSizer(szr);
}
Ah! I was adding the panel to the sizer not the canvas. It works now. Thanks.New Pagodi wrote: ↑Fri Oct 15, 2021 3:56 pmI tried changing the constructor to this and it still works for me.apoorv569 wrote: ↑Fri Oct 15, 2021 3:20 pm Thank you for the example code. Its working now. However I was not able to run the application if I set the parent of wxGLCanvas to a wxPanel instead of the top wxFrame. Is it not possible to use a panel for the canvas? Or is the problem was with using a sizer for panel, as I had a sizer for panel as well?
Are you sure you're setting the parent for the canvas correctly and adding it to the sizer with the correct flags?Code: Select all
wxGlewFrame::wxGlewFrame(wxWindow* parent) : wxFrame(parent, wxID_ANY, wxString()) { wxPanel* bg = new wxPanel(this,wxID_ANY); // Create the canvas and context. #if wxCHECK_VERSION(3,1,0) // These settings should work with any GPU from the last 10 years. wxGLAttributes dispAttrs; dispAttrs.PlatformDefaults().RGBA().DoubleBuffer().EndList(); wxGLContextAttrs cxtAttrs; cxtAttrs.PlatformDefaults().CoreProfile().OGLVersion(3, 3).EndList(); m_canvas = new wxGLCanvas(bg, dispAttrs); m_context = new wxGLContext(m_canvas, NULL, &cxtAttrs); if ( !m_context->IsOK() ) { SetTitle("Failed to create context."); return; } #else int dispAttrs[] = { 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, dispAttrs); 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 full created. On windows, we can finish now. #ifdef __WXMSW__ InitGL(); #elif defined(__WXGTK__) m_canvas->Bind(wxEVT_CREATE, [this](wxWindowCreateEvent&){InitGL();}); #endif // defined wxBoxSizer* szr = new wxBoxSizer(wxVERTICAL); szr->Add(m_canvas, wxSizerFlags(1).Expand().Border(wxALL)); bg->SetSizer(szr); }
Hi, Sorry to bother again, I'm having a slight problem. I copied the code to my real application, all is good, the applications open and works fine, except I get error saying,New Pagodi wrote:
Are you sure you're setting the parent for the canvas correctly and adding it to the sizer with the correct flags?
Code: Select all
15:46:26: Debug: Failed to initialize GLEW.
Yes, I am following the exact steps/code you shared above. Here is the link to the InitGL() on my repository https://gitlab.com/samplehive/sample-hi ... r.cpp#L107New Pagodi wrote: ↑Sat Oct 16, 2021 1:51 pm You need to have created a context and called SetCurrent with the context or GLEW initialization will fail. The initialization requires reading a bunch of global data that is only set correctly once those two things have been done.
Code: Select all
this->SetDoubleBuffered(true);
I commented out line 89, and added the sizer, but I'm getting the same error still, failed to initialize glew.New Pagodi wrote: ↑Sun Oct 17, 2021 5:12 pm I think line 89
needs to be removed (at least on windows - on linux it seems to work even with that line). At least for me on windows, glew initialization seems to succeed but none of the calls actually work.Code: Select all
this->SetDoubleBuffered(true);
Also, you never seem to be adding the canvas to a sizer in the wave form viewer panel.
Code: Select all
WaveformViewer::WaveformViewer(wxWindow* parentFrame, wxWindow* window, 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),
m_ParentFrame(parentFrame), m_Window(window), m_Database(database), m_Library(library), m_MediaCtrl(mediaCtrl),
m_ConfigFilepath(configFilepath), m_DatabaseFilepath(databaseFilepath)
{
m_CanvasSizer = new wxBoxSizer(wxVERTICAL);
// 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
m_CanvasSizer->Add(m_Canvas, wxSizerFlags(1).Expand().Border(wxALL)); <----
this->SetSizer(m_CanvasSizer);
m_CanvasSizer->Fit(this);
m_CanvasSizer->SetSizeHints(this);
m_CanvasSizer->Layout();
// this->SetDoubleBuffered(true);
// 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);
// Bind(wxEVT_KEY_DOWN, &WaveformViewer::OnControlKeyDown, this);
Bind(wxEVT_KEY_UP, &WaveformViewer::OnControlKeyUp, this);
}