update: 2012/06/24
reference:
1. Beginning OpenGL ES 2.0 with GLKit Part 1 | Ray Wenderlich
2. I touchs: OpenGL ES 2.0 with GLKit Part 1 - 1
GLKViewController
A. GLKViewController 介紹
1. 說明:
我們可以使用更容易的方式來完成之前所作的事, 使用: GLKViewController.
先前, 之所以使用 GLKView, 是讓我們可以了解使用 GLKViewController
背後的重點, 並節省了撰寫那些程式碼, 還可進一步自行撰寫你想要的
額外功能.
2. 開啟 AppDelegate.h 檔案, 修改如下:
....
//@interface AppDelegate : UIResponder <UIApplicationDelegate, GLKViewDelegate>
//@update for set the GLKViewController's delegate to the current class
@interface AppDelegate : UIResponder <UIApplicationDelegate, GLKViewDelegate, GLKViewControllerDelegate>
{
//@add
float _curRed;
BOOL _increasing;
}
....
//@add
//@update: comment it
//- (void)render:(CADisplayLink *)displayLink;
....
3. 開啟 AppDelegate.m 檔案, 修改如下:
....
// step 1
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//@add
_increasing = YES;
_curRed = 0.0;
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
//@add for GLKView
//
// step 1: Create a OpenGL context
//
// 1-1: An EAGLContext manages all of the information iOS needs to draw with OpenGL.
// 1-2: And specify what version of the API you want to use.(Here, OpenGL ES 2.0)
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
// step 2: Create a GLKView
//
// This creates a new instance of a GLKView, and makes it as large as the entire window.
GLKView *view = [[GLKView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// step 3: Set the GLKView's context
//
// Tell GLKView to use the OpenGL context.
view.context = context;
// step 4: Set the GLKView's delegate
//
// 4-1: This sets the current class (AppDelegate) as the GLKView's delegate.
// 4-2: This means whenever the view needs to be redrawn, it will call
// a method named glkView:drawInRect on whatever class you specify here.
// We will implement this inside the App Delegate shortly to contain
// some basic OpenGL commands to paint the screen red.
view.delegate = self;
//@add: for synchronize
//@update: comment it
/*
view.enableSetNeedsDisplay = NO;
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render:)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
*/
// step 5: Add the GLKView as a subview
//@update: comment it
//[self.window addSubview:view];
// step 6: for GLKViewController
//
// 6-1: Create a GLKViewController
//
// This creates a new instance of a GLKViewController programatically.
//
// In this case, it has no XIB associated.
GLKViewController *viewController = [[GLKViewController alloc] initWithNibName:nil bundle:nil];
// 6-2: Set the GLKViewController's view
//
// The root view of a GLKViewController should be a GLKView,
// so we set it to the one we already created.
viewController.view = view;
// 6-3: Set the GLKViewController's delegate
//
// We set the current class (AppDelegate) as the delegate of the GLKViewController.
//
// This means that the GLKViewController will notify us each frame
// so we can run game logic, or when the game pauses.
viewController.delegate = self;
// 6-4: Set the preferred FPS
//
// The GLKViewController will call your draw method a certain number of times
// per second.
//
// The default value is 30 FPS. Apple's guidelines are to set this to whatever your app
// can reliably support to the frame rate is consistent and doesn't seem to stutter.
//
// This app is very simple so can easily run at 60 FPS, so we set it to that.
//
// If you want to see the actual number of times the OS will attempt to call your
// update/draw methods, check the read-only framesPerSecond property.
viewController.preferredFramesPerSecond = 60;
// 6-5: Set the rootViewController
//
// We want this view controller to be the first thing that shows up,
// so we add it as the rootViewController of the window.
//
// We no longer need to add the view as a subview of the window manually,
// because it's the root view of the GLKViewController.
//
// We no longer need the code to run the render loop and tell the GLView
// to refresh each frame – GLKViewController does that for us in the background!
// So go ahead and comment out the render method as well.
self.window.rootViewController = viewController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
....
// step 2
//@update: comment it
/*
- (void)render:(CADisplayLink *)displayLink
{
GLKView *view = [self.window.subviews objectAtIndex:0];
[view display];
}
*/
....
// step 3
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
//@add
//@update: comment it
/*
if (_increasing) {
_curRed += 0.01;
} else {
_curRed -= 0.01;
}
if (_curRed >= 1.0) {
_curRed = 1.0;
_increasing = NO;
}
if (_curRed <= 0.0) {
_curRed = 0.0;
_increasing = YES;
}
*/
// specify the RGB and alpha (transparency) values to use when clearing the screen.
//glClearColor(1.0, 0.0, 0.0, 1.0);
//@update
glClearColor(_curRed, 0.0, 0.0, 1.0);
// actually perform the clearing.
glClear(GL_COLOR_BUFFER_BIT);
}
....
// step 4
#pragma mark - GLKViewControllerDelegate
//@add for implement delegate method
- (void)glkViewControllerUpdate:(GLKViewController *)controller
{
// property: timeSinceLastUpdate
//
// it guarantees the animation will always proceed at the same speed,
// regardless of the frame rate.
if (_increasing) {
_curRed += 1.0 * controller.timeSinceLastUpdate;
} else {
_curRed -= 1.0 * controller.timeSinceLastUpdate;
}
if (_curRed >= 1.0) {
_curRed = 1.0;
_increasing = NO;
}
if (_curRed <= 0.0) {
_curRed = 0.0;
_increasing = YES;
}
}
....
4. 編譯並執行:
結果與之前相同
--------------------------------------------------------------------------------
B. GLKViewController 與 Storyboards
1. 新增 GLKViewController 子類別檔案:
Xcode > File > New > New File...
iOS > Cocoa Touch > Objective-C class > Next
Class: HelloGLKitViewController
Subclass of: GLKViewController (如果無法選取到, 就自行輸入)
> Next > Create
****************************************************
2. 開啟 HelloGLKitViewController.m 檔案, 修改如下:
....
// step 1:
@interface HelloGLKitViewController ()
{
//@add
float _curRed;
BOOL _increasing;
}
//@add
@property (strong, nonatomic) EAGLContext *context;
@end
@implementation HelloGLKitViewController
//@add
@synthesize context = _context;
....
// step 2:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//@add
// 1. create an OpenGL ES 2.0 context
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(@"Failed to create ES context");
}
// 2. Our root view is a GLKView, so we cast it as one.
//
// We then set its context to the OpenGL context we just created.
GLKView *view = (GLKView *)self.view;
view.context = self.context;
// 3. Note
//
// We don't have to set the view controller as the view's delegate
// – GLKViewController does this automatically behind the scenes.
}
....
// step 3:
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
//@add
//
// we check to see if the current context is our context
if ([EAGLContext currentContext] == self.context) {
// set it to nil if so
[EAGLContext setCurrentContext:nil];
}
// clear out your reference to it.
self.context = nil;
}
....
// step 4:
#pragma mark - GLKViewDelegate
//@add
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(_curRed, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
}
....
// step 5:
#pragma mark - GLKViewControllerDelegate
//@add
- (void)update
{
if (_increasing) {
_curRed += 1.0 * self.timeSinceLastUpdate;
} else {
_curRed -= 1.0 * self.timeSinceLastUpdate;
}
if (_curRed >= 1.0) {
_curRed = 1.0;
_increasing = NO;
}
if (_curRed <= 0.0) {
_curRed = 0.0;
_increasing = YES;
}
}
....
****************************************************
3. 新增 Storyboard 檔案:
Xcode > File > New > New File...
iOS > User Interface > Storyboard > Next
Device Family: iPhone
Save As: MainStoryboard.storyboard
> Create
****************************************************
4. 開啟 MainStoryboard.storyboard 檔案, 修改如下:
a. 從右方的 Objects panel 拖拉一個 View Controller 進來:
將 Class 由 UIViewController 改選為: HelloGLKitViewController.
Identity Inspector, 將 Class 由 UIView 改選為: GLKView.
5. 開啟 HelloGLKit-Info.plist 檔案, 修改如下:
a. 在下方空白的地方按下: control + 滑鼠左鍵 > Add Row
Key: Main storyboard file base name
Type: StringValue: MainStoryboard
****************************************************
6. 移除不再使用的程式碼:
a. 開啟 AppDelegate.h 檔案, 修改如下:
#import <UIKit/UIKit.h>
//@add
//#import <GLKit/GLKit.h>
//#import <QuartzCore/QuartzCore.h> // used for CADisplayLink
@interface AppDelegate : UIResponder <UIApplicationDelegate>
//@update for set as GLKView's delegate
//@interface AppDelegate : UIResponder <UIApplicationDelegate, GLKViewDelegate>
//@update for set the GLKViewController's delegate to the current class
//@interface AppDelegate : UIResponder <UIApplicationDelegate, GLKViewDelegate, GLKViewControllerDelegate>
{
//@add
/*
float _curRed;
BOOL _increasing;
*/
}
@property (strong, nonatomic) UIWindow *window;
//@add
//@update: comment it
//- (void)render:(CADisplayLink *)displayLink;
@end
b. 開啟 AppDelegate.m 檔案, 修改如下:
....
// step 1:
#pragma mark - GLKViewDelegate
/*
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
....
}
*/
....
// step 2:
#pragma mark - GLKViewControllerDelegate
/*
- (void)glkViewControllerUpdate:(GLKViewController *)controller
{
....
}
*/
....
// step 3:
/*
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
....
}
*///@update
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return YES;
}
****************************************************
7. 編譯並執行:
結果與之前相同.
備註: 到目前為止的專案架構, 已經與你選擇用 OpenGL Game 樣板來新增
專案非常類似了(除了有一大堆其它你可以刪除的程式碼), 以後就可以
選擇 OpenGL Game 樣板來建立新專案了, 這可以省下一點時間.
--------------------------------------------------------------------------------
C. GLKViewController 與暫停
1. 開啟 HelloGLKitViewController.m 檔案, 修改如下:
....
//@add
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.paused = !self.paused;
}
....
2. 編譯並執行:
任何時間, 輕觸螢幕, 便會停止動畫或繼續執行動畫. 在場景後面的機制,
是 GLKViewController 停止 / 繼續 呼叫 glkView:drawInRect: 與 update 方法.
3. 除此之外, GLKViewController 有一個 pauseOnWillResignActive 屬性,
預設值為 YES, 代表, 當使用者按下 home 按鈕或者接受到一個中止的訊號,
例如有某人來電, 你的遊戲會自動地暫停. 類似地, 它也有一個
resumeOnDidBecomeActive 屬性, 預設值為 YES, 代表當使用者回到你的 App ,
遊戲就會自動繼續, 真是方便.
4. GLKViewController 的其它 "時間資訊" 屬性:
a. timeSinceLastDraw
從最近一次呼叫 draw 方法, 到目前的時間. 這可能會與 timeSinceLastUpdate
不同, 因為執行 update 方法需要花一些時間.
b. timeSinceFirstResume
從 GLKViewController 第一次重新開始發送更新訊息, 到目前的時間.
如果你的 GLKViewController 是第一個會展現的東西, 這通常代表從你的
App 啟動(launched) 到目前的時間.
c. timeSinceLastResume
最近一次 GLKViewController 重新開始發送更新訊息, 到目前的時間.
這通常代表從你的 App 最近一次從暫停恢復執行(unpaused) 到目前的時間.
5. 開啟 HelloGLKitViewController.m 檔案, 修改如下:
....
//@add
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//@add for time info
NSLog(@"timeSinceLastUpdate: %f", self.timeSinceLastUpdate);
NSLog(@"timeSinceLastDraw: %f", self.timeSinceLastDraw);
NSLog(@"timeSinceFirstResume: %f", self.timeSinceFirstResume);
NSLog(@"timeSinceLastResume: %f", self.timeSinceLastResume);
self.paused = !self.paused;
}
....
6. 編譯並執行:
按 home 鍵 > 回復 > 輕觸螢幕:
HelloGLKit[1421:fb03] timeSinceLastUpdate: 0.033285
HelloGLKit[1421:fb03] timeSinceLastDraw: 0.033285
HelloGLKit[1421:fb03] timeSinceFirstResume: 7.780801
HelloGLKit[1421:fb03] timeSinceLastResume: 0.991113
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。