Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

MaxFreud

macrumors newbie
Original poster
Jan 5, 2011
22
0
Hi all,

I am making a simple iPad game that includes some OpenGL code; I am using Jeff Lamarche's Xcode template, which includes a UIView subclass for the OpenGL stuff. It is called GLView, and it comes with its view controller, called GLViewController. Here are those classes for reference:

Code:
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>

#import "GLView.h"
#import "ConstantsAndMacros.h"


@interface GLView ()
@property (nonatomic, retain) EAGLContext *context;
@property (nonatomic, assign) NSTimer *animationTimer;
- (BOOL) createFramebuffer;
- (void) destroyFramebuffer;
@end

#pragma mark -

@implementation GLView

@synthesize context;
@synthesize animationTimer;
@synthesize animationInterval;
@synthesize delegate;

+ (Class)layerClass 
{
    return [CAEAGLLayer class];
}
- (id)initWithCoder:(NSCoder*)coder {
    
    if ((self = [super initWithCoder:coder])) {
        // Get the layer
        CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
        
        eaglLayer.opaque = YES;
        eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                        [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
        
#if kAttemptToUseOpenGLES2
        context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        if (context == NULL)
        {
#endif
            context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
            
            if (!context || ![EAGLContext setCurrentContext:context]) {
                [self release];
                return nil;
            }
#if kAttemptToUseOpenGLES2
        }
#endif
        
        animationInterval = 1.0 / kRenderingFrequency;
    }
    return self;
}
- (void)drawView 
{
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    [delegate drawView:self];
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
- (void)layoutSubviews 
{
    [EAGLContext setCurrentContext:context];
    [self destroyFramebuffer];
    [self createFramebuffer];
    [self drawView];
}
- (BOOL)createFramebuffer 
{
    glGenFramebuffersOES(1, &viewFramebuffer);
    glGenRenderbuffersOES(1, &viewRenderbuffer);
    
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
    
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
    
    if (USE_DEPTH_BUFFER) 
    {
        glGenRenderbuffersOES(1, &depthRenderbuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
    }
    
    if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) 
    {
        NSLog(@"failed to make complete framebuffer object %4x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
        return NO;
    }
    
    [delegate setupView:self];
    return YES;
}
- (void)destroyFramebuffer 
{
    glDeleteFramebuffersOES(1, &viewFramebuffer);
    viewFramebuffer = 0;
    glDeleteRenderbuffersOES(1, &viewRenderbuffer);
    viewRenderbuffer = 0;
    
    if(depthRenderbuffer) 
    {
        glDeleteRenderbuffersOES(1, &depthRenderbuffer);
        depthRenderbuffer = 0;
    }
}
- (void)startAnimation 
{
    self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
}
- (void)stopAnimation 
{
    self.animationTimer = nil;
}
- (void)setAnimationTimer:(NSTimer *)newTimer 
{
    [animationTimer invalidate];
    animationTimer = newTimer;
}

- (void)setAnimationInterval:(NSTimeInterval)interval 
{
    animationInterval = interval;
    if (animationTimer) 
    {
        [self stopAnimation];
        [self startAnimation];
    }
}
- (void)dealloc 
{
    [self stopAnimation];
    
    if ([EAGLContext currentContext] == context) 
        [EAGLContext setCurrentContext:nil];
    
    [context release];  
    [super dealloc];
}

@end

Code:
#import "GLViewController.h"
#import "ConstantsAndMacros.h"
#import "OpenGLCommon.h"
#import "OpenGLTexture3D.h"
#import "gazeShip.h"

@implementation GLViewController

@synthesize texture;

- (void)drawView:(UIView *)theView
{
    static GLfloat rot = 0.0;
    
    glColor4f(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    // Drawing code here
    glEnableClientState(GL_VERTEX_ARRAY);
//    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);

    [texture bind];
    glColor4f(1.0, 0.0, 0.0, 0.0);
    glLoadIdentity();
    glTranslatef(0.0, 0.2, -1.7);
    glRotatef(90.0, 0.0, 0.0, 1.0);
    glRotatef(170.0, 0.0, 1.0, 0.0);
    glRotatef(rot, 0.0, 0.0, 1.0);
    glVertexPointer(3, GL_FLOAT, 0, shipVerts);
    glTexCoordPointer(2, GL_FLOAT, 0, shipTexCoords);
    glDrawArrays(GL_TRIANGLES, 0, shipNumVerts);
    
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);
    
    static NSTimeInterval lastDrawTime;
    if (lastDrawTime)
    {
        NSTimeInterval timeSinceLastDraw = [NSDate timeIntervalSinceReferenceDate] - lastDrawTime;
        rot+=35 * timeSinceLastDraw;  
    }
    lastDrawTime = [NSDate timeIntervalSinceReferenceDate];
}

-(void)setupView:(GLView*)view
{
    const GLfloat zNear = 0.01, zFar = 1000.0, fieldOfView = 45.0; 
	GLfloat size;
    
    ((GLView*)(self.view)).delegate = self;
    
    // Enabling GL_DEPTH_TEST is used for depth buffering
    // this allows openGL to properly obscure one object
    // when another one is in front of it.
	glEnable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION); 
	size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0); 
	CGRect rect = view.bounds; 
	glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size / 
			   (rect.size.width / rect.size.height), zNear, zFar); 
	glViewport(0, 0, rect.size.width, rect.size.height);  
	glMatrixMode(GL_MODELVIEW);
	

    // Enable lighting
    glEnable(GL_LIGHTING);
    
    // Turn the first light on
    glEnable(GL_LIGHT0);
    
    // Define the ambient component of the first light
    static const Color3D light0Ambient[] = {{0.4, 0.4, 0.4, 1.0}};
	glLightfv(GL_LIGHT0, GL_AMBIENT, (const GLfloat *)light0Ambient);
    
    // Define the diffuse component of the first light
    static const Color3D light0Diffuse[] = {{0.7, 0.7, 0.7, 1.0}};
	glLightfv(GL_LIGHT0, GL_DIFFUSE, (const GLfloat *)light0Diffuse);
    
    // Define the specular component and shininess of the first light
    static const Color3D light0Specular[] = {{0.7, 0.7, 0.7, 1.0}};
    glLightfv(GL_LIGHT0, GL_SPECULAR, (const GLfloat *)light0Specular);
    
    // Define the position of the first light
    // const GLfloat light0Position[] = {10.0, 10.0, 10.0}; 
    static const Vertex3D light0Position[] = {{5.0, 5.0, 5.0}};
	glLightfv(GL_LIGHT0, GL_POSITION, (const GLfloat *)light0Position); 
	
    // Calculate light vector so it points at the object
    static const Vertex3D objectPoint[] = {{0.0, 0.0, -5.0}};
    const Vertex3D lightVector = Vector3DMakeWithStartAndEndPoints(light0Position[0], objectPoint[0]);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, (GLfloat *)&lightVector);
    
    NSString *path = [[NSBundle mainBundle] pathForResource:@"BrushedAluminum" ofType:@"jpg"];
    OpenGLTexture3D *newTexture = [[OpenGLTexture3D alloc] initWithFilename:path width:512 height:512];
    self.texture = newTexture;
    [newTexture release];

	glLoadIdentity(); 
}
- (void)dealloc 
{
    [super dealloc];
}

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft
            || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

