2015-06-15 18:23:57 +02:00
//
// 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.5 f , -0.5 f , -0.5 f , 1.0 f , 0.0 f , 0.0 f ,
0.5 f , 0.5 f , -0.5 f , 1.0 f , 0.0 f , 0.0 f ,
0.5 f , -0.5 f , 0.5 f , 1.0 f , 0.0 f , 0.0 f ,
0.5 f , -0.5 f , 0.5 f , 1.0 f , 0.0 f , 0.0 f ,
0.5 f , 0.5 f , -0.5 f , 1.0 f , 0.0 f , 0.0 f ,
0.5 f , 0.5 f , 0.5 f , 1.0 f , 0.0 f , 0.0 f ,
0.5 f , 0.5 f , -0.5 f , 0.0 f , 1.0 f , 0.0 f ,
-0.5 f , 0.5 f , -0.5 f , 0.0 f , 1.0 f , 0.0 f ,
0.5 f , 0.5 f , 0.5 f , 0.0 f , 1.0 f , 0.0 f ,
0.5 f , 0.5 f , 0.5 f , 0.0 f , 1.0 f , 0.0 f ,
-0.5 f , 0.5 f , -0.5 f , 0.0 f , 1.0 f , 0.0 f ,
-0.5 f , 0.5 f , 0.5 f , 0.0 f , 1.0 f , 0.0 f ,
-0.5 f , 0.5 f , -0.5 f , -1.0 f , 0.0 f , 0.0 f ,
-0.5 f , -0.5 f , -0.5 f , -1.0 f , 0.0 f , 0.0 f ,
-0.5 f , 0.5 f , 0.5 f , -1.0 f , 0.0 f , 0.0 f ,
-0.5 f , 0.5 f , 0.5 f , -1.0 f , 0.0 f , 0.0 f ,
-0.5 f , -0.5 f , -0.5 f , -1.0 f , 0.0 f , 0.0 f ,
-0.5 f , -0.5 f , 0.5 f , -1.0 f , 0.0 f , 0.0 f ,
-0.5 f , -0.5 f , -0.5 f , 0.0 f , -1.0 f , 0.0 f ,
0.5 f , -0.5 f , -0.5 f , 0.0 f , -1.0 f , 0.0 f ,
-0.5 f , -0.5 f , 0.5 f , 0.0 f , -1.0 f , 0.0 f ,
-0.5 f , -0.5 f , 0.5 f , 0.0 f , -1.0 f , 0.0 f ,
0.5 f , -0.5 f , -0.5 f , 0.0 f , -1.0 f , 0.0 f ,
0.5 f , -0.5 f , 0.5 f , 0.0 f , -1.0 f , 0.0 f ,
0.5 f , 0.5 f , 0.5 f , 0.0 f , 0.0 f , 1.0 f ,
-0.5 f , 0.5 f , 0.5 f , 0.0 f , 0.0 f , 1.0 f ,
0.5 f , -0.5 f , 0.5 f , 0.0 f , 0.0 f , 1.0 f ,
0.5 f , -0.5 f , 0.5 f , 0.0 f , 0.0 f , 1.0 f ,
-0.5 f , 0.5 f , 0.5 f , 0.0 f , 0.0 f , 1.0 f ,
-0.5 f , -0.5 f , 0.5 f , 0.0 f , 0.0 f , 1.0 f ,
0.5 f , -0.5 f , -0.5 f , 0.0 f , 0.0 f , -1.0 f ,
-0.5 f , -0.5 f , -0.5 f , 0.0 f , 0.0 f , -1.0 f ,
0.5 f , 0.5 f , -0.5 f , 0.0 f , 0.0 f , -1.0 f ,
0.5 f , 0.5 f , -0.5 f , 0.0 f , 0.0 f , -1.0 f ,
-0.5 f , -0.5 f , -0.5 f , 0.0 f , 0.0 f , -1.0 f ,
-0.5 f , 0.5 f , -0.5 f , 0.0 f , 0.0 f , -1.0 f
} ;
@ 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.0 f , 0.4 f , 0.4 f , 1.0 f ) ;
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.0 f ) , aspect , 0.1 f , 100.0 f ) ;
self . effect . transform . projectionMatrix = projectionMatrix ;
GLKMatrix4 baseModelViewMatrix = GLKMatrix4MakeTranslation ( 0.0 f , 0.0 f , -4.0 f ) ;
baseModelViewMatrix = GLKMatrix4Rotate ( baseModelViewMatrix , _rotation , 0.0 f , 1.0 f , 0.0 f ) ;
// Compute the model view matrix for the object rendered with GLKit
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation ( 0.0 f , 0.0 f , -1.5 f ) ;
modelViewMatrix = GLKMatrix4Rotate ( modelViewMatrix , _rotation , 1.0 f , 1.0 f , 1.0 f ) ;
modelViewMatrix = GLKMatrix4Multiply ( baseModelViewMatrix , modelViewMatrix ) ;
self . effect . transform . modelviewMatrix = modelViewMatrix ;
// Compute the model view matrix for the object rendered with ES2
modelViewMatrix = GLKMatrix4MakeTranslation ( 0.0 f , 0.0 f , 1.5 f ) ;
modelViewMatrix = GLKMatrix4Rotate ( modelViewMatrix , _rotation , 1.0 f , 1.0 f , 1.0 f ) ;
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
{
2018-01-31 00:16:44 +01:00
// Start the dear imgui frame
[ self . imgui newFrame ] ;
// Create some UI elements
DebugHUD_DoInterface ( & _hud ) ;
// Render
2015-06-15 18:23:57 +02:00
glClearColor ( 0.65 f , 0.65 f , 0.65 f , 1.0 f ) ;
glClear ( GL_COLOR _BUFFER _BIT | GL_DEPTH _BUFFER _BIT ) ;
2018-01-31 00:16:44 +01:00
2015-06-15 18:23:57 +02:00
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 ) ;
2018-01-31 00:16:44 +01:00
2015-06-15 18:23:57 +02:00
self . effect . light0 . diffuseColor = GLKVector4Make ( _hud . cubeColor2 [ 0 ] , _hud . cubeColor2 [ 1 ] , _hud . cubeColor2 [ 2 ] , 1.0 f ) ;
2018-01-31 00:16:44 +01:00
// Render dear imgui as the last thing in the frame if possible
2015-06-15 18:23:57 +02:00
[ 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