LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 10-04-2024, 04:14 PM   #1
mostlyharmless
Senior Member
 
Registered: Jan 2008
Distribution: Arch/Manjaro, might try Slackware again
Posts: 1,857
Blog Entries: 14

Rep: Reputation: 284Reputation: 284Reputation: 284
opengl and C++ puzzle #2


Hello again, I'm back with another puzzle no doubt indicating my deep misunderstanding of some fundamental concepts. Unfortunately, I'm not sure I can condense it down to a small piece of code for duplication, so at this point I'm looking for more general clues

I'm writing to opengl, the main action (simplified) looks like this,
in the main program the global variables are declared:
Code:
int nV;
int nE;
std::vector<GLuint> Elements(nE);
std::vector<GLfloat> Vertices(nV);
GLfloat* vertices = Vertices.data();
GLuint* elements = Elements.data();
std::vector<GLuint> Elements2(nE);
std::vector<GLfloat> Vertices2(nV);
GLfloat* vertices2 = Vertices2.data();
GLuint* elements2 = Elements2.data()
which calls GLwidget.cpp

in the GLwidget.h
Code:
extern std::vector<GLuint> Elements;
extern std::vector<GLfloat> Vertices;
extern GLfloat* vertices;
extern GLuint* elements;
extern std::vector<GLuint> Elements2;
extern std::vector<GLfloat> Vertices2;
extern GLfloat* vertices2;
extern GLuint* elements2;

GLuint elementbuffers[4];
GLuint vertexbuffers[4];
where (simplified) we have
Code:
void GLwidget::initializeGL()
{
.....
  m_vao.create();
  m_vao.bind();

  // Create buffers
  glGenBuffers(4, vertexbuffers);
  glGenBuffers(4, elementbuffers);
....
}

void GLwidget::paintGL(void)
{
    // Clear the screen    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    m_vao.bind();

    for (int i=0; i <= 3; i++)
    {
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexbuffers[i]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffers[i]);
    QMatrix4x4 mMVP;

    if (i == 1) {
        if (!LoadSurfaceToBuffer(nV, nE, vertexbuffers[i], elementbuffers[i], vertices2, elements2)) return;
    }

    if (i == 2) {
        if (!LoadSurfaceToBuffer(nV, nE, vertexbuffers[i], elementbuffers[i], vertices, elements)) return;;
    }

......

    shaderProgram->bind();
    shaderProgram->setUniformValue(m_viewMatrixLoc, mMVP);
    shaderProgram->setUniformValue(m_projMatrixLoc, projectionMatrix);
    glDrawElements(GL_TRIANGLES, nE, GL_UNSIGNED_INT, 0);

    // Unbind buffers
    glBindBuffer(vertexbuffers[i],0);
    glBindBuffer(elementbuffers[i],0);
    }

........

    m_vao.release(); }
with
Code:
bool GLwidget::LoadSurfaceToBuffer(int nV, int nE, GLuint vertexbuffer, GLuint elementbuffer, GLfloat* vertices, GLuint* elements)
{
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    GLint data_size_in_bytes = sizeof(GLfloat)*nV;                              // 4-bytes per float x number of vertices
    glBufferData(GL_ARRAY_BUFFER, data_size_in_bytes, vertices, GL_STATIC_DRAW);
    GLint size = 0;
    glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
     if(data_size_in_bytes != size)
      {
       glDeleteBuffers(1, &vertexbuffer);
       std::cout << "Error in vertices buffer: " << data_size_in_bytes << ", " << size << std::endl;
       return false;
      }
     if (!glIsBuffer(vertexbuffer)) return false;

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
    data_size_in_bytes = sizeof(GLuint)*nE;                // 4-bytes per int x number of elements
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size_in_bytes, elements, GL_STATIC_DRAW);
    size = 0;
    glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
     if(data_size_in_bytes != size)
       {
        glDeleteBuffers(1, &elementbuffer);
        std::cout << "Error in element buffer: " << data_size_in_bytes << ", " << size << std::endl;
        return false;
       }
     if (!glIsBuffer(elementbuffer)) return false;

    // positions, colors and normals all stored as floats: 9 * sizeof(GLfloat) = 3 x 3 floats
    // vertex position
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat), nullptr);
                                                           // offset 0, 9 floats = 3 positions + 3 normals+ 3 colors per vertex
    // vertex normals
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
                                                           // offset 3 because normals start after 3 positions.
    // color attribute
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
                                                          // offset 6 because colors start after 3 positions + 3 normals
    // Unbind buffer
    glBindBuffer(vertexbuffer,0);
    glBindBuffer(elementbuffer,0);

    return true;
}
All of this works brilliantly to display an image or multiple from elementbuffers[i] and vertexbuffers[i]... usually. If there's only one image, ie. if I only use vertices/elements, not vertices2/elements2, there is no issue. If I draw both, depending on the images, the first one drawn will have a large section not rendered when the second one is drawn. So first I populate vertices/elements: looks great! then I populate vertices2/elements2 and the image made from elements/vertices is missing a big chunk of the image. Oddly enough, doing this in a separate function:

