12 void mouseDoubleClickEvent(QMouseEvent *event);
13 private:
14 void draw();
15 int faceAtPosition(const QPoint &pos);
16 GLfloat rotationX;
17 GLfloat rotationY;
18 GLfloat rotationZ;
19 QColor faceColors[4];
20 QPoint lastPos;
21 }
Класс Tetrahedron наследует QGLWidget. Функции класса QGLWidget initializeGL(), resizeGL() и paintGL() переопределяются. Обработчики событий мышки класса QWidget переопределяются обычным образом.
01 Tetrahedron::Tetrahedron(QWidget *parent)
02 : QGLWidget(parent)
03 {
04 setFormat(QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer)
05 rotationX = -21.0;
06 rotationY = -57.0;
07 rotationZ = 0.0;
08 faceColors[0] = Qt::red;
09 faceColors[1] = Qt::green;
10 faceColors[2] = Qt::blue;
11 faceColors[3] = Qt::yellow;
12 }
В конструкторе мы вызываем функцию QGLWidget::setFormat() для установки контекста экрана OpenGL и инициализируем закрытые переменные этого класса.
01 void Tetrahedron::initializeGL()
02 {
03 qglClearColor(Qt::black);
04 glShadeModel(GL_FLAT);
05 glEnable(GL_DEPTH_TEST);
06 glEnable(GL_CULL_FACE);
07 }
Функция initializeGL() вызывается только один раз перед вызовом функции paintGL(). Именно в этом месте мы можем задавать контекст воспроизведения OpenGL, определять списки отображаемых элементов и выполнять остальную инициализацию.
Весь программный код является стандартным кодом OpenGL, за исключением вызовов функции qglClearColor() класса QGLWidget. Если бы мы захотели строго придерживаться стандартных возможностей OpenGL, мы вместо этого вызывали бы функцию glClearColor() при использовании режима RGBA и glClearIndex() при использовании режима индексированных цветов.
01 void Tetrahedron::resizeGL(int width, int height)
02 {
03 glViewport(0, 0, width, height);
04 glMatrixMode(GL_PROJECTION);
05 glLoadIdentity();
06 GLfloat x = GLfloat(width) / height;
07 glFrustum(-x, x, -1.0, 1.0, 4.0, 15.0);
08 glMatrixMode(GL_MODELVIEW);
09 }
Функция resizeGL() вызывается один раз перед первым вызовом функции paintGL(), но после вызова функции initializeGL(). Oнa также всегда вызывается при изменении размера виджета. Именно в этом месте мы можем задавать область отображения OpenGL, ее проекцию и делать любые другие настройки, зависящие от размера виджета.
01 void Tetrahedron::paintGL()
02 {
03 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
04 draw();
05 }
Функция paintGL() вызывается всякий раз, когда необходимо перерисовать виджет. Это напоминает функцию QWidget::paintEvent(), но вместо функций класса QPainter здесь мы используем функции библиотеки OpenGL. Реальное рисование выполняется закрытой функцией draw().
01 void Tetrahedron::draw()
02 {
04 static const GLfloat P1[3]= { 0.0, -1.0, +2.0 };
05 static const GLfloat P2[3] = { +1.73205081, -1.0, -1.0 };
06 static const GLfloat P3[3] = { -1.73205081, -1.0, -1.0 };
07 static const GLfloat P4[3] = { 0.0, +2.0, 0.0 };
08 static const GLfloat * const coords[4][3] = {
09 { P1, P2, РЗ }, { P1, РЗ, P4 }, { P1, P4, P2 }, { P2, P4, РЗ }
10 };
11 glMatrixMode(GL_MODELVIEW);
12 glLoadIdentity();
13 glTranslatef(0.0, 0.0, -10.0);
14 glRotatef(rotationX, 1.0, 0.0, 0.0);
15 glRotatef(rotationY, 0.0, 1.0, 0.0);
16 glRotatef(rotationZ, 0.0, 0.0, 1.0);
17 for (int i = 0; i < 4; ++i) {
18 glLoadName(i);
19 glBegin(GL_TRIANGLES);
20 qglColor(faceColors[i]);
21 for (int j = 0; j < 3; ++j) {
22 glVertex3f(coords[i][j][0],
23 coords[i][j][1], coords[i][j][2]);
24 }
25 glEnd();
26 }
27 }
В функции draw() мы рисуем тетраэдр, учитывая повороты по осям x, у и z, а также цвета в массиве faceColors. Везде вызываются стандартные функции библиотеки OpenGL, за исключением вызова qglColor(). Вместо этого мы могли бы использовать одну из функций OpenGL — glColor3d() или glIndex() — в зависимости от используемого режима.
01 void Tetrahedron::mousePressEvent(QMouseEvent *event)
02 {
03 lastPos = event->pos();
04 }
05 void Tetrahedron::mouseMoveEvent(QMouseEvent *event)
06 {
07 GLfloat dx = GLfloat(event->x() - lastPos.x()) / width();
08 GLfloat dy = GLfloat(event->y() - lastPos.y()) / height();
09 if (event->buttons() & Qt::LeftButton) {