GL
**

About OpenGL
============

OpenGL is a standard API for drawing three-dimensional graphics.  From its origin in Silicon Graphics's workstations the early 1990s, today it has become ubiquitous, with implementations on mobile phones, televisions, tablets, desktops, and even web browsers.

OpenGL has been able to achieve such widespread adoption not just because it co-evolved with powerful graphics hardware, but also because it was conceived of as an interface specification and not a piece of source code.  In fact, these days it is a family of APIs, available in several flavors and versions:

OpenGL 1.x
     This series of specifications started with the original releases in 1992, and ended with OpenGL 1.5 in 2003.  This era corresponds to a time when graphics cards were less powerful and more special-purpose, with dedicated hardware to handle such details as fog and lighting. As such the OpenGL 1.x API reflects the capabilities of these special units.

OpenGL 2.x
     By the early 2000s, graphics hardware had become much more general-purpose and needed a more general-purpose API.  The so-called fixed-function rendering pipeline of the earlier years was replaced with a programmable rendering pipeline, in which effects that would have required special hardware were instead performed by custom programs running on the graphics card.  OpenGL added support for allocating buffer objects on the graphics card, and for shader programs, which did the actual rendering. In time, this buffer-focused API came to be the preferred form of talking to the GL.

OpenGL ES
     OpenGL ES was a ``cut-down'' version of OpenGL 2.x, designed to be small enough to appeal to embedded device vendors.  OpenGL ES 1.x removed some of the legacy functionality from OpenGL, while adding interfaces to use fixed-point math, for devices without floating-point units.  OpenGL ES 2.x went farther still, removing the fixed-function pipeline entirely.  OpenGL ES 2.x is common on current smart phone platforms.

OpenGL 3.x and above
     The OpenGL 3.x series followed the lead of OpenGL ES, first deprecating (in 3.0) and then removing (in 3.1) the fixed-function pipeline.  OpenGL 3.0 was released in 2008, but the free Mesa impementation only began supporting it in 2012, so it is currently (UPDATED) less common.

Figl wraps the OpenGL 2.1 API.  It's a ubiquitous subset of the OpenGL implementations that are actually deployed in the wild; its legacy API looks back to OpenGL 1.x, while the buffer-oriented API is compatible with OpenGL ES.

The full OpenGL 2.1 specification is available at http://www.opengl.org/registry/doc/glspec21.20061201.pdf.

GL Contexts
===========

All this talk about drawing is very well and good, but how do you actually get a canvas?  Interestingly enough, this is outside the purview of the OpenGL specification.  There are specific ways to get an OpenGL context for each different windowing system that is out there.  OpenGL is all crayons and no paper.

For the X window system, there is a standard API for creating a GL context given a window (or a drawable), GLX.  See GLX, for more information on its binding in Guile.

Bseides creating contexts from native windows or drawables, each backend also supports functions to make a context current.  The OpenGL API is stateful; you can think of each call as taking an implicit current context parameter, which holds the current state of the GL and is operated on by the function in question. Contexts are thread-specific, and one context should not be active on more than one thread at a time.

All calls to OpenGL functions must be made while a context is active; otherwise the result is undefined.  Hopefully while you are getting used to this rule, your driver is nice enough not to crash on you if you call a function outside a GL context, but it's not even required to do that.  Backend-specific functions may or may not require a context to be current; for example, Windows requires a context to be current, wheras GLX does not.

There have been a few attempts at abstracting away the need for calling API specific to a given windowing system, notably GLUT and EGL.  GLUT is the older of the two, and though it is practically unchanged since the mid-1990s, it is still widely used on desktops. See GLUT, for more on GLUT.

EGL is technically part of OpenGL ES, and was designed with the modern OpenGL API and mobile hardware in mind, though it also works on the desktop.  Figl does not yet have an EGL binding.

Rendering
=========

