GLVERTEX QUICK REFERENCE SHEET
----

INTRODUCTION:

The glVertex software is a header-only C++ library. It is a
convenience wrapper around OpenGL and GLSL. The main objective is to
leverage the usage of the modern programmable OpenGL pipeline, so that
VBOs, FBOs and GLSL shaders can be created easily. The frame work also
restitutes the main conceptual parts of the legacy OpenGL fixed
function pipeline, which is no longer available as part of the OpenGL
programmable pipeline. In particular it brings back the so called
immediate mode as described by the OpenGL 1.2 specification.

----

INSTALLATION AND COMPILATION:

To get started, see the quick start sheet ("QUICKSTART.txt").

----

USAGE PRELIMINARIES:

To use the glVertex library, we need to include the "glvertex.h" C++
header:

~~~~
 #include <glvertex.h>
~~~~

The glVertex library restitutes parts of the legacy OpenGL 1.2
interface but aims not to be perfectly compatible. To account for
that, all functions of the glVertex library share a "lgl" prefix. So
instead of writing

~~~~
 glVertex3d(0,0,0); // C style
~~~~

we write

~~~~
 lglVertex(0,0,0); // C++ style
~~~~

----

QT PROGRAMMING TEMPLATE:

The "lgl_Qt_GLUI" class of the frame work provides a rendering window,
which creates an OpenGL rendering context with an appropriate OpenGL
core profile. The Qt programming template "qt_template.cpp" derives
from this class and implements the following methods:

* C++ constructor:
 * for initialization code, that needs to be executed once WITHOUT an OpenGL rendering context

* initializeOpenGL():
 * for initialization code, that needs to be executed once WITH an OpenGL rendering context

* renderOpenGL(double dt):
 * for rendering code, that is executed once for each rendered frame
 * the parameter dt is the time in seconds since the last rendered frame

----

2D USAGE EXAMPLE:

Here is a usage example that first clears the frame buffer and then
renders a single 2D line in immediate mode from the bottom-left to the
top-right corner of the rendering window. The two end points of the
line segment are specified by two consecutive vertices via
lglVertex(). Under the hood, the immediate mode calls are translated
to the creation of according vertex buffers (VBOs) and GLSL shaders,
which simulate the fixed functionality of the legacy OpenGL 1.2
programming interface:

~~~~
#include <glvertex.h>

...

void renderOpenGL(double dt)
{
   // clear frame buffer
   lglClearColor(0,0,0);
   lglClear();

   // render a diagonal line
   lglBegin(LGL_LINES);
      lglVertex(-1,-1,0);
      lglVertex(1,1,0);
   lglEnd();
}
~~~~

----

3D USAGE EXAMPLE:

Here is another usage example that renders a single 3D triangle in
immediate mode. The 3D perspective and the position and lookat of the
viewer is specified with lglPerspective() and lglLookAt():

~~~~
#include <glvertex.h>

...

void renderOpenGL(double dt)
{
   // clear frame buffer
   lglClear();

   // specify camera parameters
   double fovy = 90;
   double aspect = (double)width()/height();
   double nearp = 0.1;
   double farp = 10;

   // matrix setup
   lglMatrixMode(LGL_PROJECTION);
   lglLoadIdentity();
   lglPerspective(fovy, aspect, nearp, farp);
   lglMatrixMode(LGL_MODELVIEW);
   lglLoadIdentity();
   lglLookAt(0,0,1, 0,0,0, 0,1,0);

   // render triangle
   lglBegin(LGL_TRIANGLES);
      lglColor(1,0,0);
      lglVertex(-0.5,-0.5,0);
      lglColor(0,1,0);
      lglVertex(0.5,-0.5,0);
      lglColor(0,0,1);
      lglVertex(0,0.5,0);
   lglEnd();
}
~~~~

A short hand for the above legacy matrix setup is:

