2009-11-07 10:41:14 +00:00

380 lines
11 KiB
Objective-C

//
// EAGLView.m
// AppleCoder-OpenGLES-00
//
// Created by Simon Maurice on 18/03/09.
// Copyright Simon Maurice 2009. All rights reserved.
//
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>
#import "EAGLView.h"
#import "WiiMoteOpenGLDemoAppDelegate.h"
#define USE_DEPTH_BUFFER 1
#define DEGREES_TO_RADIANS(__ANGLE) ((__ANGLE) / 180.0 * M_PI)
// A class extension to declare private methods
@interface EAGLView ()
@property (nonatomic, retain) EAGLContext *context;
@property (nonatomic, assign) NSTimer *animationTimer;
- (BOOL) createFramebuffer;
- (void) destroyFramebuffer;
@end
@implementation EAGLView
@synthesize context;
@synthesize animationTimer;
@synthesize animationInterval;
// You must implement this method
+ (Class)layerClass {
return [CAEAGLLayer class];
}
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Get the layer
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8,
kEAGLDrawablePropertyColorFormat, nil];
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context]) {
[self release];
return nil;
}
animationInterval = 1.0 / 60.0;
rota = 0.0;
[self setupView];
[self loadTexture];
}
return self;
}
- (void)drawView {
// Our new object definition code goes here
const GLfloat cubeVertices[] = {
// Define the front face
-0.24415584, 1.0, 0.207792208, // top left
-0.24415584, -1.0, 0.207792208, // bottom left
0.24415584, -1.0, 0.207792208, // bottom right
0.24415584, 1.0, 0.207792208, // top right
// Top face
-0.24415584, 1.0, -0.207792208, // top left (at rear)
-0.24415584, 1.0, 0.207792208, // bottom left (at front)
0.24415584, 1.0, 0.207792208, // bottom right (at front)
0.24415584, 1.0, -0.207792208, // top right (at rear)
// Rear face
0.24415584, 1.0, -0.207792208, // top right (when viewed from front)
0.24415584, -1.0, -0.207792208, // bottom right
-0.24415584, -1.0, -0.207792208, // bottom left
-0.24415584, 1.0, -0.207792208, // top left
// bottom face
-0.24415584, -1.0, 0.207792208,
-0.24415584, -1.0, -0.207792208,
0.24415584, -1.0, -0.207792208,
0.24415584, -1.0, 0.207792208,
// left face
-0.24415584, 1.0, -0.207792208,
-0.24415584, 1.0, 0.207792208,
-0.24415584, -1.0, 0.207792208,
-0.24415584, -1.0, -0.207792208,
// right face
0.24415584, 1.0, 0.207792208,
0.24415584, 1.0, -0.207792208,
0.24415584, -1.0, -0.207792208,
0.24415584, -1.0, 0.207792208
};
const GLfloat squareTextureCoords[] = {
// Front face - WiiTop
0, 0, // top left
0, 0.749023438, // bottom left
0.18359375, 0.749023438, // bottom right
0.18359375, 0, // top right
// Top face - WiiRear
0.25, 1, // top left
0.25, 0.844726563, // bottom left
0.43359375, 0.844726563, // bottom right
0.43359375, 1, // top right
// Rear face
0.25, 0, // bottom right
0.25, 0.751953125, // top right
0.43359375, 0.751953125, // top left
0.43359375, 0, // bottom left
// Bottom face
0, 0.84375, // top left
0, 1, // bottom left
0.18359375, 1, // bottom right
0.18359375, 0.84375, // top right
// Left face
0.5, 0, // bottom left
0.6640625, 0, // bottom right
0.6640625, 0.751953125, // top right
0.5, 0.751953125, // top left
// Right face
0.75, 0, // bottom left
0.9140625, 0, // bottom right
0.9140625, 0.751953125, // top right
0.75, 0.751953125, // top left
};
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(0, 0, backingWidth, backingHeight);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
// Our new drawing code goes here
glLoadIdentity();
glTranslatef(0.0, 0.0, -2.0);
#ifdef USE_BLUETOOTH
glRotatef(rotateX, 1.0f, 0.0f, 0.0f);
glRotatef(rotateY, 0.0f, 1.0f, 0.0f);
glRotatef(rotateZ, 0.0f, 0.0f, 1.0f);
// glRotatef(1.0f, rotateX, rotateY, rotateZ);
#else
rota += 1;
glRotatef(rota, 0.0, 0.5, 0.0);
glRotatef(rota, 0.0, 0.0, 1.0);
#endif
glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, squareTextureCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glColor4f(1.0, 1.0, 1.0, 1.0);
// Draw the front face in Red
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
// Draw the top face in green
glDrawArrays(GL_TRIANGLE_FAN, 4, 4);
// Draw the rear face in Blue
glDrawArrays(GL_TRIANGLE_FAN, 8, 4);
// Draw the bottom face
glDrawArrays(GL_TRIANGLE_FAN, 12, 4);
// Draw the left face
glDrawArrays(GL_TRIANGLE_FAN, 16, 4);
// Draw the right face
glDrawArrays(GL_TRIANGLE_FAN, 20, 4);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
[self checkGLError:NO];
}
- (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 %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
return NO;
}
return YES;
}
- (void)setupView {
const GLfloat zNear = 0.1, zFar = 1000.0, fieldOfView = 60.0;
GLfloat size;
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
// This give us the size of the iPhone display
CGRect rect = self.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);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
- (void)loadTexture {
CGImageRef textureImage = [UIImage imageNamed:@"wiimote_texture.png"].CGImage;
if (textureImage == nil) {
NSLog(@"Failed to load texture image");
return;
}
NSInteger texWidth = CGImageGetWidth(textureImage);
NSInteger texHeight = CGImageGetHeight(textureImage);
GLubyte *textureData = (GLubyte *)malloc(texWidth * texHeight * 4);
CGContextRef textureContext = CGBitmapContextCreate(textureData,
texWidth, texHeight,
8, texWidth * 4,
CGImageGetColorSpace(textureImage),
kCGImageAlphaPremultipliedLast);
CGContextDrawImage(textureContext, CGRectMake(0.0, 0.0, (float)texWidth, (float)texHeight), textureImage);
CGContextRelease(textureContext);
glGenTextures(1, &textures[0]);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
free(textureData);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glEnable(GL_TEXTURE_2D);
}
- (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)checkGLError:(BOOL)visibleCheck {
GLenum error = glGetError();
switch (error) {
case GL_INVALID_ENUM:
NSLog(@"GL Error: Enum argument is out of range");
break;
case GL_INVALID_VALUE:
NSLog(@"GL Error: Numeric value is out of range");
break;
case GL_INVALID_OPERATION:
NSLog(@"GL Error: Operation illegal in current state");
break;
case GL_STACK_OVERFLOW:
NSLog(@"GL Error: Command would cause a stack overflow");
break;
case GL_STACK_UNDERFLOW:
NSLog(@"GL Error: Command would cause a stack underflow");
break;
case GL_OUT_OF_MEMORY:
NSLog(@"GL Error: Not enough memory to execute command");
break;
case GL_NO_ERROR:
if (visibleCheck) {
NSLog(@"No GL Error");
}
break;
default:
NSLog(@"Unknown GL Error");
break;
}
}
- (void)setRotationX:(int)x Y:(int)y Z:(int)z{
// NSLog(@"BT data: %u %u %u", x , y ,z);
rotateX = x;
rotateY = y;
rotateZ = z;
}
- (void)dealloc {
[self stopAnimation];
if ([EAGLContext currentContext] == context) {
[EAGLContext setCurrentContext:nil];
}
[context release];
[super dealloc];
}
@end