To draw with OpenGL, you obtain a drawing context (see GL Contexts) and send the GL some geometry.  (You can think of the GL as a layer over your graphics card.)  You can give the GL points, lines, and triangles in three-dimensional space.  You configure your GL to render a certain part of space, and it takes your geometry, rasterizes it, and writes it to the screen (when you tell it to).

That's the basic idea.  You can customize most parts of this rendering pipeline, by specifying attributes of your geometry with the OpenGL API, and by programmatically operating on the geometry and the pixels with programs called shaders.

GL is an immediate-mode graphics API, which is to say that it doesn't keep around a scene graph of objects.  Instead, at every frame you as the OpenGL user have to tell the GL what is in the world, and how to paint it.  It's a fairly low-level interface, but a powerful one. See http://www.opengl.org/wiki/Rendering_Pipeline_Overview, for more details.

In the old days of OpenGL 1.0, it was common to call a function to paint each individual vertex.  You'll still see this style in some old tutorials.  This quickly gets expensive if you have a lot of vertexes, though.  This style, known as Legacy OpenGL, was deprecated and even removed from some versions of OpenGL.  See http://www.opengl.org/wiki/Legacy_OpenGL, for more on the older APIs.

Instead, the newer thing to do is to send the geometry to the GL in a big array buffer, and have the GL draw geometry from the buffer.  The newer functions like glGenBuffers allocate buffers, returning an integer that names a buffer managed by the GL.  You as a user can update the contents of the buffer, but when drawing you reference the buffer by name.  This has the advantage of reducing the chatter and data transfer between you and the GL, though it can be less convenient to use.

So which API should you use?  Use what you feel like using, if you have a choice.  Legacy OpenGL isn't going away any time soon on the desktop.  Sometimes you don't have a choice, though; for example, when targeting a device that only supports OpenGL ES 2.x, legacy OpenGL is unavailable.

But if you want some advice, we suggest that you use the newer APIs. Not only will your code be future-proof and more efficient on the GL level, reducing the number of API calls improves performance, and it can reduce the amount of heap allocation in your program.  All floating-point numbers are currently allocated on the heap in Guile, and doing less floating-point math in tight loops can only be a good thing.

GL API
======

The procedures exported from the (figl gl) module are documented below, organized by their corresponding section in the OpenGL 2.1 specification.

     (use-modules (figl gl))

See http://www.opengl.org/registry/doc/glspec21.20061201.pdf, for more information.

OpenGL Operation
----------------

Begin/End Paradigm
..................

 -- Macro: gl-begin begin-mode body ...
     Begin immediate-mode drawing with BEGIN-MODE, evaluate the sequence of BODY expressions, and then end drawing (as with glBegin and glEnd).

     The values produced by the last BODY expression are returned to the continuation of the gl-begin.

 -- Function: gl-edge-flag boundary?
     Flag edges as either boundary or nonboundary.  Note that the edge mode is only significant if the polygon-mode is line or point.

Vertex Specification
....................

 -- Function: gl-vertex x y [z=0.0] [w=1.0]
     Draw a vertex at the given coordinates.

The following procedures modify the current per-vertex state.  Drawing a vertex captures the current state and associates it with the vertex.

 -- Function: gl-texture-coordinate s [t=0.0] [r=0.0] [q=1.0]
     Set the current texture coordinate.

 -- Function: gl-multi-texture-coordinate texture s [t=0.0] [r=0.0] [q=1.0]
     Set the current texture coordinate for a specific texture unit.

 -- Function: gl-color red green blue [alpha=1.0]
     Set the current color.

 -- Function: gl-vertex-attribute index x [y=0.0] [z=0.0] [w=1.0]
     Set the current value of a generic vertex attribute.

 -- Function: gl-normal x y z
     Set the current normal vector.  By default the normal should have unit length, though setting (enable-cap rescale-normal) or (enable-cap normalize) can change this.

 -- Function: gl-fog-coordinate coord
     Set the current fog coordinate.

 -- Function: gl-secondary-color red green blue
     Set the current secondary color.

 -- Function: gl-index c
     Set the current color index.