-(void) viewWillAppear:(BOOL)animated
{
    NSLog(@"View will appear");
    
    [((GLView*)(self.view)) startAnimation];
}

- (void) viewWillDisappear:(BOOL)animated
{
    NSLog(@"View will disappear");
    
    [((GLView*)(self.view)) stopAnimation];
}
@end

I have created another view with its view controller:

Code:
#import "GazeDemoAppDelegate.h"
#import "GazeIntroViewController.h"
#import "SettingsPopover.h"

@implementation GazeIntroViewController

@synthesize screenWidth, screenHeight;
@synthesize calibrationMode;
@synthesize testMode;
@synthesize gazeTitle, instructions, logo, calibrate, settings, squareView;
@synthesize start;
@synthesize glView;


#pragma Init and Memory

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
        connected = NO;
        [self setupViewWithCalibrationState:NO];
    }
    return self;
}

- (void) setupViewWithCalibrationState:(BOOL)done
{
    calibrationDone = done;
    
    gazeTitle.hidden = NO;
    instructions.hidden = NO;
    logo.hidden = NO;
    calibrate.hidden = NO;
    settings.hidden = NO;
    squareView.hidden = YES;
    //TODO: Replace YES with !done
    start.hidden = YES;
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
    
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    
    NSLog(@"Am I first responder? %@", [self.view isFirstResponder]?@"Yes":@"No");
    
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    
    self.screenWidth = screenRect.size.width;
    self.screenHeight = screenRect.size.height;
    
    if (!connected) {
        calibrate.enabled = NO;
    }
    
    if([self.view becomeFirstResponder])
        NSLog(@"Assumed 1st responder");
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
	return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft
            || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

#pragma mark UI Action Methods

- (IBAction)calibratePressed:(id)sender
{
    //gazeTitle, instructions, logo, calibrate, settings, square
    gazeTitle.hidden = YES;
    instructions.hidden = YES;
    logo.hidden = YES;
    calibrate.hidden = YES;
    settings.hidden = YES;
    squareView.hidden = NO;
    start.hidden = YES;
    
    [GazeDemoAppDelegate singleton].calibrationMode = YES;
    [[NetworkManager singleton] beginCalibration];
}

- (IBAction)settingsPressed:(id)sender
{
    if (settingsPopover.isPopoverVisible) {
        [settingsPopover dismissPopoverAnimated:YES];
    }
    else
    {
        SettingsPopover* content = [[SettingsPopover alloc] init];
        
        // setup the popover for use
        settingsPopover = [[UIPopoverController alloc] initWithContentViewController:content];
        settingsPopover.popoverContentSize = CGSizeMake(360., 200.);
        settingsPopover.delegate = self;
        
        [settingsPopover presentPopoverFromRect:((UIButton*)sender).frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
        
        [content release];
    }
}

- (IBAction)startPressed:(id)sender
{
    CGRect frame = [self.view frame];
    CGRect newFrame = CGRectMake(frame.origin.x, frame.origin.y + 1024, frame.size.width, frame.size.height);;
    [UIView animateWithDuration:1
                     animations:^{
                         self.view.frame = newFrame;
                     }
                     completion:^(BOOL finished){
                         NSLog(@"Finished Animations: %@", finished?@"YES":@"NO");
                         [[GazeDemoAppDelegate singleton] displayGameView];
                     }];
}

@end

GazeIntroViewController has its own xib file. As for the instance of GLView, inside of MainWindow.xib, I have this:
- Window
- App Delegate
- GLViewController
- View (set up as a GLView instance)

Inside of the xib files (both MainWindow and GazeIntroViewController) I have set up the views to have a width of 1024 and height of 768 and the orientation to landscape. (This app will ONLY run in landscape)

My applicationDidFinishLaunching:
Code:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
    viewController = [[GazeIntroViewController alloc] initWithNibName:@"GazeIntroViewController" bundle:[NSBundle mainBundle]];
    
    [window addSubview:glView];
    [glView setFrame:[glView.superview frame]];
//    [window addSubview:viewController.view];
//    [window bringSubviewToFront:viewController.view];
    
    g_AppDelegate = self;
    calibrationMode = NO;
    
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    self.screenWidth = screenRect.size.height;
    self.screenHeight = screenRect.size.width;
    
    [window setFrame:CGRectMake(0, 0, 768, 1024)];
    [viewController.view setFrame:[viewController.view.superview frame]];
    
    [window makeKeyAndVisible];
    
    NSLog(@"Window subviews are: %@", [[window subviews] description]);
    NSLog(@"Window status is: %@", [window description]);
}

These are my two problems (and the reason for all those setFrame calls):
  1. If I uncomment those two lines in applicationDidFinishLaunching, my GazeIntroViewController view will show up rotated 90 deg. As in: the device is in landscape, but the view appears fixed to the 'portrait' position and will not move. The only way I can get that view to display correctly is if, inside MainWindow.xib, I set the instance of GLView to be inside of the window. Why does it work this way? I really want to understand this behaviour because it limits what I can do with views in code.
  2. Regardless of the orientation, the GLView will display nothing but a purple screen. There are no errors; I don't know how to proceed for debugging. Note that this project started from the OpenGL template linked to above. Before I started adding new views to it, it was perfectly OK rendering my models.

Any help?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.