Sources/Toolkits/Classes/OpenGLFragmentShaderUtilityToolkit.m
//--------------------------------------------------------------------------- |
// |
// File: OpenGLFragmentShaderUtilityToolkit.m |
// |
// Abstract: Utility class for compiling a fragment shader and binding |
// it to a program object |
// |
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple |
// Computer, Inc. ("Apple") in consideration of your agreement to the |
// following terms, and your use, installation, modification or |
// redistribution of this Apple software constitutes acceptance of these |
// terms. If you do not agree with these terms, please do not use, |
// install, modify or redistribute this Apple software. |
// |
// In consideration of your agreement to abide by the following terms, and |
// subject to these terms, Apple grants you a personal, non-exclusive |
// license, under Apple's copyrights in this original Apple software (the |
// "Apple Software"), to use, reproduce, modify and redistribute the Apple |
// Software, with or without modifications, in source and/or binary forms; |
// provided that if you redistribute the Apple Software in its entirety and |
// without modifications, you must retain this notice and the following |
// text and disclaimers in all such redistributions of the Apple Software. |
// Neither the name, trademarks, service marks or logos of Apple Computer, |
// Inc. may be used to endorse or promote products derived from the Apple |
// Software without specific prior written permission from Apple. Except |
// as expressly stated in this notice, no other rights or licenses, express |
// or implied, are granted by Apple herein, including but not limited to |
// any patent rights that may be infringed by your derivative works or by |
// other works in which the Apple Software may be incorporated. |
// |
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
// |
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
// POSSIBILITY OF SUCH DAMAGE. |
// |
// Copyright (c) 2008 Apple Inc., All rights reserved. |
// |
//--------------------------------------------------------------------------- |
//------------------------------------------------------------------------ |
#import <OpenGL/gl.h> |
#import <OpenGL/OpenGL.h> |
#import "OpenGLAlertsUtilityToolkit.h" |
#import "OpenGLFragmentShaderUtilityToolkit.h" |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
struct FragmentShaderAttributes |
{ |
GLint *uniformLocation; // A parameter to the fragment program |
GLuint uniformCount; // the number of uniforms |
GLhandleARB programObject; // The program used to update |
BOOL fragmentShaderIsInstalled; // True if the fragment shader installed |
}; |
typedef struct FragmentShaderAttributes FragmentShaderAttributes; |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
#pragma mark -- Compiling, link & bind to a program object -- |
//------------------------------------------------------------------------ |
static GLvoid DisplayAlertWithStatus( GLenum theStatus ) |
{ |
OpenGLAlertsUtilityToolkit *alert = [OpenGLAlertsUtilityToolkit withAlertType:alertIsForOpenGLShaders]; |
if ( alert ) |
{ |
[alert displayAlertBox:theStatus]; |
} // if |
} // DisplayAlertWithStatus |
//------------------------------------------------------------------------ |
static GLhandleARB LoadShader( GLenum theShaderType, const GLcharARB **theShader, GLint *theShaderCompiled ) |
{ |
GLhandleARB shaderObj = NULL; |
if ( theShader != NULL ) |
{ |
GLint infoLogLength = 0; |
// For details on glCreateShaderObjectARB refer to: |
// |
// http://developer.3dlabs.com/openGL2/slapi/CreateShaderObjectARB.htm |
shaderObj = glCreateShaderObjectARB( theShaderType ); |
// For details onn glShaderSourceARB refer to: |
// |
// http://developer.3dlabs.com/openGL2/slapi/ShaderSourceARB.htm |
glShaderSourceARB( shaderObj, 1, theShader, NULL ); |
// For details on glCompileShaderARB refer to: |
// |
// http://developer.3dlabs.com/openGL2/slapi/CompileShaderARB.htm |
glCompileShaderARB( shaderObj ); |
// For details on glGetObjectParameterARB refer to: |
// |
// http://developer.3dlabs.com/openGL2/slapi/GetObjectParameterARB.htm |
glGetObjectParameterivARB( shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infoLogLength ); |
if ( infoLogLength > 0 ) |
{ |
GLchar *infoLog = (GLchar *)malloc( infoLogLength ); |
if ( infoLog != NULL ) |
{ |
// For details on glGetInfoLogARB refer to: |
// |
// http://developer.3dlabs.com/openGL2/slapi/GetInfoLogARB.htm |
glGetInfoLogARB( shaderObj, infoLogLength, &infoLogLength, infoLog ); |
NSLog( @">> MESSAGE: Shader compile log:\n%s\n", infoLog ); |
free( infoLog ); |
} // if |
} // if |
glGetObjectParameterivARB( shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, theShaderCompiled ); |
if ( *theShaderCompiled == 0 ) |
{ |
DisplayAlertWithStatus( GL_OBJECT_COMPILE_STATUS_ARB ); |
NSLog( @">> ERROR: Failed to compile shader %s\n", theShader ); |
} // if |
} // if |
else |
{ |
*theShaderCompiled = 0; |
} // else |
return shaderObj; |
} // LoadShader |
//------------------------------------------------------------------------ |
static BOOL GetFragmentShader( const GLchar *theFragmentShaderSource, GLhandleARB *theFragmentShader ) |
{ |
GLhandleARB fragmentShader = NULL; // the fragment shader to update |
GLint fragmentShaderCompiled = 0; |
BOOL fragmentShaderCompilationSuccess = YES; |
// Load and compile both shaders |
fragmentShader = LoadShader( GL_FRAGMENT_SHADER_ARB, &theFragmentShaderSource, &fragmentShaderCompiled ); |
// Ensure both shaders compiled |
if ( !fragmentShaderCompiled ) |
{ |
if ( fragmentShader != NULL ) |
{ |
// For details on glDeleteObjectARB refer to: |
// |
// http://developer.3dlabs.com/openGL2/slapi/DeleteObjectARB.htm |
glDeleteObjectARB( fragmentShader ); |
fragmentShader = NULL; |
} // if |
fragmentShaderCompilationSuccess = NO; |
} // if |
*theFragmentShader = fragmentShader; |
return fragmentShaderCompilationSuccess; |
} // GetFragmentShader |
//------------------------------------------------------------------------ |
static BOOL LinkProgram( GLhandleARB theProgramObject ) |
{ |
GLint infoLogLength = 0; |
GLint programLinked = 0; |
BOOL programLinkSuccess = YES; |
// For details on glLinkProgramARB refer to: |
// |
// http://developer.3dlabs.com/openGL2/slapi/LinkProgramARB.htm |
glLinkProgramARB( theProgramObject ); |
glGetObjectParameterivARB( theProgramObject , GL_OBJECT_INFO_LOG_LENGTH_ARB, &infoLogLength ); |
if ( infoLogLength > 0) |
{ |
GLchar *infoLog = (GLchar *)malloc( infoLogLength ); |
glGetInfoLogARB( theProgramObject, infoLogLength, &infoLogLength, infoLog ); |
NSLog( @">> MESSAGE: Program link log:\n%s\n", infoLog ); |
free( infoLog ); |
} // if |
glGetObjectParameterivARB( theProgramObject, GL_OBJECT_LINK_STATUS_ARB, &programLinked ); |
if ( programLinked == 0 ) |
{ |
DisplayAlertWithStatus( GL_OBJECT_LINK_STATUS_ARB ); |
NSLog( @">> ERROR: Failed to link program %ld\n", (GLint)theProgramObject ); |
programLinkSuccess = NO; |
} // if |
return programLinkSuccess; |
} // LinkProgram |
//------------------------------------------------------------------------ |
static BOOL GetProgramObject( GLhandleARB *theFragmentShader, GLhandleARB *theProgramObject ) |
{ |
BOOL programLinked = YES; |
// Create a program object and link with the fragment shaders |
// For details on glCreateProgramObjectARB refer to: |
// |
// http://developer.3dlabs.com/openGL2/slapi/CreateProgramObjectARB.htm |
*theProgramObject = glCreateProgramObjectARB(); |
if ( *theFragmentShader != NULL ) |
{ |
// For details on glAttachObjectARB refer to: |
// |
// http://developer.3dlabs.com/openGL2/slapi/AttachObjectARB.htm |
glAttachObjectARB( *theProgramObject, *theFragmentShader ); |
glDeleteObjectARB( *theFragmentShader); // Release |
*theFragmentShader = NULL; |
} // if |
programLinked = LinkProgram( *theProgramObject ); |
if ( !programLinked ) |
{ |
glDeleteObjectARB( *theProgramObject ); |
*theProgramObject = NULL; |
programLinked = NO; |
} // if |
return programLinked; |
} // GetProgramObject |
//------------------------------------------------------------------------ |
static GLint *GetUniformLocationsFromNames( GLhandleARB theProgramObject, NSArray *theUniformKeys ) |
{ |
GLint *theUniformLocation = NULL; |
if ( theUniformKeys ) |
{ |
GLuint theUniformLocationsCount = [theUniformKeys count]; |
theUniformLocation = (GLint *)malloc( theUniformLocationsCount * sizeof(GLint) ); |
if ( theUniformLocation != NULL ) |
{ |
id theUniformKey = nil; |
GLcharARB *theUniformName = NULL; |
GLint theUniformLocationIndex = 0; |
for (theUniformKey in theUniformKeys) |
{ |
theUniformName = (GLcharARB *)[theUniformKey cStringUsingEncoding:NSASCIIStringEncoding]; |
// For details on glGetUniformLocationARB refer to: |
// |
// http://developer.3dlabs.com/openGL2/slapi/GetUniformLocationARB.htm |
theUniformLocation[theUniformLocationIndex] = glGetUniformLocationARB( theProgramObject, theUniformName ); |
theUniformLocationIndex++; |
} // for |
} // if |
} // if |
return theUniformLocation; |
} // GetUniformNamesFromArray |
//------------------------------------------------------------------------ |
static BOOL GetNewProgramObject( const GLchar *theFragmentShaderSource, |
NSArray *theUniformKeys, |
FragmentShaderAttributesRef theFragmentShaderAttributesRef ) |
{ |
GLhandleARB programObject = NULL; // the program used to update |
GLhandleARB fragmentShader = NULL; // the fragment shader to update |
BOOL gotProgramObject = NO; |
// Load and compile the fragment shader and bind this to a program object |
if ( GetFragmentShader( theFragmentShaderSource, &fragmentShader ) ) |
{ |
// If we succeeded in compiling the fragment shader, now link and |
// bind it to a program object |
if( GetProgramObject( &fragmentShader, &programObject ) ) |
{ |
// Get location of the uniform(s) |
theFragmentShaderAttributesRef->programObject = programObject; |
theFragmentShaderAttributesRef->uniformLocation = GetUniformLocationsFromNames( programObject, theUniformKeys ); |
theFragmentShaderAttributesRef->uniformCount = [theUniformKeys count]; |
gotProgramObject = YES; |
} // if |
} // if |
return gotProgramObject; |
} // GetNewProgramObject |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
#pragma mark -- Load the fragment shader source -- |
//------------------------------------------------------------------------ |
static GLcharARB *GetFragmentShaderSourceFromResource( NSString *theFragmentShaderResourceName ) |
{ |
GLcharARB *fragmentShaderSource = NULL; |
NSBundle *applicationBundle = [NSBundle mainBundle]; |
if ( applicationBundle ) |
{ |
// Load the fragment shader source (text file) from the application bundle |
NSString *fragmentShaderTempSource = [applicationBundle pathForResource:theFragmentShaderResourceName ofType: @"frag"]; |
if ( fragmentShaderTempSource ) |
{ |
// Convert the shader source from a NSString into a C-string |
fragmentShaderTempSource = [NSString stringWithContentsOfFile:fragmentShaderTempSource]; |
fragmentShaderSource = (GLcharARB *)[fragmentShaderTempSource cStringUsingEncoding:NSASCIIStringEncoding]; |
} //if |
} // if |
return fragmentShaderSource; |
} // getFragmentShaderSourceFromResource |
//------------------------------------------------------------------------ |
// |
// A fragment shader represents a computational kernel applied in parallel |
// to multiple fragments simultaneously. |
// |
//------------------------------------------------------------------------ |
static BOOL GetFragmentShaderFromSource( NSString *theFragmentshaderName, |
NSArray *theUniformKeys, |
FragmentShaderAttributesRef theFragmentShaderAttributesRef ) |
{ |
BOOL fragmentShaderIsLoaded = NO; |
// Get the GLSL fragment shader source (a text file) from the |
// application bundle and return it as a C-String |
GLcharARB *fragmentShaderSource = GetFragmentShaderSourceFromResource( theFragmentshaderName ); |
if ( fragmentShaderSource != NULL ) |
{ |
// Get the program object by first compiling the fragment shader source, |
// then linking the compiled shader, and binding it to a program object |
fragmentShaderIsLoaded = GetNewProgramObject( fragmentShaderSource, theUniformKeys, theFragmentShaderAttributesRef ); |
if ( !fragmentShaderIsLoaded ) |
{ |
NSLog( @">> ERROR: Failed to load, compile and bind the fragment \"%@\" shader to the program object!\n", theFragmentshaderName ); |
} // if |
} // if |
return fragmentShaderIsLoaded; |
} // GetFragmentShaderFromSource |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
#pragma mark -- Handling opaque data reference memory -- |
//------------------------------------------------------------------------ |
static FragmentShaderAttributesRef CallocFragmentShaderAttributesRef( ) |
{ |
FragmentShaderAttributesRef fragmentShaderAttributes = (FragmentShaderAttributesRef)malloc( sizeof( FragmentShaderAttributes ) ); |
if ( fragmentShaderAttributes != NULL ) |
{ |
fragmentShaderAttributes->programObject = NULL; |
fragmentShaderAttributes->uniformLocation = NULL; |
fragmentShaderAttributes->uniformCount = 0; |
fragmentShaderAttributes->fragmentShaderIsInstalled = NO; |
} // if |
return fragmentShaderAttributes; |
} // CallocFragmentShaderAttributesRef |
//------------------------------------------------------------------------ |
static GLvoid FreeFragmentShaderAttributesRef( FragmentShaderAttributesRef theFragmentShaderAttributesRef ) |
{ |
// Delete OpenGL resources |
if ( theFragmentShaderAttributesRef->programObject != NULL ) |
{ |
glDeleteObjectARB( theFragmentShaderAttributesRef->programObject ); |
} // if |
if ( theFragmentShaderAttributesRef->uniformLocation != NULL ) |
{ |
free( theFragmentShaderAttributesRef->uniformLocation ); |
} // if |
if ( theFragmentShaderAttributesRef != NULL ) |
{ |
free( theFragmentShaderAttributesRef ); |
} // if |
theFragmentShaderAttributesRef = NULL; |
} // FreeFragmentShaderAttributesRef |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
@implementation OpenGLFragmentShaderUtilityToolkit |
//------------------------------------------------------------------------ |
- (id) initWithFragmentShaderInAppBundle:(NSString *)theFragmentShaderName |
uniformKeys:(NSArray *)theUniformKeys |
bounds:(NSRect)thebounds |
{ |
self = [super initWithBounds:thebounds]; |
if ( theFragmentShaderName != nil ) |
{ |
fragmentShaderAttributes = CallocFragmentShaderAttributesRef( ); |
if ( fragmentShaderAttributes != NULL ) |
{ |
fragmentShaderAttributes->fragmentShaderIsInstalled |
= GetFragmentShaderFromSource( theFragmentShaderName, |
theUniformKeys, |
fragmentShaderAttributes ); |
} // if |
} // if |
return self; |
} // initWithFragmentShaderInAppBundle |
//------------------------------------------------------------------------ |
- (void) dealloc |
{ |
// Delete OpenGL resources |
FreeFragmentShaderAttributesRef( fragmentShaderAttributes ); |
// Notify the superclass |
[super dealloc]; |
} // dealloc |
//------------------------------------------------------------------------ |
- (GLint *) uniformLocation |
{ |
return fragmentShaderAttributes->uniformLocation; |
} // uniformLocation |
//------------------------------------------------------------------------ |
- (GLuint) uniformCount |
{ |
return fragmentShaderAttributes->uniformCount; |
} // uniformCount |
//------------------------------------------------------------------------ |
- (void) enable |
{ |
// For details on glUseProgramObjectARB refer to: |
// |
// http://developer.3dlabs.com/openGL2/slapi/UseProgramObjectARB.htm |
glUseProgramObjectARB( fragmentShaderAttributes->programObject ); |
} // enable |
//------------------------------------------------------------------------ |
- (void) disable |
{ |
glUseProgramObjectARB( NULL ); |
} // disable |
//------------------------------------------------------------------------ |
// |
// Run the fragment shader over the geometry/model texture. |
// |
//------------------------------------------------------------------------ |
- (void) execute |
{ |
// Enable the computational kernel |
glUseProgramObjectARB( fragmentShaderAttributes->programObject ); |
// Generate data in the form of a quad the size of our viewport |
[self quads]; |
// Disable the computational kernel |
glUseProgramObjectARB( NULL ); |
} // execute |
//------------------------------------------------------------------------ |
- (BOOL) installed |
{ |
return fragmentShaderAttributes->fragmentShaderIsInstalled; |
} // installed |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
@end |
//------------------------------------------------------------------------ |
//------------------------------------------------------------------------ |
Copyright © 2008 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2008-02-06