Rectangles
..........

 -- Function: gl-rectangle x1 y1 x2 y2
     Draw a rectangle in immediate-mode with a given pair of corner points.

Coordinate Transformation
.........................

 -- Function: gl-depth-range near-val far-val
     Specify the mapping of the near and far clipping planes, respectively, to window coordinates.

 -- Function: gl-viewport x y width height
     Set the viewport: the pixel position of the lower-left corner of the viewport rectangle, and the width and height of the viewport.

 -- Function: gl-load-matrix m [#:transpose=#f]
     Load a matrix.  M should be a packed vector in column-major order.

     Note that Guile's two-dimensional arrays are stored in row-major order, so you might need to transpose the matrix as it is loaded (via the #:transpose keyword argument).

 -- Function: gl-multiply-matrix m [#:transpose=#f]
     Multiply the current matrix by M.  As with gl-load-matrix, you might need to transpose the matrix first.

 -- Function: set-gl-matrix-mode matrix-mode
     Set the current matrix mode.  See the matrix-mode enumerator.

 -- Macro: with-gl-push-matrix body ...
     Save the current matrix, evaluate the sequence of BODY expressions, and restore the saved matrix.

 -- Function: gl-load-identity
     Load the identity matrix.

 -- Function: gl-rotate angle x y z
     Rotate the current matrix about the vector (X,Y,Z).  ANGLE should be specified in degrees.

 -- Function: gl-translate x y z
     Translate the current matrix.

 -- Function: gl-scale x y z
     Scale the current matrix.

 -- Function: gl-frustum left right bottom top near-val far-val
     Multiply the current matrix by a perspective matrix.  LEFT, RIGHT, BOTTOM, and TOP are the coordinates of the corresponding clipping planes.  NEAR-VAL and FAR-VAL specify the distances to the near and far clipping planes.

 -- Function: gl-ortho left right bottom top near-val far-val
     Multiply the current matrix by a perspective matrix.  LEFT, RIGHT, BOTTOM, and TOP are the coordinates of the corresponding clipping planes.  NEAR-VAL and FAR-VAL specify the distances to the near and far clipping planes.

 -- Function: set-gl-active-texture texture
     Set the active texture unit.

 -- Function: gl-enable enable-cap
 -- Function: gl-disable enable-cap
     Enable or disable server-side GL capabilities.

Colors and Coloring
...................

 -- Function: set-gl-shade-model mode
     Select flat or smooth shading.

Rasterization
-------------

Per-Fragment Operations
-----------------------

 -- Function: set-gl-stencil-function stencil-function k [#:mask] [#:face]
     Set the front and/or back function and the reference value K for stencil testing.  Without the FACE keyword argument, both functions are set.  The default MASK is all-inclusive.

 -- Function: set-gl-stencil-operation stencil-fail depth-fail depth-pass [#:face]
     Set the front and/or back stencil test actions.  Without the FACE keyword argument, both stencil test actions are set.  See the stencil-op enumeration for possible values for STENCIL-FAIL, DEPTH-FAIL, and DEPTH-PASS.

 -- Function: set-gl-blend-equation mode-rgb [mode-alpha=mode-rgb]
     Set the blend equation.  With one argument, set the same blend equation for all components.  Pass two arguments to specify a separate equation for the alpha component.

 -- Function: set-gl-blend-function src-rgb dest-rgb [src-alpha=src-rgb] [dest-alpha=dest-rgb]
     Set the blend function.  With two arguments, set the same blend function for all components.  Pass an additional two arguments to specify separate functions for the alpha components.

 -- Function: set-gl-scissor x y width height
     Define the scissor box.  The box is defined in window coordinates, with (X,Y) being the lower-left corner of the box.

 -- Function: set-gl-sample-coverage value invert
     Specify multisample coverage parameters.

 -- Function: set-gl-alpha-function func ref
     Specify the alpha test function.  See the alpha-function enumerator.

 -- Function: set-gl-depth-function func
     Specify the depth test function.  See the depth-function enumerator. p defun

      -- Function: set-gl-blend-color r g b a
          Specify the blend color.

      -- Function: set-gl-logic-operation opcode
          Specify a logical pixel operation for color index rendering.

Whole Framebuffer Operations
............................

 -- Function: set-gl-draw-buffers buffers
     Specify a list of color buffers to be drawn into.  BUFFERS should be a list of draw-buffer-mode enumerated values.

 -- Function: set-gl-stencil-mask mask [#:face]
     Control the writing of individual bits into the front and/or back stencil planes.  With one argument, the stencil mask for both states are set.

 -- Function: set-gl-draw-buffer mode
     Specify the buffer or buffers to draw into.

 -- Function: set-gl-index-mask mask
     Control the writing of individual bits into the color index buffers.

 -- Function: set-gl-color-mask red? green? blue? alpha?
     Enable and disable writing of frame buffer color components.

 -- Function: set-gl-depth-mask enable?
     Enable and disable writing into the depth buffer.

 -- Function: gl-clear mask
     Clear a set of buffers to pre-set values.  Use the clear-buffer-mask enumerator to specify which buffers to clear.

 -- Function: set-gl-clear-color r g b a
     Set the clear color for the color buffers.

 -- Function: set-gl-clear-index c
     Set the clear index for the color index buffers.

 -- Function: set-gl-clear-depth depth
     Set the clear value for the depth buffer.

 -- Function: set-gl-clear-stencil-value s
     Set the clear value for the stencil buffer.

 -- Function: set-gl-clear-accumulation-color r g b a
     Set the clear color for the accumulation buffer.

 -- Function: set-gl-accumulation-buffer-operation op value
     Operate on the accumulation buffer.  OP may be one of the accum-op enumerated values.  The interpretation of VALUE depends on OP.

Drawing, Reading and Copying Pixels
...................................

 -- Function: set-gl-read-buffer mode
     Select a color buffer source for pixels.  Use read-buffer-mode to select a mode.

 -- Function: gl-copy-pixels x y width height type
     Copy pixels from a screen-aligned rectangle in the frame buffer to a region relative to the current raster position.  TYPE selects which buffer to copy from.

Special Functions
-----------------

State and State Requests
------------------------

Querying GL State
.................

 -- Macro: with-gl-push-attrib bits body ...
     Save part of the current state, evaluation the sequence of BODY expressions, then restore the state.  Use attrib-mask to specify which parts of the state to save.

GL Enumerations
===============

     [file low-level-gl-enums.texi not included]

Low-Level GL
============

     [file low-level-gl.texi not included]

GL Extensions
=============

     The future is already here -- it's just not very evenly distributed.

     -- William Gibson

Before interfaces end up in core OpenGL, the are usually present as vendor-specific or candidate extensions.  Indeed, the making of an OpenGL standard these days seems to be a matter of simply collecting a set of mature extensions and making them coherent.

Figl doesn't currently provide specific interfaces for extensions. Perhaps it should, but that's a lot of work that we haven't had time to do.  Contributions are welcome.

In the meantime, if you know enough about GL to know that you need an extension, you can define one yourself -- after all, Figl is all a bunch of Scheme code anyway.

For example, let's say you decide that you need to render to a framebuffer object.  You go to http://www.opengl.org/registry/ and pick out an extension, say http://www.opengl.org/registry/specs/ARB/framebuffer_object.txt.

This extension defines a procedure, GLboolean glIsRenderBuffer(GLuint).  So you define it:

     (use-modules (figl gl runtime) (figl gl types))
     (define-gl-procedure (glIsRenderBuffer (buf GLuint) -> GLboolean)
       "Render buffer predicate.  Other docs here.")

And that's that.  It's a low-level binding, but what did you expect?

Note that you'll still need to check for the availability of this extension at runtime with (glGetString GL_EXTENSIONS).