Configuration window revisited
Making configuration dialog in plain win32 api wasn't good option. I realized it when I was warming up before dive-in into Linux GLX api. What the hell am I doing, I thought for a while, and started to rethink my approach. Implementing OpenGL context creation for each platform wasn't fun at all and for sure it could eat up more time that I wanted to invest.
I've decided to try the latest Qt (4.7) and I've begun seeking information about methods of creating new OpenGL 3.0> context in Qt windowing system. I've found only this old thread, no decent examples. Just like this kind of topic has died and nobody wanted to investigate it any further.
I've started to mess around with code from this thread, but after a while of browsing through Qt 4.7 documentation I've found out that new context creation is already supported.
Things turned out quite well and I've managed to redesign layout and rewrite the old dialog logic in few days and gain additional target systems. Adding other platforms will be easier now. I had only to reimplement some platform specific functions for resolution list retrieval, setting video mode in fullscreen and detecting/setting VSync (as there are different OpenGL extensions for each platform).
For now I've tested everything on Windows XP and Linux Ubuntu 32/64 bit (I don't have resolution list retrieval/setting on Linux yet though) and two graphics cards (NVIDIA GTS 250 and low-end Intel GMA 950). The other positive thing was that I was forced to move all OpenGL specific things to separate renderer class, so now I can easily reuse my OpenGL renderer code in other windowing systems.
Firstly I was doing it, because I had to remove all the traces of OpenGL includes from headers of Qt widgets. You know, awful compiler errors in Qt library and dreaded GLEW preprocessor error indicating that **gl.h** was included before **glew.h** header. But in the end this step turned out to be good design-wise and I believe that I have cleaner code now with minimum of dependencies.
As you can see I've added additional panels for input devices configuration and sound which were missing in last dialog version along with some nice icons.
OpenGL 3.0> context creation
Here is my example OpenGL window implementation with support of newer contexts, interface looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#ifndef R3D_QTOPENGLWINDOW_H
#define R3D_QTOPENGLWINDOW_H
#include <QGLWidget>
#include <R3D_core.h>
#include <R3D_oglRenderer.h>
namespace Ui {
class R3D_qtOpenGLwindow;
}
class R3D_qtOpenGLwindow : public QGLWidget {
Q_OBJECT
public:
R3D_qtOpenGLwindow(const QGLFormat &format, QWidget *parent=0,
const QGLWidget * shareWidget =0, Qt::WindowFlags f=0 );
~R3D_qtOpenGLwindow();
Replicant3D::R3D_oglRenderer *getOpenGlRenderer(){return pRenderer;}
protected:
void changeEvent(QEvent *e);
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
void timerEvent(QTimerEvent *);
void closeEvent(QCloseEvent *event);
private:
Ui::R3D_qtOpenGLwindow *ui;
Replicant3D::R3D_oglRenderer *pRenderer;
};
#endif // R3D_QTOPENGLWINDOW_H
And here is an implementation (very basic):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <cmath>
#include <iostream>
#include "ui_r3d_qtopenglwindow.h"
#include "r3d_qtopenglwindow.h"
#define TIMER_HZ 60
R3D_qtOpenGLwindow::R3D_qtOpenGLwindow (const QGLFormat &format, QWidget *parent,const QGLWidget * shareWidget , Qt::WindowFlags f )
:QGLWidget( format, parent, shareWidget , f),ui(new Ui::R3D_qtOpenGLwindow()),pRenderer(NULL){
ui->setupUi(this);
setWindowTitle(tr("Replicant3D"));
pRenderer=new Replicant3D::R3D_oglRenderer((tINT32)winId());
startTimer(TIMER_HZ);
}
R3D_qtOpenGLwindow::~R3D_qtOpenGLwindow() {
delete ui;ui=0;
delete pRenderer;pRenderer=0;
}
void R3D_qtOpenGLwindow::changeEvent(QEvent *e){
QWidget::changeEvent(e);
switch (e->type()) {
default:
break;
}
}
void R3D_qtOpenGLwindow::initializeGL(){
pRenderer->init();
}
void R3D_qtOpenGLwindow::resizeGL(int w, int h){
pRenderer->resize(w,h);
}
void R3D_qtOpenGLwindow::paintGL(){
pRenderer->draw();
}
void R3D_qtOpenGLwindow::timerEvent(QTimerEvent *){
pRenderer->update();
update();
}
void R3D_qtOpenGLwindow::closeEvent(QCloseEvent *event){
std::cout<<"closing R3D_qtOpenGLwindow.."<<std::endl;
}
To get the possibility of explicit context creation I overloaded constructor with QGLFormat &format reference as parameter.
R3D_core.h holds only some helper macros and typedefs for built-in C++ types. All OpenGL calls are made through separate renderer class (Replicant3D::R3D_oglRenderer) which is in separate compilation unit to avoid conflict of gl headers from Qt GL widget and GLEW library headers. In renderer object I am initialising GLEW to have easy possibility to query and use OpenGL extensions.
Notice that in headers Qt widgets definitions has to be included first, overlooking this can lead to compile-time disaster.
And now how it looks in use:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int glMajorVer=3;
int glMinorVer=3;
QGLFormat::OpenGLContextProfile profile=QGLFormat::CompatibilityProfile;
QGLFormat fbFormat;
_fbFormat.setDoubleBuffer(true);
_fbFormat.setAlpha(true);
_fbFormat.setRgba(true);
_fbFormat.setAlphaBufferSize(8);
_fbFormat.setDepthBufferSize(16);
_fbFormat.setStencilBufferSize(8);
_fbFormat.setDirectRendering(true);
_fbFormat.setProfile(profile);
_fbFormat.setVersion (glMajorVer,glMinorVer);
_fbFormat.setSampleBuffers (true);
bool sbEnabled= _fbFormat.sampleBuffers();
int samples=_fbFormat.samples();
//create dummy window and get config if exists
R3D_qtOpenGLwindow *pGLwindow=new R3D_qtOpenGLwindow(_fbFormat);
pGLwindow->setAttribute(Qt::WA_DeleteOnClose,true);
pGLwindow->resize(800, 600);
pGLwindow->show();
We simply specify desired OpenGL minor and major version (OpenGL 3.3), profile (core, compatibility or legacy), set frame buffer, desired settings in QGLFormat and pass it to newly created widget.
The cool thing is that if we specify greater OpenGL context creation than it is supported in hardware, then there will be fallback to greatest possible version. I've chosen QGLFormat::CompatibilityProfile to check if sample rendering code will be working on older cards.
To detect VSync and FSAA hardware capabilities I've checked extensions through GLEW and it involved creation of dummy window with size (1,1). But after new window settings validation I've used FSAA and VSync functionalities provided in QGLFormat.