From c87b98e3f77d575db11e81a619db5b5c32fba871 Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauld.mccarthy@gmail.com>
Date: Tue, 5 Jan 2016 11:30:45 +0000
Subject: [PATCH] Tensor/ARB assembly documentation.

---
 fsl/fsleyes/gl/gl14/gllabel_frag.prog      |  6 +-
 fsl/fsleyes/gl/gl14/gllinevector_vert.prog | 15 ++---
 fsl/fsleyes/gl/gl14/glmodel_frag.prog      |  6 +-
 fsl/fsleyes/gl/gl14/glvector_frag.prog     | 49 +++++++++--------
 fsl/fsleyes/gl/gl14/glvolume_frag.prog     |  6 +-
 fsl/fsleyes/gl/gl21/gltensor_funcs.py      | 64 +++++++++++++++++++---
 fsl/fsleyes/gl/gltensor.py                 | 31 +++++++++--
 fsl/fsleyes/gl/shaders/glsl/program.py     |  4 ++
 8 files changed, 118 insertions(+), 63 deletions(-)

diff --git a/fsl/fsleyes/gl/gl14/gllabel_frag.prog b/fsl/fsleyes/gl/gl14/gllabel_frag.prog
index 72badca3b..47835b5db 100644
--- a/fsl/fsleyes/gl/gl14/gllabel_frag.prog
+++ b/fsl/fsleyes/gl/gl14/gllabel_frag.prog
@@ -16,7 +16,7 @@
 #                          outlines. The yzw components specify the
 #                          border/outline widths along each axis.
 #
-# Input attributes:
+# Input varyings:
 #
 #   texCoord - Fragment texture coordinates
 #   voxCoord - Fragment voxel coordinates
@@ -26,10 +26,6 @@
 #   imageTexture - 3D texture containing the image data
 #   lutTexture   - 1D texture containing the lookup table colours
 #
-# Outputs:
-#
-#   result.color - Fragment colour.
-#
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
 
diff --git a/fsl/fsleyes/gl/gl14/gllinevector_vert.prog b/fsl/fsleyes/gl/gl14/gllinevector_vert.prog
index 525c90508..9a8c43c5e 100644
--- a/fsl/fsleyes/gl/gl14/gllinevector_vert.prog
+++ b/fsl/fsleyes/gl/gl14/gllinevector_vert.prog
@@ -2,18 +2,15 @@
 #
 # Vertex program for rendering GLLineVector instances.
 #
-# Inputs:
-#    state.matrix.mvp - MVP transformation matrix
-#    vertex.position  - Vertex position in the voxel coordinate system.
+# Input parameters:
 # 
-#    program.local[0] - (first three components) inverse of image shape
-#    program.local[1] - (first three components) Offset to apply to transformed
-#                       voxel coordinates before flooring to integers.
+#    invImageShape  - (first three components) inverse of image shape
+#    voxelOffsets   - (first three components) Offset to apply to transformed
+#                     voxel coordinates before flooring to integers.
 #
 # Outputs:
-#    result.position    - the vertex position
-#    result.texcoord[0] - the texture coordinates
-#    result.texcoord[1] - the voxel coordinates
+#    texCoord - the texture coordinates
+#    voxCoord - the voxel coordinates
 #
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
diff --git a/fsl/fsleyes/gl/gl14/glmodel_frag.prog b/fsl/fsleyes/gl/gl14/glmodel_frag.prog
index a1f2d079c..3d3d1ee04 100644
--- a/fsl/fsleyes/gl/gl14/glmodel_frag.prog
+++ b/fsl/fsleyes/gl/gl14/glmodel_frag.prog
@@ -8,12 +8,8 @@
 # Input textures:
 #   renderTexture - 2D texture containing the rendered model.
 #
-# Input attributes:
+# Input varyings:
 #   texCoord  - Texture coordinates
-#   
-#
-# Outputs:
-#   result.color         - Fragment colour.
 #
 # Author: Paul McCarthy <pauldmccarthy@gmail.com> 
 #