~~~~
   ...

   // matrix setup
   lglProjection(fovy, aspect, nearp, farp);
   lglView(0,0,1, 0,0,0, 0,1,0);

   ...
~~~~

Geometric primitives are specified within a lglBegin(type) / lglEnd()
section with the following supported primitive types:

* LGL_LINES: two consecutive vertices construct a line segment
* LGL_LINE_STRIP: one consecutive vertex appends another segment to a polyline
* LGL_TRIANGLES: three consecutive vertices construct a triangle
* LGL_TRIANGLE STRIP: one consecutive vertex appends another triangle to a strip
* LGL_QUADS: four consecutive vertices construct a quadrilateral
* LGL_QUADSTRIP: two consecutive vertices append another quadrilateral to a strip

Per-vertex attributes are specified before lglVertex() with:

* lglColor: per-vertex colors to be interpolated
* lglNormal: per-vertex normals for lighting
* lglTexCoord: per-vertex texture coordinates for texture mapping

The displayed scene can be rotated with the mouse using a trackball
manipulator. The corresponding manipulator matrix is available via
lglGetManip() resp. lglGetInverseTransposeManip(). The rotation anchor
is the lookat position.

For graphical debugging, press Ctrl-w to show the wireframe of the
rendered geometry. Programmatically, this behavior can be enabled via
lglPolygonMode(LGL_LINE).

----

3D TRANSFORMATIONS:

In order to transform a rendered object, the following legacy-style
transformations are available:

* lglTranslate(vec3(vector))
* lglRotate(degrees, vec3(axis));
* lglScale(factor);

All of the above transformations multiply a corresponding 4x4 matrix
onto the current model-view matrix (from the right-hand side). The
current matrix, which is the top of a matrix stack, can be duplicated
with lglPushMatrix() and dropped with lglPopMatrix().

The current model-view matrix can be set to a matrix M with
lglModelView(M). The current projection matrix is set with
lglProjection(M);

----

GLSLMATH USAGE:

Internally, the glVertex package uses the GLSLmath library to perform
linear math calculations such as the calculation of projection,
viewing and transformation matrices as shown in the above examples.

The legacy-style matrix setup used in the previous example is
equivalent to the following matrix calculations using GLSLmath:

~~~~
// look at world origin (0,0,0) from (0,0,2) with up being (0,1,0)
mat4 MV = mat4::lookat(vec3(0,0,2), vec3(0,0,0), vec3(0,1,0));
// camera perspective defining field-of-view etc.
mat4 P = mat4::perspective(fovy, aspect, nearp, farp);

// mvp matrix setup
mat4 MVP = P * MV;
lglLoadMatrix(MVP);
~~~~

----

GLSLMATH QUICK OVERVIEW:

* Creating a 3D vector:

~~~~
  vec3 v(0,0,-10);
~~~~

* Accessing the components of a 3D vector:

~~~~
  double x = v.x;
  double y = v.y;
  double z = v.z;
~~~~

* Printing a 3D vector:

~~~~
  std::cout << "v = " << v << std::endl;
   yields
  "v = (0, 0, -10)"
~~~~

* Getting the length and norm of a vector:

~~~~
  vec3 v(0,3,4);
  double l = v.length(); // yields 5
  double l2 = v.norm(); // yields 25
~~~~

* Averaging two vectors p1 and p2:

~~~~
  vec3 p1(-10,0,0), p2(10,0,0);
  vec3 v = 0.5*(p1+p2); // yields (0,0,0)
~~~~

* Linear interpolation of two vectors p1 and p2:

  Let w be the linear interpolation factor in the range [0..1]:

~~~~
  vec3 p1(-10,0,0), p2(10,0,0);

  double w = 0.5;
  vec3 v = (1-w)*p1 + w*p2; // yields (0,0,0)
~~~~

* Calculating the dot product:

~~~~
  vec3 a(1,0,0), b(0,0,1);
  double d = a.dot(b); // yields 0
