Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to render graphics components in the separate classes in Qt OpenGL?

How to render graphics components in the separate classes in Qt OpenGL?

Scheduled Pinned Locked Moved Solved General and Desktop
qopenglwidgetgraphicsqt5openglrendering
4 Posts 2 Posters 2.1k 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.
  • E Offline
    E Offline
    Eager
    wrote on 6 Jul 2018, 10:39 last edited by
    #1

    I have subclassed QOpenGLWidget to myOpenGLWidget and I can easily use paintGL function to render whatever I want but as the complexity of my project increases I want to define graphics components(circle, rectangle, curves etc) in separate classes and then render them in their own classes by providing a method like draw() in those components classes. But I dont understand how glDrawArrays() will know to draw in myOpenGLWidget?

    Can somebody help me out in this regard? Any sample code or any external links to helpful resources or a sample code would also be much appreciated.

    1 Reply Last reply
    0
    • E Offline
      E Offline
      Eager
      wrote on 6 Jul 2018, 13:03 last edited by
      #3

      I found the solution and it was simple!

      Let suppose we want to draw a circle from another class than the subclass of the QOpenGLWidget. Let the circle class be named as Circle. All you have to do is to inherit it from QOpenGLFunctions/QOpenGLExtraFunctions. Now remember that you can't use anything related to OpenGL before the call of QOpenGLWidget subclass's initialize() method. So you have to think about a way to initialize the Circle when QOpenGLWidget subclass's initialize() is called. The easiest way is to define your own an init() method in Circle class and call it from QOpenGLWidget subclass's initialize(). And remember that you must have to call initializeOpenGLFunctions() in the beginning of the Circle init() method. That's it!

      Similarly define a method draw() in Circle class and call it from paintGL() method of QOpenGLWidget subclass. In draw() method, you don't have to call initializeOpenGLFunctions().

      Circle.h

      #ifndef CIRCLE_H
      #define CIRCLE_H
      
      #include <QOpenGLExtraFunctions>
      
      class Circle : protected QOpenGLExtraFunctions
      {
      public:
          Circle();
      
          GLuint m_circle_shaderProgramID;
          GLuint m_circle_VAO;
          GLuint m_circle_VBO;
          void init();
          void draw();
      };
      
      #endif // CIRCLE_H
      

      Circle.cpp

      #include "Circle.h"
      #include <QVector>
      
      Circle::Circle()
      {
      }
      
      void Circle::init()
      {
          initializeOpenGLFunctions();
      
          static const char * vs_source[] =
          {
             "#version 430 core                                 \n"
             "                                                  \n"
             " layout (location = 0) in vec2 aPos;              \n"
             "                                                  \n"
             "void main(void)                                   \n"
             "{                                                 \n"
             "    gl_Position = vec4(aPos , 0.0, 1.0);          \n"
             "}                                                 \n"
          };
      
          static const char * fs_source[] =
          {
             "#version 430 core                                 \n"
             "out vec4 color;                                   \n"
             "                                                  \n"
             "void main(void)                                   \n"
             "{                                                 \n"
             "    color = vec4(1.0, 0.0, 0.0, 1.0);             \n"
             "}                                                 \n"
          };
      
          m_circle_shaderProgramID = glCreateProgram();
          GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
          glShaderSource(fs, 1, fs_source, NULL);
          glCompileShader(fs);
      
          GLuint vs = glCreateShader(GL_VERTEX_SHADER);
          glShaderSource(vs, 1, vs_source, NULL);
          glCompileShader(vs);
      
          glAttachShader(m_circle_shaderProgramID, vs);
          glAttachShader(m_circle_shaderProgramID, fs);
      
          glLinkProgram(m_circle_shaderProgramID);
      
          glDeleteShader(vs);
          glDeleteShader(fs);
      
          glGenVertexArrays(1, &m_circle_VAO);
          glGenBuffers(1, &m_circle_VBO);
      }
      
      void Circle::draw()
      {
          float cx = 0.5f;
          float cy = 0.5f;
          float r  = 0.1f;
          int num_segments = 100;
      
          float theta = 2 * M_PI / float(num_segments);
          float c = cosf(theta); //precalculate the sine and cosine
          float s = sinf(theta);
          float t;
      
          float x = r; //we start at angle = 0
          float y = 0;
      
          QVector <float> vector;
          vector.clear();
      
          for(int i = 0; i < num_segments; i++)
          {
              //apply translation
              vector.append(x+cx);
              vector.append(y+cy);
      
              //apply the rotation matrix
              t = x;
              x = c * x - s * y;
              y = s * t + c * y;
          }
      
          glBindVertexArray(m_circle_VAO);
      
          glBindBuffer(GL_ARRAY_BUFFER, m_circle_VBO);
          glBufferData(GL_ARRAY_BUFFER, vector.size()*sizeof(float), vector.data(), GL_STATIC_DRAW);
      
          glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
          glEnableVertexAttribArray(0);
          glBindBuffer(GL_ARRAY_BUFFER, 0);
      
          glUseProgram(m_circle_shaderProgramID);
          glDrawArrays(GL_LINE_LOOP, 0, num_segments);    // Simple Circle
          glDrawArrays(GL_TRIANGLE_FAN, 0, num_segments); // Filled Circle
      }
      

      Again, call init() from initialize() while call draw() from paintGL() method of QOpenGLWidget subclass like myOpenGLWidget.

      1 Reply Last reply
      2
      • S Offline
        S Offline
        SGaist
        Lifetime Qt Champion
        wrote on 6 Jul 2018, 11:12 last edited by
        #2

        Hi,

        Take a look at the OpenGL Function Calls, Headers and QOpenGLFunctions chapter in QOpenGLWidget's documentation.

        You can grab the QOpenGLFunctions allocated to the current context line shown in the code samples of that chapter and you pass that to your helper class to do the drawing.

        It's the same as when you pass a QPainter instance to helper classes in order to draw on something.

        Hope it helps

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        E 1 Reply Last reply 6 Jul 2018, 13:08
        3
        • E Offline
          E Offline
          Eager
          wrote on 6 Jul 2018, 13:03 last edited by
          #3

          I found the solution and it was simple!

          Let suppose we want to draw a circle from another class than the subclass of the QOpenGLWidget. Let the circle class be named as Circle. All you have to do is to inherit it from QOpenGLFunctions/QOpenGLExtraFunctions. Now remember that you can't use anything related to OpenGL before the call of QOpenGLWidget subclass's initialize() method. So you have to think about a way to initialize the Circle when QOpenGLWidget subclass's initialize() is called. The easiest way is to define your own an init() method in Circle class and call it from QOpenGLWidget subclass's initialize(). And remember that you must have to call initializeOpenGLFunctions() in the beginning of the Circle init() method. That's it!

          Similarly define a method draw() in Circle class and call it from paintGL() method of QOpenGLWidget subclass. In draw() method, you don't have to call initializeOpenGLFunctions().

          Circle.h

          #ifndef CIRCLE_H
          #define CIRCLE_H
          
          #include <QOpenGLExtraFunctions>
          
          class Circle : protected QOpenGLExtraFunctions
          {
          public:
              Circle();
          
              GLuint m_circle_shaderProgramID;
              GLuint m_circle_VAO;
              GLuint m_circle_VBO;
              void init();
              void draw();
          };
          
          #endif // CIRCLE_H
          

          Circle.cpp

          #include "Circle.h"
          #include <QVector>
          
          Circle::Circle()
          {
          }
          
          void Circle::init()
          {
              initializeOpenGLFunctions();
          
              static const char * vs_source[] =
              {
                 "#version 430 core                                 \n"
                 "                                                  \n"
                 " layout (location = 0) in vec2 aPos;              \n"
                 "                                                  \n"
                 "void main(void)                                   \n"
                 "{                                                 \n"
                 "    gl_Position = vec4(aPos , 0.0, 1.0);          \n"
                 "}                                                 \n"
              };
          
              static const char * fs_source[] =
              {
                 "#version 430 core                                 \n"
                 "out vec4 color;                                   \n"
                 "                                                  \n"
                 "void main(void)                                   \n"
                 "{                                                 \n"
                 "    color = vec4(1.0, 0.0, 0.0, 1.0);             \n"
                 "}                                                 \n"
              };
          
              m_circle_shaderProgramID = glCreateProgram();
              GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
              glShaderSource(fs, 1, fs_source, NULL);
              glCompileShader(fs);
          
              GLuint vs = glCreateShader(GL_VERTEX_SHADER);
              glShaderSource(vs, 1, vs_source, NULL);
              glCompileShader(vs);
          
              glAttachShader(m_circle_shaderProgramID, vs);
              glAttachShader(m_circle_shaderProgramID, fs);
          
              glLinkProgram(m_circle_shaderProgramID);
          
              glDeleteShader(vs);
              glDeleteShader(fs);
          
              glGenVertexArrays(1, &m_circle_VAO);
              glGenBuffers(1, &m_circle_VBO);
          }
          
          void Circle::draw()
          {
              float cx = 0.5f;
              float cy = 0.5f;
              float r  = 0.1f;
              int num_segments = 100;
          
              float theta = 2 * M_PI / float(num_segments);
              float c = cosf(theta); //precalculate the sine and cosine
              float s = sinf(theta);
              float t;
          
              float x = r; //we start at angle = 0
              float y = 0;
          
              QVector <float> vector;
              vector.clear();
          
              for(int i = 0; i < num_segments; i++)
              {
                  //apply translation
                  vector.append(x+cx);
                  vector.append(y+cy);
          
                  //apply the rotation matrix
                  t = x;
                  x = c * x - s * y;
                  y = s * t + c * y;
              }
          
              glBindVertexArray(m_circle_VAO);
          
              glBindBuffer(GL_ARRAY_BUFFER, m_circle_VBO);
              glBufferData(GL_ARRAY_BUFFER, vector.size()*sizeof(float), vector.data(), GL_STATIC_DRAW);
          
              glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
              glEnableVertexAttribArray(0);
              glBindBuffer(GL_ARRAY_BUFFER, 0);
          
              glUseProgram(m_circle_shaderProgramID);
              glDrawArrays(GL_LINE_LOOP, 0, num_segments);    // Simple Circle
              glDrawArrays(GL_TRIANGLE_FAN, 0, num_segments); // Filled Circle
          }
          

          Again, call init() from initialize() while call draw() from paintGL() method of QOpenGLWidget subclass like myOpenGLWidget.

          1 Reply Last reply
          2
          • S SGaist
            6 Jul 2018, 11:12

            Hi,

            Take a look at the OpenGL Function Calls, Headers and QOpenGLFunctions chapter in QOpenGLWidget's documentation.

            You can grab the QOpenGLFunctions allocated to the current context line shown in the code samples of that chapter and you pass that to your helper class to do the drawing.

            It's the same as when you pass a QPainter instance to helper classes in order to draw on something.

            Hope it helps

            E Offline
            E Offline
            Eager
            wrote on 6 Jul 2018, 13:08 last edited by
            #4

            @SGaist
            Thank you so much! Your response was much helpful!

            1 Reply Last reply
            2

            2/4

            6 Jul 2018, 11:12

            • Login

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