Improve wxQt OpenGL canvas implementation:

- Support wxGLContext::SetCurrent.
- Pass GL canvas attributes via ParseAttribList to handle defaults.
- Remove OpenGL not implemented message.
- Prevent QGLWidget from changing OpenGL state before we paint.
- Set Qt::StrongFocus for wxQtGLWidget to allow keyboard input.
- Use QtCanPaintWithoutActivePainter to fix wxPaintDCImpl assert when using wxGLCanvas.
This commit is contained in:
Alex Shvartzkop 2024-01-10 02:41:59 +03:00
parent 57349c2aaa
commit 966b6e9460
5 changed files with 184 additions and 69 deletions

View file

@ -24,6 +24,9 @@ public:
virtual bool SetCurrent(const wxGLCanvas& win) const override;
private:
QGLContext* m_glContext = nullptr;
wxDECLARE_CLASS(wxGLContext);
};
@ -78,7 +81,9 @@ public:
virtual bool SwapBuffers() override;
static bool ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format);
virtual bool QtCanPaintWithoutActivePainter() const override;
static bool ConvertWXAttrsToQtGL(const wxGLAttributes &glattrs, const wxGLContextAttrs ctxAttrs, QGLFormat &format);
private:
wxDECLARE_CLASS(wxGLCanvas);

View file

@ -151,6 +151,7 @@ public:
void QtSetPicture( QPicture* pict );
QPainter *QtGetPainter();
virtual bool QtCanPaintWithoutActivePainter() const;
virtual bool QtHandlePaintEvent ( QWidget *handler, QPaintEvent *event );
virtual bool QtHandleResizeEvent ( QWidget *handler, QResizeEvent *event );

View file

@ -126,7 +126,7 @@ wxPaintDCImpl::wxPaintDCImpl( wxDC *owner )
wxPaintDCImpl::wxPaintDCImpl( wxDC *owner, wxWindow *win )
: wxWindowDCImpl( owner, win )
{
wxCHECK_RET( m_isWindowPainter,
wxCHECK_RET( m_isWindowPainter || win->QtCanPaintWithoutActivePainter(),
"wxPaintDC can't be created outside wxEVT_PAINT handler" );
}

View file

@ -16,26 +16,20 @@
#include <QtWidgets/QGestureRecognizer>
#include <QtWidgets/QGestureEvent>
#if defined(__VISUALC__)
#pragma message("OpenGL support is not implemented in wxQt")
#else
#warning "OpenGL support is not implemented in wxQt"
#endif
wxGCC_WARNING_SUPPRESS(unused-parameter)
class wxQtGLWidget : public wxQtEventSignalHandler< QGLWidget, wxGLCanvas >
{
public:
wxQtGLWidget(wxWindow *parent, wxGLCanvas *handler, QGLFormat format)
: wxQtEventSignalHandler<QGLWidget,wxGLCanvas>(parent, handler)
{
setFormat(format);
setAutoBufferSwap( false );
}
: wxQtEventSignalHandler<QGLWidget, wxGLCanvas>(parent, handler)
{
setFormat(format);
setAutoBufferSwap(false);
setFocusPolicy(Qt::StrongFocus);
}
protected:
virtual void showEvent ( QShowEvent * event ) override;
virtual void hideEvent ( QHideEvent * event ) override;
virtual void resizeEvent ( QResizeEvent * event ) override;
virtual void paintEvent ( QPaintEvent * event ) override;
@ -43,16 +37,6 @@ protected:
virtual void paintGL() override;
};
void wxQtGLWidget::showEvent ( QShowEvent * event )
{
QGLWidget::showEvent( event );
}
void wxQtGLWidget::hideEvent ( QHideEvent * event )
{
QGLWidget::hideEvent( event );
}
void wxQtGLWidget::resizeEvent ( QResizeEvent * event )
{
QGLWidget::resizeEvent(event);
@ -84,6 +68,7 @@ wxGLContextAttrs& wxGLContextAttrs::CoreProfile()
{
// AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB,
// GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
AddAttribute(wx_GL_COMPAT_PROFILE);
SetNeedsARB();
return *this;
}
@ -92,6 +77,9 @@ wxGLContextAttrs& wxGLContextAttrs::MajorVersion(int val)
{
if ( val > 0 )
{
AddAttribute(WX_GL_MAJOR_VERSION);
AddAttribute(val);
if ( val >= 3 )
SetNeedsARB();
}
@ -102,12 +90,15 @@ wxGLContextAttrs& wxGLContextAttrs::MinorVersion(int val)
{
if ( val >= 0 )
{
AddAttribute(WX_GL_MINOR_VERSION);
AddAttribute(val);
}
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::CompatibilityProfile()
{
AddAttribute(wx_GL_COMPAT_PROFILE);
SetNeedsARB();
return *this;
}
@ -168,7 +159,7 @@ wxGLContextAttrs& wxGLContextAttrs::PlatformDefaults()
void wxGLContextAttrs::EndList()
{
// AddAttribute(None);
AddAttribute(0);
}
// ----------------------------------------------------------------------------
@ -190,6 +181,7 @@ void wxGLContextAttrs::EndList()
wxGLAttributes& wxGLAttributes::RGBA()
{
AddAttribute(WX_GL_RGBA);
return *this;
}
@ -197,24 +189,28 @@ wxGLAttributes& wxGLAttributes::BufferSize(int val)
{
if ( val >= 0 )
{
AddAttribute(WX_GL_BUFFER_SIZE);
AddAttribute(val);
}
return *this;
}
wxGLAttributes& wxGLAttributes::Level(int val)
{
// AddAttribute(GLX_LEVEL);
AddAttribute(WX_GL_LEVEL);
AddAttribute(val);
return *this;
}
wxGLAttributes& wxGLAttributes::DoubleBuffer()
{
AddAttribute(WX_GL_DOUBLEBUFFER);
return *this;
}
wxGLAttributes& wxGLAttributes::Stereo()
{
AddAttribute(WX_GL_STEREO);
return *this;
}
@ -222,6 +218,8 @@ wxGLAttributes& wxGLAttributes::AuxBuffers(int val)
{
if ( val >= 0 )
{
AddAttribute(WX_GL_AUX_BUFFERS);
AddAttribute(val);
}
return *this;
}
@ -230,15 +228,23 @@ wxGLAttributes& wxGLAttributes::MinRGBA(int mRed, int mGreen, int mBlue, int mAl
{
if ( mRed >= 0)
{
AddAttribute(WX_GL_MIN_RED);
AddAttribute(mRed);
}
if ( mGreen >= 0)
{
AddAttribute(WX_GL_MIN_GREEN);
AddAttribute(mGreen);
}
if ( mBlue >= 0)
{
AddAttribute(WX_GL_MIN_BLUE);
AddAttribute(mBlue);
}
if ( mAlpha >= 0)
{
AddAttribute(WX_GL_MIN_ALPHA);
AddAttribute(mAlpha);
}
return *this;
}
@ -247,6 +253,8 @@ wxGLAttributes& wxGLAttributes::Depth(int val)
{
if ( val >= 0 )
{
AddAttribute(WX_GL_DEPTH_SIZE);
AddAttribute(val);
}
return *this;
}
@ -255,6 +263,8 @@ wxGLAttributes& wxGLAttributes::Stencil(int val)
{
if ( val >= 0 )
{
AddAttribute(WX_GL_DEPTH_SIZE);
AddAttribute(val);
}
return *this;
}
@ -263,40 +273,44 @@ wxGLAttributes& wxGLAttributes::MinAcumRGBA(int mRed, int mGreen, int mBlue, int
{
if ( mRed >= 0)
{
AddAttribute(WX_GL_MIN_ACCUM_RED);
AddAttribute(mRed);
}
if ( mGreen >= 0)
{
AddAttribute(WX_GL_MIN_ACCUM_GREEN);
AddAttribute(mGreen);
}
if ( mBlue >= 0)
{
AddAttribute(WX_GL_MIN_ACCUM_BLUE);
AddAttribute(mBlue);
}
if ( mAlpha >= 0)
{
AddAttribute(WX_GL_MIN_ACCUM_ALPHA);
AddAttribute(mAlpha);
}
return *this;
}
wxGLAttributes& wxGLAttributes::SampleBuffers(int val)
{
#ifdef GLX_SAMPLE_BUFFERS_ARB
if ( val >= 0 && wxGLCanvasX11::IsGLXMultiSampleAvailable() )
if ( val >= 0 )
{
AddAttribute(GLX_SAMPLE_BUFFERS_ARB);
AddAttribute(WX_GL_SAMPLE_BUFFERS);
AddAttribute(val);
}
#endif
return *this;
}
wxGLAttributes& wxGLAttributes::Samplers(int val)
{
#ifdef GLX_SAMPLES_ARB
if ( val >= 0 && wxGLCanvasX11::IsGLXMultiSampleAvailable() )
if ( val >= 0 )
{
AddAttribute(GLX_SAMPLES_ARB);
AddAttribute(WX_GL_SAMPLES);
AddAttribute(val);
}
#endif
return *this;
}
@ -309,11 +323,12 @@ wxGLAttributes& wxGLAttributes::FrameBuffersRGB()
void wxGLAttributes::EndList()
{
AddAttribute(0);
}
wxGLAttributes& wxGLAttributes::PlatformDefaults()
{
// No GLX specific values
// No Qt specific values
return *this;
}
@ -324,15 +339,33 @@ wxGLAttributes& wxGLAttributes::PlatformDefaults()
wxIMPLEMENT_CLASS(wxGLContext, wxWindow);
wxGLContext::wxGLContext(wxGLCanvas *WXUNUSED(win), const wxGLContext* WXUNUSED(other), const wxGLContextAttrs *WXUNUSED(ctxAttrs))
wxGLContext::wxGLContext(wxGLCanvas *win,
const wxGLContext *other,
const wxGLContextAttrs *ctxAttrs)
{
QGLWidget *qglWidget = static_cast<QGLWidget *>(win->GetHandle());
m_glContext = qglWidget->context();
if (m_glContext != nullptr)
{
m_isOk = true;
}
}
bool wxGLContext::SetCurrent(const wxGLCanvas&) const
bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
{
// I think I must destroy and recreate the QGLWidget to change the context?
// win->GetHandle()->makeCurrent();
return false;
QGLWidget *qglWidget = static_cast<QGLWidget *>(win.GetHandle());
QGLContext *context = qglWidget->context();
if (context != m_glContext)
{
// I think I must destroy and recreate the QGLWidget to change the context?
wxLogDebug("Calling wxGLContext::SetCurrent with a different canvas is not supported in wxQt");
return false;
}
qglWidget->makeCurrent();
return true;
}
//---------------------------------------------------------------------------
@ -403,8 +436,11 @@ bool wxGLCanvas::Create(wxWindow *parent,
const wxString& name,
const wxPalette& palette)
{
wxLogError("Missing implementation of " + wxString(__FUNCTION__));
return false;
const int* attrsList = dispAttrs.GetGLAttrs();
wxCHECK_MSG(attrsList, false, "wxGLAttributes object is empty.");
return Create(parent, id, pos, size, style, name, attrsList, palette);
}
bool wxGLCanvas::Create(wxWindow *parent,
@ -421,17 +457,35 @@ bool wxGLCanvas::Create(wxWindow *parent,
#endif // wxUSE_PALETTE
wxUnusedVar(palette); // Unused when wxDEBUG_LEVEL==0
QGLFormat format;
if (!wxGLCanvas::ConvertWXAttrsToQtGL(attribList, format))
// Separate display/context attributes, set defaults.
wxGLAttributes dispAttrs;
wxGLContextAttrs ctxAttrs;
if (!ParseAttribList(attribList, dispAttrs, &ctxAttrs))
return false;
QGLFormat format;
if (!wxGLCanvas::ConvertWXAttrsToQtGL(dispAttrs, ctxAttrs, format))
return false;
// Return false if any attribute is unsupported
if ( !IsDisplaySupported(attribList) )
{
wxFAIL_MSG("Can't find a pixel format for the requested attributes");
return false;
}
m_qtWindow = new wxQtGLWidget(parent, this, format);
// Create and register a custom pan recognizer, available to all instances of this class.
QGestureRecognizer* pPanRecognizer = new PanGestureRecognizer();
QGestureRecognizer::registerRecognizer(pPanRecognizer);
return wxWindow::Create( parent, id, pos, size, style, name );
if ( !wxWindow::Create( parent, id, pos, size, style, name ) )
return false;
SetBackgroundStyle(wxBG_STYLE_PAINT);
return true;
}
bool wxGLCanvas::SwapBuffers()
@ -440,11 +494,16 @@ bool wxGLCanvas::SwapBuffers()
return true;
}
/* static */
bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format)
bool wxGLCanvas::QtCanPaintWithoutActivePainter() const
{
if (!wxattrs)
return true;
return true;
}
/* static */
bool wxGLCanvas::ConvertWXAttrsToQtGL(const wxGLAttributes &wxGLAttrs, const wxGLContextAttrs wxCtxAttrs, QGLFormat &format)
{
const int *glattrs = wxGLAttrs.GetGLAttrs();
const int *ctxattrs = wxCtxAttrs.GetGLAttrs();
// set default parameters to false
format.setDoubleBuffer(false);
@ -452,14 +511,16 @@ bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format)
format.setAlpha(false);
format.setStencil(false);
for ( int arg = 0; wxattrs[arg] != 0; arg++ )
for (int arg = 0; glattrs && glattrs[arg] != 0; arg++)
{
// indicates whether we have a boolean attribute
bool isBoolAttr = false;
int v = wxattrs[arg+1];
switch ( wxattrs[arg] )
int v = glattrs[arg+1];
switch ( glattrs[arg] )
{
// Pixel format attributes
case WX_GL_BUFFER_SIZE:
format.setRgba(false);
// I do not know how to set the buffer size, so fail
@ -489,7 +550,7 @@ bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format)
return false;
case WX_GL_MIN_RED:
format.setRedBufferSize(v*8);
format.setRedBufferSize(v);
break;
case WX_GL_MIN_GREEN:
@ -532,17 +593,54 @@ bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format)
// can we somehow indicate if it's not supported?
break;
case WX_GL_MAJOR_VERSION:
format.setVersion ( v,0 );
break;
default:
wxLogDebug(wxT("Unsupported OpenGL attribute %d"),
wxattrs[arg]);
glattrs[arg]);
continue;
}
if ( !isBoolAttr ) {
if ( !isBoolAttr )
{
if ( !v )
return false; // zero parameter
arg++;
}
}
for (int arg = 0; ctxattrs && ctxattrs[arg] != 0; arg++)
{
// indicates whether we have a boolean attribute
bool isBoolAttr = false;
int v = ctxattrs[arg+1];
switch ( ctxattrs[arg] )
{
// Context attributes
case WX_GL_MAJOR_VERSION:
format.setVersion ( v, format.minorVersion() );
break;
case WX_GL_MINOR_VERSION:
format.setVersion ( format.majorVersion(), v );
break;
case WX_GL_CORE_PROFILE:
format.setProfile(QGLFormat::CoreProfile);
break;
case wx_GL_COMPAT_PROFILE:
format.setProfile(QGLFormat::CompatibilityProfile);
break;
default:
wxLogDebug(wxT("Unsupported OpenGL attribute %d"),
ctxattrs[arg]);
continue;
}
if ( !isBoolAttr )
{
if ( !v )
return false; // zero parameter
arg++;
@ -553,23 +651,29 @@ bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format)
}
/* static */
bool
wxGLCanvasBase::IsDisplaySupported(const int *attribList)
bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs)
{
QGLFormat format;
const int* attrsList = dispAttrs.GetGLAttrs();
if (!wxGLCanvas::ConvertWXAttrsToQtGL(attribList, format))
return false;
wxCHECK_MSG(attrsList, false, "wxGLAttributes object is empty.");
return QGLWidget(format).isValid();
return IsDisplaySupported(attrsList);
}
/* static */
bool
wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs)
bool wxGLCanvasBase::IsDisplaySupported(const int *attribList)
{
wxLogError("Missing implementation of " + wxString(__FUNCTION__));
return false;
// Separate display/context attributes, set defaults.
wxGLAttributes dispAttrs;
wxGLContextAttrs ctxAttrs;
if (!ParseAttribList(attribList, dispAttrs, &ctxAttrs))
return false;
QGLFormat format;
if (!wxGLCanvas::ConvertWXAttrsToQtGL(dispAttrs, ctxAttrs, format))
return false;
return QGLWidget(format).isValid();
}
// ----------------------------------------------------------------------------

View file

@ -1830,6 +1830,11 @@ QPainter *wxWindowQt::QtGetPainter()
return m_qtPainter.get();
}
bool wxWindowQt::QtCanPaintWithoutActivePainter() const
{
return false;
}
bool wxWindowQt::EnableTouchEvents(int eventsMask)
{
wxCHECK_MSG( GetHandle(), false, "can't be called before creating the window" );