~~~~

* Calculating the cross product:

~~~~
  vec3 a(1,0,0), b(0,0,1);
  vec3 c = a.cross(b); // yields (0,-1,0)
~~~~

* Computing a normalized direction vector from two position vectors:

~~~~
  vec4 p1(0,20,0), p2(0,10,0);
  vec4 d = (p2-p1).normalize(); // yields (0,-1,0)
~~~~

  Note that p1 and p2 are position vectors with homogeneous coordinate
  w=1 and d is a direction vector with homogeneous coordinate w=0!

* Component swizzeling:

~~~~
  vec4 a(1,2,3,4);
  vec4 b(a.wzyx());      // yields (4,3,2,1)
  vec4 c(b.zw(),b.xy()); // yields (2,1,4,3)
~~~~

* Procedural-style vector operations:

  length of a vector v: length(v)
  dot product of two vectors a and b: dot(a, b)
  cross product of two vectors a and b: cross(a, b)
  norm of a vector v: norm(v)
  normalization of a vector v: normalize(v)
  reflection of a vector v at a surface normal n: reflect(v, n);
  linear interpolation of two vectors a and b with factor w: lerp(w, a, b)
  blending two colors a and b: blend(a, b)

* Creating a 3x3 identity matrix:

~~~~
  mat3 I;
   or
  mat3 M(1);
~~~~

* Printing a 3x3 matrix:

~~~~
  std::cout << "I = " << I << std::endl;
   yields
  "I = ((1, 0, 0), (0, 1, 0), (0, 0, 1))"
~~~~

* Creating a 3x3 diagonal matrix:

~~~~
  mat3 D(vec3(1,2,3));
~~~~

* Creating a 3x3 matrix from three row vectors and multiplying it with a vector:

~~~~
  mat3 M(vec3(0,1,0),
         vec3(-1,0,0),
         vec3(0,0,1));

  vec3 v(-10,0,0);
  v = M*v; // yields (0,10,0)
~~~~

* Pretty-printing a 3x3 matrix:

~~~~
  glslmath::print(M, "M");

  prints:

      /       0             1             0       \
  M = |      -1             0             0       |
      \       0             0             1       /
~~~~

* Creating a 3x3 matrix from three column resp. row vectors:

~~~~
  mat3 Mc = mat3::columns(vec3(a,b,c), vec3(d,e,f), vec3(g,h,i));
  mat3 Mr = mat3::rows(a,b,c, d,e,f, g,h,i);
~~~~

* Available 4x4 matrix transformations as defined by the OpenGL standard:

  translation by a vector v: mat4::translate(v)
  rotation about an axis a and an angle of d degrees: mat4::rotate(d, a)
  scaling with a factor f: mat4::scale(f)

Procedural-style 4x4 matrix transformations:

  translation by a vector v: translate(M, v)
  rotation about an axis a and an angle of d degrees: rotate(M, d, a)
  scaling with a factor f: scale(M, f)

  The above procedures multiply the corresponding transformation
  matrix onto a given matrix M (from the right-hand side).

* Using mat4 for MVP calculations as defined by the OpenGL standard:

~~~~
  mat4 P = mat4::perspective(90,1,1,100);
  mat4 V = mat4::lookat(vec3(0,3,10), vec3(0,0,0), vec3(0,1,0));
  mat4 M = mat4::translate(0,0,-10) * mat4::rotate(90, vec3(0,1,0)) * mat4::scale(3);

  mat4 MVP = P*V*M;
~~~~

  Note that the order of matrix multiplications is the reverse of the
  logical order of the applied transformations.

* By default, matrices are multiplied from the right-hand side, e.g.:

~~~~
  mat4 M = mat4::translate(0,0,-10);
  M *= mat4::rotate(90, vec3(0,1,0)); // M = T*R
~~~~

  But matrices can also be multiplied from the left hand-side to
  reverse the order of transformations:

~~~~
  mat4 M = mat4::translate(0,0,-10);
  M <<= mat4::rotate(90, vec3(0,1,0)); // M = R*T
~~~~

* Calculating the inverse transpose of the MVP matrix (used for normal transformations):

~~~~
  mat4 M = MVP.invert().transpose();
~~~~

* Procedural-style matrix operations:

  determinant of a matrix M: determinant(M)
  transposition of a matrix M: transpose(M)
  inversion of a matrix M: inverse(M)

See the GLSLmath documentation ("glslmath.txt") for more details.

----

VBO USAGE EXAMPLE:

A VBO contains pre-defined geometry, that is vertices and associated
attributes. For example, to render a sphere, we declare a
corresponding VBO object and render it for each frame:

~~~~
#include <glvertex.h>

...

// declare vbo (as a member variable)
lglSphere sphere;

...

// render vbo (in the renderOpenGL method)
lglRender(sphere);
~~~~

----

PRE-DEFINED VBOS:

For convenience, the following geometric objects are available as
pre-defined VBOs:
* lglCube: unit cube
* lglWireCube: unit wireframe cube
* lglBox: rectangular box
* lglTet: unit tetrahedron
* lglPyramid: unit pyramid
* lglPyramidBase: unit pyramid base
* lglPrism: slanted unit prism
* lglSphere: unit sphere
* lglHemisphere: unit hemisphere
* lglCylinder: unit cylinder
* lglHemiCylinder: unit hemi-cylinder
* lglDisc: unit disc
* lglHemiDisc: unit hemi-disc
* lglCone: unit cone
* lglConeBase: unit cone base
* lglRing: ring geometry
* lglArc: arc geometry
* lglTorus: unit torus
* lglHemiTorus: unit hemi-torus
* lglObj: pre-loaded geometry from an OBJ file
* lglTeapot: the Melitta resp. Utah teapot
* lglCoordSys: colored unit coordinate system axis

----

VBO LOADING EXAMPLE:

Given that a graphical object has been modeled (e.g. with Blender) and
saved in the Alias/Wavefront format (.obj), this object can be loaded
into a VBO as follows:

~~~~
#include <glvertex.h>

...

// declare vbo
lglVBO *vbo;

...

// load obj
vbo = lglLoadObj("teapot.obj");
assert(vbo);

...

// render vbo
lglRender(vbo);
~~~~

Note that the object file to be loaded needs to reside in the same
directory as the executed program.

----

VBO CREATION EXAMPLE:

Besides simulating the fixed function pipeline, the glVertex library
is also handy for creating custom VBOs:

~~~~
#include <glvertex.h>

...

// declare vbo
lglVBO vbo;

...

// compile vbo
vbo.lglBegin(LGL_TRIANGLES);
   vbo.lglColor(1,0,0);
   vbo.lglVertex(-0.5,-0.5,0);
   vbo.lglColor(0,1,0);
   vbo.lglVertex(0.5,-0.5,0);
   vbo.lglColor(0,0,1);
   vbo.lglVertex(0,0.5,0);
vbo.lglEnd();

...

// render vbo
lglRender(vbo);
~~~~

----

COLORING:

The specification of per-vertex colors (with lglColor) automatically
triggers the setup of a default GLSL shader, which interpolates the
colors during rasterization. Further lighting or texturing operations
modulate that color.

----

LIGHTING:

The specification of per-vertex normals (with lglNormal) automatically
triggers the setup of a default GLSL shader, which performs
Blinn-Phong shading. The latter can be configured with the lglLight()
method, which takes the usual Blinn-Phong lighting terms as parameters
for a single directional or positional light source. If the light
source is not defined to be a camera light, the light vector is
multiplied with the inverse transpose of the actual model-view
matrix. To define the light vector in world coordinates, the
model-view matrix must therefore contain the viewing matrix. The
default setting is a white directional light source positioned at the
origin of the camera coordinate system, which modulates the vertex
colors.

