Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

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

    General and Desktop
    qopenglwidget graphics qt5 opengl rendering
    2
    4
    1403
    Loading More Posts
    • 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
      Eager last edited by

      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 Reply Quote 0
      • E
        Eager last edited by

        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 Reply Quote 2
        • SGaist
          SGaist Lifetime Qt Champion last edited by

          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 Reply Quote 3
          • E
            Eager last edited by

            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 Reply Quote 2
            • E
              Eager @SGaist last edited by

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

              1 Reply Last reply Reply Quote 2
              • First post
                Last post