Small examples for game development in Qt, OpenGL, Box2D, Bullet Physics, and OpenAL
-
Play sound with PyOpenAL
This example shows a button with "Play Sound" text. When you press the button, music will play.
import sys from openal import oalOpen from PySide6.QtWidgets import QApplication, QPushButton, QWidget class Widget(QWidget): def __init__(self): super().__init__() self.setWindowTitle("PyOpenAL, PySide6") self.resize(300, 150) self.btn = QPushButton("Play Sound", self) self.btn.clicked.connect(self.onPlay) self.source = oalOpen("assets/bounce.wav") def onPlay(self): self.source.play() if __name__ == "__main__": app = QApplication(sys.argv) w = Widget() w.show() sys.exit(app.exec())
-
-
An empty OpenGL window with glClearColor and glClear to fill the background with color.
QOpenGLWindow in Python:
import sys from OpenGL.GL import GL_COLOR_BUFFER_BIT, glClear, glClearColor from PySide6.QtCore import Qt from PySide6.QtOpenGL import QOpenGLWindow from PySide6.QtWidgets import QApplication class OpenGLWindow(QOpenGLWindow): def __init__(self): super().__init__() self.setTitle("OpenGL ES 2.0, PySide6, Python") self.resize(350, 350) def initializeGL(self): glClearColor(0.1, 0.3, 0.2, 1) def resizeGL(self, w, h): pass def paintGL(self): glClear(GL_COLOR_BUFFER_BIT) if __name__ == "__main__": QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL) app = QApplication(sys.argv) w = OpenGLWindow() w.show() sys.exit(app.exec())
QOpenGLWidget in Python:
import sys from OpenGL.GL import GL_COLOR_BUFFER_BIT, glClear, glClearColor from PySide6.QtCore import Qt from PySide6.QtOpenGLWidgets import QOpenGLWidget from PySide6.QtWidgets import QApplication class OpenGLWidget(QOpenGLWidget): def __init__(self): super().__init__() self.setWindowTitle("OpenGL ES 2.0, PySide6, Python") self.resize(350, 350) def initializeGL(self): glClearColor(0.1, 0.3, 0.2, 1) def resizeGL(self, w, h): pass def paintGL(self): glClear(GL_COLOR_BUFFER_BIT) if __name__ == "__main__": QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL) app = QApplication(sys.argv) w = OpenGLWidget() w.show() sys.exit(app.exec())
QOpenGLWindow in C++:
#include <QtGui/QOpenGLFunctions> #include <QtOpenGL/QOpenGLWindow> #include <QtWidgets/QApplication> #include <QtWidgets/QWidget> class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions { public: OpenGLWindow() { setTitle("OpenGL ES 2.0, Qt6, C++"); resize(350, 350); } void initializeGL() override { initializeOpenGLFunctions(); glClearColor(0.1f, 0.3f, 0.2f, 1.f); } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); } }; int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL); QApplication app(argc, argv); OpenGLWindow w; w.show(); return app.exec(); }
QT += core gui openglwidgets CONFIG += c++17 SOURCES += \ main.cpp
QOpenGLWidget in C++:
#include <QtGui/QOpenGLFunctions> #include <QtOpenGLWidgets/QOpenGLWidget> #include <QtWidgets/QApplication> class OpenGLWidget : public QOpenGLWidget, private QOpenGLFunctions { public: OpenGLWidget() { setWindowTitle("OpenGL ES 2.0, Qt6, C++"); resize(350, 350); } void initializeGL() override { initializeOpenGLFunctions(); glClearColor(0.1f, 0.3f, 0.2f, 1.f); } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); } }; int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL); QApplication app(argc, argv); OpenGLWidget w; w.show(); return app.exec(); }
QT += core gui openglwidgets CONFIG += c++17 SOURCES += \ main.cpp
-
A simple square without a transformation matrix
PySide6, Python:
import sys import numpy as np from OpenGL.GL import (GL_COLOR_BUFFER_BIT, GL_FLOAT, GL_TRIANGLE_STRIP, glClear, glClearColor, glDrawArrays) from PySide6.QtCore import Qt from PySide6.QtOpenGL import (QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram, QOpenGLWindow) from PySide6.QtWidgets import QApplication class OpenGLWindow(QOpenGLWindow): def __init__(self): super().__init__() self.setTitle("OpenGL ES 2.0, PySide6, Python") self.resize(350, 350) def initializeGL(self): glClearColor(0.1, 0.3, 0.2, 1) vertShaderSrc = """ attribute vec2 aPosition; void main() { gl_Position = vec4(aPosition, 0.0, 1.0); } """ fragShaderSrc = """ #ifdef GL_ES precision mediump float; #endif void main() { gl_FragColor = vec4(0.5, 0.2, 0.9, 1.0); } """ program = QOpenGLShaderProgram(self) program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertShaderSrc) program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragShaderSrc) program.link() program.bind() vertPositions = np.array([ -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5], dtype=np.float32) self.vertPosBuffer = QOpenGLBuffer() self.vertPosBuffer.create() self.vertPosBuffer.bind() self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4) program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2) program.enableAttributeArray("aPosition") def resizeGL(self, w, h): pass def paintGL(self): glClear(GL_COLOR_BUFFER_BIT) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) if __name__ == "__main__": QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL) app = QApplication(sys.argv) w = OpenGLWindow() w.show() sys.exit(app.exec())
Qt 6, C++:
main.cpp
#include <QtGui/QOpenGLFunctions> #include <QtOpenGL/QOpenGLBuffer> #include <QtOpenGL/QOpenGLShader> #include <QtOpenGL/QOpenGLShaderProgram> #include <QtOpenGL/QOpenGLWindow> #include <QtWidgets/QApplication> class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions { public: OpenGLWindow() { setTitle("OpenGL ES 2.0, Qt6, C++"); resize(350, 350); } void initializeGL() override { initializeOpenGLFunctions(); glClearColor(0.1f, 0.3f, 0.2f, 1.f); QString vertShaderSrc = "attribute vec2 aPosition;\n" "void main()\n" "{\n" " gl_Position = vec4(aPosition, 0.0, 1.0);\n" "}\n"; QString fragShaderSrc = "#ifdef GL_ES\n" "precision mediump float;\n" "#endif\n" "void main()\n" "{\n" " gl_FragColor = vec4(0.5, 0.2, 0.9, 1.0);\n" "}\n"; QOpenGLShaderProgram *program = new QOpenGLShaderProgram(this); program->create(); program->addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex, vertShaderSrc); program->addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment, fragShaderSrc); program->link(); program->bind(); float vertPositions[] = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f }; m_vertPosBuffer.create(); m_vertPosBuffer.bind(); m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions)); program->setAttributeBuffer("aPosition", GL_FLOAT, 0, 2); program->enableAttributeArray("aPosition"); } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } private: QOpenGLBuffer m_vertPosBuffer; }; int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL); QApplication app(argc, argv); OpenGLWindow w; w.show(); return app.exec(); }
simple-rectangle-opengles2-qt6-cpp.pro
QT += core gui openglwidgets CONFIG += c++17 SOURCES += \ main.cpp
-
Transformed rectangle
PySide6, Python:
import sys import numpy as np from OpenGL.GL import (GL_COLOR_BUFFER_BIT, GL_FLOAT, GL_TRIANGLE_STRIP, glClear, glClearColor, glDrawArrays) from PySide6.QtCore import Qt from PySide6.QtGui import QMatrix4x4, QSurfaceFormat, QVector3D from PySide6.QtOpenGL import (QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram, QOpenGLWindow) from PySide6.QtWidgets import QApplication class OpenGLWindow(QOpenGLWindow): def __init__(self): super().__init__() self.setTitle("OpenGL ES 2.0, PySide6, Python") self.initialWindowWidth = 380 self.initialWindowHeight = 380 self.resize(self.initialWindowWidth, self.initialWindowHeight) self.worldWidth = 100 self.worldHeight = 100 surfaceFormat = QSurfaceFormat() surfaceFormat.setDepthBufferSize(24) surfaceFormat.setSamples(4) self.setFormat(surfaceFormat) def initializeGL(self): glClearColor(0.04, 0.62, 0.48, 1) vertShaderSrc = """ attribute vec2 aPosition; uniform mat4 uMvpMatrix; void main() { gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0); } """ fragShaderSrc = """ #ifdef GL_ES precision mediump float; #endif void main() { gl_FragColor = vec4(0.62, 0.04, 0.18, 1.0); } """ self.program = QOpenGLShaderProgram() self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertShaderSrc) self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragShaderSrc) self.program.link() self.program.bind() vertPositions = np.array([ -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5], dtype=np.float32) self.vertPosBuffer = QOpenGLBuffer() self.vertPosBuffer.create() self.vertPosBuffer.bind() self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4) self.program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2) self.program.enableAttributeArray("aPosition") self.uMvpMatrixLocation = self.program.uniformLocation("uMvpMatrix") self.viewMatrix = QMatrix4x4() self.viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0)) self.projMatrix = QMatrix4x4() self.projViewMatrix = QMatrix4x4() self.modelMatrix = QMatrix4x4() self.mvpMatrix = QMatrix4x4() def resizeGL(self, w, h): coofWidth = w / self.initialWindowWidth coofHeight = h / self.initialWindowHeight self.projMatrix.setToIdentity() self.projMatrix.ortho(0, self.worldWidth * coofWidth, 0, self.worldHeight * coofHeight, 1, -1) self.projViewMatrix = self.projMatrix * self.viewMatrix def paintGL(self): glClear(GL_COLOR_BUFFER_BIT) self.modelMatrix.setToIdentity() self.modelMatrix.translate(QVector3D(50, 50, 0)) self.modelMatrix.rotate(10, QVector3D(0, 0, 1)) self.modelMatrix.scale(QVector3D(80, 10, 1)) self.mvpMatrix = self.projViewMatrix * self.modelMatrix self.program.setUniformValue(self.uMvpMatrixLocation, self.mvpMatrix) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) if __name__ == "__main__": QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL) app = QApplication(sys.argv) w = OpenGLWindow() w.show() sys.exit(app.exec())
Qt6, C++:
main.cpp
#include <QtGui/QMatrix4x4> #include <QtGui/QOpenGLFunctions> #include <QtGui/QSurfaceFormat> #include <QtGui/QVector3D> #include <QtOpenGL/QOpenGLBuffer> #include <QtOpenGL/QOpenGLShader> #include <QtOpenGL/QOpenGLShaderProgram> #include <QtOpenGL/QOpenGLWindow> #include <QtWidgets/QApplication> class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions { public: OpenGLWindow() { setTitle("OpenGL ES 2.0, Qt6, C++"); resize(380, 380); QSurfaceFormat surfaceFormat; surfaceFormat.setDepthBufferSize(24); surfaceFormat.setSamples(4); setFormat(surfaceFormat); } void initializeGL() override { initializeOpenGLFunctions(); glClearColor(0.04f, 0.62f, 0.48f, 1.f); QString vertShaderSrc = "attribute vec2 aPosition;\n" "uniform mat4 uMvpMatrix;" "void main()\n" "{\n" " gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);\n" "}\n"; QString fragShaderSrc = "#ifdef GL_ES\n" "precision mediump float;\n" "#endif\n" "void main()\n" "{\n" " gl_FragColor = vec4(0.62, 0.04, 0.18, 1.0);\n" "}\n"; m_program.create(); m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex, vertShaderSrc); m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment, fragShaderSrc); m_program.link(); m_program.bind(); float vertPositions[] = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f }; m_vertPosBuffer.create(); m_vertPosBuffer.bind(); m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions)); m_program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2); m_program.enableAttributeArray("aPosition"); m_uMvpMatrixLocation = m_program.uniformLocation("uMvpMatrix"); m_viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0)); } void resizeGL(int w, int h) override { const float coofWidth = w / (float)m_initialWindowWidth; const float coofHeight = h / (float)m_initialWindowHeight; m_projMatrix.setToIdentity(); m_projMatrix.ortho(0.f, m_worldWidth * coofWidth, 0.f, m_worldHeight * coofHeight, 1.f, -1.f); m_projViewMatrix = m_projMatrix * m_viewMatrix; } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); m_modelMatrix.setToIdentity(); m_modelMatrix.translate(QVector3D(50, 50, 0)); m_modelMatrix.rotate(10, QVector3D(0, 0, 1)); m_modelMatrix.scale(QVector3D(80, 10, 1)); m_mvpMatrix = m_projViewMatrix * m_modelMatrix; m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } private: QOpenGLBuffer m_vertPosBuffer; QOpenGLShaderProgram m_program; int m_uMvpMatrixLocation; QMatrix4x4 m_mvpMatrix; QMatrix4x4 m_projMatrix; QMatrix4x4 m_viewMatrix; QMatrix4x4 m_projViewMatrix; QMatrix4x4 m_modelMatrix; const int m_initialWindowWidth = 380; const int m_initialWindowHeight = 380; const float m_worldWidth = 100.f; const float m_worldHeight = 100.f; }; int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL); QApplication app(argc, argv); OpenGLWindow w; w.show(); return app.exec(); }
transformed-rectangle-opengles2-qt6-cpp.pro
QT += core gui openglwidgets CONFIG += c++17 SOURCES += \ main.cpp
-
Game loop and delta time with QOpenGLWindow
PySide6, Python:
import sys from OpenGL.GL import GL_COLOR_BUFFER_BIT, glClear, glClearColor from PySide6.QtCore import QElapsedTimer, Qt from PySide6.QtGui import QSurfaceFormat from PySide6.QtOpenGL import QOpenGLWindow from PySide6.QtWidgets import QApplication class OpenGLWindow(QOpenGLWindow): def __init__(self): super().__init__() self.setTitle("OpenGL ES 2.0, PySide6, Python") self.resize(350, 350) surfaceFormat = QSurfaceFormat() surfaceFormat.setDepthBufferSize(24) surfaceFormat.setSamples(4) surfaceFormat.setSwapInterval(0) self.frameSwapped.connect(self.update) self.setFormat(surfaceFormat) def initializeGL(self): glClearColor(0.1, 0.3, 0.2, 1) self.elapsedTimer = QElapsedTimer() self.elapsedTimer.start() def resizeGL(self, w, h): pass def paintGL(self): glClear(GL_COLOR_BUFFER_BIT) dt = self.elapsedTimer.elapsed() / 1000 self.elapsedTimer.restart() print("dt =", dt) if __name__ == "__main__": QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL) app = QApplication(sys.argv) w = OpenGLWindow() w.show() sys.exit(app.exec())
Qt6, C++:
main.cpp
#include <QtCore/QElapsedTimer> #include <QtGui/QOpenGLFunctions> #include <QtGui/QSurfaceFormat> #include <QtOpenGL/QOpenGLWindow> #include <QtWidgets/QApplication> class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions { public: OpenGLWindow() { setTitle("OpenGL ES 2.0, Qt6, C++"); resize(350, 350); QSurfaceFormat surfaceFormat; surfaceFormat.setDepthBufferSize(24); surfaceFormat.setSamples(4); surfaceFormat.setSwapInterval(0); connect(this, SIGNAL(frameSwapped()), this, SLOT(update())); setFormat(surfaceFormat); } void initializeGL() override { initializeOpenGLFunctions(); glClearColor(0.1f, 0.3f, 0.2f, 1.f); m_elapsedTimer.start(); } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); float dt = m_elapsedTimer.elapsed() / 1000.f; m_elapsedTimer.restart(); qDebug() << "dt =" << dt; } private: QElapsedTimer m_elapsedTimer; }; int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL); QApplication app(argc, argv); OpenGLWindow w; w.show(); return app.exec(); }
game-loop-dt-qopenglwindow-opengles2-qt6-cpp.pro
QT += core gui openglwidgets CONFIG += c++17 SOURCES += \ main.cpp
-
Game loop and delta time with QOpenGLWidget
PySide6, Python:
import sys from OpenGL.GL import GL_COLOR_BUFFER_BIT, glClear, glClearColor from PySide6.QtCore import QElapsedTimer, Qt, QTimer from PySide6.QtOpenGLWidgets import QOpenGLWidget from PySide6.QtWidgets import QApplication class OpenGLWidget(QOpenGLWidget): def __init__(self): super().__init__() self.setWindowTitle("OpenGL ES 2.0, PySide6, Python") self.resize(350, 350) def initializeGL(self): glClearColor(0.1, 0.3, 0.2, 1) self.elapsedTimer = QElapsedTimer() self.elapsedTimer.start() self.timer = QTimer() self.timer.timeout.connect(self.update) self.timer.start(1000//60) def resizeGL(self, w, h): pass def paintGL(self): glClear(GL_COLOR_BUFFER_BIT) dt = self.elapsedTimer.elapsed() / 1000 self.elapsedTimer.restart() print("dt =", dt) if __name__ == "__main__": QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL) app = QApplication(sys.argv) w = OpenGLWidget() w.show() sys.exit(app.exec())
Qt6, C++:
main.cpp
#include <QtCore/QElapsedTimer> #include <QtCore/QTimer> #include <QtGui/QOpenGLFunctions> #include <QtOpenGLWidgets/QOpenGLWidget> #include <QtWidgets/QApplication> class OpenGLWidget : public QOpenGLWidget, private QOpenGLFunctions { public: OpenGLWidget() { setWindowTitle("OpenGL ES 2.0, Qt6, C++"); resize(350, 350); } void initializeGL() override { initializeOpenGLFunctions(); glClearColor(0.1f, 0.3f, 0.2f, 1.f); // connect(&m_timer, &QTimer::timeout, &OpenGLWidget::update); connect(&m_timer, SIGNAL(timeout()), this, SLOT(update())); m_elapsedTimer.start(); m_timer.start(); } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); float dt = m_elapsedTimer.elapsed() / 1000.f; m_elapsedTimer.restart(); qDebug() << "dt =" << dt; } private: QElapsedTimer m_elapsedTimer; QTimer m_timer; }; int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL); QApplication app(argc, argv); OpenGLWidget w; w.show(); return app.exec(); }
game-loop-dt-qopenglwidget-opengles2-qt6-cpp.pro
QT += core gui openglwidgets CONFIG += c++17 SOURCES += \ main.cpp
-
Keyboard handling
PySide6, Python:
import sys from OpenGL.GL import GL_COLOR_BUFFER_BIT, glClear, glClearColor from PySide6.QtCore import QElapsedTimer, Qt from PySide6.QtGui import QSurfaceFormat from PySide6.QtOpenGL import QOpenGLWindow from PySide6.QtWidgets import QApplication class OpenGLWindow(QOpenGLWindow): def __init__(self): super().__init__() self.setTitle("OpenGL ES 2.0, PySide6, Python") self.resize(350, 350) surfaceFormat = QSurfaceFormat() surfaceFormat.setDepthBufferSize(24) surfaceFormat.setSamples(4) surfaceFormat.setSwapInterval(0) self.frameSwapped.connect(self.update) self.setFormat(surfaceFormat) self.keys = { "up": False, "left": False, "down": False, "right": False } def initializeGL(self): glClearColor(0.1, 0.3, 0.2, 1) self.elapsedTimer = QElapsedTimer() self.elapsedTimer.start() def resizeGL(self, w, h): pass def paintGL(self): glClear(GL_COLOR_BUFFER_BIT) dt = self.elapsedTimer.elapsed() / 1000 self.elapsedTimer.restart() # print("dt =", dt) self.keyboardHandler() def keyboardHandler(self): if self.keys["up"]: print("up") if self.keys["left"]: print("left") if self.keys["down"]: print("down") if self.keys["right"]: print("right") def keyPressEvent(self, event): if event.key() == Qt.Key.Key_W or event.key() == Qt.Key.Key_Up: self.keys["up"] = True if event.key() == Qt.Key.Key_A or event.key() == Qt.Key.Key_Left: self.keys["left"] = True if event.key() == Qt.Key.Key_S or event.key() == Qt.Key.Key_Down: self.keys["down"] = True if event.key() == Qt.Key.Key_D or event.key() == Qt.Key.Key_Right: self.keys["right"] = True def keyReleaseEvent(self, event): if event.key() == Qt.Key.Key_W or event.key() == Qt.Key.Key_Up: self.keys["up"] = False if event.key() == Qt.Key.Key_A or event.key() == Qt.Key.Key_Left: self.keys["left"] = False if event.key() == Qt.Key.Key_S or event.key() == Qt.Key.Key_Down: self.keys["down"] = False if event.key() == Qt.Key.Key_D or event.key() == Qt.Key.Key_Right: self.keys["right"] = False if __name__ == "__main__": QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL) app = QApplication(sys.argv) w = OpenGLWindow() w.show() sys.exit(app.exec())
Qt6, C++:
main.cpp
#include <QtCore/QElapsedTimer> #include <QtCore/QMap> #include <QtGui/QKeyEvent> #include <QtGui/QOpenGLFunctions> #include <QtGui/QSurfaceFormat> #include <QtOpenGL/QOpenGLWindow> #include <QtWidgets/QApplication> class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions { public: OpenGLWindow() { setTitle("OpenGL ES 2.0, Qt6, C++"); resize(350, 350); } void initializeGL() override { initializeOpenGLFunctions(); glClearColor(0.1f, 0.3f, 0.2f, 1.f); QSurfaceFormat surfaceFormat; surfaceFormat.setDepthBufferSize(24); surfaceFormat.setSamples(4); surfaceFormat.setSwapInterval(0); connect(this, SIGNAL(frameSwapped()), this, SLOT(update())); setFormat(surfaceFormat); m_elapsedTimer.start(); } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); float dt = m_elapsedTimer.elapsed() / 1000.f; m_elapsedTimer.restart(); // qDebug() << "dt =" << dt; keyboardHandler(); } void keyboardHandler() { if (m_keys["up"]) { qDebug() << "up"; } if (m_keys["left"]) { qDebug() << "left"; } if (m_keys["down"]) { qDebug() << "down"; } if (m_keys["right"]) { qDebug() << "right"; } } void keyPressEvent(QKeyEvent *event) override { if (event->key() == Qt::Key::Key_W || event->key() == Qt::Key::Key_Up) { m_keys["up"] = true; } if (event->key() == Qt::Key::Key_A || event->key() == Qt::Key::Key_Left) { m_keys["left"] = true; } if (event->key() == Qt::Key::Key_S || event->key() == Qt::Key::Key_Down) { m_keys["down"] = true; } if (event->key() == Qt::Key::Key_D || event->key() == Qt::Key::Key_Right) { m_keys["right"] = true; } } void keyReleaseEvent(QKeyEvent *event) override { if (event->key() == Qt::Key::Key_W || event->key() == Qt::Key::Key_Up) { m_keys["up"] = false; } if (event->key() == Qt::Key::Key_A || event->key() == Qt::Key::Key_Left) { m_keys["left"] = false; } if (event->key() == Qt::Key::Key_S || event->key() == Qt::Key::Key_Down) { m_keys["down"] = false; } if (event->key() == Qt::Key::Key_D || event->key() == Qt::Key::Key_Right) { m_keys["right"] = false; } } private: QElapsedTimer m_elapsedTimer; QMap<QString, bool> m_keys; }; int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL); QApplication app(argc, argv); OpenGLWindow w; w.show(); return app.exec(); }
keyboard-handling-opengles2-qt6-cpp.pro
QT += core gui openglwidgets CONFIG += c++17 SOURCES += \ main.cpp
-
Draw a few rectangles with different colors
I have replaced the following code in the Transformed rectangle example:
def paintGL(self): glClear(GL_COLOR_BUFFER_BIT) self.modelMatrix.setToIdentity() self.modelMatrix.translate(QVector3D(50, 50, 0)) self.modelMatrix.rotate(10, QVector3D(0, 0, 1)) self.modelMatrix.scale(QVector3D(80, 10, 1)) self.mvpMatrix = self.projViewMatrix * self.modelMatrix self.program.setUniformValue(self.uMvpMatrixLocation, self.mvpMatrix) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
with this one:
def paintGL(self): glClear(GL_COLOR_BUFFER_BIT) self.drawRectangle(x = 50, y = 50, w = 80, h = 10, angle = 10, color = QVector3D(0.62, 0.04, 0.18)) self.drawRectangle(x = 30, y = 20, w = 50, h = 20, angle = 0, color = QVector3D(0.3, 0.07, 0.5)) self.drawRectangle(x = 50, y = 80, w = 40, h = 15, angle = -20, color = QVector3D(0.2, 0.3, 0.1)) def drawRectangle(self, x, y, w, h, angle, color): self.modelMatrix.setToIdentity() self.modelMatrix.translate(QVector3D(x, y, 0)) self.modelMatrix.rotate(angle, QVector3D(0, 0, 1)) self.modelMatrix.scale(QVector3D(w, h, 1)) self.mvpMatrix = self.projViewMatrix * self.modelMatrix self.program.setUniformValue(self.uMvpMatrixLocation, self.mvpMatrix) self.program.setUniformValue(self.uColorLocation, color) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
PySide6, Python:
import sys import numpy as np from OpenGL.GL import (GL_COLOR_BUFFER_BIT, GL_FLOAT, GL_TRIANGLE_STRIP, glClear, glClearColor, glDrawArrays) from PySide6.QtCore import Qt from PySide6.QtGui import QMatrix4x4, QSurfaceFormat, QVector3D from PySide6.QtOpenGL import (QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram, QOpenGLWindow) from PySide6.QtWidgets import QApplication class OpenGLWindow(QOpenGLWindow): def __init__(self): super().__init__() self.setTitle("OpenGL ES 2.0, PySide6, Python") self.initialWindowWidth = 380 self.initialWindowHeight = 380 self.resize(self.initialWindowWidth, self.initialWindowHeight) self.worldWidth = 100 self.worldHeight = 100 surfaceFormat = QSurfaceFormat() surfaceFormat.setDepthBufferSize(24) surfaceFormat.setSamples(4) self.setFormat(surfaceFormat) def initializeGL(self): glClearColor(0.04, 0.62, 0.48, 1) vertShaderSrc = """ attribute vec2 aPosition; uniform mat4 uMvpMatrix; void main() { gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0); } """ fragShaderSrc = """ #ifdef GL_ES precision mediump float; #endif uniform vec3 uColor; void main() { gl_FragColor = vec4(uColor, 1.0); } """ self.program = QOpenGLShaderProgram() self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertShaderSrc) self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragShaderSrc) self.program.link() self.program.bind() vertPositions = np.array([ -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5], dtype=np.float32) self.vertPosBuffer = QOpenGLBuffer() self.vertPosBuffer.create() self.vertPosBuffer.bind() self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4) self.program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2) self.program.enableAttributeArray("aPosition") self.uColorLocation = self.program.uniformLocation("uColor") self.uMvpMatrixLocation = self.program.uniformLocation("uMvpMatrix") self.viewMatrix = QMatrix4x4() self.viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0)) self.projMatrix = QMatrix4x4() self.projViewMatrix = QMatrix4x4() self.modelMatrix = QMatrix4x4() self.mvpMatrix = QMatrix4x4() def resizeGL(self, w, h): coofWidth = w / self.initialWindowWidth coofHeight = h / self.initialWindowHeight self.projMatrix.setToIdentity() self.projMatrix.ortho(0, self.worldWidth * coofWidth, 0, self.worldHeight * coofHeight, 1, -1) self.projViewMatrix = self.projMatrix * self.viewMatrix def paintGL(self): glClear(GL_COLOR_BUFFER_BIT) self.drawRectangle(x = 50, y = 50, w = 80, h = 10, angle = 10, color = QVector3D(0.62, 0.04, 0.18)) self.drawRectangle(x = 30, y = 20, w = 50, h = 20, angle = 0, color = QVector3D(0.3, 0.07, 0.5)) self.drawRectangle(x = 50, y = 80, w = 40, h = 15, angle = -20, color = QVector3D(0.2, 0.3, 0.1)) def drawRectangle(self, x, y, w, h, angle, color): self.modelMatrix.setToIdentity() self.modelMatrix.translate(QVector3D(x, y, 0)) self.modelMatrix.rotate(angle, QVector3D(0, 0, 1)) self.modelMatrix.scale(QVector3D(w, h, 1)) self.mvpMatrix = self.projViewMatrix * self.modelMatrix self.program.setUniformValue(self.uMvpMatrixLocation, self.mvpMatrix) self.program.setUniformValue(self.uColorLocation, color) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) if __name__ == "__main__": QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL) app = QApplication(sys.argv) w = OpenGLWindow() w.show() sys.exit(app.exec())
Qt6, C++:
main.cpp
#include <QtGui/QMatrix4x4> #include <QtGui/QOpenGLFunctions> #include <QtGui/QSurfaceFormat> #include <QtGui/QVector3D> #include <QtOpenGL/QOpenGLBuffer> #include <QtOpenGL/QOpenGLShader> #include <QtOpenGL/QOpenGLShaderProgram> #include <QtOpenGL/QOpenGLWindow> #include <QtWidgets/QApplication> class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions { public: OpenGLWindow() { setTitle("OpenGL ES 2.0, Qt6, C++"); resize(380, 380); QSurfaceFormat surfaceFormat; surfaceFormat.setDepthBufferSize(24); surfaceFormat.setSamples(4); setFormat(surfaceFormat); } void initializeGL() override { initializeOpenGLFunctions(); glClearColor(0.04f, 0.62f, 0.48f, 1.f); QString vertShaderSrc = "attribute vec2 aPosition;\n" "uniform mat4 uMvpMatrix;" "void main()\n" "{\n" " gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);\n" "}\n"; QString fragShaderSrc = "#ifdef GL_ES\n" "precision mediump float;\n" "#endif\n" "uniform vec3 uColor;\n" "void main()\n" "{\n" " gl_FragColor = vec4(uColor, 1.0);\n" "}\n"; m_program.create(); m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex, vertShaderSrc); m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment, fragShaderSrc); m_program.link(); m_program.bind(); float vertPositions[] = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f }; m_vertPosBuffer.create(); m_vertPosBuffer.bind(); m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions)); m_program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2); m_program.enableAttributeArray("aPosition"); m_uColorLocation = m_program.uniformLocation("uColor"); m_uMvpMatrixLocation = m_program.uniformLocation("uMvpMatrix"); m_viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0)); } void resizeGL(int w, int h) override { const float coofWidth = w / (float)m_initialWindowWidth; const float coofHeight = h / (float)m_initialWindowHeight; m_projMatrix.setToIdentity(); m_projMatrix.ortho(0.f, m_worldWidth * coofWidth, 0.f, m_worldHeight * coofHeight, 1.f, -1.f); m_projViewMatrix = m_projMatrix * m_viewMatrix; } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); drawRectangle(50, 50, 80, 10, 10, QVector3D(0.62, 0.04, 0.18)); drawRectangle(30, 20, 50, 20, 0, QVector3D(0.3, 0.07, 0.5)); drawRectangle(50, 80, 40, 15, -20, QVector3D(0.2, 0.3, 0.1)); } void drawRectangle(float x, float y, float w, float h, float angle, const QVector3D& color) { m_modelMatrix.setToIdentity(); m_modelMatrix.translate(QVector3D(x, y, 0)); m_modelMatrix.rotate(angle, QVector3D(0, 0, 1)); m_modelMatrix.scale(QVector3D(w, h, 1)); m_mvpMatrix = m_projViewMatrix * m_modelMatrix; m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix); m_program.setUniformValue(m_uColorLocation, color); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } private: QOpenGLBuffer m_vertPosBuffer; QOpenGLShaderProgram m_program; int m_uColorLocation; int m_uMvpMatrixLocation; QMatrix4x4 m_mvpMatrix; QMatrix4x4 m_projMatrix; QMatrix4x4 m_viewMatrix; QMatrix4x4 m_projViewMatrix; QMatrix4x4 m_modelMatrix; const int m_initialWindowWidth = 380; const int m_initialWindowHeight = 380; const float m_worldWidth = 100.f; const float m_worldHeight = 100.f; }; int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL); QApplication app(argc, argv); OpenGLWindow w; w.show(); return app.exec(); }
draw-a-few-rectangles-opengles2-qt6-cpp.pro
QT += core gui openglwidgets CONFIG += c++17 SOURCES += \ main.cpp
WebAssembly demo on the free Netlify hosting
How it looks on Android 7 with scrcpy:
-
Scale the game world in the center of the screen
PySide6, Python:
import sys import numpy as np from OpenGL.GL import (GL_COLOR_BUFFER_BIT, GL_FLOAT, GL_SCISSOR_TEST, GL_TRIANGLE_STRIP, glClear, glClearColor, glDisable, glDrawArrays, glEnable, glScissor, glViewport) from PySide6.QtCore import Qt from PySide6.QtGui import QMatrix4x4, QSurfaceFormat, QVector3D from PySide6.QtOpenGL import (QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram, QOpenGLWindow) from PySide6.QtWidgets import QApplication class OpenGLWindow(QOpenGLWindow): def __init__(self): super().__init__() self.setTitle("OpenGL ES 2.0, PySide6, Python") self.resize(380, 380) self.worldWidth = 200 self.worldHeight = 100 self.worldAspect = self.worldHeight / self.worldWidth surfaceFormat = QSurfaceFormat() surfaceFormat.setDepthBufferSize(24) surfaceFormat.setSamples(4) self.setFormat(surfaceFormat) def initializeGL(self): vertShaderSrc = """ attribute vec2 aPosition; uniform mat4 uMvpMatrix; void main() { gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0); } """ fragShaderSrc = """ #ifdef GL_ES precision mediump float; #endif uniform vec3 uColor; void main() { gl_FragColor = vec4(uColor, 1.0); } """ self.program = QOpenGLShaderProgram() self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertShaderSrc) self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragShaderSrc) self.program.link() self.program.bind() vertPositions = np.array([ -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5], dtype=np.float32) self.vertPosBuffer = QOpenGLBuffer() self.vertPosBuffer.create() self.vertPosBuffer.bind() self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4) self.program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2) self.program.enableAttributeArray("aPosition") self.uColorLocation = self.program.uniformLocation("uColor") self.uMvpMatrixLocation = self.program.uniformLocation("uMvpMatrix") self.viewMatrix = QMatrix4x4() self.viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0)) self.projMatrix = QMatrix4x4() self.projViewMatrix = QMatrix4x4() self.modelMatrix = QMatrix4x4() self.mvpMatrix = QMatrix4x4() def resizeGL(self, w, h): deviceW = w * self.devicePixelRatio() deviceH = h * self.devicePixelRatio() deviceAspect = deviceH / deviceW if deviceAspect > self.worldAspect: self.viewportWidth = int(deviceW) self.viewportHeight = int(deviceW * self.worldAspect) self.viewportX = 0 self.viewportY = int((deviceH - self.viewportHeight) / 2) else: self.viewportWidth = int(deviceH / self.worldAspect) self.viewportHeight = int(deviceH) self.viewportX = int((deviceW - self.viewportWidth) / 2) self.viewportY = 0 self.projMatrix.setToIdentity() self.projMatrix.ortho(0, self.worldWidth, 0, self.worldHeight, 1, -1) self.projViewMatrix = self.projMatrix * self.viewMatrix def paintGL(self): glClearColor(0.2, 0.2, 0.2, 1) glClear(GL_COLOR_BUFFER_BIT) glViewport(self.viewportX, self.viewportY, self.viewportWidth, self.viewportHeight) glScissor(self.viewportX, self.viewportY, self.viewportWidth, self.viewportHeight) glClearColor(0.04, 0.62, 0.48, 1) glEnable(GL_SCISSOR_TEST) glClear(GL_COLOR_BUFFER_BIT) glDisable(GL_SCISSOR_TEST) # Square self.drawRectangle(x = 100, y = 50, w = 50, h = 50, angle = 0, color = QVector3D(0.3, 0.07, 0.5)) # Left border self.drawRectangle(x = 5, y = 50, w = 5, h = 85, angle = 0, color = QVector3D(0.62, 0.04, 0.18)) # Right border self.drawRectangle(x = 195, y = 50, w = 5, h = 85, angle = 0, color = QVector3D(0.62, 0.04, 0.18)) # Top border self.drawRectangle(x = 100, y = 95, w = 185, h = 5, angle = 0, color = QVector3D(0.62, 0.04, 0.18)) # Bottom border self.drawRectangle(x = 100, y = 5, w = 185, h = 5, angle = 0, color = QVector3D(0.62, 0.04, 0.18)) def drawRectangle(self, x, y, w, h, angle, color): self.modelMatrix.setToIdentity() self.modelMatrix.translate(QVector3D(x, y, 0)) self.modelMatrix.rotate(angle, QVector3D(0, 0, 1)) self.modelMatrix.scale(QVector3D(w, h, 1)) self.mvpMatrix = self.projViewMatrix * self.modelMatrix self.program.setUniformValue(self.uMvpMatrixLocation, self.mvpMatrix) self.program.setUniformValue(self.uColorLocation, color) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) if __name__ == "__main__": QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL) app = QApplication(sys.argv) w = OpenGLWindow() w.show() sys.exit(app.exec())
Qt6, C++:
main.cpp
#include <QtGui/QMatrix4x4> #include <QtGui/QOpenGLFunctions> #include <QtGui/QSurfaceFormat> #include <QtGui/QVector3D> #include <QtOpenGL/QOpenGLBuffer> #include <QtOpenGL/QOpenGLShader> #include <QtOpenGL/QOpenGLShaderProgram> #include <QtOpenGL/QOpenGLWindow> #include <QtWidgets/QApplication> class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions { public: OpenGLWindow() { setTitle("OpenGL ES 2.0, Qt6, C++"); resize(380, 380); QSurfaceFormat surfaceFormat; surfaceFormat.setDepthBufferSize(24); surfaceFormat.setSamples(4); setFormat(surfaceFormat); } void initializeGL() override { initializeOpenGLFunctions(); glClearColor(0.04f, 0.62f, 0.48f, 1.f); QString vertShaderSrc = "attribute vec2 aPosition;\n" "uniform mat4 uMvpMatrix;" "void main()\n" "{\n" " gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);\n" "}\n"; QString fragShaderSrc = "#ifdef GL_ES\n" "precision mediump float;\n" "#endif\n" "uniform vec3 uColor;\n" "void main()\n" "{\n" " gl_FragColor = vec4(uColor, 1.0);\n" "}\n"; m_program.create(); m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex, vertShaderSrc); m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment, fragShaderSrc); m_program.link(); m_program.bind(); float vertPositions[] = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f }; m_vertPosBuffer.create(); m_vertPosBuffer.bind(); m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions)); m_program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2); m_program.enableAttributeArray("aPosition"); m_uColorLocation = m_program.uniformLocation("uColor"); m_uMvpMatrixLocation = m_program.uniformLocation("uMvpMatrix"); m_viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0)); } void resizeGL(int w, int h) override { int deviceW = w * devicePixelRatio(); int deviceH = h * devicePixelRatio(); float deviceAspect = deviceH / (float) deviceW; if (deviceAspect > m_worldAspect) { m_viewportWidth = deviceW; m_viewportHeight = (int) deviceW * m_worldAspect; m_viewportX = 0; m_viewportY = (int) (deviceH - m_viewportHeight) / 2.f; } else { m_viewportWidth = (int) deviceH / m_worldAspect; m_viewportHeight = deviceH; m_viewportX = (int) (deviceW - m_viewportWidth) / 2.f; m_viewportY = 0; } m_projMatrix.setToIdentity(); m_projMatrix.ortho(0.f, m_worldWidth, 0.f, m_worldHeight, 1.f, -1.f); m_projViewMatrix = m_projMatrix * m_viewMatrix; } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); glClearColor(0.2, 0.2, 0.2, 1); glClear(GL_COLOR_BUFFER_BIT); glViewport(m_viewportX, m_viewportY, m_viewportWidth, m_viewportHeight); glScissor(m_viewportX, m_viewportY, m_viewportWidth, m_viewportHeight); glClearColor(0.04, 0.62, 0.48, 1); glEnable(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); // Square drawRectangle(100, 50, 50, 50, 0, QVector3D(0.3, 0.07, 0.5)); // Left border drawRectangle(5, 50, 5, 85, 0, QVector3D(0.62, 0.04, 0.18)); // Right border drawRectangle(195, 50, 5, 85, 0, QVector3D(0.62, 0.04, 0.18)); // Top border drawRectangle(100, 95, 185, 5, 0, QVector3D(0.62, 0.04, 0.18)); // Bottom border drawRectangle(100, 5, 185, 5, 0, QVector3D(0.62, 0.04, 0.18)); } void drawRectangle(float x, float y, float w, float h, float angle, const QVector3D& color) { m_modelMatrix.setToIdentity(); m_modelMatrix.translate(QVector3D(x, y, 0)); m_modelMatrix.rotate(angle, QVector3D(0, 0, 1)); m_modelMatrix.scale(QVector3D(w, h, 1)); m_mvpMatrix = m_projViewMatrix * m_modelMatrix; m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix); m_program.setUniformValue(m_uColorLocation, color); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } private: QOpenGLBuffer m_vertPosBuffer; QOpenGLShaderProgram m_program; int m_uColorLocation; int m_uMvpMatrixLocation; QMatrix4x4 m_mvpMatrix; QMatrix4x4 m_projMatrix; QMatrix4x4 m_viewMatrix; QMatrix4x4 m_projViewMatrix; QMatrix4x4 m_modelMatrix; const float m_worldWidth = 200.f; const float m_worldHeight = 100.f; float m_worldAspect = m_worldHeight / m_worldWidth; int m_viewportX; int m_viewportY; int m_viewportWidth; int m_viewportHeight; }; int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL); QApplication app(argc, argv); OpenGLWindow w; w.show(); return app.exec(); }
scale-the-world-in-the-center-opengles2-qt6-cpp.pro
QT += core gui openglwidgets CONFIG += c++17 SOURCES += \ main.cpp
WebAssembly demo on the free Netlify hosting
How it looks on Android:
-
Place
QLabel
overQOpenGLWidget
PySide6, Python:
import sys from OpenGL.GL import (GL_COLOR_BUFFER_BIT, GL_SCISSOR_TEST, glClear, glClearColor, glDisable, glEnable, glScissor, glViewport) from PySide6.QtCore import Qt from PySide6.QtGui import QSurfaceFormat from PySide6.QtOpenGLWidgets import QOpenGLWidget from PySide6.QtWidgets import QApplication, QLabel class OpenGLWidget(QOpenGLWidget): def __init__(self): super().__init__() self.setWindowTitle("OpenGL ES 2.0, PySide6, Python") self.resize(380, 380) self.worldWidth = 200 self.worldHeight = 100 self.worldAspect = self.worldHeight / self.worldWidth surfaceFormat = QSurfaceFormat() surfaceFormat.setDepthBufferSize(24) surfaceFormat.setSamples(4) self.setFormat(surfaceFormat) self.scoreLabel = QLabel("Score: 0", self) self.scoreLabel.setStyleSheet("font-size: 24px;") def initializeGL(self): pass def resizeGL(self, w, h): deviceW = w * self.devicePixelRatio() deviceH = h * self.devicePixelRatio() deviceAspect = deviceH / deviceW if deviceAspect > self.worldAspect: self.viewportWidth = int(deviceW) self.viewportHeight = int(deviceW * self.worldAspect) self.viewportX = 0 self.viewportY = int((deviceH - self.viewportHeight) / 2) else: self.viewportWidth = int(deviceH / self.worldAspect) self.viewportHeight = int(deviceH) self.viewportX = int((deviceW - self.viewportWidth) / 2) self.viewportY = 0 def paintGL(self): glClearColor(0.2, 0.2, 0.2, 1) glClear(GL_COLOR_BUFFER_BIT) glViewport(self.viewportX, self.viewportY, self.viewportWidth, self.viewportHeight) glScissor(self.viewportX, self.viewportY, self.viewportWidth, self.viewportHeight) glClearColor(0.04, 0.62, 0.48, 1) glEnable(GL_SCISSOR_TEST) glClear(GL_COLOR_BUFFER_BIT) glDisable(GL_SCISSOR_TEST) self.scoreLabel.move(self.viewportX / self.devicePixelRatio() + 10, self.viewportY / self.devicePixelRatio() + 10); if __name__ == "__main__": QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL) app = QApplication(sys.argv) w = OpenGLWidget() w.show() sys.exit(app.exec())
Qt6, C++:
main.cpp
#include <QtGui/QOpenGLFunctions> #include <QtGui/QSurfaceFormat> #include <QtWidgets/QApplication> #include <QtWidgets/QLabel> #include <QtOpenGLWidgets/QOpenGLWidget> class OpenGLWidget : public QOpenGLWidget, private QOpenGLFunctions { public: OpenGLWidget() { setWindowTitle("OpenGL ES 2.0, Qt6, C++"); resize(380, 380); QSurfaceFormat surfaceFormat; surfaceFormat.setDepthBufferSize(24); surfaceFormat.setSamples(4); setFormat(surfaceFormat); m_pScoreLabel = new QLabel("Score: 0", this); m_pScoreLabel->setStyleSheet("font-size: 24px;"); } void initializeGL() override { initializeOpenGLFunctions(); } void resizeGL(int w, int h) override { int deviceW = w * devicePixelRatio(); int deviceH = h * devicePixelRatio(); float deviceAspect = deviceH / (float) deviceW; if (deviceAspect > m_worldAspect) { m_viewportWidth = deviceW; m_viewportHeight = (int) deviceW * m_worldAspect; m_viewportX = 0; m_viewportY = (int) (deviceH - m_viewportHeight) / 2.f; qDebug() << deviceH << m_viewportHeight << m_viewportY; } else { m_viewportWidth = (int) deviceH / m_worldAspect; m_viewportHeight = deviceH; m_viewportX = (int) (deviceW - m_viewportWidth) / 2.f; m_viewportY = 0; } } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); glClearColor(0.2, 0.2, 0.2, 1); glClear(GL_COLOR_BUFFER_BIT); glViewport(m_viewportX, m_viewportY, m_viewportWidth, m_viewportHeight); glScissor(m_viewportX, m_viewportY, m_viewportWidth, m_viewportHeight); glClearColor(0.04, 0.62, 0.48, 1); glEnable(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); m_pScoreLabel->move(m_viewportX / devicePixelRatio() + 10, m_viewportY / devicePixelRatio() + 10); } private: const float m_worldWidth = 200.f; const float m_worldHeight = 100.f; float m_worldAspect = m_worldHeight / m_worldWidth; int m_viewportX; int m_viewportY; int m_viewportWidth; int m_viewportHeight; QLabel *m_pScoreLabel; }; int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL); QApplication app(argc, argv); OpenGLWidget w; w.show(); return app.exec(); }
qlabel-over-qopenglwidget-opengles2-qt6-cpp.pro
QT += core gui openglwidgets CONFIG += c++17 SOURCES += \ main.cpp
It doesn't work on WebAssembly: see demo. Because of this bug: https://bugreports.qt.io/browse/QTBUG-120651 But you can use the patch from the "Gerrit Reviews" (read the comments on the bug report)
But it works on Android:
-
@8Observer8 Hi! I tested your example with QOpenGLWindow
For my Mac I can compile project using :QT += core gui openglwidgets
instead of :
QT += core gui opengl widgets win32: LIBS += -lopengl32 # I don't set it for Mac
I think it can be similar on Windows.
-
@Bondrusiek said in Small examples for game development in Qt, OpenGL, Box2D, Bullet Physics, and OpenAL:
I think it can be similar on Windows.
I confirm that it works on Windows. I'm guessing that the
openglwidgets
module includes theopengl
andwidgets
modules. I've modified the examples to be the same forQOpenGLWindow
andQOpenGLWidget
:QT += core gui openglwidgets CONFIG += c++17 SOURCES += \ main.cpp
Thank you very much!