diff --git a/fsl/fsleyes/gl/gl14/gllabel_frag.prog b/fsl/fsleyes/gl/gl14/gllabel_frag.prog index b5d2b3b373c3e523380c02be947043332e822c61..ffd480db9976a6154c491da774d2664586118aa3 100644 --- a/fsl/fsleyes/gl/gl14/gllabel_frag.prog +++ b/fsl/fsleyes/gl/gl14/gllabel_frag.prog @@ -29,27 +29,24 @@ TEMP lutCoord; TEMP invNumLabels; TEMP voxValue; -PARAM imageShape = program.local[4]; -MOV invNumLabels, program.local[5]; -PARAM outline = program.local[6]; +PARAM imageShape = {{ param_imageShape }}; +MOV invNumLabels, {{ param_invNumLabels }}; +PARAM outline = {{ param_outline }}; # This matrix scales the voxel value to # lie in a range which is appropriate to # the current display range -PARAM voxValXform[4] = { program.local[0], - program.local[1], - program.local[2], - program.local[3] }; +PARAM voxValXform[4] = {{ param4_voxValXform }}; # retrieve the voxel coordinates, # bail if they are are out of bounds -MOV voxCoord, fragment.texcoord[1]; +MOV voxCoord, {{ varying_voxCoord }}; #pragma include test_in_bounds.prog # look up image voxel value # from 3D image texture -TEX voxValue, fragment.texcoord[0], texture[0], 3D; +TEX voxValue, {{ varying_texCoord }}, {{ texture_imageTexture }}, 3D; # Scale the texture value # to its original voxel value @@ -63,7 +60,7 @@ MUL lutCoord, lutCoord, invNumLabels; # look up the appropriate colour # in the 1D colour map texture -TEX result.color, lutCoord.x, texture[1], 1D; +TEX result.color, lutCoord.x, {{ texture_lutTexture }}, 1D; # Test whether this fragment lies @@ -74,7 +71,7 @@ TEMP val; TEMP tol; TEMP offsets; -MOV coord, fragment.texcoord[0]; +MOV coord, {{ varying_texCoord }}; MOV val, voxValue; MOV tol, invNumLabels.x; MUL tol, tol, 0.001; diff --git a/fsl/fsleyes/gl/gl14/gllabel_funcs.py b/fsl/fsleyes/gl/gl14/gllabel_funcs.py index ed60037950cd92482cc4d8ba244c6821f1168eff..22b9f92aa07c3577b45aede040775c370a6c8ebe 100644 --- a/fsl/fsleyes/gl/gl14/gllabel_funcs.py +++ b/fsl/fsleyes/gl/gl14/gllabel_funcs.py @@ -14,24 +14,18 @@ defined in the :mod:`.gl14.glvolume_funcs` are re-used by this module. """ -import numpy as np - -import OpenGL.GL as gl -import OpenGL.raw.GL._types as gltypes -import OpenGL.GL.ARB.fragment_program as arbfp -import OpenGL.GL.ARB.vertex_program as arbvp +import numpy as np import fsl.fsleyes.gl.shaders as shaders - -import glvolume_funcs +import glvolume_funcs def init(self): """Calls the :func:`compileShaders` and :func:`updateShaderState` functions. """ - self.vertexProgram = None - self.fragmentProgram = None + + self.shader = None compileShaders( self) updateShaderState(self) @@ -39,48 +33,39 @@ def init(self): def destroy(self): """Deletes handles to the vertex/fragment shader programs. """ - arbvp.glDeleteProgramsARB(1, gltypes.GLuint(self.vertexProgram)) - arbfp.glDeleteProgramsARB(1, gltypes.GLuint(self.fragmentProgram)) + self.shader.delete() + self.shader = None def compileShaders(self): """Compiles the vertex and fragment shader programs used to render :class:`.GLLabel` instances. """ - if self.vertexProgram is not None: - arbvp.glDeleteProgramsARB(1, gltypes.GLuint(self.vertexProgram)) + if self.shader is not None: + self.shader.delete() - if self.fragmentProgram is not None: - arbfp.glDeleteProgramsARB(1, gltypes.GLuint(self.fragmentProgram)) - - vertShaderSrc = shaders.getVertexShader( 'glvolume') - fragShaderSrc = shaders.getFragmentShader('gllabel') + vertSrc = shaders.getVertexShader( 'glvolume') + fragSrc = shaders.getFragmentShader('gllabel') + textures = { + 'imageTexture' : 0, + 'lutTexture' : 1, + } - vertexProgram, fragmentProgram = shaders.compilePrograms( - vertShaderSrc, fragShaderSrc) - - self.vertexProgram = vertexProgram - self.fragmentProgram = fragmentProgram + self.shader = shaders.ARBPShader(vertSrc, fragSrc, textures) def updateShaderState(self): """Updates all shader program variables. """ opts = self.displayOpts - + # enable the vertex and fragment programs - gl.glEnable(arbvp.GL_VERTEX_PROGRAM_ARB) - gl.glEnable(arbfp.GL_FRAGMENT_PROGRAM_ARB) - - arbvp.glBindProgramARB(arbvp.GL_VERTEX_PROGRAM_ARB, - self.vertexProgram) - arbfp.glBindProgramARB(arbfp.GL_FRAGMENT_PROGRAM_ARB, - self.fragmentProgram) + self.shader.load() voxValXform = self.imageTexture.voxValXform - shape = list(self.image.shape[:3]) + shape = list(self.image.shape[:3]) + [0] offsets = opts.outlineWidth / \ - np.array(self.image.shape[:3], dtype=np.float32) + np.array(self.image.shape[:3], dtype=np.float32) invNumLabels = 1.0 / (opts.lut.max() + 1) if opts.transform == 'affine': @@ -92,14 +77,13 @@ def updateShaderState(self): if opts.outline: offsets = [1] + list(offsets) else: offsets = [0] + list(offsets) - shaders.setVertexProgramVector( 0, shape + [0]) - shaders.setFragmentProgramMatrix(0, voxValXform) - shaders.setFragmentProgramVector(4, shape + [0]) - shaders.setFragmentProgramVector(5, [invNumLabels, 0, 0, 0]) - shaders.setFragmentProgramVector(6, offsets) + self.shader.setVertParam('imageShape', shape) + self.shader.setFragParam('imageShape', shape) + self.shader.setFragParam('voxValXform', voxValXform) + self.shader.setFragParam('invNumLabels', [invNumLabels, 0, 0, 0]) + self.shader.setFragParam('outline', offsets) - gl.glDisable(arbvp.GL_VERTEX_PROGRAM_ARB) - gl.glDisable(arbfp.GL_FRAGMENT_PROGRAM_ARB) + self.shader.unload() preDraw = glvolume_funcs.preDraw diff --git a/fsl/fsleyes/gl/gl14/glmodel_frag.prog b/fsl/fsleyes/gl/gl14/glmodel_frag.prog index 2959110730fef376b9fec605b38cb9a193a98b40..a645f8de9c6bad363ac956a9ef61ece4f13d8747 100644 --- a/fsl/fsleyes/gl/gl14/glmodel_frag.prog +++ b/fsl/fsleyes/gl/gl14/glmodel_frag.prog @@ -19,11 +19,11 @@ TEMP output; # edge detection tolerance is # 1 / 255 - a colour change of 1 bit PARAM tol = 0.00392156862745098; -PARAM offsets = program.local[0]; +PARAM offsets = {{ param_offsets }}; -MOV coord, fragment.texcoord[0]; +MOV coord, {{ varying_texCoord }}; -TEX val, coord, texture[0], 2D; +TEX val, coord, {{ texture_renderTexture }}, 2D; #pragma include edge2D.prog diff --git a/fsl/fsleyes/gl/gl14/glmodel_funcs.py b/fsl/fsleyes/gl/gl14/glmodel_funcs.py index 5feb43e56bc4ce2c7178c8e65cf033e3953b5c6b..a57db666f8fd71e151457e48e0210d554a526e2c 100644 --- a/fsl/fsleyes/gl/gl14/glmodel_funcs.py +++ b/fsl/fsleyes/gl/gl14/glmodel_funcs.py @@ -9,12 +9,7 @@ class to render :class:`.Model` overlays in an OpenGL 1.4 compatible manner. """ -import OpenGL.GL as gl -import OpenGL.raw.GL._types as gltypes -import OpenGL.GL.ARB.fragment_program as arbfp -import OpenGL.GL.ARB.vertex_program as arbvp - -import fsl.fsleyes.gl.shaders as shaders +import fsl.fsleyes.gl.shaders as shaders def compileShaders(self): @@ -23,22 +18,20 @@ def compileShaders(self): instance. """ - vertShaderSrc = shaders.getVertexShader( 'glmodel') - fragShaderSrc = shaders.getFragmentShader('glmodel') + vertSrc = shaders.getVertexShader( 'glmodel') + fragSrc = shaders.getFragmentShader('glmodel') - vertexProgram, fragmentProgram = shaders.compilePrograms( - vertShaderSrc, fragShaderSrc) + textures = {'renderTexture' : 0} - self.vertexProgram = vertexProgram - self.fragmentProgram = fragmentProgram + self.shader = shaders.ARBPShader(vertSrc, fragSrc, textures) def destroy(self): """Deletes the vertex/fragment shader programs that were compiled by :func:`compileShaders`. - """ - arbvp.glDeleteProgramsARB(1, gltypes.GLuint(self.vertexProgram)) - arbfp.glDeleteProgramsARB(1, gltypes.GLuint(self.fragmentProgram)) + """ + self.shader.delete() + self.shader = None def updateShaders(self): @@ -48,22 +41,15 @@ def updateShaders(self): offsets = self.getOutlineOffsets() loadShaders(self) - shaders.setFragmentProgramVector(0, list(offsets) + [0, 0]) + self.shader.setFragParam('offsets', list(offsets) + [0, 0]) unloadShaders(self) def loadShaders(self): """Loads the :class:`.GLModel` vertex/fragment shader programs. """ - gl.glEnable(arbvp.GL_VERTEX_PROGRAM_ARB) - gl.glEnable(arbfp.GL_FRAGMENT_PROGRAM_ARB) - - arbvp.glBindProgramARB(arbvp.GL_VERTEX_PROGRAM_ARB, - self.vertexProgram) - arbfp.glBindProgramARB(arbfp.GL_FRAGMENT_PROGRAM_ARB, - self.fragmentProgram) - + self.shader.load() + def unloadShaders(self): """Un-loads the :class:`.GLModel` vertex/fragment shader programs. """ - gl.glDisable(arbvp.GL_VERTEX_PROGRAM_ARB) - gl.glDisable(arbfp.GL_FRAGMENT_PROGRAM_ARB) + self.shader.unload() diff --git a/fsl/fsleyes/gl/gl14/glmodel_vert.prog b/fsl/fsleyes/gl/gl14/glmodel_vert.prog index 0b38e89499a62c5fde60f6b652a662a90d1dcb67..f7a6a421ccb34da3e0b8392ed800ae10d799b8b3 100644 --- a/fsl/fsleyes/gl/gl14/glmodel_vert.prog +++ b/fsl/fsleyes/gl/gl14/glmodel_vert.prog @@ -20,6 +20,6 @@ DP4 result.position.z, state.matrix.mvp.row[2], vertex.position; DP4 result.position.w, state.matrix.mvp.row[3], vertex.position; # Copy the vertex texture coordinate -MOV result.texcoord[0], vertex.texcoord[0]; +MOV {{ varying_texCoord }}, {{ attr_texCoord }}; END diff --git a/fsl/fsleyes/gl/gl14/glvolume_frag.prog b/fsl/fsleyes/gl/gl14/glvolume_frag.prog index 03afb3a4eaa51f6be1f9435f5abd1ed5409ba567..621d8bfc38542da4d3aa679539c4482bf1b7badf 100644 --- a/fsl/fsleyes/gl/gl14/glvolume_frag.prog +++ b/fsl/fsleyes/gl/gl14/glvolume_frag.prog @@ -66,29 +66,26 @@ TEMP useNegCmap; TEMP negVoxValue; TEMP negClipValue; -PARAM imageShape = program.local[4]; -PARAM clipping = program.local[5]; -PARAM negCmap = program.local[6]; +PARAM imageShape = {{ param_imageShape }}; +PARAM clipping = {{ param_clipping }}; +PARAM negCmap = {{ param_negCmap }}; # This matrix scales the voxel value to # lie in a range which is appropriate to # the current display range -PARAM voxValXform[4] = { program.local[0], - program.local[1], - program.local[2], - program.local[3] }; +PARAM voxValXform[4] = {{ param4_voxValXform }}; # retrieve the voxel coordinates, # bail if they are are out of bounds -MOV voxCoord, fragment.texcoord[1]; +MOV voxCoord, {{ varying_voxCoord }}; #pragma include test_in_bounds.prog # look up image voxel value # and clipping value from 3D # image/clipping textures -TEX voxValue.x, fragment.texcoord[0], texture[0], 3D; -TEX clipValue.x, fragment.texcoord[0], texture[3], 3D; +TEX voxValue.x, {{ varying_texCoord }}, {{ texture_imageTexture }}, 3D; +TEX clipValue.x, {{ varying_texCoord }}, {{ texture_clipTexture }}, 3D; # If the image texture is the clip # texture, overwrite the clip value @@ -165,12 +162,12 @@ MAD voxValue, voxValue, voxValXform[0].x, voxValXform[3].x; # look up the appropriate colour # in the 1D colour map texture -TEX posColour, voxValue.x, texture[1], 1D; -TEX negColour, voxValue.x, texture[2], 1D; +TEX posColour, voxValue.x, {{ texture_colourTexture }}, 1D; +TEX negColour, voxValue.x, {{ texture_negColourTexture }}, 1D; # useNegCmap is negative if the # negative colour map should be # used, positive otherwise. CMP result.color, useNegCmap.x, negColour, posColour; -END \ No newline at end of file +END diff --git a/fsl/fsleyes/gl/gl14/glvolume_funcs.py b/fsl/fsleyes/gl/gl14/glvolume_funcs.py index 98202e938eb3616363915dab15132ce2934b8a4e..af9bf226b8ccfaec74cb4acbd7fd3e331fdd55cc 100644 --- a/fsl/fsleyes/gl/gl14/glvolume_funcs.py +++ b/fsl/fsleyes/gl/gl14/glvolume_funcs.py @@ -11,11 +11,8 @@ class to render :class:`.Image` overlays in an OpenGL 1.4 compatible manner. import logging -import numpy as np -import OpenGL.GL as gl -import OpenGL.raw.GL._types as gltypes -import OpenGL.GL.ARB.fragment_program as arbfp -import OpenGL.GL.ARB.vertex_program as arbvp +import numpy as np +import OpenGL.GL as gl import fsl.utils.transform as transform import fsl.fsleyes.gl.shaders as shaders @@ -27,8 +24,7 @@ log = logging.getLogger(__name__) def init(self): """Calls :func:`compileShaders` and :func:`updateShaderState`.""" - self.vertexProgram = None - self.fragmentProgram = None + self.shader = None compileShaders( self) updateShaderState(self) @@ -37,8 +33,8 @@ def init(self): def destroy(self): """Deletes handles to the vertex/fragment programs.""" - arbvp.glDeleteProgramsARB(1, gltypes.GLuint(self.vertexProgram)) - arbfp.glDeleteProgramsARB(1, gltypes.GLuint(self.fragmentProgram)) + self.shader.delete() + self.shader = None def compileShaders(self): @@ -49,20 +45,19 @@ def compileShaders(self): ``framgentProgram`` respectively. """ - if self.vertexProgram is not None: - arbvp.glDeleteProgramsARB(1, gltypes.GLuint(self.vertexProgram)) - - if self.fragmentProgram is not None: - arbfp.glDeleteProgramsARB(1, gltypes.GLuint(self.fragmentProgram)) - - vertShaderSrc = shaders.getVertexShader( 'glvolume') - fragShaderSrc = shaders.getFragmentShader('glvolume') + if self.shader is not None: + self.shader.delete() - vertexProgram, fragmentProgram = shaders.compilePrograms( - vertShaderSrc, fragShaderSrc) + vertSrc = shaders.getVertexShader( 'glvolume') + fragSrc = shaders.getFragmentShader('glvolume') + textures = { + 'imageTexture' : 0, + 'colourTexture' : 1, + 'negColourTexture' : 2, + 'clipTexture' : 3 + } - self.vertexProgram = vertexProgram - self.fragmentProgram = fragmentProgram + self.shader = shaders.ARBPShader(vertSrc, fragSrc, textures) def updateShaderState(self): @@ -70,13 +65,7 @@ def updateShaderState(self): opts = self.displayOpts # enable the vertex and fragment programs - gl.glEnable(arbvp.GL_VERTEX_PROGRAM_ARB) - gl.glEnable(arbfp.GL_FRAGMENT_PROGRAM_ARB) - - arbvp.glBindProgramARB(arbvp.GL_VERTEX_PROGRAM_ARB, - self.vertexProgram) - arbfp.glBindProgramARB(arbfp.GL_FRAGMENT_PROGRAM_ARB, - self.fragmentProgram) + self.shader.load() # The voxValXform transformation turns # an image texture value into a raw @@ -104,16 +93,19 @@ def updateShaderState(self): clipLo = opts.clippingRange[0] * clipXform[0, 0] + clipXform[3, 0] clipHi = opts.clippingRange[1] * clipXform[0, 0] + clipXform[3, 0] texZero = 0.0 * imgXform[ 0, 0] + imgXform[ 3, 0] - - shaders.setVertexProgramVector( 0, shape + [0]) - - shaders.setFragmentProgramMatrix(0, voxValXform) - shaders.setFragmentProgramVector(4, shape + [0]) - shaders.setFragmentProgramVector(5, [clipLo, clipHi, invClip, imageIsClip]) - shaders.setFragmentProgramVector(6, [useNegCmap, texZero, 0, 0]) - gl.glDisable(arbvp.GL_VERTEX_PROGRAM_ARB) - gl.glDisable(arbfp.GL_FRAGMENT_PROGRAM_ARB) + + shape = shape + [0] + clipping = [clipLo, clipHi, invClip, imageIsClip] + negCmap = [useNegCmap, texZero, 0, 0] + + self.shader.setVertParam('imageShape', shape) + self.shader.setFragParam('voxValXform', voxValXform) + self.shader.setFragParam('imageShape', shape) + self.shader.setFragParam('clipping', clipping) + self.shader.setFragParam('negCmap', negCmap) + + self.shader.unload() def preDraw(self): @@ -121,34 +113,18 @@ def preDraw(self): # enable drawing from a vertex array gl.glEnableClientState(gl.GL_VERTEX_ARRAY) - - gl.glClientActiveTexture(gl.GL_TEXTURE0) - gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY) - - # enable the vertex and fragment programs - gl.glEnable(arbvp.GL_VERTEX_PROGRAM_ARB) - gl.glEnable(arbfp.GL_FRAGMENT_PROGRAM_ARB) - - arbvp.glBindProgramARB(arbvp.GL_VERTEX_PROGRAM_ARB, - self.vertexProgram) - arbfp.glBindProgramARB(arbfp.GL_FRAGMENT_PROGRAM_ARB, - self.fragmentProgram) + self.shader.load() def draw(self, zpos, xform=None): """Draws a slice of the image at the given Z location. """ vertices, voxCoords, texCoords = self.generateVertices(zpos, xform) - - # Tex coords are texture 0 coords - # Vox coords are texture 1 coords - vertices = np.array(vertices, dtype=np.float32).ravel('C') - texCoords = np.array(texCoords, dtype=np.float32).ravel('C') - gl.glVertexPointer(3, gl.GL_FLOAT, 0, vertices) + self.shader.setAttr('texCoord', texCoords) - gl.glClientActiveTexture(gl.GL_TEXTURE0) - gl.glTexCoordPointer(3, gl.GL_FLOAT, 0, texCoords) + vertices = np.array(vertices, dtype=np.float32).ravel('C') + gl.glVertexPointer(3, gl.GL_FLOAT, 0, vertices) gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6) @@ -168,14 +144,11 @@ def drawAll(self, zposes, xforms): vertices[ i * 6: i * 6 + 6, :] = v texCoords[i * 6: i * 6 + 6, :] = tc - vertices = vertices .ravel('C') - texCoords = texCoords.ravel('C') + self.shader.setAttr('texCoord', texCoords) + vertices = vertices.ravel('C') + gl.glVertexPointer(3, gl.GL_FLOAT, 0, vertices) - - gl.glClientActiveTexture(gl.GL_TEXTURE0) - gl.glTexCoordPointer(3, gl.GL_FLOAT, 0, texCoords) - gl.glDrawArrays(gl.GL_TRIANGLES, 0, nslices * 6) @@ -183,10 +156,5 @@ def postDraw(self): """Cleans up the GL state after drawing from the given :class:`.GLVolume` instance. """ - gl.glDisableClientState(gl.GL_VERTEX_ARRAY) - gl.glClientActiveTexture(gl.GL_TEXTURE0) - gl.glDisableClientState(gl.GL_TEXTURE_COORD_ARRAY) - - gl.glDisable(arbfp.GL_FRAGMENT_PROGRAM_ARB) - gl.glDisable(arbvp.GL_VERTEX_PROGRAM_ARB) + self.shader.unload() diff --git a/fsl/fsleyes/gl/gl14/glvolume_vert.prog b/fsl/fsleyes/gl/gl14/glvolume_vert.prog index 4bcce0edbfda57e4c5713f4f8d350aa417402271..c79622486fc5ab3de1b01eecc83a2e359fc73f02 100644 --- a/fsl/fsleyes/gl/gl14/glvolume_vert.prog +++ b/fsl/fsleyes/gl/gl14/glvolume_vert.prog @@ -6,17 +6,18 @@ # passes the corresponding voxel and texture coordinates through to the # fragment program. # -# Inputs: -# vertex.texcoord[0] - Texture coordinates -# program.local[0] - image shape -# +# Input parameters: +# imageShape - image shape +# +# Input attributes: +# texCoord - Texture coordinates # # Outputs: # result.texcoord[0] - Texture coordinates # result.texcoord[1] - Voxel coordinates # -PARAM imageShape = program.local[0]; +PARAM imageShape = {{ param_imageShape }}; TEMP voxCoord; @@ -26,12 +27,12 @@ DP4 result.position.y, state.matrix.mvp.row[1], vertex.position; DP4 result.position.z, state.matrix.mvp.row[2], vertex.position; DP4 result.position.w, state.matrix.mvp.row[3], vertex.position; -MOV result.texcoord[0], vertex.texcoord[0]; - -# Transform the texture coordinates into voxel coordinates -MOV voxCoord, vertex.texcoord[0]; +# Transform the texture coordinates +# into voxel coordinates +MOV voxCoord, {{ attr_texCoord }}; MUL voxCoord, voxCoord, imageShape; -MOV result.texcoord[1], voxCoord; +MOV {{ varying_texCoord }}, {{ attr_texCoord }}; +MOV {{ varying_voxCoord }}, voxCoord; -END \ No newline at end of file +END diff --git a/fsl/fsleyes/gl/shaders/__init__.py b/fsl/fsleyes/gl/shaders/__init__.py index 9aa640e70e9ab7f1c24d17482e4f22017fcf232c..47dd75c03704ea571afd125c231960ac4b728b07 100644 --- a/fsl/fsleyes/gl/shaders/__init__.py +++ b/fsl/fsleyes/gl/shaders/__init__.py @@ -7,127 +7,19 @@ import logging -import os.path as op +import os.path as op -import fsl.fsleyes.gl as fslgl +import fsl.fsleyes.gl as fslgl -import glsl.parse as glslparse -import glsl.program as glslprogram -import arbp.parse as arbpparse -import arbp.program as arbpprogram +import glsl.program as glslprogram +import arbp.program as arbpprogram log = logging.getLogger(__name__) GLSLShader = glslprogram.GLSLShader -ARBPShaer = arbpprogram.ARBPShader -parseGLSL = glslparse .parseGLSL -parseARBP = arbpparse .parseARBP - - - -def setVertexProgramVector(index, vector): - """Convenience function which sets the vertex program local parameter - at the given index to the given 4 component vector. - """ - import OpenGL.GL.ARB.vertex_program as arbvp - - arbvp.glProgramLocalParameter4fARB( - arbvp.GL_VERTEX_PROGRAM_ARB, index, *vector) - - -def setVertexProgramMatrix(index, matrix): - """Convenience function which sets four vertex program local parameters, - starting at the given index, to the given ``4*4`` matrix. - """ - - import OpenGL.GL.ARB.vertex_program as arbvp - - for i, row in enumerate(matrix): - arbvp.glProgramLocalParameter4fARB( - arbvp.GL_VERTEX_PROGRAM_ARB, i + index, - row[0], row[1], row[2], row[3]) - - -def setFragmentProgramVector(index, vector): - """Convenience function which sets the fragment program local parameter - at the given index to the given 4 component vector. - """ - - import OpenGL.GL.ARB.fragment_program as arbfp - - arbfp.glProgramLocalParameter4fARB( - arbfp.GL_FRAGMENT_PROGRAM_ARB, index, *vector) - - -def setFragmentProgramMatrix(index, matrix): - """Convenience function which sets four fragment program local parameters, - starting at the given index, to the given ``4*4`` matrix. - """ - - import OpenGL.GL.ARB.fragment_program as arbfp - - for i, row in enumerate(matrix): - arbfp.glProgramLocalParameter4fARB( - arbfp.GL_FRAGMENT_PROGRAM_ARB, i + index, - row[0], row[1], row[2], row[3]) - - -def compilePrograms(vertexProgramSrc, fragmentProgramSrc): - """Compiles the given vertex and fragment programs (written according - to the ``ARB_vertex_program`` and ``ARB_fragment_program`` extensions), - and returns references to the compiled programs. - """ - - import OpenGL.GL as gl - import OpenGL.GL.ARB.fragment_program as arbfp - import OpenGL.GL.ARB.vertex_program as arbvp - - gl.glEnable(arbvp.GL_VERTEX_PROGRAM_ARB) - gl.glEnable(arbfp.GL_FRAGMENT_PROGRAM_ARB) - - fragmentProgram = arbfp.glGenProgramsARB(1) - vertexProgram = arbvp.glGenProgramsARB(1) - - # vertex program - try: - arbvp.glBindProgramARB(arbvp.GL_VERTEX_PROGRAM_ARB, - vertexProgram) - - arbvp.glProgramStringARB(arbvp.GL_VERTEX_PROGRAM_ARB, - arbvp.GL_PROGRAM_FORMAT_ASCII_ARB, - len(vertexProgramSrc), - vertexProgramSrc) - - except: - - position = gl.glGetIntegerv(arbvp.GL_PROGRAM_ERROR_POSITION_ARB) - message = gl.glGetString( arbvp.GL_PROGRAM_ERROR_STRING_ARB) - - raise RuntimeError('Error compiling vertex program ' - '({}): {}'.format(position, message)) - - # fragment program - try: - arbfp.glBindProgramARB(arbfp.GL_FRAGMENT_PROGRAM_ARB, - fragmentProgram) - - arbfp.glProgramStringARB(arbfp.GL_FRAGMENT_PROGRAM_ARB, - arbfp.GL_PROGRAM_FORMAT_ASCII_ARB, - len(fragmentProgramSrc), - fragmentProgramSrc) - except: - position = gl.glGetIntegerv(arbfp.GL_PROGRAM_ERROR_POSITION_ARB) - message = gl.glGetString( arbfp.GL_PROGRAM_ERROR_STRING_ARB) - - raise RuntimeError('Error compiling fragment program ' - '({}): {}'.format(position, message)) - - gl.glDisable(arbvp.GL_VERTEX_PROGRAM_ARB) - gl.glDisable(arbfp.GL_FRAGMENT_PROGRAM_ARB) - - return vertexProgram, fragmentProgram +ARBPShader = arbpprogram.ARBPShader def getVertexShader(prefix): diff --git a/fsl/fsleyes/gl/shaders/arbp/parse.py b/fsl/fsleyes/gl/shaders/arbp/parse.py index 7d3bb8f337d59a89bbcef7baf2b892399a075e5d..ea094e6a2186165988bf274ca14311e47f9b7497 100644 --- a/fsl/fsleyes/gl/shaders/arbp/parse.py +++ b/fsl/fsleyes/gl/shaders/arbp/parse.py @@ -50,31 +50,37 @@ def parseARBP(vertSrc, fragSrc): 'varying' : vVaryings} -def fillARBP(vertSrc, fragSrc, vertParams, fragParams, textures, attrs): +def fillARBP(vertSrc, + fragSrc, + vertParams, + vertParamLens, + fragParams, + fragParamLens, + textures, + attrs): - if vertParams is None: vertParams = {} - if fragParams is None: fragParams = {} - if textures is None: textures = {} - if attrs is None: attrs = {} - vertVars = _findDeclaredVariables(vertSrc) fragVars = _findDeclaredVariables(fragSrc) _checkVariableValidity( vertVars, fragVars, vertParams, fragParams, textures, attrs) - for name, (number, length) in vertParams.items(): + for name, number in vertParams.items(): + + length = vertParamLens[name] if length == 1: name = 'param_{}' .format(name) else: name = 'param{}_{}'.format(name, length) vertParams[name] = _param(number, length) - for name, (number, length) in fragParams.items(): + for name, number in fragParams.items(): + + length = fragParamLens[name] if length == 1: name = 'param_{}' .format(name) - else: name = 'param{}_{}'.format(name, length) - + else: name = 'param{}_{}'.format(length, name) + fragParams[name] = _param(number, length) textures = {'texture_{}'.format(n) : _texture(v) @@ -195,7 +201,7 @@ def _param(number, length): bits = ['program.local[{}]'.format(n) for n in range(number, number + length)] - return '{{ {} }}'.format(','.join(bits)) + return '{{ {} }}'.format(', '.join(bits)) def _texture(number): diff --git a/fsl/fsleyes/gl/shaders/arbp/program.py b/fsl/fsleyes/gl/shaders/arbp/program.py index 6c0386250299a73724374ea2f4989979b45b0f81..6d20a3abb67239453f15f1d9c90257fb40b96e6e 100644 --- a/fsl/fsleyes/gl/shaders/arbp/program.py +++ b/fsl/fsleyes/gl/shaders/arbp/program.py @@ -7,35 +7,175 @@ import logging +import numpy as np + import OpenGL.GL as gl import OpenGL.raw.GL._types as gltypes import OpenGL.GL.ARB.fragment_program as arbfp import OpenGL.GL.ARB.vertex_program as arbvp +import parse + log = logging.getLogger(__name__) class ARBPShader(object): - def __init__(self, - vertSrc, - fragSrc, - paramMap=None, - textureMap=None, - vertAttMap=None): + def __init__(self, vertSrc, fragSrc, textureMap=None): + + decs = parse.parseARBP(vertSrc, fragSrc) + + vParams = decs['vertParam'] + fParams = decs['fragParam'] + + if len(vParams) > 0: vParams, vLens = zip(*vParams) + else: vParams, vLens = [], [] + if len(fParams) > 0: fParams, fLens = zip(*fParams) + else: fParams, fLens = [], [] + + vLens = {name : length for name, length in zip(vParams, vLens)} + fLens = {name : length for name, length in zip(fParams, fLens)} + + self.vertParams = vParams + self.vertParamLens = vLens + self.fragParams = fParams + self.fragParamLens = fLens + self.textures = decs['texture'] + self.attrs = decs['attr'] + + poses = self.__generatePositions(textureMap) + vpPoses, fpPoses, texPoses, attrPoses = poses + + self.vertParamPositions = vpPoses + self.fragParamPositions = fpPoses + self.texturePositions = texPoses + self.attrPositions = attrPoses + + vertSrc, fragSrc = parse.fillARBP(vertSrc, + fragSrc, + self.vertParamPositions, + self.vertParamLens, + self.fragParamPositions, + self.fragParamLens, + self.texturePositions, + self.attrPositions) + + vp, fp = self.__compile(vertSrc, fragSrc) + + self.vertexProgram = vp + self.fragmentProgram = fp + - self.__vertexProgram = None - self.__fragmentProgram = None + def delete(self): + arbvp.glDeleteProgramsARB(1, gltypes.GLuint(self.vertexProgram)) + arbfp.glDeleteProgramsARB(1, gltypes.GLuint(self.fragmentProgram)) - if textureMap is None: textureMap = {} - if paramMap is None: paramMap = {} - if vertAttMap is None: vertAttMap = {} + def load(self): + gl.glEnable(arbvp.GL_VERTEX_PROGRAM_ARB) + gl.glEnable(arbfp.GL_FRAGMENT_PROGRAM_ARB) - def delete(self): - arbvp.glDeleteProgramsARB(1, gltypes.GLuint(self.__vertexProgram)) - arbfp.glDeleteProgramsARB(1, gltypes.GLuint(self.__fragmentProgram)) + arbvp.glBindProgramARB(arbvp.GL_VERTEX_PROGRAM_ARB, + self.vertexProgram) + arbfp.glBindProgramARB(arbfp.GL_FRAGMENT_PROGRAM_ARB, + self.fragmentProgram) + + for attr in self.attrs: + texUnit = self.__getAttrTexUnit(attr) + + gl.glClientActiveTexture(texUnit) + gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY) + + + def unload(self): + gl.glDisable(arbfp.GL_FRAGMENT_PROGRAM_ARB) + gl.glDisable(arbvp.GL_VERTEX_PROGRAM_ARB) + + for attr in self.attrs: + texUnit = self.__getAttrTexUnit(attr) + + gl.glClientActiveTexture(texUnit) + gl.glDisableClientState(gl.GL_TEXTURE_COORD_ARRAY) + + + def setVertParam(self, name, value): + + pos = self.vertParamPositions[name] + value = np.array(value, dtype=np.float32).reshape((-1, 4)) + + for i, row in enumerate(value): + arbvp.glProgramLocalParameter4fARB( + arbvp.GL_VERTEX_PROGRAM_ARB, pos + i, + row[0], row[1], row[2], row[3]) + + + def setFragParam(self, name, value): + + pos = self.fragParamPositions[name] + value = np.array(value, dtype=np.float32).reshape((-1, 4)) + + for i, row in enumerate(value): + arbfp.glProgramLocalParameter4fARB( + arbfp.GL_FRAGMENT_PROGRAM_ARB, pos + i, + row[0], row[1], row[2], row[3]) + + + def setAttr(self, name, value): + + texUnit = self.__getAttrTexUnit(name) + size = value.shape[1] + value = np.array(value, dtype=np.float32) + value = value.ravel('C') + + gl.glClientActiveTexture(texUnit) + gl.glTexCoordPointer(size, gl.GL_FLOAT, 0, value) + + + def __getAttrTexUnit(self, attr): + + pos = self.attrPositions[attr] + texUnit = 'GL_TEXTURE{}'.format(pos) + texUnit = getattr(gl, texUnit) + + return texUnit + + + def __generatePositions(self, textureMap=None): + + vpPoses = {} + fpPoses = {} + texPoses = {} + attrPoses = {} + + # Vertex parameters + pos = 0 + for name in self.vertParams: + vpPoses[name] = pos + pos += self.vertParamLens[name] + + # Fragment parameters + pos = 0 + for name in self.fragParams: + fpPoses[name] = pos + pos += self.fragParamLens[name] + + # Vertex attributes + for i, name in enumerate(self.attrs): + attrPoses[name] = i + + # Texture positions. If the caller did + # not provide a texture map in __init__, + # we'll generate some positions. + if textureMap is None: + + names = self.textures + poses = range(len(names)) + texPoses = {n : p for n, p in zip(names, poses)} + else: + texPoses = dict(textureMap) + + return vpPoses, fpPoses, texPoses, attrPoses def __compile(self, vertSrc, fragSrc): @@ -47,7 +187,12 @@ class ARBPShader(object): gl.glEnable(arbfp.GL_FRAGMENT_PROGRAM_ARB) fragProg = arbfp.glGenProgramsARB(1) - vertProg = arbvp.glGenProgramsARB(1) + vertProg = arbvp.glGenProgramsARB(1) + + # Make sure the source is plain + # ASCII - not unicode + vertSrc = str(vertSrc) + fragSrc = str(fragSrc) # vertex program try: