Graphics/3D Graphics iPhone; Sensors




CS185c

Chris Pollett

Apr 18, 2012

Outline

Introduction

QuartzTestView.h

QuartzTestView.m

Here is the implementation of QuartzTestView. The drawRect method is where we override the base UIView ways of drawing things. We also have code to handle touch events (when they start, end and how they change).


#import "QuartzTestView.h"
#import "UIColor-Random.h"


@implementation QuartzTestView

@synthesize firstTouch;
@synthesize lastTouch;
@synthesize currentColor;
@synthesize shapeType;
@synthesize drawImage;
@synthesize useRandomColor;

//we're using initWithCoder as we are loading the view from a nib
// and so init and initWithFrame will never be called
-(id)initWithCoder:(NSCoder *)coder
{
    if((self = [super initWithCoder:coder])) {
        self.currentColor = [UIColor redColor];
        self.useRandomColor = NO;
    if(drawImage == nil)
        self.drawImage = [UIImage imageNamed:@"myphoto.png"];
    }
    return self;
}


// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect 
{
    CGContextRef context = UIGraphicsGetCurrentContext();
	
    CGContextSetLineWidth(context, 2.0);
    CGContextSetStrokeColorWithColor(context, currentColor.CGColor);
    CGContextSetFillColorWithColor(context, currentColor.CGColor);

    CGRect currentRect = CGRectMake(
        (firstTouch.x > lastTouch.x) ? lastTouch.x : firstTouch.x,
        (firstTouch.y > lastTouch.y) ? lastTouch.y : lastTouch.y,
        fabsf(firstTouch.x - lastTouch.x), 
        fabsf(firstTouch.y -lastTouch.y));
    switch (shapeType)
    {
        case kLineShape:
           CGContextMoveToPoint(context, firstTouch.x, firstTouch.y);
           CGContextAddLineToPoint(context, lastTouch.x, lastTouch.y);
           CGContextStrokePath(context);
        break;

        case kRectShape:
           CGContextAddRect(context, currentRect);
           CGContextDrawPath(context, kCGPathFillStroke);
        break;

        case kEllipseShape:
           CGContextAddEllipseInRect(context, currentRect);
           CGContextDrawPath(context, kCGPathFillStroke);
        break;

        case kImageShape: {
           CGFloat horizontalOffset = drawImage.size.width/2;
			
           CGFloat verticalOffset = drawImage.size.width/2;
           CGPoint drawPoint = CGPointMake(lastTouch.x - horizontalOffset, 
               lastTouch.y - verticalOffset);
           [drawImage drawAtPoint:drawPoint];
        break;
        }
        default:
        break;
    }
}

// Basic idea for touch handlers is to store in fields the touch info and redraw
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    if(useRandomColor)
        self.currentColor = [UIColor randomColor];
    UITouch *touch = [touches anyObject]; //touches recieves all 
                                          //finger presses we just need one
    firstTouch = [touch locationInView:self]; //store touch start info
    lastTouch = [touch locationInView:self];

    [self setNeedsDisplay]; // redraw view
}
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"hi there, this method does nothing");
}
	
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{	
    UITouch *touch = [touches anyObject];
    lastTouch = [touch locationInView:self];
    [self setNeedsDisplay]; // redraw view	
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    lastTouch = [touch locationInView:self];
    [self setNeedsDisplay]; // redraw view	
}

- (void)dealloc 
{
    [currentColor release];
    [drawImage release];
    [super dealloc];
}

@end

QuartzTestViewController.h

QuartzTestViewController.m

QuartzTestViewController.xib

Using Locations and the Accelerometer

SensorTestsViewController.h

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

@interface SensorTestsViewController : UIViewController <CLLocationManagerDelegate, 
	UIAccelerometerDelegate> {
	IBOutlet UILabel *locationLabel;
	IBOutlet UILabel *headingLabel;
	IBOutlet UILabel *accelerometerLabel;
	CLLocationManager *locationManager;
}
@property (retain, nonatomic) UILabel *locationLabel;
@property (retain, nonatomic) UILabel *headingLabel;
@property (retain, nonatomic) UILabel *accelerometerLabel;

@end

SensorTestsViewController.xib

SensorTestsViewController.m

Remarks

Sensor App Running

Android Sensor's Revisited

AcceleratorDemo.java

Creating an OpenGL ES Application

Our EAGLView

startAnimation and drawView

ES2Renderer rendering

render code

The code to render things should look reasonably familiar if you followed the Android examples...

- (void) render
{
    // Replace the implementation of this method to do your own custom drawing
    
    static const GLfloat squareVertices[] = {
        -0.5f, -0.33f,
         0.5f, -0.33f,
        -0.5f,  0.33f,
         0.5f,  0.33f,
    };
	
    static const GLubyte squareColors[] = {
        255, 255,   0, 255,
        0,   255, 255, 255,
        0,     0,   0,   0,
        255,   0, 255, 255,
    };
    
	static float transY = 0.0f;
	
	// This application only creates a single context which is already set current at this point.
	// This call is redundant, but needed if dealing with multiple contexts.
    [EAGLContext setCurrentContext:context];
    
	// This application only creates a single default framebuffer which is already bound at this point.
	// This call is redundant, but needed if dealing with multiple framebuffers.
    glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
    glViewport(0, 0, backingWidth, backingHeight);
    
    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
	// Use shader program
    glUseProgram(program);
	
	// Update uniform value
	glUniform1f(uniforms[UNIFORM_TRANSLATE], (GLfloat)transY);
	transY += 0.075f;	
	
	// Update attribute values
    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, 1, 0, squareColors);
    glEnableVertexAttribArray(ATTRIB_COLOR);
    
	// Validate program before drawing. This is a good check, but only really necessary in a debug build.
	// DEBUG macro must be defined in your debug configurations if that's not already the case.
#if defined(DEBUG)
	if (![self validateProgram:program])
	{
		NSLog(@"Failed to validate program: %d", program);
		return;
	}
#endif
	
    // Draw
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	
	// This application only creates a single color renderbuffer which is already bound at this point.
	// This call is redundant, but needed if dealing with multiple renderbuffers.
    glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER];
}

Translating from Android OpenGL to iPhone GL