//
// Effects.m
// DiceRoller
//
// Created by Jacques Questiaux on 2012/06/18.
// Copyright (c) 2012 j.questiaux@gmail.com. All rights reserved.
//
#import "Effects.h"
@interface Effects (){
}
@end
@implementation Effects
- (id) init {
if([super init]){
cameraLookAt = GLKVector3Make(0, 0, 0);
cameraUp = GLKVector3Make(0, 1, 0);
lightPosition = GLKVector3Make(1, 1, 3);
lightDiffuseColour = GLKVector4Make(0.7, 0.7, 0.7, 1);
lightSpecularColour = GLKVector4Make(2, 2, 2, 1);
lightAmbientColour = GLKVector4Make(0.85, 0.85, 0.85, 1);
numberColour = GLKVector4Make(0, 0, 0, 1);
faceColour = GLKVector4Make(1, 1, 1, 1);
outlineColour = GLKVector4Make(1, 0, 0, 1);
[self setupTexture];
[self loadShaders];
[self loadToonShaders];
return self;
}
return nil;
}
- (void) prepareToDraw {
glUseProgram(TexAndLighting);
camModelViewMatrix = GLKMatrix4Multiply(cameraMatrix, modelViewMatrix);
modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, camModelViewMatrix);
GLKMatrix3 normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, modelViewProjectionMatrix.m);
glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, normalMatrix.m);
float* lp = [self vec3ToFloat:lightPosition];
glUniform3fv(uniforms[UNIFORM_VEC3_lightPosition], 1, lp);
delete lp;
float* ldc = [self vec4ToFloat:lightDiffuseColour];
glUniform4fv(uniforms[UNIFORM_VEC4_lightDiffuseColour], 1, ldc);
delete ldc;
float* lsc = [self vec4ToFloat:lightSpecularColour];
glUniform4fv(uniforms[UNIFORM_VEC4_lightSpecularColour], 1, lsc);
delete lsc;
GLKVector3 lightHalfVec = GLKVector3Normalize(GLKVector3Add(cameraPosition, lightPosition));
float* lhv = [self vec3ToFloat:lightHalfVec];
glUniform3fv(uniforms[UNIFORM_VEC3_lightHalfVector], 1, lhv);
delete lhv;
float* nc = [self vec4ToFloat:numberColour];
glUniform4fv(uniforms[UNIFORM_VEC4_NumberColour], 1, nc);
delete nc;
float* fc = [self vec4ToFloat:faceColour];
glUniform4fv(uniforms[UNIFORM_VEC4_FaceColour], 1, fc);
delete fc;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(uniforms[UNIFORM_Texture], 0);
}
- (void) drawOutline {
glUseProgram(Toon);
camModelViewMatrix = GLKMatrix4Multiply(cameraMatrix, modelViewMatrix);
modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, camModelViewMatrix);;
glUniformMatrix4fv(toon_mvp, 1, 0, modelViewProjectionMatrix.m);
float* oc = [self vec4ToFloat:outlineColour];
glUniform4fv(toon_outline, 1, oc);
delete oc;
}
- (void) setCameraPosition:(GLKVector3)cp {
cameraPosition = cp;
cameraMatrix = GLKMatrix4MakeLookAt(cameraPosition.x, cameraPosition.y, cameraPosition.z, cameraLookAt.x, cameraLookAt.y, cameraLookAt.z, cameraUp.x, cameraUp.y, cameraUp.z);
//cameraMatrix = GLKMatrix4MakeTranslation(cameraPosition.x, cameraPosition.y, cameraPosition.z);
}
- (GLKVector3) cameraPosition {
return cameraPosition;
}
- (void) setCameraLookAt:(GLKVector3)cla {
cameraLookAt = cla;
cameraMatrix = GLKMatrix4MakeLookAt(cameraPosition.x, cameraPosition.y, cameraPosition.z, cameraLookAt.x, cameraLookAt.y, cameraLookAt.z, cameraUp.x, cameraUp.y, cameraUp.z);
}
- (GLKVector3) cameraLookAt {
return cameraLookAt;
}
- (void) setupTexture {
CGImageRef spriteImage = [UIImage imageNamed:@"texture.png"].CGImage;
if (!spriteImage) {
NSLog(@"Failed to load image");
//exit(1);
}
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
CGContextRelease(spriteContext);
//texture gets read in upside down, need to manually flip it
GLubyte * spriteData2 = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));
for(int i = 0; i < width*4; i++){
for(int j = 0; j < height; j++){
spriteData2[j*width*4+i] = spriteData[(height-1-j)*width*4+i];
}
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); //IMPORTANT FOR NON POWER OF 2 TEXTURES
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData2);
free(spriteData);
free(spriteData2);
//texture = texName;
}
- (BOOL)loadShaders
{
GLuint vertShader, fragShader;
NSString *vertShaderPathname, *fragShaderPathname;
// Create shader program.
TexAndLighting = glCreateProgram();
// Create and compile vertex shader.
vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {
NSLog(@"Failed to compile vertex shader");
return NO;
}
// Create and compile fragment shader.
fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
NSLog(@"Failed to compile fragment shader");
return NO;
}
// Attach vertex shader to program.
glAttachShader(TexAndLighting, vertShader);
// Attach fragment shader to program.
glAttachShader(TexAndLighting, fragShader);
// Bind attribute locations.
// This needs to be done prior to linking.
//glBindAttribLocation(_program, ATTRIB_VERTEX, "position");
//glBindAttribLocation(_program, ATTRIB_NORMAL, "normal");
// Link program.
if (![self linkProgram:TexAndLighting]) {
NSLog(@"Failed to link program: %d", TexAndLighting);
if (vertShader) {
glDeleteShader(vertShader);
vertShader = 0;
}
if (fragShader) {
glDeleteShader(fragShader);
fragShader = 0;
}
if (TexAndLighting) {
glDeleteProgram(TexAndLighting);
TexAndLighting = 0;
}
return NO;
}
// Get uniform locations.
uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(TexAndLighting, "modelViewProjectionMatrix");
uniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(TexAndLighting, "normalMatrix");
uniforms[UNIFORM_VEC3_lightPosition] = glGetUniformLocation(TexAndLighting, "lightPosition");
uniforms[UNIFORM_VEC4_lightDiffuseColour] = glGetUniformLocation(TexAndLighting, "lightDiffuseColour");
uniforms[UNIFORM_VEC4_lightSpecularColour] = glGetUniformLocation(TexAndLighting, "lightSpecularColour");
uniforms[UNIFORM_VEC4_lightAmbientColour] = glGetUniformLocation(TexAndLighting, "lightAmbientColour");
uniforms[UNIFORM_VEC3_lightHalfVector] = glGetUniformLocation(TexAndLighting, "lightHalfVector");
uniforms[UNIFORM_Texture] = glGetUniformLocation(TexAndLighting, "Texture");
uniforms[UNIFORM_VEC4_NumberColour] = glGetUniformLocation(TexAndLighting, "numberColour");
uniforms[UNIFORM_VEC4_FaceColour] = glGetUniformLocation(TexAndLighting, "faceColour");
texCoord = glGetAttribLocation(TexAndLighting, "TexCoordIn");
vertCoord = glGetAttribLocation(TexAndLighting, "position");
normal = glGetAttribLocation(TexAndLighting, "normal");
//glEnableVertexAttribArray(texCoord);
// Release vertex and fragment shaders.
if (vertShader) {
glDetachShader(TexAndLighting, vertShader);
glDeleteShader(vertShader);
}
if (fragShader) {
glDetachShader(TexAndLighting, fragShader);
glDeleteShader(fragShader);
}
return YES;
}
- (BOOL)loadToonShaders
{
GLuint vertShader, fragShader;
NSString *vertShaderPathname, *fragShaderPathname;
// Create shader program.
Toon = glCreateProgram();
// Create and compile vertex shader.
vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Toon" ofType:@"vsh"];
if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {
NSLog(@"Failed to compile vertex shader");
return NO;
}
// Create and compile fragment shader.
fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Toon" ofType:@"fsh"];
if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
NSLog(@"Failed to compile fragment shader");
return NO;
}
// Attach vertex shader to program.
glAttachShader(Toon, vertShader);
// Attach fragment shader to program.
glAttachShader(Toon, fragShader);
// Bind attribute locations.
// This needs to be done prior to linking.
//glBindAttribLocation(Toon, vertCoord, "position");
//glBindAttribLocation(_program, effect->normal, "normal");
// Link program.
if (![self linkProgram:Toon]) {
NSLog(@"Failed to link program: %d", Toon);
if (vertShader) {
glDeleteShader(vertShader);
vertShader = 0;
}
if (fragShader) {
glDeleteShader(fragShader);
fragShader = 0;
}
if (Toon) {
glDeleteProgram(Toon);
Toon = 0;
}
return NO;
}
// Get uniform locations.
toon_mvp = glGetUniformLocation(Toon, "modelViewProjectionMatrix");
toon_outline = glGetUniformLocation(Toon, "outlineColour");
toon_vertCoord = glGetAttribLocation(Toon, "position");
// Release vertex and fragment shaders.
if (vertShader) {
glDetachShader(Toon, vertShader);
glDeleteShader(vertShader);
}
if (fragShader) {
glDetachShader(Toon, fragShader);
glDeleteShader(fragShader);
}
return YES;
}
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
{
GLint status;
const GLchar *source;
source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
if (!source) {
NSLog(@"Failed to load vertex shader");
return NO;
}
*shader = glCreateShader(type);
glShaderSource(*shader, 1, &source, NULL);
glCompileShader(*shader);
#if defined(DEBUG)
GLint logLength;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetShaderInfoLog(*shader, logLength, &logLength, log);
NSLog(@"Shader compile log:\n%s", log);
free(log);
}
#endif
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
if (status == 0) {
glDeleteShader(*shader);
return NO;
}
return YES;
}
- (BOOL)linkProgram:(GLuint)prog
{
GLint status;
glLinkProgram(prog);
#if defined(DEBUG)
GLint logLength;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
NSLog(@"Program link log:\n%s", log);
free(log);
}
#endif
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if (status == 0) {
return NO;
}
return YES;
}
- (BOOL)validateProgram:(GLuint)prog
{
GLint logLength, status;
glValidateProgram(prog);
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
NSLog(@"Program validate log:\n%s", log);
free(log);
}
glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
if (status == 0) {
return NO;
}
return YES;
}
- (float*) vec3ToFloat: (GLKVector3) v {
float * f = new float[3];
f[0] = v.x;
f[1] = v.y;
f[2] = v.z;
return f;
}
- (float*) vec4ToFloat: (GLKVector4) v {
float * f = new float[4];
f[0] = v.x;
f[1] = v.y;
f[2] = v.z;
f[3] = v.w;
return f;
}
@end