Revision control
++ // Copyright (C) 2020 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ \example cube
++ \ingroup examples-widgets-opengl
++ \title Cube OpenGL ES 2.0 example
++ \examplecategory {3D}
++
++ \brief Shows how to manually rotate a textured 3D cube with user input.
++
++ The Cube OpenGL ES 2.0 example shows how to manually rotate a textured 3D
++ cube with user input, using OpenGL ES 2.0 with Qt. It shows how to
++ handle polygon geometries efficiently and how to write a simple vertex and
++ fragment shader for a programmable graphics pipeline. In addition it
++ shows how to use quaternions for representing 3D object orientation.
++
++ This example has been written for OpenGL ES 2.0 but it works also on
++ desktop OpenGL because this example is simple enough and for the
++ most parts desktop OpenGL API is same. It compiles also without OpenGL
++ support but then it just shows a label stating that OpenGL support is
++ required.
++
++ \image cube.png Screenshot of the Cube example running on N900
++
++ The example consist of two classes:
++
++ \list
++ \li \c MainWidget extends QOpenGLWidget and contains OpenGL ES 2.0
++ initialization and drawing and mouse and timer event handling
++ \li \c GeometryEngine handles polygon geometries. Transfers polygon geometry
++ to vertex buffer objects and draws geometries from vertex buffer objects.
++ \endlist
++
++ We'll start by initializing OpenGL ES 2.0 in \c MainWidget.
++
++ \section1 Initializing OpenGL ES 2.0
++
++ Since OpenGL ES 2.0 doesn't support fixed graphics pipeline anymore it has to
++ be implemented by ourselves. This makes graphics pipeline very flexible but
++ in the same time it becomes more difficult because user has to implement graphics
++ pipeline to get even the simplest example running. It also makes graphics pipeline
++ more efficient because user can decide what kind of pipeline is needed for the
++ application.
++
++ First we have to implement vertex shader. It gets vertex data and
++ model-view-projection matrix (MVP) as parameters. It transforms vertex position
++ using MVP matrix to screen space and passes texture coordinate to
++ fragment shader. Texture coordinate will be automatically interpolated on polygon
++ faces.
++
++ \snippet cube/vshader.glsl 0
++
++ After that we need to implement second part of the graphics pipeline - fragment
++ shader. For this exercise we need to implement fragment shader that handles
++ texturing. It gets interpolated texture coordinate as a parameter and looks up
++ fragment color from the given texture.
++
++ \snippet cube/fshader.glsl 0
++
++ Using QOpenGLShaderProgram we can compile, link and bind shader code to
++ graphics pipeline. This code uses Qt Resource files to access shader source code.
++
++ \snippet cube/mainwidget.cpp 3
++
++ The following code enables depth buffering and back face culling.
++
++ \snippet cube/mainwidget.cpp 2
++
++ \section1 Loading Textures from Qt Resource Files
++
++ The \c QOpenGLWidget interface implements methods for loading textures from QImage
++ to OpenGL texture memory. We still need to use OpenGL provided functions for
++ specifying the OpenGL texture unit and configuring texture filtering options.
++
++ \snippet cube/mainwidget.cpp 4
++
++ \section1 Cube Geometry
++
++ There are many ways to render polygons in OpenGL but the most efficient way is
++ to use only triangle strip primitives and render vertices from graphics hardware
++ memory. OpenGL has a mechanism to create buffer objects to this memory area and
++ transfer vertex data to these buffers. In OpenGL terminology these are referred
++ as Vertex Buffer Objects (VBO).
++
++ \image cube_faces.png Cube faces and vertices
++
++ This is how cube faces break down to triangles. Vertices are ordered this way
++ to get vertex ordering correct using triangle strips. OpenGL determines triangle
++ front and back face based on vertex ordering. By default OpenGL uses
++ counter-clockwise order for front faces. This information is used by back face
++ culling which improves rendering performance by not rendering back faces of the
++ triangles. This way graphics pipeline can omit rendering sides of the triangle that
++ aren't facing towards screen.
++
++ Creating vertex buffer objects and transferring data to them is quite simple using
++ QOpenGLBuffer. MainWidget makes sure the GeometryEngine instance is created and
++ destroyed with the OpenGL context current. This way we can use OpenGL resources
++ in the constructor and perform proper cleanup in the destructor.
++
++ \snippet cube/geometryengine.cpp 0
++
++ \snippet cube/geometryengine.cpp 1
++
++ Drawing primitives from VBOs and telling programmable graphics pipeline how to
++ locate vertex data requires few steps. First we need to bind VBOs to be used.
++ After that we bind shader program attribute names and configure what
++ kind of data it has in the bound VBO. Finally we'll draw triangle
++ strip primitives using indices from the other VBO.
++
++ \snippet cube/geometryengine.cpp 2
++
++ \section1 Perspective Projection
++
++ Using \c QMatrix4x4 helper methods it's really easy to calculate perpective
++ projection matrix. This matrix is used to project vertices to screen space.
++
++ \snippet cube/mainwidget.cpp 5
++
++ \section1 Orientation of the 3D Object
++
++ Quaternions are handy way to represent orientation of the 3D object. Quaternions
++ involve quite complex mathematics but fortunately all the necessary mathematics
++ behind quaternions is implemented in \c QQuaternion. That allows us to store
++ cube orientation in quaternion and rotating cube around given axis is quite
++ simple.
++
++ The following code calculates rotation axis and angular speed based on mouse events.
++
++ \snippet cube/mainwidget.cpp 0
++
++ \c QBasicTimer is used to animate scene and update cube orientation. Rotations
++ can be concatenated simply by multiplying quaternions.
++
++ \snippet cube/mainwidget.cpp 1
++
++ Model-view matrix is calculated using the quaternion and by moving world by Z axis.
++ This matrix is multiplied with the projection matrix to get MVP matrix for shader
++ program.
++
++ \snippet cube/mainwidget.cpp 6
++
++ */