shader.cpp
// |
// File: shader.cpp |
// |
// Version: <1.0> |
// |
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 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 ) 2008 Apple Inc. All Rights Reserved. |
// |
//////////////////////////////////////////////////////////////////////////////////////////////////// |
#include <stdio.h> |
#include "shader.h" |
#include "data_loader.h" |
//////////////////////////////////////////////////////////////////////////////// |
Shader::Shader() : |
m_uiProgram(0) |
{ |
m_akUniforms.clear(); |
} |
Shader::~Shader() |
{ |
destroy(); |
} |
void |
Shader::destroy() |
{ |
if(m_uiProgram) |
glDeleteProgram(m_uiProgram); |
m_uiProgram = 0; |
m_akUniforms.clear(); |
} |
void |
Shader::enable() |
{ |
if(m_uiProgram == 0) |
return; |
glUseProgram(m_uiProgram); |
checkStatus("Enabling shader"); |
UniformMapIter pkIter; |
for(pkIter = m_akUniforms.begin(); pkIter != m_akUniforms.end(); pkIter++) |
{ |
Uniform kUniform = pkIter->second; |
if( kUniform.location < 0 ) |
continue; |
#ifdef DEBUG |
char acMessage[1024] = {0}; |
#endif |
switch(kUniform.length) |
{ |
case 1: |
{ |
if( kUniform.integer ) |
{ |
#ifdef DEBUG |
sprintf(acMessage, |
"Shader Uniform1i[%3d][%s] = [%d] \n", |
kUniform.location, |
pkIter->first, |
kUniform.value.i[ 0]); |
#endif |
glUniform1i( kUniform.location, kUniform.value.i[0]); |
} |
else |
{ |
#ifdef DEBUG |
sprintf(acMessage, |
"Shader Uniform1f[%3d][%s] = [%f] \n", |
kUniform.location, |
pkIter->first, |
kUniform.value.f[ 0]); |
#endif |
glUniform1f( kUniform.location, kUniform.value.f[0]); |
} |
break; |
} |
case 2: |
{ |
if( kUniform.integer ) |
{ |
#ifdef DEBUG |
sprintf(acMessage, |
"Shader Uniform2i[%3d][%s] = [%d %d] \n", |
kUniform.location, |
pkIter->first, |
kUniform.value.i[ 0], |
kUniform.value.i[ 1]); |
#endif |
glUniform2iv( kUniform.location, 2, kUniform.value.i); |
} |
else |
{ |
#ifdef DEBUG |
sprintf(acMessage, |
"Shader Uniform2f[%3d][%s] = [%f %f] \n", |
kUniform.location, |
pkIter->first, |
kUniform.value.f[ 0], |
kUniform.value.f[ 1]); |
#endif |
glUniform2fv( kUniform.location, 2, kUniform.value.f); |
} |
break; |
} |
case 3: |
{ |
if( kUniform.integer ) |
{ |
#ifdef DEBUG |
sprintf(acMessage, |
"Shader Uniform3i[%3d][%s] = [%d %d %d] \n", |
kUniform.location, |
pkIter->first, |
kUniform.value.i[ 0], |
kUniform.value.i[ 1], |
kUniform.value.i[ 2]); |
#endif |
glUniform3iv( kUniform.location, 3, kUniform.value.i); |
} |
else |
{ |
#ifdef DEBUG |
sprintf(acMessage, |
"Shader Uniform3f[%3d][%s] = [%f %f %f] \n", |
kUniform.location, |
pkIter->first, |
kUniform.value.f[ 0], |
kUniform.value.f[ 1], |
kUniform.value.f[ 2]); |
#endif |
glUniform3fv( kUniform.location, 3, kUniform.value.f); |
} |
break; |
} |
case 4: |
{ |
if( kUniform.integer ) |
{ |
#ifdef DEBUG |
sprintf(acMessage, |
"Shader Uniform4i[%3d][%s] = [%d %d %d %d] \n", |
kUniform.location, |
pkIter->first, |
kUniform.value.i[ 0], |
kUniform.value.i[ 1], |
kUniform.value.i[ 2], |
kUniform.value.i[ 3]); |
#endif |
glUniform4iv( kUniform.location, 4, kUniform.value.i); |
} |
else |
{ |
#ifdef DEBUG |
sprintf(acMessage, |
"Shader Uniform4f[%3d][%s] = [%f %f %f %f] \n", |
kUniform.location, |
pkIter->first, |
kUniform.value.f[ 0], |
kUniform.value.f[ 1], |
kUniform.value.f[ 2], |
kUniform.value.f[ 3]); |
#endif |
glUniform4fv( kUniform.location, 4, kUniform.value.f); |
} |
break; |
} |
case 16: |
{ |
if( kUniform.integer == false ) |
{ |
#ifdef DEBUG |
sprintf(acMessage, |
"Shader Uniform16f[%3d][%s] = [%f %f %f %f] [%f %f %f %f] [%f %f %f %f] [%f %f %f %f]\n", |
kUniform.location, |
pkIter->first, |
kUniform.value.f[ 0], |
kUniform.value.f[ 1], |
kUniform.value.f[ 2], |
kUniform.value.f[ 3], |
kUniform.value.f[ 4], |
kUniform.value.f[ 5], |
kUniform.value.f[ 6], |
kUniform.value.f[ 7], |
kUniform.value.f[ 8], |
kUniform.value.f[ 9], |
kUniform.value.f[10], |
kUniform.value.f[11], |
kUniform.value.f[12], |
kUniform.value.f[13], |
kUniform.value.f[14], |
kUniform.value.f[15]); |
#endif |
glUniformMatrix4fv( kUniform.location, 1, false, kUniform.value.f); |
} |
break; |
}; |
} |
#ifdef DEBUG |
char acStatusMsg[4096]; |
sprintf(acStatusMsg, "Submitting %s", acMessage ); |
checkStatus(acStatusMsg); |
#endif |
} |
checkStatus("Submitting uniforms"); |
} |
void |
Shader::disable() |
{ |
glUseProgram(0); |
checkStatus("Disabling program"); |
} |
bool |
Shader::setUniform1f(const char* acName, float fV) |
{ |
int iLocation = glGetUniformLocation(m_uiProgram, acName); |
if(iLocation < 0) |
{ |
printf("Shader Error: Invalid uniform '%s', location not found! %d\n", acName, iLocation); |
return false; |
} |
Uniform kUniform; |
kUniform.location = iLocation; |
kUniform.length = 1; |
kUniform.integer = false; |
kUniform.value.f[0] = fV; |
m_akUniforms[acName] = kUniform; |
return true; |
} |
bool |
Shader::setUniform2f(const char* acName, const float2 & rkV) |
{ |
int iLocation = glGetUniformLocation(m_uiProgram, acName); |
if(iLocation < 0) |
{ |
printf("Shader Error: Invalid uniform '%s', location not found! %d\n", acName, iLocation); |
return false; |
} |
Uniform kUniform; |
kUniform.location = iLocation; |
kUniform.length = 2; |
kUniform.integer = false; |
kUniform.value.f[0] = rkV.x; |
kUniform.value.f[1] = rkV.y; |
m_akUniforms[acName] = kUniform; |
return true; |
} |
bool |
Shader::setUniform3f(const char* acName, const float3 & rkV) |
{ |
int iLocation = glGetUniformLocation(m_uiProgram, acName); |
if(iLocation < 0) |
{ |
printf("Shader Error: Invalid uniform '%s', location not found! %d\n", acName, iLocation); |
return false; |
} |
Uniform kUniform; |
kUniform.location = iLocation; |
kUniform.length = 3; |
kUniform.integer = false; |
kUniform.value.f[0] = rkV.x; |
kUniform.value.f[1] = rkV.y; |
kUniform.value.f[2] = rkV.z; |
m_akUniforms[acName] = kUniform; |
return true; |
} |
bool |
Shader::setUniform4f(const char* acName, const float4 &rkV) |
{ |
int iLocation = glGetUniformLocation(m_uiProgram, acName); |
if(iLocation < 0) |
{ |
printf("Shader Error: Invalid uniform '%s', location not found! %d\n", acName, iLocation); |
return false; |
} |
Uniform kUniform; |
kUniform.location = iLocation; |
kUniform.length = 4; |
kUniform.integer = false; |
kUniform.value.f[0] = rkV.x; |
kUniform.value.f[1] = rkV.y; |
kUniform.value.f[2] = rkV.z; |
kUniform.value.f[3] = rkV.w; |
m_akUniforms[acName] = kUniform; |
return true; |
} |
bool |
Shader::setUniform16f(const char* acName, const float16 & rkV) |
{ |
int iLocation = glGetUniformLocation(m_uiProgram, acName); |
if(iLocation < 0) |
{ |
printf("Shader Error: Invalid uniform '%s', location not found! %d\n", acName, iLocation); |
return false; |
} |
Uniform kUniform; |
kUniform.location = iLocation; |
kUniform.length = 16; |
kUniform.integer = false; |
memcpy(kUniform.value.f, rkV, 16 * sizeof(float)); |
m_akUniforms[acName] = kUniform; |
return true; |
} |
bool |
Shader::setUniform1i(const char* acName, int iV) |
{ |
int iLocation = glGetUniformLocation(m_uiProgram, acName); |
if(iLocation < 0) |
{ |
printf("Shader Error: Invalid uniform '%s', location not found! %d\n", acName, iLocation); |
return false; |
} |
Uniform kUniform; |
kUniform.location = iLocation; |
kUniform.length = 1; |
kUniform.integer = true; |
kUniform.value.i[0] = iV; |
m_akUniforms[acName] = kUniform; |
return true; |
} |
bool |
Shader::compile( |
const char* acVertexPgmSrc, |
const char* acFragPgmSrc) |
{ |
const uint uiMaxInfoLogLength = 1000; |
char acInfoLog[uiMaxInfoLogLength]; |
int iLogLength = 0; |
destroy(); |
GLuint uiVertexShader = glCreateShader(GL_VERTEX_SHADER); |
GLuint uiFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); |
glShaderSource(uiVertexShader, 1, &acVertexPgmSrc, 0); |
glShaderSource(uiFragmentShader, 1, &acFragPgmSrc, 0); |
glCompileShader(uiVertexShader); |
glGetShaderInfoLog(uiVertexShader, uiMaxInfoLogLength, (GLsizei*) &iLogLength, (GLchar*) acInfoLog); |
if(iLogLength && strlen(acInfoLog)) |
printf("Shader: Build Log:\n%s\n", acInfoLog); |
glCompileShader(uiFragmentShader); |
glGetShaderInfoLog(uiFragmentShader, uiMaxInfoLogLength, (GLsizei*) &iLogLength, (GLchar*) acInfoLog); |
if(iLogLength && strlen(acInfoLog)) |
printf("Shader: Build Log:\n%s\n", acInfoLog); |
GLuint uiProgram = glCreateProgram(); |
glAttachShader(uiProgram, uiVertexShader); |
glAttachShader(uiProgram, uiFragmentShader); |
glLinkProgram(uiProgram); |
glGetProgramInfoLog(uiProgram, uiMaxInfoLogLength, (GLsizei*) &iLogLength, (GLchar*) acInfoLog); |
if(iLogLength) |
printf("%s\n", acInfoLog); |
GLint iSuccess = 0; |
glGetProgramiv(uiProgram, GL_LINK_STATUS, &iSuccess); |
if (iSuccess == 0) |
{ |
glGetProgramInfoLog(uiProgram, uiMaxInfoLogLength, 0, acInfoLog); |
printf("Shader: Failed to link program:\n%s\n", acInfoLog); |
glDeleteProgram(uiProgram); |
uiProgram = 0; |
return false; |
} |
m_uiProgram = uiProgram; |
return true; |
} |
bool |
Shader::loadAndCompile( |
const char* acVertexFilename, |
const char* acFragmentFilename) |
{ |
char *acResource = 0; |
uint uiLength = 0; |
char *acVertexPgmSrc = 0; |
size_t uiVertexPgmLength = 0; |
char *acFragmentPgmSrc = 0; |
size_t uiFragmentPgmLength = 0; |
FindResourcePath(acVertexFilename, &acResource, &uiLength); |
LoadTextFromFile(acResource, &acVertexPgmSrc, &uiVertexPgmLength); |
if(acResource) |
free(acResource); |
FindResourcePath(acFragmentFilename, &acResource, &uiLength); |
LoadTextFromFile(acResource, &acFragmentPgmSrc, &uiFragmentPgmLength); |
if(acResource) |
free(acResource); |
bool bSuccess = compile(acVertexPgmSrc, acFragmentPgmSrc); |
if(acVertexPgmSrc) |
free(acVertexPgmSrc); |
if(acFragmentPgmSrc) |
free(acFragmentPgmSrc); |
return bSuccess; |
} |
void |
Shader::checkStatus(const char *acMessage) |
{ |
GLenum eError = glGetError(); |
if(eError == GL_FALSE) |
return; |
if(acMessage) |
printf("Shader[%d]: OpenGL Error: %s\n", m_uiProgram, acMessage); |
switch(eError) |
{ |
case(GL_INVALID_ENUM): |
printf("Shader[%d]: OpenGL Error: Invalid Enumerate!\n", m_uiProgram); |
break; |
case(GL_INVALID_VALUE): |
printf("Shader[%d]: OpenGL Error: Invalid Value!\n", m_uiProgram); |
break; |
case(GL_INVALID_OPERATION): |
printf("Shader[%d]: OpenGL Error: Invalid Operation!\n", m_uiProgram); |
break; |
case(GL_STACK_OVERFLOW): |
printf("Shader[%d]: OpenGL Error: Stack Overflow!\n", m_uiProgram); |
break; |
case(GL_STACK_UNDERFLOW): |
printf("Shader[%d]: OpenGL Error: Stack Underflow!\n", m_uiProgram); |
break; |
case(GL_OUT_OF_MEMORY): |
printf("Shader[%d]: OpenGL Error: Out of Memory!\n", m_uiProgram); |
break; |
case(GL_INVALID_FRAMEBUFFER_OPERATION_EXT): |
printf("Shader[%d]: OpenGL Error: Invalid framebuffer operation!\n", m_uiProgram); |
break; |
default: |
printf("Shader[%d]: Unknown OpenGL Error '%d'\n", m_uiProgram, (int)eError); |
break; |
} |
} |
GLuint |
Shader::getVertexAttribLocation(const char *name) |
{ |
return glGetAttribLocation(m_uiProgram, name); |
} |
Copyright © 2011 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2011-01-12