// This code example is created for educational purpose
// by Thorsten Thormaehlen (contact: www.thormae.de).
// It is distributed without any warranty.

#include <QApplication>
#include <QOpenGLWidget>
#include <QOpenGLFunctions_2_0>
#include <QKeyEvent>
#include <QTimer>

#include <GL/glu.h>

class Renderer : protected QOpenGLFunctions_2_0 {

public:
  float t;
  int width, height;
   double nearPlane, farPlane;
   int depthBits;

public:
  Renderer() : t(0.0), nearPlane(2.0), farPlane(20.0) {}

public:

  void resize(int w, int h) {
    glViewport(0, 0, w, h);
    width = w;
    height = h;
  }

  void display() {    
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (30.0, (float)width/(float)height, nearPlane, farPlane);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // camera orbits in the y=10 plane
    // and looks at origin
    double rad = M_PI / 180.0f * t;
    gluLookAt(10.0*cos(rad), 10.0 , 10.0*sin(rad), // eye
              0.0, 0.0, 0.0, // look at
              0.0, 1.0, 0.0); // up

    //draw cube at origin
    drawCube();
  }

  void init() {
    initializeOpenGLFunctions();
    glEnable(GL_DEPTH_TEST);
    glGetIntegerv (GL_DEPTH_BITS, &depthBits);
  }

  void dispose() {
  }

private:
  void drawCube() {
    glColor3f(1.0,0.0,0.0);
    glBegin(GL_POLYGON);
    glVertex3f(-1.0f, 1.0f, 1.0f);
    glVertex3f(-1.0f,-1.0f, 1.0f);
    glVertex3f( 1.0f,-1.0f, 1.0f);
    glVertex3f( 1.0f, 1.0f, 1.0f);
    glEnd();
    glColor3f(0.0,1.0,0.0);
    glBegin(GL_POLYGON);
    glVertex3f( 1.0f, 1.0f,-1.0f);
    glVertex3f( 1.0f,-1.0f,-1.0f);
    glVertex3f(-1.0f,-1.0f,-1.0f);
    glVertex3f(-1.0f, 1.0f,-1.0f);
    glEnd();
    glColor3f(0.0,0.0,1.0);
    glBegin(GL_POLYGON);
    glVertex3f( 1.0f, 1.0f, 1.0f);
    glVertex3f( 1.0f,-1.0f, 1.0f);
    glVertex3f( 1.0f,-1.0f,-1.0f);
    glVertex3f( 1.0f, 1.0f,-1.0f);
    glEnd();
    glColor3f(1.0,1.0,0.0);
    glBegin(GL_POLYGON);
    glVertex3f(-1.0f, 1.0f,-1.0f);
    glVertex3f(-1.0f,-1.0f,-1.0f);
    glVertex3f(-1.0f,-1.0f, 1.0f);
    glVertex3f(-1.0f, 1.0f, 1.0f);
    glEnd();
    glColor3f(1.0,1.0,1.0);
    glBegin(GL_POLYGON);
    glVertex3f( 1.0f, 1.0f,-1.0f);
    glVertex3f(-1.0f, 1.0f,-1.0f);
    glVertex3f(-1.0f, 1.0f, 1.0f);
    glVertex3f( 1.0f, 1.0f, 1.0f);
    glEnd();
    glColor3f(0.0,1.0,1.0);
    glBegin(GL_POLYGON);
    glVertex3f( 1.0f, -1.0f, 1.0f);
    glVertex3f(-1.0f, -1.0f, 1.0f);
    glVertex3f(-1.0f, -1.0f,-1.0f);
    glVertex3f( 1.0f, -1.0f,-1.0f);  
    glEnd();
  }
};

class MyWidget : public QOpenGLWidget {

private:
  Renderer *renderer;
  QTimer *timer;

public:
  MyWidget(QWidget *parent = NULL) : QOpenGLWidget(parent) {
    this->setWindowTitle("ZFighting: Press + and - key to change near and far plane");
    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':
          renderer->nearPlane = 2.0;
          renderer->farPlane = 20.0;
          redraw = true;
          break;
      case '+':
          renderer->nearPlane *= 0.1;
          renderer->farPlane  *= 10.0;
          redraw = true;
          break;
      case '-':
          renderer->nearPlane *= 10.0;
          renderer->farPlane *= 0.1;
          if(renderer->nearPlane > 2.0) renderer->nearPlane = 2.0;
          if(renderer->farPlane < 20.0) renderer->farPlane = 20.0;
          redraw = true;
          break;
      }
      if(redraw) {
          QString title = QString("Precision: %1 bits Near:%2 Far:%3").arg(renderer->depthBits).arg(renderer->nearPlane).arg(renderer->farPlane);
          this->setWindowTitle(title);
          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
}