----

TEXTURING:

The specification of per-vertex texture coordinates (with lglTexCoord)
automatically triggers OpenGL legacy texturing by using a
corresponding default GLSL shader. This requires the specification of
a texture object via lglTexture2D(). Texture objects can be created
either as plain texture map via lglCreateTexmap2D() or as mip-mapped
texture via lglCreateMipmap2D(). The texture color is always
modulating the vertex color.

----

TEXTURE LOADING EXAMPLE:

With Qt as user interface library, the glVertex library supports PNG,
JPEG and all other formats supported by Qt.

Here is an example to load a PNG image file (in the application
directory) into a texture object:

~~~~
#include <glvertex_qt.h>
...
GLuint texid = lglLoadQtTexture("image.png");
...
lglTexture2D(texid);
~~~~

----

GLSL SHADERS:

To specify a custom GLSL shader, we compile or load a shader via
lglCompileGLSLProgram() resp. lglLoadGLSLProgram() and pass the
corresponding GLSL program id to lglUseProgram(). Uniform shader
variables are set with lglUniform*(). The disposal of unused custom
shaders needs to be handled explicitly via lglDeleteGLSLProgram().

The GLSL program must comply to the following rules:

* Vertices are passed in the attribute "vertex_position" (vec4).
* Colors are passed in the attribute "vertex_color" (vec4).
* Normals are passed in the attribute "vertex_normal" (vec3).
* Texture coordinates are passed in the attribute "vertex_texcoord" (vec4).
* The vertex shader may use the model-view-projection matrix "mvp" and
  transform the vertices with that matrix (uniform mat4 mvp).
* If no color attributes were specified between lglBegin() and
  lglEnd(), the fragment shader may use the actual color instead
  (uniform vec4 color).
* If normals were specified, the vertex shader may use the model-view
  matrix "mv" resp. the inverse transpose model-view matrix "mvit" to
  transform the vertex normals (uniform mat4).
* If texture coordinates were specified, the vertex shader may use the
  uniform texture matrix "tm" and transform texture coordinates with
  that matrix (uniform mat4).
* The vertex shader is required to write "gl_Position" (vec4).
* The fragment shader is required to write "gl_FragColor" (vec4).

The uniform model-view-projection matrix "mvp" is set automatically
from preceding calls of lglProjection() and lglView().

A model-view matrix M can be loaded into the built-in uniform "mv"
(resp. "mvit") with lglLoadMatrix(M) or lglModelView(M).

A texturing matrix M can be loaded into the built-in uniform "tm" with
lglTexture(M).

----

GLSL SHADER EXAMPLE:

If the shader sources are available as a single shader file with the
extension ".glsl", where the vertex and fragment shaders have been
concatenated with the separator "---", we can load the combined shader
as follows:

~~~~
const char shader_file[] = "shader.glsl";
GLuint program = lglLoadGLSLProgram(shader_file);
~~~~

If the combined shader program source is defined inline as a C-string,
we can compile the shader as follows:

~~~~
const char shader[] = "#version 120\n ...";
...
GLuint program = lglCompileGLSLProgram(shader);
~~~~

The shortest possible combined shader program is the following:

~~~~
#version 120
attribute vec4 vertex_position;
uniform mat4 mvp;
void main()
{
   gl_Position = mvp * vertex_position;
}
---
#version 120
uniform vec4 color;
void main()
{
   gl_FragColor = color;
}
~~~~

The above shader program is called the "plain shader". Compiling and
activating this shader is equivalent to:

~~~~
GLuint program = lglCompileGLSLProgram(lglPlainGLSLProgram());
...
lglUseProgram(program);
...
lglDeleteGLSLProgram(program);
~~~~

----

GLSL UNIFORMS:

A GLSL uniform is a global parameter of the shader.

If a shader contains uniform variables (besides the mandatory mv, mvp
and mvit uniforms) we can set those uniforms via lglUniform*() for the
currently active GLSL program. The uniforms need to be specified after
lglUseProgram():

~~~~
lglUseProgram(program);
...
lglUniform[i/f/fv]("name", value);
~~~~

Suffix i is for integer, f for float and fv for float arrays (vectors
and matrices).

Uniform samplers can be set with lglSampler2D(), which is just a
convenience wrapper around lglUniformi() and lglTexture2D().

----

GLSL VARYINGS:

A GLSL varying is a data channel between the fragment and the vertex
shader.

Writing values into the varying on the vertex shader side, will yield
readable values in the varying on the fragment shader side. Due to the
rasterization stage between the two shaders, the values on the
fragment shader side represent interpolated per-fragment values in eye
coordinates. For that to work, the varying needs to be declared
exactly the same on both sides:

~~~~
#version 120
...
varying vec4 vary;
...
void main()
{
   vary = ...;
   gl_Position = ...;
}
---
#version 120
...
varying vec4 vary;
...
void main()
{
   vec4 v = vary;
   gl_FragColor = v;
}
~~~~

----

GLSL SHADER EXAMPLE WITH UNIFORMS AND VARYINGS:

In this example we use a custom GLSL shader that implements simple
exponential fogging. The density of the fog is passed as a uniform to
the shader. The vertex color is passed as a varying from the vertex to
the fragment shader, so that the latter shader can modulate the vertex
colors with the exponential fog function:

~~~~
static const char shader[] =
   "#version 120\n"
   "attribute vec4 vertex_position;\n"
   "attribute vec4 vertex_color;\n"
   "uniform mat4 mvp;\n"
   "varying vec4 frag_color;\n"
   "vec4 fvertex() {return(mvp * vertex_position);}\n"
   "void main()\n"
   "{\n"
   "   frag_color = vertex_color;\n"
   "   gl_Position = fvertex();\n"
   "}\n"
   "---\n"
   "#version 120\n"
   "uniform float density;\n"
   "varying vec4 frag_color;\n"
   "void main()\n"
   "{\n"
   "   float z = 1.0f/gl_FragCoord.w;\n"
   "   float f = 1.0f-exp(-density*w*w);\n"
   "   gl_FragColor = (1.0f-f)*frag_color + f*vec4(1);\n"
   "}\n";

GLuint program = lglCompileGLSLProgram(shader);
create_lgl_Qt_ShaderEditor("shader", &program);
lglUseProgram(program);
lglUniformf("density", 0.1f);
~~~~

----

PROGRAMMING API:

In accordance with the legacy OpenGL 1.2 specification, the glVertex
library supports the following API functions:
* lglBegin, lglEnd
* lglVertex, lglColor, lglNormal, lglTexCoord
Matrix and modeling functions:
* lglLoadIdentity, lglMatrixMode,
* lglLoadMatrix, lglMultMatrix
* lglScale, lglTranslate, lglRotate
* lglOrtho, lglFrustum, lglPerspective, lglLookAt
* lglPushMatrix, lglPopMatrix
Miscellaneous functions:
* lglClear, lglClearColor, lglViewport
* lglLight, lglClipPlane, lglFog
* lglLineWidth, lglPolygonMode
* lglDepthTest, lglBackFaceCulling
* lglGetError

Additionally, it supports the following extended convenience functions:
* lglProjection, lglView, lglModelView, lglTexture
* lglLoadObj, lglRender
Texturing functions:
* lglLoadQtTexture, lglTexture2D
* lglCreateTexmap2D, lglCreateMipmap2D
GLSL functions:
* lglCompileGLSLProgram, lglUseProgram, lglDeleteGLSLProgram
* lglLoadGLSLProgram, lglPlainGLSLProgram
* lglGetManip, lglGetInverseTransposeManip
* lglUniformi, lglUniformf, lglUniformfv
* lglSampler2D

----