diff --git a/fsl/fsleyes/gl/gl14/glvector_frag.prog b/fsl/fsleyes/gl/gl14/glvector_frag.prog
index fb815f3bd..3a3fdb0a7 100644
--- a/fsl/fsleyes/gl/gl14/glvector_frag.prog
+++ b/fsl/fsleyes/gl/gl14/glvector_frag.prog
@@ -16,36 +16,37 @@
 #
 #  - Uses those voxel values to colour the fragment.
 #
-# Required inputs:
-# 
-#   fragment.texcoord[0] - Fragment texture coordinates
-#   fragment.texcoord[1] - Fragment voxel coordinates 
+# Input parameters:
+#
+#   voxValXform - Transformation matrix which transforms the vector
+#                 image voxel values from their texture value
+#                 to the original data range.
 #
-#   program.local[0]
-#   program.local[1]
-#   program.local[2]
-#   program.local[3] - Transformation matrix which transforms the vector
-#                      image voxel values from their texture value
-#                      to the original data range.
+#   cmapXform   - Transformation matrix which transforms the vector
+#                 image voxel values from their data values
+#                 to a value which can be used as texture coordinates
+#                 for the colour map textures.
 #
-#   program.local[4]
-#   program.local[5]
-#   program.local[6]
-#   program.local[7] - Transformation matrix which transforms the vector
-#                      image voxel values from their data values
-#                      to a value which can be used as texture coordinates
-#                      for the colour map textures.
+#   imageShape  - Image shape - number of voxels along the xyz
+#                 dimensions in the image
 #
-#   program.local[8] - Image shape - number of voxels along the xyz
-#                      dimensions in the image
+#   clipping    - Clipping thresholds. The (x) component contains
+#                 the low clipping threshold, and the (y) component
+#                 contains the high threshold.
 #
-#   program.local[9] - Clipping thresholds. The (x) component contains
-#                      the low clipping threshold, and the (y) component
-#                      contains the high threshold.
+# Input textures:
 #
-# Outputs:
+#   vectorTexture   - 3D texture containing the vector data.
+#   modulateTexture - 3D texture containing brightness modulation values.
+#   clipTexture     - 3D texture containing clipping values.
+#   xColourTexture  - 1D texture containing the X vector component colour map.
+#   yColourTexture  - 1D texture containing the Y vector component colour map.
+#   zColourTexture  - 1D texture containing the Z vector component colour map.
 #
-#   result.color     - The fragment colour.
+# Input varyings:
+# 
+#   texCoord - Fragment texture coordinates
+#   voxCoord - Fragment voxel coordinates 
 #
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
diff --git a/fsl/fsleyes/gl/gl14/glvolume_frag.prog b/fsl/fsleyes/gl/gl14/glvolume_frag.prog
index d446c432f..dd032c6bb 100644
--- a/fsl/fsleyes/gl/gl14/glvolume_frag.prog
+++ b/fsl/fsleyes/gl/gl14/glvolume_frag.prog
@@ -47,7 +47,7 @@
 #                 colour map is used), as a voxel value, normalised to
 #                 the image texture value range.
 #
-# Input attributes:
+# Input varyings:
 #
 #   texCoord - Fragment texture coordinates
 #   voxCoord - Fragment voxel coordinates
@@ -59,10 +59,6 @@
 #   colourTexture    - 1D texture containing colour map
 #   negColourTexture - 1D texture containing negative colour map
 #
-# Outputs:
-#
-#   result.color - The fragment colour
-#
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
 
diff --git a/fsl/fsleyes/gl/gl21/gltensor_funcs.py b/fsl/fsleyes/gl/gl21/gltensor_funcs.py
index 1eb5784de..5dd6871ea 100644
--- a/fsl/fsleyes/gl/gl21/gltensor_funcs.py
+++ b/fsl/fsleyes/gl/gl21/gltensor_funcs.py
@@ -4,8 +4,45 @@
 #
 # Author: Paul McCarthy <pauldmccarthy@gmail.com>
 #
+"""This module provides functions which are used by the :class:`.GLTensor`
+class for rendering :class:`.TensorImage` overlays in an OpenGL 2.1 compatible
+manner.
 
-import logging
+
+The eigenvalues and eigenvectors of the ``TensorImage`` are stored as 3D
+:class:`.ImageTexture` instances, using the :mod:`.gl.resources` module. For
+each voxel, the vertices of a unit sphere are passed to the ``gltensor``
+vertex shader, which looks up the eigenvectors and values for the voxel, and
+transforms the sphere accordingly.
+
+
+The rendering code makes use of the OpenGL ``ARB_draw_instanced`` extension
+so that voxel coordinates do not need to be repeated for every vertex of
+a single tensor.
+
+
+If the :attr:`.VectorOpts.colourImage` property is not set, the ``glvector``
+fragment shader is used to colour the tensors. Otherwise, the ``glvolume``
+fragment shader is used to colour the tensors according to the specified
+``colourImage``. The functions in the :mod:`.gl21.glvector_funcs` module
+are used to manage the fragment shader.
+
+
+The following textures are used for rendering a ``GLTensor`` instance - this
+is in addition to the textures that are used for :class:`.GLVector` instances
+(of which the ``GLTensor`` is a sub-class):
+
+  ============== ================== ==================
+  Attribute name Description        Texture unit
+  ============== ================== ==================
+  ``v1Texture``  First eigenvector  ``gl.GL_TEXTURE8``
+  ``v2Texture``  Second eigenvector ``gl.GL_TEXTURE9``
+  ``v3Texture``  Third eigenvector  ``gl.GL_TEXTURE10``
+  ``l1Texture``  First eigenvalue   ``gl.GL_TEXTURE11``
+  ``l2Texture``  Second eigenvalue  ``gl.GL_TEXTURE12``
+  ``l3Texture``  Third eigenvalue   ``gl.GL_TEXTURE13``
+  ============== ================== ==================
+"""
 
 
 import numpy                          as np
@@ -20,12 +57,9 @@ import fsl.fsleyes.gl.textures  as textures
 import                             glvector_funcs
 
 
-log = logging.getLogger(__name__)
-
-
 def init(self):
-    """Compiles and configures the vertex and fragment shader programs, and
-    creates textures and vertex buffers.
+    """Creates textures for the tensor eigenvalue and eigenvector images,
+    and calls :func:`compileShaders` and :func:`updateShaderState`.
     """
 
     image = self.image
@@ -37,7 +71,6 @@ def init(self):
     l2 = image.L2()
     l3 = image.L3()
 
-
     def vPrefilter(d):
         return d.transpose((3, 0, 1, 2))
 
@@ -72,6 +105,8 @@ def init(self):
 
 
 def destroy(self):
+    """Deletes the :class:`.GLSLShader`, and all textures. """
+    
     self.shader.delete()
     self.shader = None
     
@@ -86,10 +121,17 @@ def destroy(self):
 
 
 def compileShaders(self):
+    """Creates a :class:`.GLSLShader` for drawing this ``GLTensor``. This is
+    done via a call to :func:`.gl21.glvector_funcs.compileShaders`.
+    """
     self.shader = glvector_funcs.compileShaders(self, 'gltensor', indexed=True)
 
 
 def updateShaderState(self):
+    """Updates the state of the vertex and fragment shaders. The fragment
+    shader is updated via the :func:`.gl21.glvector_funcs.updateShaderState`
+    function.
+    """
 
     shader = self.shader
     opts   = self.displayOpts
@@ -154,8 +196,8 @@ def updateShaderState(self):
 
 
 def preDraw(self):
-    """Must be called before :func:`draw`. Loads the shader programs, binds
-    textures, and enables vertex arrays.
+    """Must be called before :func:`draw`. Loads the shader programs, does
+    some shader state configuration, and binds textures to texture units.
     """
     
     shader = self.shader
@@ -183,6 +225,9 @@ def preDraw(self):
     
 
 def draw(self, zpos, xform=None):
+    """Generates voxel coordinates for each tensor to be drawn, does some
+    final shader state configuration, and draws the tensors.
+    """
 
     image  = self.image
     opts   = self.displayOpts
