| """Convenience module providing common shader entry points |
| |
| The point of this module is to allow client code to use |
| OpenGL Core names to reference shader-related operations |
| even if the local hardware only supports ARB extension-based |
| shader rendering. |
| |
| There are also two utility methods compileProgram and compileShader |
| which make it easy to create demos which are shader-using. |
| """ |
| import logging |
| logging.basicConfig() |
| log = logging.getLogger( __name__ ) |
| from OpenGL.GLES2 import * |
| from OpenGL._bytes import bytes,unicode,as_8_bit |
|
|
| __all__ = [ |
| 'compileProgram', |
| 'compileShader', |
| ] |
|
|
| class ShaderProgram( int ): |
| """Integer sub-class with context-manager operation""" |
| def __enter__( self ): |
| """Start use of the program""" |
| glUseProgram( self ) |
| def __exit__( self, typ, val, tb ): |
| """Stop use of the program""" |
| glUseProgram( 0 ) |
| |
| def check_validate( self ): |
| """Check that the program validates |
| |
| Validation has to occur *after* linking/loading |
| |
| raises RuntimeError on failures |
| """ |
| glValidateProgram( self ) |
| validation = glGetProgramiv( self, GL_VALIDATE_STATUS ) |
| if validation == GL_FALSE: |
| raise RuntimeError( |
| """Validation failure (%s): %s"""%( |
| validation, |
| glGetProgramInfoLog( self ), |
| )) |
| return self |
|
|
| def check_linked( self ): |
| """Check link status for this program |
| |
| raises RuntimeError on failures |
| """ |
| link_status = glGetProgramiv( self, GL_LINK_STATUS ) |
| if link_status == GL_FALSE: |
| raise RuntimeError( |
| """Link failure (%s): %s"""%( |
| link_status, |
| glGetProgramInfoLog( self ), |
| )) |
| return self |
|
|
| def retrieve( self ): |
| """Attempt to retrieve binary for this compiled shader |
| |
| Note that binaries for a program are *not* generally portable, |
| they should be used solely for caching compiled programs for |
| local use; i.e. to reduce compilation overhead. |
| |
| returns (format,binaryData) for the shader program |
| """ |
| from OpenGL.raw.GL._types import GLint,GLenum |
| from OpenGL.arrays import GLbyteArray |
| size = GLint() |
| glGetProgramiv( self, get_program_binary.GL_PROGRAM_BINARY_LENGTH, size ) |
| result = GLbyteArray.zeros( (size.value,)) |
| size2 = GLint() |
| format = GLenum() |
| get_program_binary.glGetProgramBinary( self, size.value, size2, format, result ) |
| return format.value, result |
| def load( self, format, binary ): |
| """Attempt to load binary-format for a pre-compiled shader |
| |
| See notes in retrieve |
| """ |
| get_program_binary.glProgramBinary( self, format, binary, len(binary)) |
| self.check_validate() |
| self.check_linked() |
| return self |
|
|
| def compileProgram(*shaders, **named): |
| """Create a new program, attach shaders and validate |
| |
| shaders -- arbitrary number of shaders to attach to the |
| generated program. |
| separable (keyword only) -- set the separable flag to allow |
| for partial installation of shader into the pipeline (see |
| glUseProgramStages) |
| retrievable (keyword only) -- set the retrievable flag to |
| allow retrieval of the program binary representation, (see |
| glProgramBinary, glGetProgramBinary) |
| |
| This convenience function is *not* standard OpenGL, |
| but it does wind up being fairly useful for demos |
| and the like. You may wish to copy it to your code |
| base to guard against PyOpenGL changes. |
| |
| Usage: |
| |
| shader = compileProgram( |
| compileShader( source, GL_VERTEX_SHADER ), |
| compileShader( source2, GL_FRAGMENT_SHADER ), |
| ) |
| glUseProgram( shader ) |
| |
| Note: |
| If (and only if) validation of the linked program |
| *passes* then the passed-in shader objects will be |
| deleted from the GL. |
| |
| returns ShaderProgram() (GLuint) program reference |
| raises RuntimeError when a link/validation failure occurs |
| """ |
| program = glCreateProgram() |
| if named.get('separable'): |
| glProgramParameteri( program, separate_shader_objects.GL_PROGRAM_SEPARABLE, GL_TRUE ) |
| if named.get('retrievable'): |
| glProgramParameteri( program, get_program_binary.GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE ) |
| for shader in shaders: |
| glAttachShader(program, shader) |
| program = ShaderProgram( program ) |
| glLinkProgram(program) |
| program.check_validate() |
| program.check_linked() |
| for shader in shaders: |
| glDeleteShader(shader) |
| return program |
| def compileShader( source, shaderType ): |
| """Compile shader source of given type |
| |
| source -- GLSL source-code for the shader |
| shaderType -- GLenum GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, etc, |
| |
| returns GLuint compiled shader reference |
| raises RuntimeError when a compilation failure occurs |
| """ |
| if isinstance( source, (bytes,unicode)): |
| source = [ source ] |
| source = [ as_8_bit(s) for s in source ] |
| shader = glCreateShader(shaderType) |
| glShaderSource( shader, source ) |
| glCompileShader( shader ) |
| result = glGetShaderiv( shader, GL_COMPILE_STATUS ) |
| if result == GL_FALSE: |
| |
| |
| raise RuntimeError( |
| """Shader compile failure (%s): %s"""%( |
| result, |
| glGetShaderInfoLog( shader ), |
| ), |
| source, |
| shaderType, |
| ) |
| return shader |
|
|