Sources/Classes/Application/Model/OpenGL/Shaders/OpenGLShaderBase.m
//------------------------------------------------------------------------------// |
// File: OpenGLShaderBase.m |
// |
// Abstract: Utility toolkit for fragement and vertex shaders |
// |
// Disclaimer: IMPORTANT: This Apple software is supplied to you by |
// 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 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) 2007-2009, 2012 Apple Inc., All rights reserved. |
// |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
#import "OpenGLShaderBase.h" |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
#pragma mark - |
#pragma mark Private - Data Structure |
//------------------------------------------------------------------------------ |
struct OpenGLShaderBaseData |
{ |
NSString *mpSourceFragment; // the GLSL source for our fragment Shader |
NSString *mpSourceVertex; // the GLSL source for our vertex Shader |
GLuint mnShaderVertex; // Vertex shader id |
GLuint mnShaderFragment; // Fragment shader id |
GLuint mnProgramObject; // the program object id |
}; |
typedef struct OpenGLShaderBaseData OpenGLShaderBaseData; |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
#pragma mark - |
#pragma mark Private - Utilities - Loaders |
//------------------------------------------------------------------------------ |
static NSString *OpenGLShaderBaseLoadShaderSourceFromResource(NSString *pShaderResourceName, |
NSString *pExtension) |
{ |
NSString *pShaderSource = NULL; |
NSBundle *pAppBundle = [NSBundle mainBundle]; |
if( pAppBundle ) |
{ |
NSString *pShaderPathname = [pAppBundle pathForResource:pShaderResourceName |
ofType:pExtension]; |
if( pShaderPathname ) |
{ |
pShaderSource = [[NSString alloc] initWithContentsOfFile:pShaderPathname |
encoding:NSUTF8StringEncoding |
error:NULL]; |
} // if |
} // if |
return pShaderSource; |
} // OpenGLShaderBaseLoadShaderSourceFromResource |
//------------------------------------------------------------------------------ |
static void OpenGLShaderBaseSetSource(const GLenum nShaderType, |
NSString *pShaderPathname, |
OpenGLShaderBaseDataRef pSShader) |
{ |
if( pShaderPathname != NULL ) |
{ |
switch( nShaderType ) |
{ |
case GL_VERTEX_SHADER: |
pSShader->mpSourceVertex |
= OpenGLShaderBaseLoadShaderSourceFromResource(pShaderPathname, @"vs"); |
break; |
case GL_FRAGMENT_SHADER: |
default: |
pSShader->mpSourceFragment |
= OpenGLShaderBaseLoadShaderSourceFromResource(pShaderPathname, @"fs"); |
break; |
} // switch |
} // if |
else |
{ |
NSLog(@">> WARNING: OpenGL Shader Base - Pathname to shader is NULL!"); |
} // if |
} // OpenGLShaderBaseSetSource |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
#pragma mark - |
#pragma mark Private - Utilities - Accessors |
//------------------------------------------------------------------------------ |
static const GLchar *OpenGLShaderBaseGetShaderSource(const GLenum nShaderType, |
OpenGLShaderBaseDataRef pSShader) |
{ |
NSString *pShaderSource = nil; |
switch( nShaderType ) |
{ |
case GL_VERTEX_SHADER: |
pShaderSource = pSShader->mpSourceVertex; |
break; |
case GL_FRAGMENT_SHADER: |
default: |
pShaderSource = pSShader->mpSourceFragment; |
break; |
} // switch |
return [pShaderSource cStringUsingEncoding:NSUTF8StringEncoding]; |
} // OpenGLShaderBaseGetShaderSource |
//------------------------------------------------------------------------------ |
static void OpenGLShaderBaseSetShader(const GLenum nShaderType, |
const GLuint nShaderObject, |
OpenGLShaderBaseDataRef pSShader) |
{ |
switch( nShaderType ) |
{ |
case GL_VERTEX_SHADER: |
pSShader->mnShaderVertex = nShaderObject; |
break; |
case GL_FRAGMENT_SHADER: |
default: |
pSShader->mnShaderFragment = nShaderObject; |
break; |
} // switch |
} // OpenGLShaderBaseSetShader |
//------------------------------------------------------------------------------ |
static GLint OpenGLShaderBaseGetUniformLocation(NSString *pUniformName, |
OpenGLShaderBaseDataRef pSShader) |
{ |
GLint nUniformLoacation = -1; |
if( pSShader->mnProgramObject && pUniformName ) |
{ |
const char *pUniformString = [pUniformName cStringUsingEncoding:NSASCIIStringEncoding]; |
if( pUniformString != NULL ) |
{ |
nUniformLoacation = glGetUniformLocation(pSShader->mnProgramObject, |
pUniformString); |
if( nUniformLoacation == -1 ) |
{ |
NSLog( @">> WARNING: OpenGL Shader Base - No such uniform named \"%s\"!", pUniformString ); |
} // if |
} // if |
else |
{ |
NSLog( @">> ERROR: OpenGL Shader Base - Null uniform name!" ); |
} // if |
} // if |
else |
{ |
NSLog( @">> ERROR: OpenGL Shader Base - Invalid parameters!" ); |
} // if |
return nUniformLoacation; |
} // OpenGLShaderBaseGetUniformLocation |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
#pragma mark - |
#pragma mark Private - Utilities - Destructors |
//------------------------------------------------------------------------------ |
static void OpenGLShaderBaseDeleteProgram(OpenGLShaderBaseDataRef pSShader) |
{ |
if( pSShader->mnProgramObject ) |
{ |
if( pSShader->mnShaderVertex ) |
{ |
glDeleteShader(pSShader->mnShaderVertex); |
} // if |
if( pSShader->mnShaderFragment ) |
{ |
glDeleteShader(pSShader->mnShaderFragment); |
} // if |
// Delete the program |
glDeleteProgram(pSShader->mnProgramObject); |
glUseProgram(0); |
} // if |
} // OpenGLShaderBaseDeleteProgram |
//------------------------------------------------------------------------------ |
static void OpenGLShaderBaseDelete(OpenGLShaderBaseDataRef pSShader) |
{ |
if( pSShader != NULL ) |
{ |
OpenGLShaderBaseDeleteProgram(pSShader); |
free(pSShader); |
pSShader = NULL; |
} // if |
} // OpenGLShaderBaseDelete |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
#pragma mark - |
#pragma mark Private - Utilities - Constructors |
//------------------------------------------------------------------------------ |
static void OpenGLShaderBaseCompileShader(const GLenum nShaderType, |
GLuint nShaderObject, |
OpenGLShaderBaseDataRef pSShader) |
{ |
GLint nInfoLogLength = 0; |
const GLchar *pShaderSource = OpenGLShaderBaseGetShaderSource(nShaderType, |
pSShader); |
glShaderSource(nShaderObject, 1, &pShaderSource, NULL); |
glCompileShader(nShaderObject); |
glGetShaderiv(nShaderObject, GL_INFO_LOG_LENGTH, &nInfoLogLength); |
if( nInfoLogLength > 0 ) |
{ |
GLchar *pInfoLog = (GLchar *)malloc(nInfoLogLength); |
if( pInfoLog != NULL ) |
{ |
glGetShaderInfoLog(nShaderObject, |
nInfoLogLength, |
&nInfoLogLength, |
pInfoLog); |
NSLog(@">> INFO: OpenGL Shader Base - Shader compile log:\n%s\n", pInfoLog); |
free(pInfoLog); |
} // if |
} // if |
} // OpenGLShaderBaseCompileShader |
//------------------------------------------------------------------------------ |
static BOOL OpenGLShaderBaseValidateShader(const GLenum nShaderType, |
GLuint nShaderObject, |
OpenGLShaderBaseDataRef pSShader) |
{ |
GLint nIsCompiled = 0; |
glGetShaderiv(nShaderObject, GL_COMPILE_STATUS, &nIsCompiled); |
if( nIsCompiled == 0 ) |
{ |
const GLchar *pShaderSource = OpenGLShaderBaseGetShaderSource(nShaderType, |
pSShader); |
NSLog(@">> WARNING: OpenGL Shader Base - Failed to compile shader!\n%s\n", pShaderSource); |
NSLog(@">> WARNING: OpenGL Shader Base - Deleted shader object!"); |
glDeleteShader(nShaderObject); |
} // if |
else |
{ |
OpenGLShaderBaseSetShader(nShaderType, nShaderObject, pSShader); |
} // else |
return nIsCompiled != 0; |
} // OpenGLShaderBaseValidateShader |
//------------------------------------------------------------------------------ |
static void OpenGLShaderBaseDeleteShaderSource(const GLenum nShaderType, |
OpenGLShaderBaseDataRef pSShader) |
{ |
NSString *pShaderSource = nil; |
switch( nShaderType ) |
{ |
case GL_VERTEX_SHADER: |
pShaderSource = pSShader->mpSourceVertex; |
break; |
case GL_FRAGMENT_SHADER: |
default: |
pShaderSource = pSShader->mpSourceFragment; |
break; |
} // switch |
if(pShaderSource) |
{ |
[pShaderSource release]; |
pShaderSource = nil; |
} // if |
} // OpenGLShaderBaseDeleteShaderSource |
//------------------------------------------------------------------------------ |
static BOOL OpenGLShaderBaseCreateShader(const GLenum nShaderType, |
OpenGLShaderBaseDataRef pSShader) |
{ |
BOOL bSuccess = NO; |
GLuint nShaderObject = glCreateShader(nShaderType); |
if( nShaderObject ) |
{ |
OpenGLShaderBaseCompileShader(nShaderType, |
nShaderObject, |
pSShader); |
OpenGLShaderBaseDeleteShaderSource(nShaderType, |
pSShader); |
bSuccess = OpenGLShaderBaseValidateShader(nShaderType, |
nShaderObject, |
pSShader); |
} // if |
return bSuccess; |
} // OpenGLShaderBaseCreateShader |
//------------------------------------------------------------------------------ |
static BOOL OpenGLShaderBaseLinkProgram(OpenGLShaderBaseDataRef pSShader) |
{ |
GLint nInfoLogLength = 0; |
GLint nProgramLinked = 0; |
glLinkProgram(pSShader->mnProgramObject); |
glGetProgramiv(pSShader->mnProgramObject, |
GL_INFO_LOG_LENGTH, |
&nInfoLogLength); |
if( nInfoLogLength > 0 ) |
{ |
GLchar *pInfoLog = (GLchar *)malloc(nInfoLogLength); |
if( pInfoLog != NULL ) |
{ |
glGetProgramInfoLog(pSShader->mnProgramObject, |
nInfoLogLength, |
&nInfoLogLength, |
pInfoLog); |
NSLog(@">> INFO: OpenGL Shader Base - Program link log:\n%s\n", pInfoLog); |
free(pInfoLog); |
} // if |
} // if |
glGetProgramiv(pSShader->mnProgramObject, |
GL_LINK_STATUS, |
&nProgramLinked); |
if( nProgramLinked == 0 ) |
{ |
NSLog(@">> WARNING: OpenGL Shader Base - Failed to link program!"); |
} // if |
return nProgramLinked != 0; |
} // OpenGLShaderBaseLinkProgram |
//------------------------------------------------------------------------------ |
static BOOL OpenGLShaderBaseAcquireProgram(OpenGLShaderBaseDataRef pSShader) |
{ |
BOOL bIsValidProgram = NO; |
// Create a program object and link shaders |
pSShader->mnProgramObject = glCreateProgram(); |
if( pSShader->mnProgramObject ) |
{ |
if( pSShader->mnShaderVertex ) |
{ |
glAttachShader(pSShader->mnProgramObject, |
pSShader->mnShaderVertex); |
} // if |
if( pSShader->mnShaderFragment ) |
{ |
glAttachShader(pSShader->mnProgramObject, |
pSShader->mnShaderFragment); |
} // if |
bIsValidProgram = OpenGLShaderBaseLinkProgram(pSShader); |
if( !bIsValidProgram ) |
{ |
OpenGLShaderBaseDeleteProgram(pSShader); |
} // if |
} // if |
return bIsValidProgram; |
} // OpenGLShaderBaseAcquireProgram |
//------------------------------------------------------------------------------ |
static BOOL OpenGLShaderBaseNewProgram(OpenGLShaderBaseDataRef pSShader) |
{ |
// Load and compile both shaders |
OpenGLShaderBaseCreateShader(GL_VERTEX_SHADER, pSShader); |
OpenGLShaderBaseCreateShader(GL_FRAGMENT_SHADER, pSShader); |
// Create a program object and link both shaders |
BOOL bSuccess = OpenGLShaderBaseAcquireProgram(pSShader); |
return bSuccess; |
} // OpenGLShaderBaseNewProgram |
//------------------------------------------------------------------------------ |
static BOOL OpenGLShaderBaseValidateProgram(OpenGLShaderBaseDataRef pSShader) |
{ |
GLint nInfoLogLength = 0; |
GLint nIsValidated = 0; |
glValidateProgram(pSShader->mnProgramObject); |
glGetProgramiv(pSShader->mnProgramObject, |
GL_INFO_LOG_LENGTH, |
&nInfoLogLength); |
if( nInfoLogLength > 0 ) |
{ |
GLchar *infoLog = (GLchar *)malloc(nInfoLogLength); |
if( infoLog != NULL ) |
{ |
glGetProgramInfoLog(pSShader->mnProgramObject, |
nInfoLogLength, |
&nInfoLogLength, |
infoLog); |
NSLog(@">> INFO: OpenGL Shader Base - Program validate log:\n%s\n", infoLog); |
free(infoLog); |
} // if |
} // if |
glGetProgramiv(pSShader->mnProgramObject, |
GL_VALIDATE_STATUS, |
&nIsValidated); |
if( nIsValidated == 0 ) |
{ |
NSLog(@">> WARNING: OpenGL Shader Base - Failed to validate program!"); |
} // if |
return nIsValidated != 0; |
} // OpenGLShaderBaseValidateProgram |
//------------------------------------------------------------------------------ |
static BOOL OpenGLShaderBaseCreateProgram(const BOOL bValidate, |
OpenGLShaderBaseDataRef pSShader) |
{ |
BOOL bSuccess = OpenGLShaderBaseNewProgram(pSShader); |
if( !bSuccess ) |
{ |
NSLog(@">> WARNING: OpenGL Shader Base - Failed to create the program object!"); |
} // if |
else |
{ |
if( bValidate ) |
{ |
bSuccess = OpenGLShaderBaseValidateProgram(pSShader); |
if( !bSuccess ) |
{ |
NSLog(@">> WARNING: OpenGL Shader Base - Failed to validate the program object!"); |
} // if |
} // if |
} // else |
return bSuccess; |
} // OpenGLShaderBaseCreateProgram |
//------------------------------------------------------------------------------ |
static OpenGLShaderBaseDataRef OpenGLShaderBaseCreate(const BOOL bValidate, |
NSString *pShadersName) |
{ |
OpenGLShaderBaseDataRef pSShader = (OpenGLShaderBaseDataRef)calloc(1, sizeof(OpenGLShaderBaseData)); |
if( pSShader != NULL ) |
{ |
OpenGLShaderBaseSetSource(GL_VERTEX_SHADER, pShadersName, pSShader); |
OpenGLShaderBaseSetSource(GL_FRAGMENT_SHADER, pShadersName, pSShader); |
BOOL bSuccess = OpenGLShaderBaseCreateProgram(bValidate, pSShader); |
if( !bSuccess ) |
{ |
NSLog( @">> ERROR: OpenGL Shader Base - Failed to create & validate the program for the \"%@\" shader",pShadersName ); |
} // if |
} // if |
else |
{ |
NSLog( @">> ERROR: OpenGL Shader Base - Failure Allocating backing store for the data!" ); |
} // else |
return pSShader; |
} // OpenGLShaderBaseCreate |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
#pragma mark - |
#pragma mark Public - Interfaces |
//------------------------------------------------------------------------------ |
@implementation OpenGLShaderBase |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
#pragma mark - |
#pragma mark Public - Constructors |
//--------------------------------------------------------------------------- |
// |
// Make sure client goes through designated initializer |
// |
//--------------------------------------------------------------------------- |
- (id) init |
{ |
[self doesNotRecognizeSelector:_cmd]; |
return nil; |
} // init |
//------------------------------------------------------------------------------ |
- (id) initWithShaderSourcesInAppBundle:(NSString *)theShadersName |
validate:(const BOOL)theShaderNeedsValidation; |
{ |
self = [super init]; |
if( self ) |
{ |
mpShaderBase = OpenGLShaderBaseCreate(theShaderNeedsValidation, |
theShadersName); |
} // if |
return self; |
} // initWithShaderSourcesInAppBundle |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
#pragma mark - |
#pragma mark Public - Destructor |
//------------------------------------------------------------------------------ |
- (void) dealloc |
{ |
OpenGLShaderBaseDelete(mpShaderBase); |
[super dealloc]; |
} // dealloc |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
#pragma mark - |
#pragma mark Public - Accessors |
//------------------------------------------------------------------------------ |
- (GLuint) programObject |
{ |
return( mpShaderBase->mnProgramObject ); |
} // programObject |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
#pragma mark - |
#pragma mark Public - Utilities |
//------------------------------------------------------------------------------ |
- (void) enable |
{ |
glUseProgram(mpShaderBase->mnProgramObject); |
} // enable |
//------------------------------------------------------------------------------ |
- (void) disable |
{ |
glUseProgram(0); |
} // disable |
//------------------------------------------------------------------------------ |
- (GLint) uniformLocation:(NSString *)pUniformName |
{ |
return OpenGLShaderBaseGetUniformLocation(pUniformName, mpShaderBase); |
} // uniformLocation |
//------------------------------------------------------------------------------ |
@end |
//------------------------------------------------------------------------------ |
//------------------------------------------------------------------------------ |
Copyright © 2013 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2013-01-02