You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							481 lines
						
					
					
						
							14 KiB
						
					
					
				
			
		
		
	
	
							481 lines
						
					
					
						
							14 KiB
						
					
					
				| // | |
| //  GameViewController.m | |
| //  imguiex | |
| // | |
| #import "GameViewController.h" | |
| #import <OpenGLES/ES2/glext.h> | |
|  | |
| #import "imgui_impl_ios.h" | |
| #import "debug_hud.h" | |
|  | |
| #define BUFFER_OFFSET(i) ((char *)NULL + (i)) | |
|  | |
| #define SERVERNAME_KEY @"ServerName" | |
|  | |
| #define SERVERNAME_ALERT_TAG (10) | |
|  | |
| // Uniform index. | |
| enum | |
| { | |
|     UNIFORM_MODELVIEWPROJECTION_MATRIX, | |
|     UNIFORM_NORMAL_MATRIX, | |
|     UNIFORM_DIFFUSE_COLOR, | |
|      | |
|     NUM_UNIFORMS | |
| }; | |
| GLint uniforms[NUM_UNIFORMS]; | |
| 
 | |
| // Attribute index. | |
| enum | |
| { | |
|     ATTRIB_VERTEX, | |
|     ATTRIB_NORMAL, | |
|     NUM_ATTRIBUTES | |
| }; | |
| 
 | |
| GLfloat gCubeVertexData[216] =  | |
| { | |
|     // Data layout for each line below is: | |
|     // positionX, positionY, positionZ,     normalX, normalY, normalZ, | |
|     0.5f, -0.5f, -0.5f,        1.0f, 0.0f, 0.0f, | |
|     0.5f, 0.5f, -0.5f,         1.0f, 0.0f, 0.0f, | |
|     0.5f, -0.5f, 0.5f,         1.0f, 0.0f, 0.0f, | |
|     0.5f, -0.5f, 0.5f,         1.0f, 0.0f, 0.0f, | |
|     0.5f, 0.5f, -0.5f,          1.0f, 0.0f, 0.0f, | |
|     0.5f, 0.5f, 0.5f,         1.0f, 0.0f, 0.0f, | |
|      | |
|     0.5f, 0.5f, -0.5f,         0.0f, 1.0f, 0.0f, | |
|     -0.5f, 0.5f, -0.5f,        0.0f, 1.0f, 0.0f, | |
|     0.5f, 0.5f, 0.5f,          0.0f, 1.0f, 0.0f, | |
|     0.5f, 0.5f, 0.5f,          0.0f, 1.0f, 0.0f, | |
|     -0.5f, 0.5f, -0.5f,        0.0f, 1.0f, 0.0f, | |
|     -0.5f, 0.5f, 0.5f,         0.0f, 1.0f, 0.0f, | |
|      | |
|     -0.5f, 0.5f, -0.5f,        -1.0f, 0.0f, 0.0f, | |
|     -0.5f, -0.5f, -0.5f,       -1.0f, 0.0f, 0.0f, | |
|     -0.5f, 0.5f, 0.5f,         -1.0f, 0.0f, 0.0f, | |
|     -0.5f, 0.5f, 0.5f,         -1.0f, 0.0f, 0.0f, | |
|     -0.5f, -0.5f, -0.5f,       -1.0f, 0.0f, 0.0f, | |
|     -0.5f, -0.5f, 0.5f,        -1.0f, 0.0f, 0.0f, | |
|      | |
|     -0.5f, -0.5f, -0.5f,       0.0f, -1.0f, 0.0f, | |
|     0.5f, -0.5f, -0.5f,        0.0f, -1.0f, 0.0f, | |
|     -0.5f, -0.5f, 0.5f,        0.0f, -1.0f, 0.0f, | |
|     -0.5f, -0.5f, 0.5f,        0.0f, -1.0f, 0.0f, | |
|     0.5f, -0.5f, -0.5f,        0.0f, -1.0f, 0.0f, | |
|     0.5f, -0.5f, 0.5f,         0.0f, -1.0f, 0.0f, | |
|      | |
|     0.5f, 0.5f, 0.5f,          0.0f, 0.0f, 1.0f, | |
|     -0.5f, 0.5f, 0.5f,         0.0f, 0.0f, 1.0f, | |
|     0.5f, -0.5f, 0.5f,         0.0f, 0.0f, 1.0f, | |
|     0.5f, -0.5f, 0.5f,         0.0f, 0.0f, 1.0f, | |
|     -0.5f, 0.5f, 0.5f,         0.0f, 0.0f, 1.0f, | |
|     -0.5f, -0.5f, 0.5f,        0.0f, 0.0f, 1.0f, | |
|      | |
|     0.5f, -0.5f, -0.5f,        0.0f, 0.0f, -1.0f, | |
|     -0.5f, -0.5f, -0.5f,       0.0f, 0.0f, -1.0f, | |
|     0.5f, 0.5f, -0.5f,         0.0f, 0.0f, -1.0f, | |
|     0.5f, 0.5f, -0.5f,         0.0f, 0.0f, -1.0f, | |
|     -0.5f, -0.5f, -0.5f,       0.0f, 0.0f, -1.0f, | |
|     -0.5f, 0.5f, -0.5f,        0.0f, 0.0f, -1.0f | |
| }; | |
| 
 | |
