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 |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
|
10-04-2024, 04:14 PM
|
#1
|
Senior Member
Registered: Jan 2008
Distribution: Arch/Manjaro, might try Slackware again
Posts: 1,857
|
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.
|
|
|
10-04-2024, 07:47 PM
|
#2
|
LQ Guru
Registered: Oct 2004
Distribution: Arch
Posts: 5,300
|
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();
}
|
|
|
10-08-2024, 02:19 PM
|
#3
|
Senior Member
Registered: Jan 2008
Distribution: Arch/Manjaro, might try Slackware again
Posts: 1,857
Original Poster
|
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
|
|
|
All times are GMT -5. The time now is 08:07 PM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|