Code:
    for (int i=0; i < nV; ++i){
        vertices2[i]=vertices2[i];
        vertices[i]=vertices[i];
    }
    for (int i=0; i< nE; ++i){
        elements2[i]=elements2[i];
        elements[i]=elements[i];
    }
which does ABSOLUTELY NOTHING as far as I know, fixes the image. Either assignment fixes whichever image is screwed up, that is just:

Code:
    for (int i=0; i < nV; ++i){
        vertices[i]=vertices[i];
    }
    for (int i=0; i< nE; ++i){
        elements[i]=elements[i];
    }
fixes just the one image. So....my c++ friends, what is my Fortran brain missing now? Reassigning a variable to itself should do nothing, and yet here I am.

If I'm leaving something out please let me know. There are no unusual opengl messages (though I'll recheck that) and besides wtf does my fix do and why???

Last edited by mostlyharmless; 10-04-2024 at 04:18 PM.
 
Old 10-04-2024, 07:47 PM   #2
teckk
LQ Guru
 
Registered: Oct 2004
Distribution: Arch
Posts: 5,300
Blog Entries: 6

Rep: Reputation: 1907Reputation: 1907Reputation: 1907Reputation: 1907Reputation: 1907Reputation: 1907Reputation: 1907Reputation: 1907Reputation: 1907Reputation: 1907Reputation: 1907
I don't know. You can add -Wall -Werror to your compile line. Posting code in bits like that makes it hard for anyone to see what you are doing.

All that I can add is, here is a working example of glut painting images on top of others, if this helps you.
Code:
// Bouncing balls on a checkerboard,  arrow keys move the camera.

//g++ bballs.cpp -lm -lGL -lGLU -lglut -o BBalls

#include <GL/glut.h>
#include <cmath>

// Colors
GLfloat WHITE[] = {1, 1, 1};
GLfloat RED[] = {1, 0, 0};
GLfloat GREEN[] = {0, 1, 0};
GLfloat MAGENTA[] = {1, 0, 1};

// Camera moves horizontally in a circle centered at the origin of
// radius 10, moves vertically straight up and down.
class Camera {
    double theta;      // determines the x and z positions
    double y;          // the current y position
    double dTheta;     // increment in theta for swinging the camera around
    double dy;         // increment in y for moving the camera up/down
public:
    Camera(): theta(0), y(3), dTheta(0.04), dy(0.2) {}
    double getX() {return 10 * cos(theta);}
    double getY() {return y;}
    double getZ() {return 10 * sin(theta);}
    void moveRight() {theta += dTheta;}
    void moveLeft() {theta -= dTheta;}
    void moveUp() {y += dy;}
    void moveDown() {if (y > dy) y -= dy;}
};

// Ball has a radius, a color, and bounces up and down between a maximum height 
// and the xz plane. Its x and z coordinates are fixed. Bouncing algorithm, 
// simply moving up or down by 0.05 units at each frame.
class Ball {
    double radius;
    GLfloat* color;
    double maximumHeight;
    double x;
    double y;
    double z;
    int direction;
public:
    Ball(double r, GLfloat* c, double h, double x, double z):
        radius(r), color(c), maximumHeight(h), direction(-1), y(h), x(x), z(z) {
    }
    void update() {
        y += direction * 0.05;
        if (y > maximumHeight) {
            y = maximumHeight; direction = -1;
        } else if (y < radius) {
            y = radius; direction = 1;
        }
        glPushMatrix();
        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
        glTranslated(x, y, z);
        glutSolidSphere(radius, 30, 30);
        glPopMatrix();
    }
};