| @interface GameViewController () <UIAlertViewDelegate> | |
| { | |
|     GLuint _program; | |
|      | |
|     GLKMatrix4 _modelViewProjectionMatrix; | |
|     GLKMatrix3 _normalMatrix; | |
|     float _rotation; | |
|      | |
|     GLuint _vertexArray; | |
|     GLuint _vertexBuffer; | |
|      | |
|     DebugHUD _hud; | |
| } | |
| @property (strong, nonatomic) EAGLContext *context; | |
| @property (strong, nonatomic) GLKBaseEffect *effect; | |
| @property (strong, nonatomic) ImGuiHelper *imgui; | |
| @property (weak, nonatomic) IBOutlet UIButton *btnServername; | |
| 
 | |
| @property (strong, nonatomic) NSString *serverName; | |
| 
 | |
| - (IBAction)onServernameTapped:(id)sender; | |
| 
 | |
| - (void)setupGL; | |
| - (void)tearDownGL; | |
| 
 | |
| - (BOOL)loadShaders; | |
| - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file; | |
| - (BOOL)linkProgram:(GLuint)prog; | |
| - (BOOL)validateProgram:(GLuint)prog; | |
| @end | |
| 
 | |
| @implementation GameViewController | |
| 
 | |
| - (void)viewDidLoad | |
| { | |
|     [super viewDidLoad]; | |
|      | |
|     self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; | |
| 
 | |
|     if (!self.context) { | |
|         NSLog(@"Failed to create ES context"); | |
|     } | |
|      | |
|     GLKView *view = (GLKView *)self.view; | |
|     view.context = self.context; | |
|     view.drawableDepthFormat = GLKViewDrawableDepthFormat24; | |
|      | |
|     [self.btnServername setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; | |
|      | |
|     [self setupGL]; | |
|      | |
|     NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; | |
|     self.serverName = [userDefaults objectForKey: SERVERNAME_KEY ]; | |
|     self.imgui = [[ImGuiHelper alloc] initWithView:self.view ]; | |
|     if (self.serverName) | |
|     { | |
|         [self.btnServername setTitle:self.serverName forState:UIControlStateNormal]; | |
|         [self.imgui connectServer: self.serverName ]; | |
|     } | |
|      | |
|     DebugHUD_InitDefaults( &_hud ); | |
| } | |
| 
 | |
| - (void)dealloc | |
| {     | |
|     [self tearDownGL]; | |
|      | |
|     if ([EAGLContext currentContext] == self.context) { | |
|         [EAGLContext setCurrentContext:nil]; | |
|     } | |
| } | |
| 
 | |
| - (void)didReceiveMemoryWarning | |
| { | |
|     [super didReceiveMemoryWarning]; | |
| 
 | |
|     if ([self isViewLoaded] && ([[self view] window] == nil)) { | |
|         self.view = nil; | |
|          | |
|         [self tearDownGL]; | |
|          | |
|         if ([EAGLContext currentContext] == self.context) { | |
|             [EAGLContext setCurrentContext:nil]; | |
|         } | |
|         self.context = nil; | |
|     } | |
| 
 | |
|     // Dispose of any resources that can be recreated. | |
| } | |
| 
 | |
| 
 | |
| - (BOOL)prefersStatusBarHidden { | |
|     return YES; | |
| } | |
| 
 | |
| - (IBAction)onServernameTapped:(id)sender | |
| { | |
|     UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Set Server" message:@"Enter server name or IP for uSynergy" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Cancel", nil ]; | |
|     alert.alertViewStyle = UIAlertViewStylePlainTextInput; | |
|     alert.tag = SERVERNAME_ALERT_TAG; // cheezy way to tell which alert view we're responding to | |
|     [alert show]; | |
| } | |
| 
 | |
| - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex | |
| { | |
|     if ((buttonIndex==0)&&(alertView.tag==SERVERNAME_ALERT_TAG)) | |
|     { | |
|         // This is really janky. I usually just hardcode the servername since I'm building it anyway. | |
|         // If you want to properly handle updating the server, you'll want to tear down and recreate | |
|         // the usynergy stuff in connectServer | |
|         BOOL serverNameWasSet = self.serverName.length > 0; | |
|         NSString *serverName = [[alertView textFieldAtIndex:0] text]; | |
| 
 | |
|         if ([serverName length] > 0) { | |
|             self.serverName = serverName; | |
|             NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; | |
|             [userDefaults setObject:serverName forKey:SERVERNAME_KEY ]; | |
|             [userDefaults synchronize]; | |
|              | |
|             [self.btnServername setTitle:self.serverName forState:UIControlStateNormal]; | |
|              | |
|             // If we hadn't previously connected, try now | |
|             if (!serverNameWasSet) { | |
|                 [self.imgui connectServer:self.serverName]; | |
|             } | |
|             else | |
|             { | |
|                 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Servername Updated" | |
|                                                                 message:@"Restart the app to connect the server" | |
|                                                                delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; | |
|                 [alert show]; | |
|             } | |
|         } | |
|     } | |
| } | |
| 
 | |
| - (void)setupGL | |
| { | |
|     [EAGLContext setCurrentContext:self.context]; | |
|      | |
|     [self loadShaders]; | |
|      | |
|     self.effect = [[GLKBaseEffect alloc] init]; | |
|     self.effect.light0.enabled = GL_TRUE; | |
|     self.effect.light0.diffuseColor = GLKVector4Make(1.0f, 0.4f, 0.4f, 1.0f); | |
|      | |
|     glEnable(GL_DEPTH_TEST); | |
|      | |
|     glGenVertexArraysOES(1, &_vertexArray); | |
|     glBindVertexArrayOES(_vertexArray); | |
|      | |
|     glGenBuffers(1, &_vertexBuffer); | |
|     glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); | |
|     glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData), gCubeVertexData, GL_STATIC_DRAW); | |
|      | |
|     glEnableVertexAttribArray(GLKVertexAttribPosition); | |
|     glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0)); | |
|     glEnableVertexAttribArray(GLKVertexAttribNormal); | |
|     glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12)); | |
|      | |
|     glBindVertexArrayOES(0); | |
|      | |
| 
 | |
| } | |
| 
 | |
| - (void)tearDownGL | |
| { | |
|     [EAGLContext setCurrentContext:self.context]; | |
|      | |
|     glDeleteBuffers(1, &_vertexBuffer); | |
|     glDeleteVertexArraysOES(1, &_vertexArray); | |
|      | |
|     self.effect = nil; | |
|      | |
|     if (_program) { | |
|         glDeleteProgram(_program); | |
|         _program = 0; | |
|     } | |
| } | |
| 
 | |
