// This code example is created for educational purpose // by Thorsten Thormaehlen (contact: www.thormae.de). // It is distributed without any warranty. #include #include #include #include #include #include #include using namespace std; #define _USE_MATH_DEFINES #include #include class Renderer : protected QOpenGLFunctions_2_0 { public: float t; int mode; unsigned ayimutSegs; unsigned polarSegs; int frameCount; int currentTime; int previousTime; private: GLuint vertBufID, indicesBufID; int vertSize; public: // constructor Renderer() : t(0.0), mode(1), ayimutSegs(8), polarSegs(8), vertBufID(0), indicesBufID(0), vertSize(0) {} public: void init() { initializeOpenGLFunctions(); glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH); recreateVBOs(); } void recreateVBOs() { if(vertBufID !=0) glDeleteBuffers( 1, &vertBufID); if(indicesBufID !=0) glDeleteBuffers( 1, &indicesBufID); // generating VBO input data std::vector vertexData; std::vector indicesData; int totalSegs = ayimutSegs * polarSegs; float ayimutStep = 2.0f * M_PI / float(ayimutSegs); float polarStep = M_PI / float(polarSegs); float r = 1.0; vertSize = 0; for(unsigned m=0; m < ayimutSegs; m++) { for(unsigned n=0; n < polarSegs; n++) { float phi = ayimutStep*m; float theta = polarStep * n; // random radius int rval = rand(); r = 1.0f - 0.3f * (fabs(float(rval))/float(RAND_MAX)); // create xyz from spherical coordinates float x = r * sin(theta) * cos(phi); float y = r * sin(theta) * sin(phi); float z = r * cos(theta); vertexData.push_back(x); vertexData.push_back(y); vertexData.push_back(z); // create vertex indices indicesData.push_back(vertSize % totalSegs); indicesData.push_back((vertSize+ayimutSegs) % totalSegs); indicesData.push_back((vertSize+ayimutSegs + 1) % totalSegs); indicesData.push_back((vertSize+1) % totalSegs); vertSize++; } } // generating vertex VBO glGenBuffers(1, &vertBufID); glBindBuffer(GL_ARRAY_BUFFER, vertBufID); glBufferData(GL_ARRAY_BUFFER, vertexData.size()*sizeof(float), &vertexData[0], GL_STATIC_DRAW); // generating index VBO glGenBuffers(1, &indicesBufID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBufID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesData.size()*sizeof(int), &indicesData[0], GL_STATIC_DRAW); } void updateRandomVBOVertex() { float ayimutStep = 2.0f * float(M_PI) / float(ayimutSegs); float polarStep = float(M_PI) / float(polarSegs); float r = 1.0; // randomly select point int mval = rand(); int m = int( (ayimutSegs-1) * (fabs(float(mval))/float(RAND_MAX))); int nval = rand(); int n = int( (polarSegs-1) * (fabs(float(nval))/float(RAND_MAX))); float phi = ayimutStep*m; float theta = polarStep * n; // random radius int rval = rand(); r = 1.0f - 0.3f * (fabs(float(rval))/float(RAND_MAX)); // create xyz from spherical coordinates float x = r * sin(theta) * cos(phi); float y = r * sin(theta) * sin(phi); float z = r * cos(theta); int vertPos = (m*polarSegs + n) * 3; float newVertexData[3]; newVertexData[0] = x; newVertexData[1] = y; newVertexData[2] = z; // update vertex in VBO glBindBuffer(GL_ARRAY_BUFFER, vertBufID); glBufferSubData(GL_ARRAY_BUFFER, vertPos*sizeof(float), 3*sizeof(float), newVertexData); } void resize(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective (30.0, (float)w/(float)h, 0.1, 50.0); } void display() { // update up to 100 random vertices for(unsigned i = 0; i < 100 && i < (ayimutSegs/2); i++) { updateRandomVBOVertex(); } glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // set camera gluLookAt(3.5, -1.0, 3.5, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); // draw scene glRotatef(t, 0.0f, 0.0f, 1.0f); // activating VBO glBindBuffer(GL_ARRAY_BUFFER, vertBufID); int stride = 0; glVertexPointer(3, GL_FLOAT, stride, NULL); glEnableClientState(GL_VERTEX_ARRAY); if(mode == 0) { glColor3f(1.0f,1.0f,1.0f); }else{ glColorPointer(3, GL_FLOAT, stride, NULL); glEnableClientState(GL_COLOR_ARRAY); } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBufID); glDrawElements(GL_QUADS, vertSize*4, GL_UNSIGNED_INT, NULL); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } void dispose() { if(vertBufID !=0) glDeleteBuffers( 1, &vertBufID); if(indicesBufID !=0) glDeleteBuffers( 1, &indicesBufID); } }; class MyWidget : public QOpenGLWidget { private: Renderer *renderer; QTimer *timer; public: MyWidget(QWidget *parent = NULL) : QOpenGLWidget(parent) { this->setWindowTitle("Press 1 to change color, 2 to increase vertex count"); this->resize(320, 320); renderer = new Renderer(); timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update())); timer->start(30); } ~MyWidget() { makeCurrent(); renderer->dispose(); doneCurrent(); delete renderer; delete timer; } protected: void initializeGL() { renderer->init(); } void resizeGL(int w, int h){ renderer->resize(w, h); } void paintGL() { float offset = 1.0f; renderer->t += offset; renderer->display(); } void keyPressEvent(QKeyEvent* event){ bool redraw = false; switch(event->key()) { case '1': if(renderer->mode == 1) renderer->mode = 0; else renderer->mode = 1; redraw = true; break; case '2': if(renderer->ayimutSegs < 512) { renderer->ayimutSegs *= 4; renderer->polarSegs *= 4; }else{ renderer->ayimutSegs = 8; renderer->polarSegs = 8; } makeCurrent(); renderer->recreateVBOs(); doneCurrent(); redraw = true; break; } if(redraw) { this->update(); } } }; int main (int argc, char* argv[]) { // create a QApplication object that handles initialization, // finalization, and the main event loop QApplication appl(argc, argv); MyWidget widget; // create a widget widget.show(); //show the widget and its children return appl.exec(); // execute the application }