@@ -223,6 +268,7 @@ def draw(self, zpos, xform=None):
 
 
 def postDraw(self):
+    """Unloads the shader program, and unbinds the textures. """
 
     self.shader.unloadAtts()
     self.shader.unload()
diff --git a/fsl/fsleyes/gl/gltensor.py b/fsl/fsleyes/gl/gltensor.py
index 8ef0097a3..af54f9497 100644
--- a/fsl/fsleyes/gl/gltensor.py
+++ b/fsl/fsleyes/gl/gltensor.py
@@ -20,11 +20,23 @@ import fsl.fsleyes.gl as fslgl
 
 class GLTensor(glvector.GLVector):
     """The ``GLTensor`` class encapsulates the logic required to render
-    :class:`.TensorImage` overlays.
+    :class:`.TensorImage` overlays.  Most of the functionality is in the
+    :mod:`.gl21.gltensor_funcs` module.
+
+    .. note:: The ``GLTensor``  is not supported on versions of OpenGL older
+              than 2.1.
     """
 
     
     def __init__(self, image, display):
+        """Create a ``GLTensor``. Calls the :func:`.gl21.gltensor_funcs.init`
+        function.
+
+        :arg image:   A :class:`.TensorImage` overlay.
+        
+        :arg display: The :class:`.Display` instance associated with the
+                      ``image``.
+        """
         glvector.GLVector.__init__(self,
                                    image,
                                    display,
@@ -88,32 +100,39 @@ class GLTensor(glvector.GLVector):
 
 
     def compileShaders(self):
-        """Overrides :meth:`.GLVector.compileShaders`.
+        """Overrides :meth:`.GLVector.compileShaders`. Calls the
+        :func:`.gl21.gltensor_funcs.compileShaders` function.
         """
         fslgl.gltensor_funcs.compileShaders(self)
 
 
     def updateShaderState(self):
-        """Overrides :meth:`.GLVector.updateShaderState`.
+        """Overrides :meth:`.GLVector.updateShaderState`. Calls the
+        :func:`.gl21.gltensor_funcs.updateShaderState` function.
         """ 
         fslgl.gltensor_funcs.updateShaderState(self)
 
         
     def preDraw(self):
-        """Overrides :meth:`.GLVector.preDraw`.
+        """Overrides :meth:`.GLVector.preDraw`. Calls the
+        :meth:`.GLVector.preDraw` method, and the
+        :func:`.gl21.gltensor_funcs.preDraw` function.
         """ 
         glvector.GLVector.preDraw(self)
         fslgl.gltensor_funcs.preDraw(self)
 
 
     def draw(self, zpos, xform=None):
-        """
+        """Overrides :meth:`.GLVector.draw`. Calls the
+        :func:`.gl21.gltensor_funcs.draw` function.
         """
         fslgl.gltensor_funcs.draw(self, zpos, xform)
 
 
     def postDraw(self):
-        """Overrides :meth:`.GLVector.postDraw`.
+        """Overrides :meth:`.GLVector.postDraw`. Calls the
+        :meth:`.GLVector.postDraw` method, and the
+        :func:`.gl21.gltensor_funcs.postDraw` function.
         """ 
         glvector.GLVector.postDraw(self)
         fslgl.gltensor_funcs.postDraw(self)
diff --git a/fsl/fsleyes/gl/shaders/glsl/program.py b/fsl/fsleyes/gl/shaders/glsl/program.py
index 4a959518a..cc466420a 100644
--- a/fsl/fsleyes/gl/shaders/glsl/program.py
+++ b/fsl/fsleyes/gl/shaders/glsl/program.py
@@ -255,6 +255,10 @@ class GLSLShader(object):
 
         :arg divisor: If specified, this value is used as a divisor for this
                       attribute via the ``glVetexAttribDivisor`` function.
+
+        .. note:: If a ``divisor`` is specified, the OpenGL
+                  ``ARB_instanced_arrays`` extension must be
+                  available.
         """ 
 
         aType    = self.types[  name]
-- 
GitLab