// Checkerboard has alternating red and white squares. The number of squares is set 
// in the constructor. Each square is 1 x 1. One corner of the board is (0, 0) and 
// the board stretches out along positive x and positive z. It rests on the xz plane.  
// Spotlight at (4, 3, 7).
class Checkerboard {
    int displayListId;
    int width;
    int depth;
public:
    Checkerboard(int width, int depth): width(width), depth(depth) {}
    double centerx() {return width / 2;}
    double centerz() {return depth / 2;}
    void create() {
        displayListId = glGenLists(1);
        glNewList(displayListId, GL_COMPILE);
        GLfloat lightPosition[] = {4, 3, 7, 1};
        glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
        glBegin(GL_QUADS);
        glNormal3d(0, 1, 0);
        for (int x = 0; x < width - 1; x++) {
            for (int z = 0; z < depth - 1; z++) {
                glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, 
                    (x + z) % 2 == 0 ? RED : WHITE);
                glVertex3d(x, 0, z);
                glVertex3d(x+1, 0, z);
                glVertex3d(x+1, 0, z+1);
                glVertex3d(x, 0, z+1);
            }
        }
        glEnd();
        glEndList();
    }
        void draw() {
            glCallList(displayListId);
        }
};

// Global variables: camera, checkerboard, balls.
Checkerboard checkerboard(8, 8);
Camera camera;
Ball balls[] = {
    Ball(1, GREEN, 7, 6, 1),
    Ball(1.5, MAGENTA, 6, 3, 4),
    Ball(0.4, WHITE, 5, 1, 7)
};

// Set up global lighting parameters, create display lists.
void init() {
    glEnable(GL_DEPTH_TEST);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, WHITE);
    glLightfv(GL_LIGHT0, GL_SPECULAR, WHITE);
    glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE);
    glMaterialf(GL_FRONT, GL_SHININESS, 30);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    checkerboard.create();
}

// Draws one frame, checkerboard then the balls, from the current camera position.
void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    gluLookAt(camera.getX(), camera.getY(), camera.getZ(),
        checkerboard.centerx(), 0.0, checkerboard.centerz(), 0.0, 1.0, 0.0);
    checkerboard.draw();
    for (int i = 0; i < sizeof balls / sizeof(Ball); i++) {
        balls[i].update();
    }
    glFlush();
    glutSwapBuffers();
}

// On reshape, constructs camera that fits window.
void reshape(GLint w, GLint h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(40.0, GLfloat(w) / GLfloat(h), 1.0, 150.0);
    glMatrixMode(GL_MODELVIEW);
}

// Requests to draw next frame.
void timer(int v) {
    glutPostRedisplay();
    glutTimerFunc(1000/60, timer, v);
}

// Moves the camera according to the key pressed, then ask to refresh display.
void special(int key, int, int) {
    switch (key) {
        case GLUT_KEY_LEFT: camera.moveLeft(); break;
        case GLUT_KEY_RIGHT: camera.moveRight(); break;
        case GLUT_KEY_UP: camera.moveUp(); break;
        case GLUT_KEY_DOWN: camera.moveDown(); break;
    }
    glutPostRedisplay();
}

// Initialize GLUT, enter the main loop.
int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowPosition(80, 80);
    glutInitWindowSize(1000, 800);
    glutCreateWindow("Bouncing Balls");
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutSpecialFunc(special);
    glutTimerFunc(100, timer, 0);
    init();
    glutMainLoop();
}
 
Old 10-08-2024, 02:19 PM   #3
mostlyharmless
Senior Member
 
Registered: Jan 2008
Distribution: Arch/Manjaro, might try Slackware again
Posts: 1,857

Original Poster
Blog Entries: 14

Rep: Reputation: 284Reputation: 284Reputation: 284
teckk, thanks for your reply. I've actually got every error coding/warning turned on by default, not that all of them work, eg. bounds checking on array slices in Fortran is still broken last I checked.

As you suggested,I had been working on a cut down version/simplification to avoid only posting bits and pieces when the solution hit me. The problem is that the length of the vectors nV and nE, which represent the number of vertices and elements, can change. Using the same values for each buffer, as I clearly did in the paintGL example by calling LoadSurfacetoBuffer with a different buffer (different index [i]), but the same size nV and nE, is bound to change the image on each redraw. The crazy solution worked because I reloaded values of nV and nE again prior to doing my "absolutely nothing" code. so marking as [SOLVED] d'oh
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] OpenGL screensaver (and other OpenGL apps) won't work! 1337_powerslacker Slackware 3 08-08-2013 10:54 AM
opengl window not having title bar-using freeglut for opengl programming in c++ ashjas Fedora 0 01-19-2008 03:46 AM
Overwrite Mesa OpenGL with ATI OpenGL Carl-Fredrik Slackware 12 10-01-2004 04:33 PM
Changing from MESA OpenGL to ATI OpenGL tillyoubreakit Linux - Hardware 19 10-07-2003 08:32 PM
OpenGL is needed by plib-1.7.0- but i have opengl ! qwijibow Linux - Newbie 0 08-05-2003 08:12 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:07 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration