Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Game Development
  4. Small examples for game development in Qt, OpenGL, Box2D, Bullet Physics, and OpenAL

Small examples for game development in Qt, OpenGL, Box2D, Bullet Physics, and OpenAL

Scheduled Pinned Locked Moved Game Development
41 Posts 2 Posters 7.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • 8Observer88 Offline
    8Observer88 Offline
    8Observer8
    wrote on last edited by 8Observer8
    #17

    Loading 3D models from DAE COLLADA

    This example shows how to parse XML (.dae) using QDomDocument. It was tested on Android 7.1.1, Windows 10, and WebAssembly.

    • Click this link to run the demo in your browser
    • QOpenGLWindow: Source code on GitHub
    • QOpenGLWidget: Source code on GitHub

    Note. antialiasing works for WebAssembly with QOpenGLWindow for Qt 6.6.3 but it doesn't work for QOpenGLWidget. It was fixed in Qt 6.7.0. See the bug report: https://bugreports.qt.io/browse/QTBUG-123816

    fd06b132-c804-445f-ac4f-bb91687ff5aa-image.png

    1 Reply Last reply
    0
    • 8Observer88 Offline
      8Observer88 Offline
      8Observer8
      wrote on last edited by 8Observer8
      #18

      Pick color of a pixel with glReadPixels by mouse click or by touching on Mobile

      glReadPixels requires the following parameters:

      GLubyte pixel[4];
      glReadPixels(m_mouseX, m_mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
      

      Where m_mouseX and m_mouseY are the mouse click coordinates. You should recalculate them before of calling glReadPixels because glReadPixels uses bottom left corner as (0, 0) but Qt uses top left corner as (0, 0). You should add QWindow::devicePixelRatio() because Windows has devicePixelRatio = 1 but Android and macOS (maybe) has devicePixelRatio = 2:

      void mousePressEvent(QMouseEvent *event) override
      {
          m_mouseX = event->pos().x() * devicePixelRatio();
          m_mouseY = (height() - event->pos().y() - 1) * devicePixelRatio();
          m_mouseClicked = true;
          update();
      }
      

      pick-color-with-mouse-opengles2-qt6-cpp.gif

      pick-color-of-simple-triangle-qopenglwindow-qt6-cpp.pro

      QT += core gui openglwidgets
      
      CONFIG += c++17
      
      SOURCES += \
          main.cpp
      

      main.cpp

      #include <QtGui/QMouseEvent>
      #include <QtGui/QOpenGLFunctions>
      #include <QtOpenGL/QOpenGLBuffer>
      #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);
          }
      
      private:
          void initializeGL() override
          {
              initializeOpenGLFunctions();
              glClearColor(0.2f, 0.2f, 0.2f, 1.f);
              qDebug() << "Device pixel ratio:" << devicePixelRatio();
      
              QString vertexShaderSource =
                  "attribute vec2 aPosition;\n"
                  "void main()\n"
                  "{\n"
                  "    gl_Position = vec4(aPosition, 0.0, 1.0);\n"
                  "}\n";
      
              QString fragmentShaderSource =
                  "#ifdef GL_ES\n"
                  "precision mediump float;\n"
                  "#endif\n"
                  "void main()\n"
                  "{\n"
                  "    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
                  "}\n";
      
              m_program.create();
              m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex,
                                                vertexShaderSource);
              m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment,
                                                fragmentShaderSource);
              m_program.link();
              m_program.bind();
      
              float vertPositions[] = {
                  -0.5f, -0.5f,
                  0.5f, -0.5f,
                  0.f, 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");
          }
      
          void paintGL() override
          {
              glClear(GL_COLOR_BUFFER_BIT);
              glDrawArrays(GL_TRIANGLES, 0, 3);
      
              if (m_mouseClicked)
              {
                  // Read the pixel
                  GLubyte pixel[4];
                  glReadPixels(m_mouseX, m_mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
                  // Print a color
                  qDebug() << pixel[0] / 255.f << pixel[1] / 255.f << pixel[2] / 255.f;
                  m_mouseClicked = false;
              }
          }
      
          void mousePressEvent(QMouseEvent *event) override
          {
              m_mouseX = event->pos().x() * devicePixelRatio();
              m_mouseY = (height() - event->pos().y() - 1) * devicePixelRatio();
              m_mouseClicked = true;
              update();
          }
      
      private:
          int m_mouseX;
          int m_mouseY;
          bool m_mouseClicked = false;
          QOpenGLBuffer m_vertPosBuffer;
          QOpenGLShaderProgram m_program;
      };
      
      int main(int argc, char *argv[])
      {
          QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
          QApplication app(argc, argv);
          OpenGLWindow w;
          w.show();
          return app.exec();
      }
      
      1 Reply Last reply
      0
      • 8Observer88 Offline
        8Observer88 Offline
        8Observer8
        wrote on last edited by 8Observer8
        #19

        Perspective camera

        1273b633-a79a-41c0-bab9-16adca1581ac-image.png

        perspective-camera-opengles2-qt6-cpp.pro

        QT += core gui openglwidgets
        
        CONFIG += c++17
        
        SOURCES += \
            main.cpp
        

        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(500, 500);
        
                QSurfaceFormat surfaceFormat;
                surfaceFormat.setDepthBufferSize(24);
                surfaceFormat.setSamples(4);
                setFormat(surfaceFormat);
            }
        
            void initializeGL() override
            {
                initializeOpenGLFunctions();
                glClearColor(153.f/255.f, 220.f/255.f, 236.f/255.f, 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.058, 0.615, 0.345, 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, 3, 5), QVector3D(0, 0, 0), QVector3D(0, 1, 0));
            }
        
            void resizeGL(int w, int h) override
            {
                m_projMatrix.setToIdentity();
                m_projMatrix.perspective(50.f, w / (float) h, 0.1f, 100.f);
                m_projViewMatrix = m_projMatrix * m_viewMatrix;
            }
        
            void paintGL() override
            {
                glClear(GL_COLOR_BUFFER_BIT);
                m_modelMatrix.setToIdentity();
                m_modelMatrix.translate(QVector3D(0, 0, 0));
                m_modelMatrix.rotate(90, QVector3D(1, 0, 0));
                m_modelMatrix.scale(QVector3D(3, 3, 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;
        };
        
        int main(int argc, char *argv[])
        {
            QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
            QApplication app(argc, argv);
            OpenGLWindow w;
            w.show();
            return app.exec();
        }
        
        1 Reply Last reply
        0
        • 8Observer88 Offline
          8Observer88 Offline
          8Observer8
          wrote on last edited by
          #20

          Rotate and zoom camera

          Click here to test WebAssembly demo in the browser

          rotate-and-zoom-camera-opengles2-qt6-cpp-desktop.gif

          On Android only rotation works. Some work must be made with touch events for zooming:

          rotate-and-zoom-camera-opengles2-qt6-cpp.gif

          rotate-and-zoom-camera-opengles2-qt6-cpp.pro

          QT += core gui openglwidgets
          
          CONFIG += c++17
          
          SOURCES += \
              main.cpp
          

          main.cpp

          #include <QtGui/QMatrix4x4>
          #include <QtGui/QOpenGLFunctions>
          #include <QtGui/QSurfaceFormat>
          #include <QtGui/QVector3D>
          #include <QtGui/QMouseEvent>
          #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(500, 500);
                  m_degreesPerPixelX = 90.f / (float) width();
                  m_degreesPerPixelY = 180.f / (float) height();
          
                  QSurfaceFormat surfaceFormat;
                  surfaceFormat.setDepthBufferSize(24);
                  surfaceFormat.setSamples(4);
                  setFormat(surfaceFormat);
              }
          
              void initializeGL() override
              {
                  initializeOpenGLFunctions();
                  glClearColor(153.f/255.f, 220.f/255.f, 236.f/255.f, 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.058, 0.615, 0.345, 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 = getViewMatrix();
              }
          
              void resizeGL(int w, int h) override
              {
                  m_projMatrix.setToIdentity();
                  m_projMatrix.perspective(50.f, w / (float)h, 0.1f, 100.f);
              }
          
              void paintGL() override
              {
                  glClear(GL_COLOR_BUFFER_BIT);
                  m_modelMatrix.setToIdentity();
                  m_modelMatrix.translate(QVector3D(0, 0, 0));
                  m_modelMatrix.rotate(90, QVector3D(1, 0, 0));
                  m_modelMatrix.scale(QVector3D(3, 3, 1));
                  m_projViewMatrix = m_projMatrix * m_viewMatrix;
                  m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
                  m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
                  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
              }
          
              void mousePressEvent(QMouseEvent *event) override
              {
                  switch (event->button())
                  {
                      case Qt::MouseButton::LeftButton:
                      {
                          if (m_mouseHolding)
                              return;
          
                          m_mouseHolding = true;
                          m_mousePrevX = (float) event->pos().x();
                          m_mousePrevY = (float) event->pos().y();
                          break;
                      }
                      default:
                          break;
                  }
              }
          
              void mouseMoveEvent(QMouseEvent *event) override
              {
                  if (!m_mouseHolding)
                      return;
          
                  float x = (float) event->pos().x();
                  float y = (float) event->pos().y();
          
                  float newCameraRotX = m_cameraRotX + m_degreesPerPixelX * (y - m_mousePrevY);
                  newCameraRotX = qMax(-85.f, qMin(85.f, newCameraRotX));
                  float newCameraRotY = m_cameraRotY + m_degreesPerPixelY * (x - m_mousePrevX);
                  m_mousePrevX = x;
                  m_mousePrevY = y;
                  m_cameraRotX = newCameraRotX;
                  m_cameraRotY = newCameraRotY;
          
                  m_viewMatrix = getViewMatrix();
                  update();
              }
          
              void mouseReleaseEvent(QMouseEvent *event) override
              {
                  Q_UNUSED(event);
                  m_mouseHolding = false;
              }
          
              void wheelEvent(QWheelEvent *event) override
              {
                  float delta = event->angleDelta().y();
                  m_viewDistance += -delta / 500.f;
                  m_viewMatrix = getViewMatrix();
                  update();
              }
          
              QMatrix4x4 getViewMatrix()
              {
                  QMatrix4x4 mat;
          
                  const float cosX = qCos(m_cameraRotX / 180.f * M_PI);
                  const float sinX = qSin(m_cameraRotX / 180.f * M_PI);
                  const float cosY = qCos(m_cameraRotY / 180.f * M_PI);
                  const float sinY = qSin(m_cameraRotY / 180.f * M_PI);
          
                  mat.setColumn(0, QVector4D(cosY, sinX * sinY, -cosX * sinY, 0.f));
                  mat.setColumn(1, QVector4D(0.f, cosX, sinX, 0.f));
                  mat.setColumn(2, QVector4D(sinY, -sinX * cosY, cosX * cosY, 0.f));
                  mat.setColumn(3, QVector4D(0, 0, -m_viewDistance, 1.f));
          
                  return mat;
              }
          
          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;
              bool m_mouseHolding = false;
              float m_mousePrevX = 0.f;
              float m_mousePrevY = 0.f;
              float m_cameraRotX = 30.f;
              float m_cameraRotY = 0.f;
              float m_viewDistance = 5.f;
              float m_degreesPerPixelX;
              float m_degreesPerPixelY;
          };
          
          int main(int argc, char *argv[])
          {
              QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
              QApplication app(argc, argv);
              OpenGLWindow w;
              w.show();
              return app.exec();
          }
          
          1 Reply Last reply
          0
          • 8Observer88 Offline
            8Observer88 Offline
            8Observer8
            wrote on last edited by 8Observer8
            #21

            A circle (disk) is inscribed in a square

            WebAssembly demo on free Netlify hosting

            7839944d-05e1-4f20-881c-5ad2e41d8519-image.png

            disk-opengles2-qt6-cpp.pro

            QT += core gui openglwidgets
            
            CONFIG += c++17
            
            SOURCES += \
                main.cpp
            

            main.cpp

            #include <QtMath>
            #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[m_amountOfDiskVertices * 2 + 8]; // Disk + Square
                    float radius = 0.5f;
                    float angle = 0.f;
            
                    int index = 0;
                    // Disk center
                    vertPositions[index++] = 0.f;
                    vertPositions[index++] = 0.f;
            
                    // Disk
                    for (int i = 0; i < m_amountOfDiskVertices - 1; i++)
                    {
                        float radians = qDegreesToRadians(angle);
                        float x = radius * qCos(radians);
                        float y = radius * qSin(radians);
                        vertPositions[index++] = x;
                        vertPositions[index++] = y;
                        angle += m_angleStep;
                    }
                    // Square
                    vertPositions[index++] = -0.5f;
                    vertPositions[index++] = -0.5f;
                    vertPositions[index++] = 0.5f;
                    vertPositions[index++] = -0.5f;
                    vertPositions[index++] = -0.5f;
                    vertPositions[index++] = 0.5f;
                    vertPositions[index++] = 0.5f;
                    vertPositions[index++] = 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));
                    // Disk
                    drawDisk(100, 50, 50, QVector3D(0.8, 0.8, 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 drawDisk(float x, float y, float diameter, const QVector3D& color)
                {
                    m_modelMatrix.setToIdentity();
                    m_modelMatrix.translate(QVector3D(x, y, 0));
                    m_modelMatrix.scale(QVector3D(diameter, diameter, 1));
                    m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
                    m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
                    m_program.setUniformValue(m_uColorLocation, color);
                    glDrawArrays(GL_TRIANGLE_FAN, 0, m_amountOfDiskVertices);
                }
            
                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, m_amountOfDiskVertices, 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;
                float m_angleStep = 10.f;
                int m_amountOfDiskVertices = 360.f / m_angleStep + 2;
            };
            
            int main(int argc, char *argv[])
            {
                QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
                QApplication app(argc, argv);
                OpenGLWindow w;
                w.show();
                return app.exec();
            }
            
            1 Reply Last reply
            0
            • 8Observer88 Offline
              8Observer88 Offline
              8Observer8
              wrote on last edited by 8Observer8
              #22

              Moving a disk by mouse and touching

              WebAssembly demo on free Netlify hosting

              move-disk-by-mouse-and-touching-opengles2-qt6-cpp-android.gif

              move-disk-by-mouse-and-touching-opengles2-qt6-cpp-desktop.gif

              move-disk-by-mouse-and-touching-opengles2-qt6-cpp.pro

              QT += core gui openglwidgets
              
              CONFIG += c++17
              
              SOURCES += \
                  main.cpp
              

              main.cpp

              #include <QtMath>
              #include <QtGui/QMatrix4x4>
              #include <QtGui/QMouseEvent>
              #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[m_amountOfDiskVertices * 2 + 8]; // Disk + Square
                      float radius = 0.5f;
                      float angle = 0.f;
              
                      int index = 0;
                      // Disk center
                      vertPositions[index++] = 0.f;
                      vertPositions[index++] = 0.f;
              
                      // Disk
                      for (int i = 0; i < m_amountOfDiskVertices - 1; i++)
                      {
                          float radians = qDegreesToRadians(angle);
                          float x = radius * qCos(radians);
                          float y = radius * qSin(radians);
                          vertPositions[index++] = x;
                          vertPositions[index++] = y;
                          angle += m_angleStep;
                      }
                      // Square
                      vertPositions[index++] = -0.5f;
                      vertPositions[index++] = -0.5f;
                      vertPositions[index++] = 0.5f;
                      vertPositions[index++] = -0.5f;
                      vertPositions[index++] = -0.5f;
                      vertPositions[index++] = 0.5f;
                      vertPositions[index++] = 0.5f;
                      vertPositions[index++] = 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));
                      // Disk
                      drawDisk(m_diskPosX, m_diskPosY, 50, QVector3D(0.8, 0.8, 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 drawDisk(float x, float y, float diameter, const QVector3D& color)
                  {
                      m_modelMatrix.setToIdentity();
                      m_modelMatrix.translate(QVector3D(x, y, 0));
                      m_modelMatrix.scale(QVector3D(diameter, diameter, 1));
                      m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
                      m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
                      m_program.setUniformValue(m_uColorLocation, color);
                      glDrawArrays(GL_TRIANGLE_FAN, 0, m_amountOfDiskVertices);
                  }
              
                  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, m_amountOfDiskVertices, 4);
                  }
              
                  void mousePressEvent(QMouseEvent *event) override
                  {
                      switch (event->button()) {
                          case Qt::MouseButton::LeftButton:
                          {
                              m_mouseHolding = true;
                              int x = event->pos().x() * devicePixelRatio();
                              int y = (height() - event->pos().y() - 1) * devicePixelRatio();
                              if ((m_viewportX <= x && x < (m_viewportX + m_viewportWidth)) &&
                                  (m_viewportY <= y && y < (m_viewportY + m_viewportHeight)))
                              {
                                  float normalizedX = (x - m_viewportX) / (float) m_viewportWidth;
                                  float normalizedY = (y - m_viewportY) / (float) m_viewportHeight;
                                  m_diskPosX = m_worldWidth * normalizedX;
                                  m_diskPosY = m_worldHeight * normalizedY;
                              }
                              update();
                              break;
                          }
                          default:
                              break;
                      }
                  }
              
                  void mouseMoveEvent(QMouseEvent *event) override
                  {
                      if (!m_mouseHolding)
                          return;
              
                      int x = event->pos().x() * devicePixelRatio();
                      int y = (height() - event->pos().y() - 1) * devicePixelRatio();
                      if ((m_viewportX <= x && x < (m_viewportX + m_viewportWidth)) &&
                          (m_viewportY <= y && y < (m_viewportY + m_viewportHeight)))
                      {
                          float normalizedX = (x - m_viewportX) / (float) m_viewportWidth;
                          float normalizedY = (y - m_viewportY) / (float) m_viewportHeight;
                          m_diskPosX = m_worldWidth * normalizedX;
                          m_diskPosY = m_worldHeight * normalizedY;
                      }
                      update();
                  }
              
                  void mouseReleaseEvent(QMouseEvent *event) override
                  {
                      switch (event->button()) {
                          case Qt::MouseButton::LeftButton:
                          {
                              m_mouseHolding = false;
                              break;
                          }
                          default:
                              break;
                      }
                  }
              
              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;
                  float m_angleStep = 10.f;
                  int m_amountOfDiskVertices = 360.f / m_angleStep + 2;
                  bool m_mouseHolding = false;
                  float m_diskPosX = 100.f;
                  float m_diskPosY = 50.f;
              };
              
              int main(int argc, char *argv[])
              {
                  QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
                  QApplication app(argc, argv);
                  OpenGLWindow w;
                  w.show();
                  return app.exec();
              }
              
              1 Reply Last reply
              0
              • 8Observer88 Offline
                8Observer88 Offline
                8Observer8
                wrote on last edited by
                #23

                Custom collision detection between two disks

                WebAssembly demo on free Netlify hosting

                custom-collision-detection-disks-opengles2-qt6-cpp-android.gif

                custom-collision-detection-disks-opengles2-qt6-cpp-desktop.gif

                custom-collision-detection-disks-opengles2-qt6-cpp.pro

                QT += core gui openglwidgets
                
                CONFIG += c++17
                
                SOURCES += \
                    main.cpp
                

                main.cpp

                
                #include <QtMath>
                #include <QtGui/QMatrix4x4>
                #include <QtGui/QMouseEvent>
                #include <QtGui/QOpenGLFunctions>
                #include <QtGui/QSurfaceFormat>
                #include <QtGui/QVector3D>
                #include <QtGui/QVector4D>
                #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(500, 500);
                
                        QSurfaceFormat surfaceFormat;
                        surfaceFormat.setDepthBufferSize(24);
                        surfaceFormat.setSamples(4);
                        setFormat(surfaceFormat);
                    }
                
                    void initializeGL() override
                    {
                        initializeOpenGLFunctions();
                        glClearColor(0.04f, 0.62f, 0.48f, 1.f);
                        glEnable(GL_BLEND);
                        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                
                        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 vec4 uColor;\n"
                            "void main()\n"
                            "{\n"
                            "    gl_FragColor = uColor;\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[m_amountOfDiskVertices * 2 + 8]; // Disk + Square
                        float radius = 0.5f;
                        float angle = 0.f;
                
                        int index = 0;
                        // Disk center
                        vertPositions[index++] = 0.f;
                        vertPositions[index++] = 0.f;
                
                               // Disk
                        for (int i = 0; i < m_amountOfDiskVertices - 1; i++)
                        {
                            float radians = qDegreesToRadians(angle);
                            float x = radius * qCos(radians);
                            float y = radius * qSin(radians);
                            vertPositions[index++] = x;
                            vertPositions[index++] = y;
                            angle += m_angleStep;
                        }
                        // Square
                        vertPositions[index++] = -0.5f;
                        vertPositions[index++] = -0.5f;
                        vertPositions[index++] = 0.5f;
                        vertPositions[index++] = -0.5f;
                        vertPositions[index++] = -0.5f;
                        vertPositions[index++] = 0.5f;
                        vertPositions[index++] = 0.5f;
                        vertPositions[index++] = 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);
                
                        m_disk2Color.setW(0.2f);
                        if (dist(m_disk1PosX, m_disk1PosY, m_disk2PosX, m_disk2PosY) < 30.f)
                            m_disk2Color.setW(1.f);
                
                        // Disk
                        drawDisk(m_disk2PosX, m_disk2PosY, 30.f, m_disk2Color);
                        // Disk
                        drawDisk(m_disk1PosX, m_disk1PosY, 30.f, QVector4D(0.f, 0.f, 0.5f, 1.f));
                        // Left border
                        drawRectangle(5.f, 50.f, 5.f, 85.f, 0.f, QVector4D(0.62f, 0.04f, 0.18f, 1.f));
                        // Right border
                        drawRectangle(195.f, 50.f, 5.f, 85.f, 0.f, QVector4D(0.62f, 0.04f, 0.18f, 1.f));
                        // Top border
                        drawRectangle(100.f, 95.f, 185.f, 5.f, 0.f, QVector4D(0.62f, 0.04f, 0.18f, 1.f));
                        // Bottom border
                        drawRectangle(100.f, 5.f, 185.f, 5.f, 0.f, QVector4D(0.62f, 0.04f, 0.18f, 1.f));
                    }
                
                    float dist(float x1, float y1, float x2, float y2)
                    {
                        float deltaX = qFabs(x1 - x2);
                        float deltaY = qFabs(y1 - y2);
                        return qSqrt(qPow(deltaX, 2) + qPow(deltaY, 2));
                    }
                
                    void drawDisk(float x, float y, float diameter, const QVector4D& color)
                    {
                        m_modelMatrix.setToIdentity();
                        m_modelMatrix.translate(QVector3D(x, y, 0));
                        m_modelMatrix.scale(QVector3D(diameter, diameter, 1));
                        m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
                        m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
                        m_program.setUniformValue(m_uColorLocation, color);
                        glDrawArrays(GL_TRIANGLE_FAN, 0, m_amountOfDiskVertices);
                    }
                
                    void drawRectangle(float x, float y, float w, float h,
                        float angle, const QVector4D& 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, m_amountOfDiskVertices, 4);
                    }
                
                    void mousePressEvent(QMouseEvent *event) override
                    {
                        switch (event->button()) {
                            case Qt::MouseButton::LeftButton:
                            {
                                m_mouseHolding = true;
                                int x = event->pos().x() * devicePixelRatio();
                                int y = (height() - event->pos().y() - 1) * devicePixelRatio();
                                if ((m_viewportX <= x && x < (m_viewportX + m_viewportWidth)) &&
                                    (m_viewportY <= y && y < (m_viewportY + m_viewportHeight)))
                                {
                                    float normalizedX = (x - m_viewportX) / (float) m_viewportWidth;
                                    float normalizedY = (y - m_viewportY) / (float) m_viewportHeight;
                                    m_disk1PosX = m_worldWidth * normalizedX;
                                    m_disk1PosY = m_worldHeight * normalizedY;
                                }
                                update();
                                break;
                            }
                            default:
                                break;
                        }
                    }
                
                    void mouseMoveEvent(QMouseEvent *event) override
                    {
                        if (!m_mouseHolding)
                            return;
                
                        int x = event->pos().x() * devicePixelRatio();
                        int y = (height() - event->pos().y() - 1) * devicePixelRatio();
                        if ((m_viewportX <= x && x < (m_viewportX + m_viewportWidth)) &&
                            (m_viewportY <= y && y < (m_viewportY + m_viewportHeight)))
                        {
                            float normalizedX = (x - m_viewportX) / (float) m_viewportWidth;
                            float normalizedY = (y - m_viewportY) / (float) m_viewportHeight;
                            m_disk1PosX = m_worldWidth * normalizedX;
                            m_disk1PosY = m_worldHeight * normalizedY;
                        }
                        update();
                    }
                
                    void mouseReleaseEvent(QMouseEvent *event) override
                    {
                        switch (event->button()) {
                            case Qt::MouseButton::LeftButton:
                            {
                                m_mouseHolding = false;
                                break;
                            }
                            default:
                                break;
                        }
                    }
                
                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;
                    float m_angleStep = 10.f;
                    int m_amountOfDiskVertices = 360.f / m_angleStep + 2;
                    bool m_mouseHolding = false;
                    float m_disk1PosX = 150.f;
                    float m_disk1PosY = 50.f;
                    QVector4D m_disk2Color = QVector4D(0.8f, 0.f, 0.f, 0.2f);
                    float m_disk2PosX = 70.f;
                    float m_disk2PosY = 50.f;
                };
                
                int main(int argc, char *argv[])
                {
                    QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
                    QApplication app(argc, argv);
                    OpenGLWindow w;
                    w.show();
                    return app.exec();
                }
                1 Reply Last reply
                0
                • 8Observer88 Offline
                  8Observer88 Offline
                  8Observer8
                  wrote on last edited by 8Observer8
                  #24

                  Lines with thickness with disks between them

                  This example draws two lines from "start" to "finish" with thickness:

                  void drawLine(const QVector2D &from, const QVector2D &to, float thickness,
                      const QVector3D& color)
                  

                  It draws a rectangle. I place three disks: in the start point, between lines (where lines are connected), and in the finish point:

                          // Strip line
                          // Disk
                          QVector3D lineColor(0.25f, 0.31f, 0.85f);
                          drawDisk(20.f, 50.f, 10.f, lineColor);
                          // Line
                          drawLine(QVector2D(20.f, 50.f), QVector2D(50.f, 70.f), 10.f, lineColor);
                          // Disk
                          drawDisk(50.f, 70.f, 10.f, lineColor);
                          // Line
                          drawLine(QVector2D(50.f, 70.f), QVector2D(60.f, 20.f), 10.f, lineColor);
                          // Disk
                          drawDisk(60.f, 20.f, 10.f, lineColor);
                  

                  WebAssembly demo on free Netlify hosting

                  4432526f-86df-4ca1-be07-343e8c595415-image.png

                  7c21b577-d491-4e38-9c6d-26c4d12a73e3-image.png

                  lines-with-thickness-opengles2-qt6-cpp.pro

                  QT += core gui openglwidgets
                  
                  CONFIG += c++17
                  
                  SOURCES += \
                      main.cpp
                  

                  main.cpp

                  #include <QtMath>
                  #include <QtGui/QMatrix4x4>
                  #include <QtGui/QOpenGLFunctions>
                  #include <QtGui/QQuaternion>
                  #include <QtGui/QSurfaceFormat>
                  #include <QtGui/QVector2D>
                  #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(450, 450);
                  
                          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[m_amountOfDiskVertices * 2 + 8]; // Disk + Square
                          float radius = 0.5f;
                          float angle = 0.f;
                  
                          int index = 0;
                          // Disk center
                          vertPositions[index++] = 0.f;
                          vertPositions[index++] = 0.f;
                  
                          // Disk
                          for (int i = 0; i < m_amountOfDiskVertices - 1; i++)
                          {
                              float radians = qDegreesToRadians(angle);
                              float x = radius * qCos(radians);
                              float y = radius * qSin(radians);
                              vertPositions[index++] = x;
                              vertPositions[index++] = y;
                              angle += m_angleStep;
                          }
                          // Square
                          vertPositions[index++] = -0.5f;
                          vertPositions[index++] = -0.5f;
                          vertPositions[index++] = 0.5f;
                          vertPositions[index++] = -0.5f;
                          vertPositions[index++] = -0.5f;
                          vertPositions[index++] = 0.5f;
                          vertPositions[index++] = 0.5f;
                          vertPositions[index++] = 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.82f, 0.87f, 0.97f, 1.f);
                          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.82f, 0.87f, 0.97f, 1.f);
                          glEnable(GL_SCISSOR_TEST);
                          glClear(GL_COLOR_BUFFER_BIT);
                          glDisable(GL_SCISSOR_TEST);
                  
                          // Strip line
                          // Disk
                          QVector3D lineColor(0.25f, 0.31f, 0.85f);
                          drawDisk(20.f, 50.f, 10.f, lineColor);
                          // Line
                          drawLine(QVector2D(20.f, 50.f), QVector2D(50.f, 70.f), 10.f, lineColor);
                          // Disk
                          drawDisk(50.f, 70.f, 10.f, lineColor);
                          // Line
                          drawLine(QVector2D(50.f, 70.f), QVector2D(60.f, 20.f), 10.f, lineColor);
                          // Disk
                          drawDisk(60.f, 20.f, 10.f, lineColor);
                  
                          // Square
                          drawRectangle(100.f, 50.f, 50.f, 50.f, 0.f, QVector3D(0.3f, 0.07f, 0.5f));
                          // Disk
                          drawDisk(100.f, 50.f, 50.f, QVector3D(0.8f, 0.8f, 0.5f));
                  
                          // Borders
                          QVector3D borderColor(0.62f, 0.04f, 0.18f);
                          // Left border
                          drawRectangle(5.f, 50.f, 5.f, 85.f, 0.f, borderColor);
                          // Right border
                          drawRectangle(195.f, 50.f, 5.f, 85.f, 0.f, borderColor);
                          // Top border
                          drawRectangle(100.f, 95.f, 185.f, 5.f, 0.f, borderColor);
                          // Bottom border
                          drawRectangle(100.f, 5.f, 185.f, 5.f, 0.f, borderColor);
                      }
                  
                      void drawDisk(float x, float y, float diameter, const QVector3D& color)
                      {
                          m_modelMatrix.setToIdentity();
                          m_modelMatrix.translate(QVector3D(x, y, 0.f));
                          m_modelMatrix.scale(QVector3D(diameter, diameter, 1.f));
                          m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
                          m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
                          m_program.setUniformValue(m_uColorLocation, color);
                          glDrawArrays(GL_TRIANGLE_FAN, 0, m_amountOfDiskVertices);
                      }
                  
                      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.f));
                          m_modelMatrix.rotate(angle, QVector3D(0.f, 0.f, 1.f));
                          m_modelMatrix.scale(QVector3D(w, h, 1.f));
                          m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
                          m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
                          m_program.setUniformValue(m_uColorLocation, color);
                          glDrawArrays(GL_TRIANGLE_STRIP, m_amountOfDiskVertices, 4);
                      }
                  
                      void drawLine(const QVector2D &from, const QVector2D &to, float thickness,
                          const QVector3D& color)
                      {
                          QVector2D center;
                  
                          if (from.x() > to.x())
                          {
                              center.setX(to.x() + qFabs(from.x() - to.x()) / 2.f);
                          }
                          else
                          {
                              center.setX(from.x() + qFabs(to.x() - from.x()) / 2.f);
                          }
                  
                          if (from.y() > to.y())
                          {
                              center.setY(to.y() + qFabs(from.y() - to.y()) / 2.f);
                          }
                          else
                          {
                              center.setY(from.y() + qFabs(to.y() - from.y()) / 2.f);
                          }
                  
                          QVector3D tempVec;
                          tempVec.setX(to.x() - from.x());
                          tempVec.setY(to.y() - from.y());
                          float length = tempVec.length();
                          tempVec.normalize();
                          QQuaternion quat = QQuaternion::rotationTo(QVector3D(1.f, 0.f, 0.f), tempVec);
                  
                          m_modelMatrix.setToIdentity();
                          m_modelMatrix.translate(QVector3D(center.x(), center.y(), 0.f));
                          m_modelMatrix.rotate(quat);
                          m_modelMatrix.scale(QVector3D(length, thickness, 1.f));
                          m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
                          m_program.setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
                          m_program.setUniformValue(m_uColorLocation, color);
                          glDrawArrays(GL_TRIANGLE_STRIP, m_amountOfDiskVertices, 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 m_angleStep = 10;
                      int m_amountOfDiskVertices = 360 / m_angleStep + 2;
                  };
                  
                  int main(int argc, char *argv[])
                  {
                      QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
                      QApplication app(argc, argv);
                      OpenGLWindow w;
                      w.show();
                      return app.exec();
                  }
                  
                  1 Reply Last reply
                  0
                  • 8Observer88 Offline
                    8Observer88 Offline
                    8Observer8
                    wrote on last edited by 8Observer8
                    #25

                    Line drawer

                    Created a separate class for drawing a line.

                    WebAssembly demo on free Netlify hosting

                    4a1428fe-c102-448b-acbc-e4a4c9bdaa47-image.png

                    662df3bd-205a-4e3e-885b-50ca5700be10-image.png

                    line-drawer-opengles2-qt6-cpp.pro

                    QT += core gui openglwidgets
                    
                    win32: LIBS += -lopengl32
                    
                    CONFIG += c++17
                    
                    SOURCES += \
                        line_drawer.cpp \
                        main.cpp \
                        opengl_window.cpp
                    
                    HEADERS += \
                        line_drawer.h \
                        opengl_window.h
                    

                    main.cpp

                    #include <QtWidgets/QApplication>
                    #include "opengl_window.h"
                    
                    int main(int argc, char *argv[])
                    {
                        QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
                        QApplication app(argc, argv);
                        OpenGLWindow w;
                        w.show();
                        return app.exec();
                    }
                    

                    line_drawer.h

                    #ifndef LINE_DRAWER
                    #define LINE_DRAWER
                    
                    #include <QtGui/QMatrix4x4>
                    #include <QtGui/QVector2D>
                    #include <QtGui/QVector3D>
                    #include <QtOpenGL/QOpenGLBuffer>
                    #include <QtOpenGL/QOpenGLShaderProgram>
                    
                    class LineDrawer
                    {
                    public:
                        LineDrawer(QOpenGLShaderProgram *program);
                    
                        void draw(const QVector2D &from, const QVector2D &to,
                            const QVector3D &color, float thickness = 1.f);
                        void setProjViewMatrix(const QMatrix4x4 &projViewMatrix);
                    
                    private:
                        void bind();
                    
                    private:
                        QOpenGLShaderProgram *m_program;
                        QOpenGLBuffer m_vertPosBuffer;
                        int m_aPositionLocation;
                        int m_uMvpMatrixLocation;
                        int m_uColorLocation;
                        QMatrix4x4 m_projViewMatrix;
                        QMatrix4x4 m_modelMatrix;
                        QMatrix4x4 m_mvpMatrix;
                    };
                    
                    #endif // LINE_DRAWER
                    

                    line_drawer.cpp

                    #include "line_drawer.h"
                    
                    LineDrawer::LineDrawer(QOpenGLShaderProgram *program)
                    {
                        m_program = program;
                        m_program->bind();
                    
                        m_aPositionLocation = m_program->attributeLocation("aPosition");
                        m_uMvpMatrixLocation = m_program->uniformLocation("uMvpMatrix");
                        m_uColorLocation = m_program->uniformLocation("uColor");
                    
                        float vertPositions[] = {
                            -0.5, -0.5,
                            0.5, -0.5,
                            -0.5, 0.5,
                            0.5, 0.5
                        };
                        m_vertPosBuffer.create();
                        m_vertPosBuffer.bind();
                        m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions));
                    }
                    
                    void LineDrawer::setProjViewMatrix(const QMatrix4x4 &projViewMatrix)
                    {
                        m_projViewMatrix = projViewMatrix;
                    }
                    
                    void LineDrawer::bind()
                    {
                        m_program->bind();
                        m_vertPosBuffer.bind();
                        m_program->setAttributeBuffer(m_aPositionLocation, GL_FLOAT, 0, 2);
                        m_program->enableAttributeArray(m_aPositionLocation);
                    }
                    
                    void LineDrawer::draw(const QVector2D &from, const QVector2D &to,
                        const QVector3D &color, float thickness)
                    {
                        bind();
                        float centerX, centerY;
                        QVector3D tempVec;
                    
                        if (from.x() > to.x())
                        {
                            centerX = to.x() + std::abs(from.x() - to.x()) / 2.f;
                        }
                        else
                        {
                            centerX = from.x() + std::abs(to.x() - from.x()) / 2.f;
                        }
                    
                        if (from.y() > to.y())
                        {
                            centerY = to.y() + std::abs(from.y() - to.y()) / 2.f;
                        }
                        else
                        {
                            centerY = from.y() + std::abs(to.y() - from.y()) / 2.f;
                        }
                    
                        tempVec.setX(to.x() - from.x());
                        tempVec.setY(to.y() - from.y());
                        float length = tempVec.length();
                        tempVec.normalize();
                        QQuaternion quat = QQuaternion::rotationTo(QVector3D(1, 0, 0), tempVec);
                    
                        m_modelMatrix.setToIdentity();
                        m_modelMatrix.translate(QVector3D(centerX, centerY, 0));
                        m_modelMatrix.rotate(quat);
                        m_modelMatrix.scale(QVector3D(length, thickness, 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);
                    }
                    

                    opengl_window.h

                    #ifndef OPENGL_WINDOW_H
                    #define OPENGL_WINDOW_H
                    
                    #include <QtMath>
                    #include <QtGui/QMatrix4x4>
                    #include <QtGui/QOpenGLFunctions>
                    #include <QtGui/QQuaternion>
                    #include <QtGui/QSurfaceFormat>
                    #include <QtGui/QVector2D>
                    #include <QtGui/QVector3D>
                    #include <QtOpenGL/QOpenGLShader>
                    #include <QtOpenGL/QOpenGLShaderProgram>
                    #include <QtOpenGL/QOpenGLWindow>
                    
                    #include "line_drawer.h"
                    
                    class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions
                    {
                    public:
                        OpenGLWindow();
                    
                        ~OpenGLWindow();
                    
                    private:
                        void initializeGL() override;
                        void resizeGL(int w, int h) override;
                        void paintGL() override;
                    
                    private:
                        QOpenGLShaderProgram m_program;
                        QMatrix4x4 m_projMatrix;
                        QMatrix4x4 m_viewMatrix;
                        QMatrix4x4 m_projViewMatrix;
                        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;
                        LineDrawer *m_lineDrawer;
                    };
                    
                    #endif // OPENGL_WINDOW_H
                    

                    opengl_window.cpp

                    #include "opengl_window.h"
                    
                    OpenGLWindow::OpenGLWindow()
                    {
                        setTitle("OpenGL ES 2.0, Qt6, C++");
                        resize(450, 450);
                    
                        QSurfaceFormat surfaceFormat;
                        surfaceFormat.setDepthBufferSize(24);
                        surfaceFormat.setSamples(4);
                        setFormat(surfaceFormat);
                    }
                    
                    OpenGLWindow::~OpenGLWindow()
                    {
                        delete m_lineDrawer;
                    }
                    
                    void OpenGLWindow::initializeGL()
                    {
                        initializeOpenGLFunctions();
                    
                        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();
                    
                        m_lineDrawer = new LineDrawer(&m_program);
                    
                        m_viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0));
                    }
                    
                    void OpenGLWindow::resizeGL(int w, int h)
                    {
                        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;
                    
                        m_lineDrawer->setProjViewMatrix(m_projViewMatrix);
                    }
                    
                    void OpenGLWindow::paintGL()
                    {
                        glClear(GL_COLOR_BUFFER_BIT);
                        glClearColor(0.82f, 0.87f, 0.97f, 1.f);
                        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.82f, 0.87f, 0.97f, 1.f);
                        glEnable(GL_SCISSOR_TEST);
                        glClear(GL_COLOR_BUFFER_BIT);
                        glDisable(GL_SCISSOR_TEST);
                    
                        // X axis
                        QVector3D xAxisColor(0.80f, 0.15f, 0.18f);
                        m_lineDrawer->draw(QVector2D(30.f, 20.f), QVector2D(170.f, 20.f), xAxisColor);
                        // Arrow
                        m_lineDrawer->draw(QVector2D(165.f, 23.f), QVector2D(170.f, 20.f), xAxisColor);
                        m_lineDrawer->draw(QVector2D(165.f, 17.f), QVector2D(170.f, 20.f),xAxisColor);
                        // Divisions
                        m_lineDrawer->draw(QVector2D(50.f, 17.f), QVector2D(50.f, 23.f), xAxisColor);
                        m_lineDrawer->draw(QVector2D(70.f, 17.f), QVector2D(70.f, 23.f), xAxisColor);
                        m_lineDrawer->draw(QVector2D(90.f, 17.f), QVector2D(90.f, 23.f), xAxisColor);
                        m_lineDrawer->draw(QVector2D(110.f, 17.f), QVector2D(110.f, 23.f), xAxisColor);
                        m_lineDrawer->draw(QVector2D(130.f, 17.f), QVector2D(130.f, 23.f), xAxisColor);
                        m_lineDrawer->draw(QVector2D(150.f, 17.f), QVector2D(150.f, 23.f), xAxisColor);
                    
                        // Y axis
                        QVector3D yAxisColor(0.20f, 0.60f, 0.30f);
                        m_lineDrawer->draw(QVector2D(30.f, 20.f), QVector2D(30.f, 95.f), yAxisColor);
                        // Arrow
                        m_lineDrawer->draw(QVector2D(27.f, 90.f), QVector2D(30.f, 95.f), yAxisColor);
                        m_lineDrawer->draw(QVector2D(33.f, 90.f), QVector2D(30.f, 95.f), yAxisColor);
                        // Divisions
                        m_lineDrawer->draw(QVector2D(27.f, 40.f), QVector2D(33.f, 40.f), yAxisColor);
                        m_lineDrawer->draw(QVector2D(27.f, 60.f), QVector2D(33.f, 60.f), yAxisColor);
                        m_lineDrawer->draw(QVector2D(27.f, 80.f), QVector2D(33.f, 80.f), yAxisColor);
                    
                        // Graph
                        QVector3D graphColor(0.25f, 0.31f, 0.85f);
                        m_lineDrawer->draw(QVector2D(50.f, 40.f), QVector2D(70.f, 60.f), graphColor);
                        m_lineDrawer->draw(QVector2D(70.f, 60.f), QVector2D(130.f, 60.f), graphColor);
                        m_lineDrawer->draw(QVector2D(130.f, 60.f), QVector2D(150.f, 80.f), graphColor);
                    }
                    
                    1 Reply Last reply
                    0
                    • 8Observer88 Offline
                      8Observer88 Offline
                      8Observer8
                      wrote on last edited by
                      #26

                      Rectangle drawer

                      WebAssembly demo on free Netlify hosting

                      a826ef3c-65a8-4057-8dc6-a9952f09ae7b-image.png

                      44977ea3-f4da-492f-a58d-7549b7e21278-image.png

                      rectangle-drawer-opengles2-qt6-cpp.pro

                      QT += core gui openglwidgets
                      
                      win32: LIBS += -lopengl32
                      
                      CONFIG += c++17
                      
                      SOURCES += \
                          main.cpp \
                          opengl_window.cpp \
                          rectangle_drawer.cpp
                      
                      HEADERS += \
                          opengl_window.h \
                          rectangle_drawer.h
                      

                      main.cpp

                      #include <QtWidgets/QApplication>
                      #include "opengl_window.h"
                      
                      int main(int argc, char *argv[])
                      {
                          QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
                          QApplication app(argc, argv);
                          OpenGLWindow w;
                          w.show();
                          return app.exec();
                      }
                      

                      rectangle_drawer.h

                      #ifndef RECTANGLE_DRAWER
                      #define RECTANGLE_DRAWER
                      
                      #include <QtGui/QMatrix4x4>
                      #include <QtGui/QVector2D>
                      #include <QtGui/QVector3D>
                      #include <QtOpenGL/QOpenGLBuffer>
                      #include <QtOpenGL/QOpenGLShaderProgram>
                      
                      class RectangleDrawer
                      {
                      public:
                          RectangleDrawer(QOpenGLShaderProgram *program);
                      
                          void draw(const QVector2D &position, const QVector2D &size,
                              const QVector3D &color, float angle = 0.f);
                          void setProjViewMatrix(const QMatrix4x4 &projViewMatrix);
                      
                      private:
                          void bind();
                      
                      private:
                          QOpenGLShaderProgram *m_program;
                          QOpenGLBuffer m_vertPosBuffer;
                          int m_aPositionLocation;
                          int m_uMvpMatrixLocation;
                          int m_uColorLocation;
                          QMatrix4x4 m_projViewMatrix;
                          QMatrix4x4 m_modelMatrix;
                          QMatrix4x4 m_mvpMatrix;
                      };
                      
                      #endif // RECTANGLE_DRAWER
                      

                      rectangle_drawer.cpp

                      #include "rectangle_drawer.h"
                      
                      RectangleDrawer::RectangleDrawer(QOpenGLShaderProgram *program)
                      {
                          m_program = program;
                          m_program->bind();
                      
                          m_aPositionLocation = m_program->attributeLocation("aPosition");
                          m_uMvpMatrixLocation = m_program->uniformLocation("uMvpMatrix");
                          m_uColorLocation = m_program->uniformLocation("uColor");
                      
                          float vertPositions[] = {
                              -0.5, -0.5,
                              0.5, -0.5,
                              -0.5, 0.5,
                              0.5, 0.5
                          };
                          m_vertPosBuffer.create();
                          m_vertPosBuffer.bind();
                          m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions));
                      }
                      
                      void RectangleDrawer::setProjViewMatrix(const QMatrix4x4 &projViewMatrix)
                      {
                          m_projViewMatrix = projViewMatrix;
                      }
                      
                      void RectangleDrawer::bind()
                      {
                          m_program->bind();
                          m_vertPosBuffer.bind();
                          m_program->setAttributeBuffer(m_aPositionLocation, GL_FLOAT, 0, 2);
                          m_program->enableAttributeArray(m_aPositionLocation);
                      }
                      
                      void RectangleDrawer::draw(const QVector2D &position, const QVector2D &size,
                          const QVector3D &color, float angle)
                      {
                          bind();
                          m_modelMatrix.setToIdentity();
                          m_modelMatrix.translate(QVector3D(position.x(), position.y(), 0.f));
                          m_modelMatrix.rotate(angle, QVector3D(0.f, 0.f, 1.f));
                          m_modelMatrix.scale(QVector3D(size.x(), size.y(), 1.f));
                          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);
                      }
                      

                      opengl_window.h

                      #ifndef OPENGL_WINDOW
                      #define OPENGL_WINDOW
                      
                      #include <QtMath>
                      #include <QtGui/QMatrix4x4>
                      #include <QtGui/QOpenGLFunctions>
                      #include <QtGui/QQuaternion>
                      #include <QtGui/QSurfaceFormat>
                      #include <QtGui/QVector2D>
                      #include <QtGui/QVector3D>
                      #include <QtOpenGL/QOpenGLShader>
                      #include <QtOpenGL/QOpenGLShaderProgram>
                      #include <QtOpenGL/QOpenGLWindow>
                      
                      #include "rectangle_drawer.h"
                      
                      class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions
                      {
                      public:
                          OpenGLWindow();
                      
                          ~OpenGLWindow();
                      
                      private:
                          void initializeGL() override;
                          void resizeGL(int w, int h) override;
                          void paintGL() override;
                      
                      private:
                          QOpenGLShaderProgram m_program;
                          QMatrix4x4 m_projMatrix;
                          QMatrix4x4 m_viewMatrix;
                          QMatrix4x4 m_projViewMatrix;
                          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;
                          RectangleDrawer *m_rectangleDrawer;
                      };
                      
                      #endif // OPENGL_WINDOW
                      

                      opengl_window.cpp

                      #include "opengl_window.h"
                      
                      OpenGLWindow::OpenGLWindow()
                      {
                          setTitle("OpenGL ES 2.0, Qt6, C++");
                          resize(600, 300);
                      
                          QSurfaceFormat surfaceFormat;
                          surfaceFormat.setDepthBufferSize(24);
                          surfaceFormat.setSamples(4);
                          setFormat(surfaceFormat);
                      }
                      
                      OpenGLWindow::~OpenGLWindow()
                      {
                          delete m_rectangleDrawer;
                      }
                      
                      void OpenGLWindow::initializeGL()
                      {
                          initializeOpenGLFunctions();
                      
                          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();
                      
                          m_rectangleDrawer = new RectangleDrawer(&m_program);
                      
                          m_viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0));
                      }
                      
                      void OpenGLWindow::resizeGL(int w, int h)
                      {
                          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;
                      
                          m_rectangleDrawer->setProjViewMatrix(m_projViewMatrix);
                      }
                      
                      void OpenGLWindow::paintGL()
                      {
                          glClear(GL_COLOR_BUFFER_BIT);
                          glClearColor(0.2f, 0.2f, 0.2f, 1.f);
                          // glClearColor(0.82f, 0.87f, 0.97f, 1.f);
                          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.82f, 0.87f, 0.97f, 1.f);
                          glEnable(GL_SCISSOR_TEST);
                          glClear(GL_COLOR_BUFFER_BIT);
                          glDisable(GL_SCISSOR_TEST);
                      
                          m_rectangleDrawer->draw(QVector2D(50.f, 70.f), QVector2D(72.f, 7.f),
                              QVector3D(0.80f, 0.15f, 0.18f), -27.f);
                          m_rectangleDrawer->draw(QVector2D(160.f, 50.f), QVector2D(70.f, 5.f),
                              QVector3D(0.20f, 0.60f, 0.30f), 10.f);
                          m_rectangleDrawer->draw(QVector2D(100.f, 15.f), QVector2D(150.f, 7.f),
                              QVector3D(0.25f, 0.31f, 0.85f));
                      }
                      
                      1 Reply Last reply
                      0
                      • 8Observer88 Offline
                        8Observer88 Offline
                        8Observer8
                        wrote on last edited by 8Observer8
                        #27

                        Disk drawer

                        WebAssembly demo on free Netlify hosting

                        7f948267-de69-476e-93b8-fb71355b3423-image.png

                        29f3e494-89c4-4642-9232-5063de0acc78-image.png

                        disk-drawer-opengles2-qt6-cpp.pro

                        QT += core gui openglwidgets
                        
                        win32: LIBS += -lopengl32
                        
                        CONFIG += c++17
                        
                        SOURCES += \
                            disk_drawer.cpp \
                            main.cpp \
                            opengl_window.cpp
                        
                        HEADERS += \
                            disk_drawer.h \
                            opengl_window.h
                        

                        main.cpp

                        #include <QtWidgets/QApplication>
                        #include "opengl_window.h"
                        
                        int main(int argc, char *argv[])
                        {
                            QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
                            QApplication app(argc, argv);
                            OpenGLWindow w;
                            w.show();
                            return app.exec();
                        }
                        

                        disk_drawer.h

                        #ifndef DISK_DRAWER
                        #define DISK_DRAWER
                        
                        #include <QtGui/QMatrix4x4>
                        #include <QtGui/QVector2D>
                        #include <QtGui/QVector3D>
                        #include <QtOpenGL/QOpenGLBuffer>
                        #include <QtOpenGL/QOpenGLShaderProgram>
                        
                        class DiskDrawer
                        {
                        public:
                            DiskDrawer(QOpenGLShaderProgram *program);
                        
                            void draw(const QVector2D &position, float diameter,
                                const QVector3D &color);
                            void setProjViewMatrix(const QMatrix4x4 &projViewMatrix);
                        
                        private:
                            void bind();
                        
                        private:
                            QOpenGLShaderProgram *m_program;
                            QOpenGLBuffer m_vertPosBuffer;
                            int m_aPositionLocation;
                            int m_uMvpMatrixLocation;
                            int m_uColorLocation;
                            QMatrix4x4 m_projViewMatrix;
                            QMatrix4x4 m_modelMatrix;
                            QMatrix4x4 m_mvpMatrix;
                            int m_angleStep = 5;
                            int m_amountOfDiskVertices = 360 / m_angleStep + 2;
                        };
                        
                        #endif // DISK_DRAWER
                        

                        disk_drawer.cpp

                        #include "disk_drawer.h"
                        
                        DiskDrawer::DiskDrawer(QOpenGLShaderProgram *program)
                        {
                            m_program = program;
                            m_program->bind();
                        
                            m_aPositionLocation = m_program->attributeLocation("aPosition");
                            m_uMvpMatrixLocation = m_program->uniformLocation("uMvpMatrix");
                            m_uColorLocation = m_program->uniformLocation("uColor");
                        
                            float vertPositions[m_amountOfDiskVertices * 2];
                            float radius = 0.5f;
                            float angle = 0.f;
                            int index = 0;
                        
                            // Disk center
                            vertPositions[index++] = 0.f;
                            vertPositions[index++] = 0.f;
                        
                            for (int i = 0; i < m_amountOfDiskVertices - 1; i++)
                            {
                                float radians = qDegreesToRadians(angle);
                                float x = radius * qCos(radians);
                                float y = radius * qSin(radians);
                                vertPositions[index++] = x;
                                vertPositions[index++] = y;
                                angle += m_angleStep;
                            }
                        
                            m_vertPosBuffer.create();
                            m_vertPosBuffer.bind();
                            m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions));
                        }
                        
                        void DiskDrawer::setProjViewMatrix(const QMatrix4x4 &projViewMatrix)
                        {
                            m_projViewMatrix = projViewMatrix;
                        }
                        
                        void DiskDrawer::bind()
                        {
                            m_program->bind();
                            m_vertPosBuffer.bind();
                            m_program->setAttributeBuffer(m_aPositionLocation, GL_FLOAT, 0, 2);
                            m_program->enableAttributeArray(m_aPositionLocation);
                        }
                        
                        void DiskDrawer::draw(const QVector2D &position, float diameter,
                            const QVector3D &color)
                        {
                            bind();
                            m_modelMatrix.setToIdentity();
                            m_modelMatrix.translate(QVector3D(position.x(), position.y(), 0.f));
                            m_modelMatrix.scale(QVector3D(diameter, diameter, 1.f));
                            m_mvpMatrix = m_projViewMatrix * m_modelMatrix;
                            m_program->setUniformValue(m_uMvpMatrixLocation, m_mvpMatrix);
                            m_program->setUniformValue(m_uColorLocation, color);
                            glDrawArrays(GL_TRIANGLE_FAN, 0, m_amountOfDiskVertices);
                        }
                        

                        opengl_window.h

                        #ifndef OPENGL_WINDOW
                        #define OPENGL_WINDOW
                        
                        #include <QtMath>
                        #include <QtGui/QMatrix4x4>
                        #include <QtGui/QOpenGLFunctions>
                        #include <QtGui/QQuaternion>
                        #include <QtGui/QSurfaceFormat>
                        #include <QtGui/QVector2D>
                        #include <QtGui/QVector3D>
                        #include <QtOpenGL/QOpenGLShader>
                        #include <QtOpenGL/QOpenGLShaderProgram>
                        #include <QtOpenGL/QOpenGLWindow>
                        
                        #include "disk_drawer.h"
                        
                        class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions
                        {
                        public:
                            OpenGLWindow();
                        
                            ~OpenGLWindow();
                        
                        private:
                            void initializeGL() override;
                            void resizeGL(int w, int h) override;
                            void paintGL() override;
                        
                        private:
                            QOpenGLShaderProgram m_program;
                            QMatrix4x4 m_projMatrix;
                            QMatrix4x4 m_viewMatrix;
                            QMatrix4x4 m_projViewMatrix;
                            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;
                            DiskDrawer *m_diskDrawer;
                        };
                        
                        #endif // OPENGL_WINDOW
                        

                        opengl_window.cpp

                        #include "opengl_window.h"
                        
                        OpenGLWindow::OpenGLWindow()
                        {
                            setTitle("OpenGL ES 2.0, Qt6, C++");
                            resize(600, 300);
                        
                            QSurfaceFormat surfaceFormat;
                            surfaceFormat.setDepthBufferSize(24);
                            surfaceFormat.setSamples(4);
                            setFormat(surfaceFormat);
                        }
                        
                        OpenGLWindow::~OpenGLWindow()
                        {
                            delete m_diskDrawer;
                        }
                        
                        void OpenGLWindow::initializeGL()
                        {
                            initializeOpenGLFunctions();
                        
                            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();
                        
                            m_diskDrawer = new DiskDrawer(&m_program);
                        
                            m_viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0));
                        }
                        
                        void OpenGLWindow::resizeGL(int w, int h)
                        {
                            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;
                        
                            m_diskDrawer->setProjViewMatrix(m_projViewMatrix);
                        }
                        
                        void OpenGLWindow::paintGL()
                        {
                            glClear(GL_COLOR_BUFFER_BIT);
                            // glClearColor(0.2f, 0.2f, 0.2f, 1.f);
                            glClearColor(0.82f, 0.87f, 0.97f, 1.f);
                            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.82f, 0.87f, 0.97f, 1.f);
                            glEnable(GL_SCISSOR_TEST);
                            glClear(GL_COLOR_BUFFER_BIT);
                            glDisable(GL_SCISSOR_TEST);
                        
                            m_diskDrawer->draw(QVector2D(50.f, 70.f), 40.f,
                                QVector3D(0.80f, 0.15f, 0.18f));
                            m_diskDrawer->draw(QVector2D(160.f, 50.f), 50.f,
                                QVector3D(0.20f, 0.60f, 0.30f));
                            m_diskDrawer->draw(QVector2D(100.f, 15.f), 20.f,
                                QVector3D(0.25f, 0.31f, 0.85f));
                        }
                        
                        1 Reply Last reply
                        0
                        • 8Observer88 Offline
                          8Observer88 Offline
                          8Observer8
                          wrote on last edited by 8Observer8
                          #28

                          Ring drawer using line drawer

                          The RingDrawer class uses the LineDrawer class to draw the segments of a ring. For example, for number of segments equals to 10:

                          void RingDrawer::draw(const QVector2D &center, float radius,
                              const QVector3D &color, int numberOfSegments, float thickness)
                          {
                              float angle = 0.f;
                              const float angleStep = 360.f / numberOfSegments;
                          
                              float x = radius * qCos(qDegreesToRadians(angle));
                              float y = radius * qSin(qDegreesToRadians(angle));
                              QVector2D from(center.x() + x, center.y() + y);
                              angle += angleStep;
                          
                              for (int i = 0; i < numberOfSegments; i++)
                              {
                                  x = radius * qCos(qDegreesToRadians(angle));
                                  y = radius * qSin(qDegreesToRadians(angle));
                                  QVector2D to(center.x() + x, center.y() + y);
                                  m_lineDrawer->draw(from, to, color, thickness);
                                  angle += angleStep;
                                  from = to;
                              }
                          }
                          

                          72b84185-de20-4c48-a487-c69398bae1d2-image.png

                          For number of segments equals to 50: WebAssembly demo on free Netlify hosting

                          26c86b27-e3fc-4501-987e-e92f21ae14b1-image.png

                          61fc9cf8-eebc-48bb-9000-f3c3bc2d16d2-image.png

                          ring-drawer-opengles2-qt6-cpp.pro

                          QT += core gui openglwidgets
                          
                          win32: LIBS += -lopengl32
                          
                          CONFIG += c++17
                          
                          SOURCES += \
                              line_drawer.cpp \
                              main.cpp \
                              opengl_window.cpp \
                              ring_drawer.cpp
                          
                          HEADERS += \
                              line_drawer.h \
                              opengl_window.h \
                              ring_drawer.h
                          

                          main.cpp

                          #include <QtWidgets/QApplication>
                          #include "opengl_window.h"
                          
                          int main(int argc, char *argv[])
                          {
                              QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
                              QApplication app(argc, argv);
                              OpenGLWindow w;
                              w.show();
                              return app.exec();
                          }
                          

                          ring_drawer.h

                          #ifndef RING_DRAWER
                          #define RING_DRAWER
                          
                          #include "line_drawer.h"
                          
                          class RingDrawer
                          {
                          public:
                              RingDrawer(QOpenGLShaderProgram *program);
                              ~RingDrawer();
                          
                              void draw(const QVector2D &center, float radius,
                                  const QVector3D &color, int numberOfSegments = 50,
                                  float thickness = 1.f);
                              void setProjViewMatrix(const QMatrix4x4 &projViewMatrix);
                          
                          private:
                              LineDrawer *m_lineDrawer;
                          };
                          
                          #endif // RING_DRAWER
                          

                          ring_drawer.cpp

                          #include <QtMath>
                          
                          #include "ring_drawer.h"
                          
                          RingDrawer::RingDrawer(QOpenGLShaderProgram *program)
                          {
                              m_lineDrawer = new LineDrawer(program);
                          }
                          
                          RingDrawer::~RingDrawer()
                          {
                              delete m_lineDrawer;
                          }
                          
                          void RingDrawer::setProjViewMatrix(const QMatrix4x4 &projViewMatrix)
                          {
                              m_lineDrawer->setProjViewMatrix(projViewMatrix);
                          }
                          
                          void RingDrawer::draw(const QVector2D &center, float radius,
                              const QVector3D &color, int numberOfSegments, float thickness)
                          {
                              float angle = 0.f;
                              const float angleStep = 360.f / numberOfSegments;
                          
                              float x = radius * qCos(qDegreesToRadians(angle));
                              float y = radius * qSin(qDegreesToRadians(angle));
                              QVector2D from(center.x() + x, center.y() + y);
                              angle += angleStep;
                          
                              for (int i = 0; i < numberOfSegments; i++)
                              {
                                  x = radius * qCos(qDegreesToRadians(angle));
                                  y = radius * qSin(qDegreesToRadians(angle));
                                  QVector2D to(center.x() + x, center.y() + y);
                                  m_lineDrawer->draw(from, to, color, thickness);
                                  angle += angleStep;
                                  from = to;
                              }
                          }
                          

                          opengl_window.h

                          #ifndef OPENGL_WINDOW
                          #define OPENGL_WINDOW
                          
                          #include <QtMath>
                          #include <QtGui/QMatrix4x4>
                          #include <QtGui/QOpenGLFunctions>
                          #include <QtGui/QQuaternion>
                          #include <QtGui/QSurfaceFormat>
                          #include <QtGui/QVector2D>
                          #include <QtGui/QVector3D>
                          #include <QtOpenGL/QOpenGLShader>
                          #include <QtOpenGL/QOpenGLShaderProgram>
                          #include <QtOpenGL/QOpenGLWindow>
                          
                          #include "ring_drawer.h"
                          
                          class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions
                          {
                          public:
                              OpenGLWindow();
                          
                              ~OpenGLWindow();
                          
                          private:
                              void initializeGL() override;
                              void resizeGL(int w, int h) override;
                              void paintGL() override;
                          
                          private:
                              QOpenGLShaderProgram m_program;
                              QMatrix4x4 m_projMatrix;
                              QMatrix4x4 m_viewMatrix;
                              QMatrix4x4 m_projViewMatrix;
                              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;
                              RingDrawer *m_ringDrawer;
                          };
                          
                          #endif // OPENGL_WINDOW
                          

                          opengl_window.cpp

                          #include "opengl_window.h"
                          
                          OpenGLWindow::OpenGLWindow()
                          {
                              setTitle("OpenGL ES 2.0, Qt6, C++");
                              resize(600, 300);
                          
                              QSurfaceFormat surfaceFormat;
                              surfaceFormat.setDepthBufferSize(24);
                              surfaceFormat.setSamples(4);
                              setFormat(surfaceFormat);
                          }
                          
                          OpenGLWindow::~OpenGLWindow()
                          {
                              delete m_ringDrawer;
                          }
                          
                          void OpenGLWindow::initializeGL()
                          {
                              initializeOpenGLFunctions();
                          
                          
                              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();
                          
                              m_ringDrawer = new RingDrawer(&m_program);
                          
                              m_viewMatrix.lookAt(QVector3D(0, 0, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0));
                          }
                          
                          void OpenGLWindow::resizeGL(int w, int h)
                          {
                              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;
                          
                              m_ringDrawer->setProjViewMatrix(m_projViewMatrix);
                          }
                          
                          void OpenGLWindow::paintGL()
                          {
                              glClear(GL_COLOR_BUFFER_BIT);
                              // glClearColor(0.2f, 0.2f, 0.2f, 1.f);
                              glClearColor(0.82f, 0.87f, 0.97f, 1.f);
                              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.82f, 0.87f, 0.97f, 1.f);
                              glEnable(GL_SCISSOR_TEST);
                              glClear(GL_COLOR_BUFFER_BIT);
                              glDisable(GL_SCISSOR_TEST);
                          
                              m_ringDrawer->draw(QVector2D(50.f, 70.f), 20.f,
                                  QVector3D(0.80f, 0.15f, 0.18f));
                              m_ringDrawer->draw(QVector2D(160.f, 50.f), 25.f,
                                  QVector3D(0.20f, 0.60f, 0.30f));
                              m_ringDrawer->draw(QVector2D(100.f, 15.f), 10.f,
                                  QVector3D(0.25f, 0.31f, 0.85f));
                          }
                          

                          line_drawer.h

                          #ifndef LINE_DRAWER
                          #define LINE_DRAWER
                          
                          #include <QtGui/QMatrix4x4>
                          #include <QtGui/QVector2D>
                          #include <QtGui/QVector3D>
                          #include <QtOpenGL/QOpenGLBuffer>
                          #include <QtOpenGL/QOpenGLShaderProgram>
                          
                          class LineDrawer
                          {
                          public:
                              LineDrawer(QOpenGLShaderProgram *program);
                          
                              void draw(const QVector2D &from, const QVector2D &to,
                                  const QVector3D &color, float thickness = 1.f);
                              void setProjViewMatrix(const QMatrix4x4 &projViewMatrix);
                          
                          private:
                              void bind();
                          
                          private:
                              QOpenGLShaderProgram *m_program;
                              QOpenGLBuffer m_vertPosBuffer;
                              int m_aPositionLocation;
                              int m_uMvpMatrixLocation;
                              int m_uColorLocation;
                              QMatrix4x4 m_projViewMatrix;
                              QMatrix4x4 m_modelMatrix;
                              QMatrix4x4 m_mvpMatrix;
                          };
                          
                          #endif // LINE_DRAWER
                          

                          line_drawer.cpp

                          #include "line_drawer.h"
                          
                          LineDrawer::LineDrawer(QOpenGLShaderProgram *program)
                          {
                              m_program = program;
                              m_program->bind();
                          
                              m_aPositionLocation = m_program->attributeLocation("aPosition");
                              m_uMvpMatrixLocation = m_program->uniformLocation("uMvpMatrix");
                              m_uColorLocation = m_program->uniformLocation("uColor");
                          
                              float vertPositions[] = {
                                  -0.5, -0.5,
                                  0.5, -0.5,
                                  -0.5, 0.5,
                                  0.5, 0.5
                              };
                              m_vertPosBuffer.create();
                              m_vertPosBuffer.bind();
                              m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions));
                          }
                          
                          void LineDrawer::setProjViewMatrix(const QMatrix4x4 &projViewMatrix)
                          {
                              m_projViewMatrix = projViewMatrix;
                          }
                          
                          void LineDrawer::bind()
                          {
                              m_program->bind();
                              m_vertPosBuffer.bind();
                              m_program->setAttributeBuffer(m_aPositionLocation, GL_FLOAT, 0, 2);
                              m_program->enableAttributeArray(m_aPositionLocation);
                          }
                          
                          void LineDrawer::draw(const QVector2D &from, const QVector2D &to,
                              const QVector3D &color, float thickness)
                          {
                              bind();
                              float centerX, centerY;
                              QVector3D tempVec;
                          
                              if (from.x() > to.x())
                              {
                                  centerX = to.x() + std::abs(from.x() - to.x()) / 2.f;
                              }
                              else
                              {
                                  centerX = from.x() + std::abs(to.x() - from.x()) / 2.f;
                              }
                          
                              if (from.y() > to.y())
                              {
                                  centerY = to.y() + std::abs(from.y() - to.y()) / 2.f;
                              }
                              else
                              {
                                  centerY = from.y() + std::abs(to.y() - from.y()) / 2.f;
                              }
                          
                              tempVec.setX(to.x() - from.x());
                              tempVec.setY(to.y() - from.y());
                              float length = tempVec.length();
                              tempVec.normalize();
                              QQuaternion quat = QQuaternion::rotationTo(QVector3D(1, 0, 0), tempVec);
                          
                              m_modelMatrix.setToIdentity();
                              m_modelMatrix.translate(QVector3D(centerX, centerY, 0));
                              m_modelMatrix.rotate(quat);
                              m_modelMatrix.scale(QVector3D(length, thickness, 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);
                          }
                          
                          1 Reply Last reply
                          0
                          • 8Observer88 Offline
                            8Observer88 Offline
                            8Observer8
                            wrote on last edited by 8Observer8
                            #29

                            Orbit controls

                            I have created the OrbitControls class to pan a camera with right mouse button, rotate with the left mouse button, and zoom in/out with the wheel:

                            WebAssembly demo on free Netlify hosting

                            orbit-controls-opengles2-qt6-cpp-desktop.gif

                            It is not ready to pan and zoom in/out on Android, rotation only:

                            orbit-controls-opengles2-qt6-cpp-android.gif

                            Source code for QOpenGLWindow, Qt6, C++

                            1 Reply Last reply
                            0
                            • 8Observer88 Offline
                              8Observer88 Offline
                              8Observer8
                              wrote on last edited by
                              #30

                              How to set up Box2D in Qt Creator from sources for build for Android, Desktop, and WebAssembly

                              I have recorded this video today. But I don't like it. The voice is too low. I will make another video later and I will delete this one.

                              https://www.youtube.com/watch?v=OE4OOPQC7Nk

                              1 Reply Last reply
                              0
                              • 8Observer88 Offline
                                8Observer88 Offline
                                8Observer8
                                wrote on last edited by 8Observer8
                                #31

                                Detecting a mobile browser with Qt WebAssembly (topic)

                                It is important to determine whether a WebAssembly game is running on a mobile device or a personal computer in order to show or hide the joystick.

                                #ifdef Q_OS_WASM
                                #include <emscripten.h>
                                #endif
                                
                                #include "widget.h"
                                
                                #ifdef Q_OS_WASM
                                EM_JS(bool, isMobile, (), {
                                    return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
                                })
                                #endif
                                
                                Widget::Widget(QWidget *parent)
                                    : QWidget(parent)
                                {
                                    bool isMobile = false;
                                
                                #ifdef Q_OS_WASM
                                    isMobile = isMobile();
                                #endif
                                
                                #if defined Q_OS_ANDROID || defined Q_OS_IOS
                                    isMobile = true;
                                #endif
                                
                                    qDebug() << "isMobile:" << isMobile;
                                }
                                

                                Don't forget to add wasm: here:

                                QT += core gui widgets
                                
                                CONFIG += c++17
                                
                                wasm: INCLUDEPATH += "C:\emsdk\upstream\emscripten\cache\sysroot\include"
                                
                                SOURCES += \
                                    main.cpp \
                                    widget.cpp
                                
                                HEADERS += \
                                    widget.h
                                
                                1 Reply Last reply
                                0
                                • 8Observer88 Offline
                                  8Observer88 Offline
                                  8Observer8
                                  wrote on last edited by 8Observer8
                                  #32

                                  Get data with Qt client from deployed Node.js server using WebSockets (topic)

                                  My following Qt 6.6.3 example works on Android, Desktop, and Web (with Qt WebAssembly). It prints data received from the server. The server contains the Box2D-WASM library. It sends the gravity value in JSON format when a client is connected. It is useful example to make multiplayer games with physics on the server side. I have deployed the example on free Glitch hosting: https://glitch.com/edit/#!/merciful-regal-soursop from the GitHub repository: send-gravity-from-server-to-client-box2d-wasm-js The client contains only one main.cpp file. It outputs the following information to the console:

                                  connected
                                  "{\"action\":\"scGravity\",\"data\":\"{\\\"x\\\":0,\\\"y\\\":-3}\"}"
                                  

                                  You should download OpenSSL to run the following example on Android. Open the following window in Qt Creator (Edit > Preferences... > Devices > Android):

                                  b861ca0d-d29e-4c0d-8fd7-6e29bcafe64c-image.png

                                  Add the following path to your pro-file:

                                  QT += core gui websockets widgets
                                  
                                  android: include(C:/Qt/Tools/OpenSSL-1.1.1j/Win_x64/bin/openssl.pri)
                                  
                                  CONFIG += c++17
                                  
                                  SOURCES += \
                                      main.cpp
                                  

                                  Read how to add OpenSSL to your CMake project if you use CMake instead of QMake in the Qt documentaion: Adding OpenSSL Support for Android

                                  Build the following example for Android, Desktop, and WebAssembly (I have tested it):

                                  main.cpp

                                  #include <QtNetwork/QNetworkRequest>
                                  #include <QtWebSockets/QWebSocket>
                                  #include <QtWidgets/QApplication>
                                  #include <QtWidgets/QWidget>
                                  
                                  class Widget : public QWidget
                                  {
                                      Q_OBJECT
                                  
                                  public:
                                      Widget()
                                      {
                                          setWindowTitle("Show gravity from server with Box2D-WASM");
                                          resize(420, 200);
                                  
                                          connect(&m_webSocket, &QWebSocket::connected,
                                              this, &Widget::onConnected);
                                          connect(&m_webSocket, &QWebSocket::textMessageReceived,
                                              this, &Widget::onMessageReceived);
                                          connect(&m_webSocket, &QWebSocket::errorOccurred,
                                              this, &Widget::onErrorOccurred);
                                  
                                          QUrl url("wss://merciful-regal-soursop.glitch.me");
                                  
                                          QNetworkRequest request;
                                          request.setUrl(url);
                                          request.setRawHeader(QByteArray("User-Agent"),
                                              QByteArray("Mozilla/5.0 "
                                                         "(Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                                                         "Chrome/124.0.0.0 Safari/537.36"));
                                  
                                          m_webSocket.open(request);
                                      }
                                  
                                  private slots:
                                  
                                      void onConnected()
                                      {
                                          qDebug() << "connected";
                                      }
                                      void onMessageReceived(const QString &message)
                                      {
                                          qDebug() << message;
                                      }
                                  
                                      void onErrorOccurred(QAbstractSocket::SocketError error)
                                      {
                                          qDebug() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
                                          qDebug() << "Error:" << error;
                                          qDebug() << "Device supports OpenSSL:" << QSslSocket::supportsSsl();
                                          qDebug() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
                                      }
                                  
                                  private:
                                      QWebSocket m_webSocket;
                                  };
                                  
                                  #include "main.moc"
                                  
                                  int main(int argc, char *argv[])
                                  {
                                      QApplication app(argc, argv);
                                      Widget w;
                                      w.show();
                                      return app.exec();
                                  }
                                  
                                  1 Reply Last reply
                                  0
                                  • 8Observer88 Offline
                                    8Observer88 Offline
                                    8Observer8
                                    wrote on last edited by 8Observer8
                                    #33

                                    How to set up PyOpenAL

                                    PyOpenAL (released Dec 17, 2019): https://pypi.org/project/PyOpenAL/

                                    pip install PyOpenAL

                                    You can use original OpenAL API but PyOpenAL has a helpful wrapper functions. If your audio file plays with problems try to open it in the Audacity and export it with Encoding: Signed 16-bit PCM:

                                    c07a9d66-47ea-4b65-8aa3-118a493cf312-image.png

                                    1 Reply Last reply
                                    0
                                    • 8Observer88 Offline
                                      8Observer88 Offline
                                      8Observer8
                                      wrote on last edited by 8Observer8
                                      #34

                                      Play sound by button click with PyOpenAL

                                      pip install PyOpenAL PySide6

                                      73e73f44-539e-4fba-87f9-82c87287db89-image.png

                                      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())
                                      

                                      These are the Audacity settings when exporting an audio file. By default for PyOpenAL it must be "Encoding: Signed 16-bit PCM":

                                      8c4c929f-5dfa-45a4-a1ed-14a8bd6f2957-image.png

                                      1 Reply Last reply
                                      0
                                      • 8Observer88 Offline
                                        8Observer88 Offline
                                        8Observer8
                                        wrote on last edited by 8Observer8
                                        #35

                                        Music volume slider

                                        pip install PyOpenAL PySide6

                                        ccf148fa-c523-49cb-9330-5cfdbe97003f-image.png

                                        The free audio file from itch is used in this example.

                                        import sys
                                        
                                        from openal import oalOpen, oalQuit
                                        from PySide6.QtCore import Qt
                                        from PySide6.QtWidgets import (QApplication, QCheckBox, QHBoxLayout, QPushButton,
                                                                     QSlider, QVBoxLayout, QWidget)
                                        
                                        
                                        class Widget(QWidget):
                                        
                                            def __init__(self):
                                                super().__init__()
                                                self.setWindowTitle("PyOpenAL, PySide6")
                                                self.resize(300, 150)
                                        
                                                # Music check box
                                                playMusic = QCheckBox("Play music")
                                                # playMusic.toggle()
                                                # print(playMusic.isChecked())
                                                playMusic.stateChanged.connect(self.onPlayMusic)
                                        
                                                # Sound button
                                                playSoundButton = QPushButton("Play sound")
                                                playSoundButton.clicked.connect(self.onPlaySound)
                                        
                                                mousicVolume = 0.1
                                        
                                                # Volume slider
                                                volumeSlider = QSlider(Qt.Orientation.Horizontal)
                                                volumeSlider.setValue(int(mousicVolume * 100))
                                                volumeSlider.valueChanged[int].connect(self.onChangeVolume)
                                        
                                                self.mousicSource = oalOpen("assets/infant_tour.wav")
                                                self.soundSource = oalOpen("assets/bounce.wav")
                                                self.mousicSource.set_gain(mousicVolume)
                                        
                                                self.mousicSource.set_looping(True)
                                        
                                                vbox = QVBoxLayout()
                                                vbox.addWidget(volumeSlider)
                                                vbox.addWidget(playMusic)
                                                vbox.addWidget(playSoundButton)
                                                vbox.addStretch(1)
                                        
                                                hbox = QHBoxLayout()
                                                hbox.addLayout(vbox)
                                                hbox.addStretch(1)
                                                self.setLayout(hbox)
                                        
                                            def onPlayMusic(self, state):
                                                
                                                if state == Qt.CheckState.Checked.value:
                                                    self.mousicSource.play()
                                                else:
                                                    self.mousicSource.pause()
                                        
                                            def onPlaySound(self):
                                                self.soundSource.play()
                                        
                                            def onChangeVolume(self, value):
                                                self.mousicSource.set_gain(value / 100)
                                        
                                            def closeEvent(self, event):
                                                oalQuit()
                                        
                                        if __name__ == "__main__":
                                            app = QApplication(sys.argv)
                                            w = Widget()
                                            w.show()
                                            sys.exit(app.exec())
                                        
                                        1 Reply Last reply
                                        0
                                        • 8Observer88 Offline
                                          8Observer88 Offline
                                          8Observer8
                                          wrote on last edited by 8Observer8
                                          #36

                                          Custom OpenGL button for WebAssembly and Android

                                          You cannot make the standard Qt button for WebAssembly because of this bug: https://bugreports.qt.io/browse/QTBUG-120651 (you can use the patch from the "Gerrit Reviews") But OpenGL allows to make custom GUI elements.

                                          WebAssembly demo on free Netlify hosting (QOpenGLWindow)

                                          QOpenGLWindow works on Android 7.1.2 in the mobile browser without problems. You can find a lot of GUI game assets on itch: https://itch.io/game-assets/tag-gui I use the following GUI game asset in this demo: https://wenrexa.itch.io/holoui I have used Free Texture Packer to pack to button textures to one texture + json-file. Text was added in GIMP.

                                          Source code for Qt6 C++

                                          custom-start-button-opengl21-qt6-cpp.gif

                                          The same demo for SDL3:

                                          Click buttons with color ID using glReadPixels

                                          Demo in the browser

                                          This example uses the following GUI asset: https://wenrexa.itch.io/holoui. You can find a lot of GUI assets on itch: https://itch.io/game-assets/tag-gui I packed the GUI textures using Free Texture Packer to one texture + JSON. RapidJSON is used to parse the JSON file.

                                          Tools: SDL3, Emscripten, C++, CMake, OpenGL ES 2.0, GLM, stb_image, Free Texture Packer, and RapidJSON

                                          click-buttons-with-color-id.gif

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved