#include <QGuiApplication>
 #include <QTimer>
 #include <QMouseEvent>
 #include <QWindow>
 #include <QOpenGLContext>
 #include <QOpenGLShaderProgram>
 #include "qglpainter.h"
 #include "qglabstracteffect.h"
 #include "qgltexture2d.h"
 #include "qglshaderprogrameffect.h"
 #include "pageflipmath_p.h"
 class PageFlipGradientEffect;
 class PageFlipView : public QWindow
 {
     Q_OBJECT
 public:
     PageFlipView(QWindow *parent = 0);
     ~PageFlipView();
     void setBlend(bool value) { blend = value; }
     void setVertical(bool value) { vertical = value; }
 public Q_SLOTS:
     void update();
 protected:
     void resizeGL(int width, int height);
     void initializeGL();
     void paintGL();
     void exposeEvent(QExposeEvent *e);
     void mousePressEvent(QMouseEvent *e);
 private slots:
     void animate();
 private:
     void ensureContext();
     void setAlphaValue(QGLPainter *painter, GLfloat value);
     bool blend;
     bool vertical;
     qreal posn;     
     QSize pageSize; 
     QRect pageRect1;
     QRect pageRect2;
     QColor colors[4];
     int colorIndex;
     QGLTexture2D textures[4];
     QGLTexture2D gradientTexture;
     PageFlipMath pageFlipMath;
     PageFlipGradientEffect *effect;
     QOpenGLContext *context;
     bool initialised;
     QSurfaceFormat format;
     bool updateQueued;
 };
 class PageFlipGradientEffect : public QGLShaderProgramEffect
 {
 public:
     PageFlipGradientEffect();
     ~PageFlipGradientEffect();
     void setAlphaValue(GLfloat value);
 };
 PageFlipView::PageFlipView(QWindow *parent)
     : QWindow(parent)
     , context(0)
     , initialised(false)
     , updateQueued(false)
 {
     format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
     format.setDepthBufferSize(24);
     setSurfaceType(QWindow::OpenGLSurface);
     setFormat(format);
     posn = 0.0f;
     blend = false;
     vertical = false;
     colors[0] = QColor(0, 192, 192, 255);
     colors[1] = QColor(192, 0, 0, 255);
     colors[2] = QColor(192, 192, 0, 255);
     colors[3] = QColor(128, 128, 0, 255);
     colorIndex = 0;
     QTimer *timer = new QTimer(this);
     connect(timer, SIGNAL(timeout()), this, SLOT(animate()));
     timer->start(40);
     effect = new PageFlipGradientEffect();
 }
 PageFlipView::~PageFlipView()
 {
     textures[0].cleanupResources();
     textures[1].cleanupResources();
     textures[2].cleanupResources();
     textures[3].cleanupResources();
     gradientTexture.cleanupResources();
     delete effect;
 }
 void PageFlipView::exposeEvent(QExposeEvent *e)
 {
     Q_UNUSED(e);
     updateQueued = false;
     ensureContext();
     QRect rect = geometry();
     resizeGL(rect.width(), rect.height());
     if (!initialised)
         initializeGL();
     paintGL();
     context->swapBuffers(this);
 }
 void PageFlipView::resizeGL(int width, int height)
 {
     glViewport(0, 0, width, height);
 }
 void PageFlipView::initializeGL()
 {
     QGLPainter painter(this);
     
     
     
     int width = 227;
     int height = 320;
     pageSize = QSize(width, height);
     textures[0].setImage(QImage(QLatin1String(":/qqpage1.png")));
     textures[1].setImage(QImage(QLatin1String(":/qqpage2.png")));
     textures[2].setImage(QImage(QLatin1String(":/qqpage3.png")));
     textures[3].setImage(QImage(QLatin1String(":/qqpage4.png")));
     gradientTexture.setImage(QImage(QLatin1String(":/gradient.png")));
     if (painter.hasOpenGLFeature(QOpenGLFunctions::BlendColor))
         painter.glBlendColor(0, 0, 0, 0);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     if (painter.hasOpenGLFeature(QOpenGLFunctions::BlendEquation))
         painter.glBlendEquation(GL_FUNC_ADD);
     else if (painter.hasOpenGLFeature(QOpenGLFunctions::BlendEquationSeparate))
         painter.glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
     glEnable(GL_BLEND);
     if (vertical)
         pageFlipMath.setStartCorner(PageFlipMath::VerticalBottomRight);
     else
         pageFlipMath.setStartCorner(PageFlipMath::BottomRight);
     initialised = true;
 }
 void PageFlipView::paintGL()
 {
     QGLPainter painter(this);
     QRect rect = this->geometry();
     int midx = rect.width() / 2;
     int topy = (rect.height() - pageSize.height()) / 2;
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     QMatrix4x4 projm;
     projm.ortho(rect);
     painter.projectionMatrix() = projm;
     painter.modelViewMatrix().setToIdentity();
     if (vertical) {
         pageRect2 = QRect(QPoint(midx - pageSize.width() / 2, topy), pageSize);
         pageRect1 = QRect(QPoint(pageRect2.x() - pageSize.width(), topy), pageSize);
     } else {
         pageRect1 = QRect(QPoint(midx - pageSize.width(), topy), pageSize);
         pageRect2 = QRect(QPoint(midx, topy), pageSize);
     }
     pageFlipMath.setPageRect(pageRect2);
     pageFlipMath.setShowPageReverse(false);
     pageFlipMath.compute(posn);
     QGLAttributeValue positions
         (2, GL_FLOAT, pageFlipMath.stride(), pageFlipMath.vertexArray());
     QGLAttributeValue texCoords
         (2, GL_FLOAT, pageFlipMath.stride(), pageFlipMath.vertexArray() + 2);
     QGLAttributeValue gradientCoords
         (1, GL_FLOAT, pageFlipMath.stride(), pageFlipMath.vertexArray() + 4);
     if (painter.isFixedFunction())
         painter.setStandardEffect(QGL::FlatReplaceTexture2D);
     else
         painter.setUserEffect(effect);
     painter.setColor(colors[colorIndex]);
     painter.glActiveTexture(GL_TEXTURE0);
     textures[colorIndex].bind();
     if (!painter.isFixedFunction()) {
         painter.glActiveTexture(GL_TEXTURE1);
         gradientTexture.bind();
     }
     painter.clearAttributes();
     painter.setVertexAttribute(QGL::Position, positions);
     painter.setVertexAttribute(QGL::TextureCoord0, texCoords);
     painter.setVertexAttribute(QGL::CustomVertex0, gradientCoords);
     setAlphaValue(&painter, 1.0f);
     painter.update();
     pageFlipMath.drawPage(0);
     painter.setColor(colors[(colorIndex + 1) % 4]);
     painter.glActiveTexture(GL_TEXTURE0);
     textures[(colorIndex + 1) % 4].bind();
     setAlphaValue(&painter, 1.0f);
     painter.update();
     pageFlipMath.drawPage(1);
     painter.setColor(colors[(colorIndex + 2) % 4]);
     if (!pageFlipMath.showPageReverse())
         textures[(colorIndex + 2) % 4].bind();
     if (blend)
         setAlphaValue(&painter, 0.75f);
     else
         setAlphaValue(&painter, 1.0f);
     painter.update();
     pageFlipMath.drawPage(2);
     painter.setColor(colors[(colorIndex + 3) % 4]);
     textures[(colorIndex + 3) % 4].bind();
     setAlphaValue(&painter, 1.0f);
     painter.update();
     pageFlipMath.drawPage(3);
     glBindTexture(GL_TEXTURE_2D, 0);
     painter.glActiveTexture(GL_TEXTURE1);
     glBindTexture(GL_TEXTURE_2D, 0);
     painter.setStandardEffect(QGL::FlatColor);
     painter.clearAttributes();
     painter.setVertexAttribute(QGL::Position, positions);
     painter.setVertexAttribute(QGL::TextureCoord0, texCoords);
     painter.setVertexAttribute(QGL::CustomVertex0, gradientCoords);
     painter.setColor(QColor(0, 0, 0, 255));
     painter.update();
     pageFlipMath.drawOutline(2);
 }
 void PageFlipView::mousePressEvent(QMouseEvent *e)
 {
     int x = e->x();
     int y = e->y();
     bool changed = true;
     if (vertical) {
         if (x >= pageRect2.x() && x < (pageRect2.x() + 20) &&
                 y >= pageRect2.y() && y < (pageRect2.y() + 20))
             pageFlipMath.setStartCorner(PageFlipMath::VerticalTopLeft);
         else if (x >= pageRect2.x() && x < (pageRect2.x() + 20) &&
                     y >= (pageRect2.bottom() - 20) && y <= pageRect2.bottom())
             pageFlipMath.setStartCorner(PageFlipMath::VerticalBottomLeft);
         else if (x >= (pageRect2.right() - 20) && x <= pageRect2.right() &&
                     y >= pageRect2.y() && y < (pageRect2.y() + 20))
             pageFlipMath.setStartCorner(PageFlipMath::VerticalTopRight);
         else if (x >= (pageRect2.right() - 20) && x <= pageRect2.right() &&
                     y >= (pageRect2.bottom() - 20) && y <= pageRect2.bottom())
             pageFlipMath.setStartCorner(PageFlipMath::VerticalBottomRight);
         else
             changed = false;
     } else {
         if (x >= pageRect1.x() && x < (pageRect1.x() + 20) &&
                 y >= pageRect1.y() && y < (pageRect1.y() + 20))
             pageFlipMath.setStartCorner(PageFlipMath::TopLeft);
         else if (x >= pageRect1.x() && x < (pageRect1.x() + 20) &&
                     y >= (pageRect1.bottom() - 20) && y <= pageRect1.bottom())
             pageFlipMath.setStartCorner(PageFlipMath::BottomLeft);
         else if (x >= pageRect2.x() && x < (pageRect2.x() + 20) &&
                     y >= pageRect2.y() && y < (pageRect2.y() + 20))
             pageFlipMath.setStartCorner(PageFlipMath::TopLeftOnePage);
         else if (x >= pageRect2.x() && x < (pageRect2.x() + 20) &&
                     y >= (pageRect2.bottom() - 20) && y <= pageRect2.bottom())
             pageFlipMath.setStartCorner(PageFlipMath::BottomLeftOnePage);
         else if (x >= (pageRect2.right() - 20) && x <= pageRect2.right() &&
                     y >= pageRect2.y() && y < (pageRect2.y() + 20))
             pageFlipMath.setStartCorner(PageFlipMath::TopRight);
         else if (x >= (pageRect2.right() - 20) && x <= pageRect2.right() &&
                     y >= (pageRect2.bottom() - 20) && y <= pageRect2.bottom())
             pageFlipMath.setStartCorner(PageFlipMath::BottomRight);
         else
             changed = false;
     }
     if (changed)
         posn = 0.0f;
     QWindow::mousePressEvent(e);
 }
 void PageFlipView::animate()
 {
     posn += 0.04f;
     if (posn >= 1.0f) {
         posn = 0.0f;
         colorIndex = (colorIndex + 2) % 4;
     }
     update();
 }
 void PageFlipView::update()
 {
     if (!updateQueued)
     {
         updateQueued = true;
         QGuiApplication::postEvent(this, new QExposeEvent(geometry()));
     }
 }
 void PageFlipView::setAlphaValue(QGLPainter *painter, GLfloat value)
 {
     if (!painter->isFixedFunction())
         effect->setAlphaValue(value);
 }
 static char const gradientVertexShader[] =
     "attribute highp vec4 qt_Vertex;\n"
     "attribute highp vec4 qt_MultiTexCoord0;\n"
     "attribute highp float qt_Custom0;\n"
     "uniform mediump mat4 qt_ModelViewProjectionMatrix;\n"
     "varying highp vec4 qt_TexCoord0;\n"
     "varying highp float qGradCtrl;\n"
     "void main(void)\n"
     "{\n"
     "    gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex;\n"
     "    qt_TexCoord0 = qt_MultiTexCoord0;\n"
     "    qGradCtrl = qt_Custom0;\n"
     "}\n";
 static char const gradientFragmentShader[] =
     "uniform sampler2D qt_Texture0;\n"
     "uniform sampler2D qt_Texture1;\n"
     "uniform mediump float alphaValue;\n"
     "varying highp vec4 qt_TexCoord0;\n"
     "varying highp float qGradCtrl;\n"
     "void main(void)\n"
     "{\n"
     "    mediump vec4 col = texture2D(qt_Texture0, qt_TexCoord0.st);\n"
     "    mediump vec4 gradcol = texture2D(qt_Texture1, vec2(qGradCtrl, qt_TexCoord0.t));\n"
     "    gl_FragColor = vec4((col * gradcol).xyz, alphaValue);\n"
     "}\n";
 PageFlipGradientEffect::PageFlipGradientEffect()
 {
     setVertexShader(gradientVertexShader);
     setFragmentShader(gradientFragmentShader);
 }
 PageFlipGradientEffect::~PageFlipGradientEffect()
 {
 }
 void PageFlipGradientEffect::setAlphaValue(GLfloat value)
 {
     program()->setUniformValue("alphaValue", value);
 }
 inline void PageFlipView::ensureContext()
 {
     if (!context)
     {
         context = new QOpenGLContext();
         context->setFormat(format);
 #ifndef QT_NO_DEBUG_STREAM
         QSurfaceFormat oldFormat = format;
 #endif
         context->create();
         
         
         format = context->format();
 #ifndef QT_NO_DEBUG_STREAM
         if (oldFormat != format)
             qWarning() << "Could not create context requested:\n"
                        << oldFormat << "\nactual format:\n" << format;
 #endif
     }
     context->makeCurrent(this);
 }
 int main(int argc, char *argv[])
 {
     QGuiApplication app(argc, argv);
     PageFlipView view;
     QStringList args = QCoreApplication::arguments();
     if (args.contains(QLatin1String("-blend")))
         view.setBlend(true);
     if (args.contains(QLatin1String("-vertical")))
         view.setVertical(true);
     int w_pos = args.indexOf("-width");
     int h_pos = args.indexOf("-height");
     if (w_pos >= 0 && h_pos >= 0)
     {
         bool ok = true;
         int w = args.at(w_pos + 1).toInt(&ok);
         if (!ok)
         {
             qWarning() << "Could not parse width argument:" << args;
             return 1;
         }
         int h = args.at(h_pos + 1).toInt(&ok);
         if (!ok)
         {
             qWarning() << "Could not parse height argument:" << args;
             return 1;
         }
         view.resize(w, h);
     }
     else
     {
         view.resize(800, 600);
     }
     view.show();
     return app.exec();
 }
 #include "pageflip.moc"