| #pragma mark - GLKView and GLKViewController delegate methods | |
|  | |
| - (void)update | |
| { | |
|     float aspect = fabs(self.view.bounds.size.width / self.view.bounds.size.height); | |
|     GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f); | |
|      | |
|     self.effect.transform.projectionMatrix = projectionMatrix; | |
|      | |
|     GLKMatrix4 baseModelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -4.0f); | |
|     baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, _rotation, 0.0f, 1.0f, 0.0f); | |
|      | |
|     // Compute the model view matrix for the object rendered with GLKit | |
|     GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -1.5f); | |
|     modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 1.0f, 1.0f, 1.0f); | |
|     modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix); | |
|      | |
|     self.effect.transform.modelviewMatrix = modelViewMatrix; | |
|      | |
|     // Compute the model view matrix for the object rendered with ES2 | |
|     modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, 1.5f); | |
|     modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 1.0f, 1.0f, 1.0f); | |
|     modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix); | |
|      | |
|     _normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL); | |
|      | |
|     _modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix); | |
|      | |
|     _rotation += self.timeSinceLastUpdate * (_hud.rotation_speed * (M_PI / 180.0)); | |
| } | |
| 
 | |
| 
 | |
| - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect | |
| { | |
|     glClearColor(0.65f, 0.65f, 0.65f, 1.0f); | |
|     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
|      | |
|     glBindVertexArrayOES(_vertexArray); | |
|      | |
|     // Render the object with GLKit | |
|     [self.effect prepareToDraw]; | |
|      | |
|     glDrawArrays(GL_TRIANGLES, 0, 36); | |
|      | |
|     // Render the object again with ES2 | |
|     glUseProgram(_program); | |
|      | |
|     glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m); | |
|     glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m); | |
|     glUniform3f(uniforms[UNIFORM_DIFFUSE_COLOR], _hud.cubeColor1[0], _hud.cubeColor1[1], _hud.cubeColor1[2] ); | |
| 
 | |
|     glDrawArrays(GL_TRIANGLES, 0, 36); | |
|      | |
|     [self.imgui newFrame]; | |
|      | |
|     // Now do our ImGUI UI | |
|     DebugHUD_DoInterface( &_hud ); | |
|      | |
|     self.effect.light0.diffuseColor = GLKVector4Make( _hud.cubeColor2[0], _hud.cubeColor2[1], _hud.cubeColor2[2], 1.0f); | |
|      | |
|     // Now render Imgui | |
|     [self.imgui render]; | |
|      | |
| } | |
| 
 | |
| #pragma mark -  OpenGL ES 2 shader compilation | |
|  | |
| - (BOOL)loadShaders | |
| { | |
|     GLuint vertShader, fragShader; | |
|     NSString *vertShaderPathname, *fragShaderPathname; | |
|      | |
|     // Create shader program. | |
|     _program = 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(_program, vertShader); | |
|      | |
|     // Attach fragment shader to program. | |
|     glAttachShader(_program, fragShader); | |
|      | |
|     // Bind attribute locations. | |
|     // This needs to be done prior to linking. | |
|     glBindAttribLocation(_program, GLKVertexAttribPosition, "position"); | |
|     glBindAttribLocation(_program, GLKVertexAttribNormal, "normal"); | |
|      | |
|     // Link program. | |
|     if (![self linkProgram:_program]) { | |
|         NSLog(@"Failed to link program: %d", _program); | |
|          | |
|         if (vertShader) { | |
|             glDeleteShader(vertShader); | |
|             vertShader = 0; | |
|         } | |
|         if (fragShader) { | |
|             glDeleteShader(fragShader); | |
|             fragShader = 0; | |
|         } | |
|         if (_program) { | |
|             glDeleteProgram(_program); | |
|             _program = 0; | |
|         } | |
|          | |
|         return NO; | |
|     } | |
|      | |
|     // Get uniform locations. | |
|     uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(_program, "modelViewProjectionMatrix"); | |
|     uniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(_program, "normalMatrix"); | |
|     uniforms[UNIFORM_DIFFUSE_COLOR] = glGetUniformLocation(_program, "diffuseColor"); | |
|      | |
|     // Release vertex and fragment shaders. | |
|     if (vertShader) { | |
|         glDetachShader(_program, vertShader); | |
|         glDeleteShader(vertShader); | |
|     } | |
|     if (fragShader) { | |
|         glDetachShader(_program, 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; | |
| } | |
| 
 | |
| @end
 | |
| 
 |