Search code examples
c++openglglutglm-mathopengl-compat

Displaying two different objects on same screen


I am trying to display a sphere and a torus on the same screen, but it seems like the "glutInitDisplayMode" is what is causing me to display only one. When I keep it as glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA |GLUT_DEPTH) the torus displays.

When I keep it as glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH) the sphere displays. What can I do to display both?

The render code is below:

static void render(void) {

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    // clear the drawing buffer.
    glClear(GL_COLOR_BUFFER_BIT);
    // clear the identity matrix.
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -5.0);
    glColor3f(0.0, 0.0, 0.0);
    glRotatef(zRotated, 0.0, 0.0, 1.0);
    // scaling transfomation 
    glScalef(1.0, 1.0, 1.0);
    // built-in (glut library) function , draw you a sphere.
    glutSolidTorus(innerRadius, outerRadius, sides, rings);
    // Flush buffers to screen

    glFlush();

  // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   // activate our shader program
    glUseProgram(programId);

   // turn on depth buffering
   glEnable(GL_DEPTH_TEST);

   float aspectRatio = (float)width / (float)height;
   glm::mat4 projection = glm::perspective(glm::radians(45.0f), aspectRatio, 0.1f, 1000.0f);


   // view matrix - orient everything around our preferred view
   glm::mat4 view = glm::lookAt(
      glm::vec3(40,30,30), // eye/camera location
      glm::vec3(0,0,0),    // where to look
      glm::vec3(0,1,0)     // up
   );

   // model matrix: translate, scale, and rotate the model
   glm::vec3 rotationAxis(0,1,0);
   glm::mat4 model = glm::mat4(1.0f);
   model = glm::rotate(model, glm::radians(angle), glm::vec3(0, 1, 0)); // rotate about the y-axis
   model = glm::scale(model, glm::vec3(25.0f, 25.0f, 25.0f));

   // model-view-projection matrix
   glm::mat4 mvp = projection * view * model;
   GLuint mvpMatrixId = glGetUniformLocation(programId, "MVP");
   glUniformMatrix4fv(mvpMatrixId, 1, GL_FALSE, &mvp[0][0]);

   // texture sampler - a reference to the texture we've previously created
   // send the texture id to the texture sampler
   GLuint textureUniformId = glGetUniformLocation(programId, "textureSampler");
   glActiveTexture(GL_TEXTURE0);
   glBindTexture(GL_TEXTURE_2D, textureId);
   glUniform1i(textureUniformId, 0);

   // find the names (ids) of each vertex attribute
   GLint positionAttribId = glGetAttribLocation(programId, "position");
   GLint colourAttribId = glGetAttribLocation(programId, "colour");
   GLint textureCoordsAttribId = glGetAttribLocation(programId, "textureCoords");
   GLint normalAttribId = glGetAttribLocation(programId, "normal");

   // provide the vertex positions to the shaders
   glBindBuffer(GL_ARRAY_BUFFER, positions_vbo);
   glEnableVertexAttribArray(positionAttribId);
   glVertexAttribPointer(positionAttribId, 3, GL_FLOAT, GL_FALSE, 0, nullptr);

   // provide the vertex texture coordinates to the shaders
   glBindBuffer(GL_ARRAY_BUFFER, textureCoords_vbo);
   glEnableVertexAttribArray(textureCoordsAttribId);
   glVertexAttribPointer(textureCoordsAttribId, 2, GL_FLOAT, GL_FALSE, 0, nullptr);

   // provide the vertex normals to the shaders
   glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
   glEnableVertexAttribArray(normalAttribId);
   glVertexAttribPointer(normalAttribId, 3, GL_FLOAT, GL_FALSE, 0, nullptr);

    // draw the triangles
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glDrawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, (void*)0);

    // disable the attribute arrays
   glDisableVertexAttribArray(positionAttribId);
   glDisableVertexAttribArray(textureCoordsAttribId);
   glDisableVertexAttribArray(normalAttribId);
   glDisableVertexAttribArray(colourAttribId);

    // make the draw buffer to display buffer (i.e. display what we have drawn)
    glutSwapBuffers(); 
}

Solution

  • glutSolidTorus draws a torus, by the use of the fixed function attributes. For this a compatibility profile OpenGL Context indispensable.

    glutSolidTorus is not compatible with you shader program. Invalidate the currently installed program, before glutSolidTorus:

    glUseProgram(0);
    glutSolidTorus(innerRadius, outerRadius, sides, rings);
    

    Note, OpenGL is a state engine. If a program is installed, it is kept, until another program is installed or it is invalidated, even beyond frames. In you case is is not an issue in the first frame, but it would be still installed at the begin of the 2nd frame, when glutSolidTorus is called.

    If you are use a double buffered window (GLUT_DOUBLE) you have to call glutSwapBuffers. glutSwapBuffers swaps the buffers. The buffer in which was drawn, is shown in the window. The buffer which was show int eh window is prepared for drawing in the next frame.

    In a single buffered window you can do glFlush. This forces OpenGL to finish drawing. Since the buffer which is draw to is the same, which is shown on the window, this causes that all what is drawing to the buffer is immediately shown in the window.

    Move the singe glFlush call form the middle of the render function to its end, right before glutSwapBuffers:

    void render()
    {
        // ...
    
        glUseProgram(0);
        glutSolidTorus(innerRadius, outerRadius, sides, rings);
    
        // glFlush(); <---- delete
    
        // ...
    
        glUseProgram(programId);
    
        // ...
    
        glDrawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, (void*)0);
    
        // ...
    
        glFlush();
        glutSwapBuffers(); 
    }