// // 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