update: 2012/03/30
reference:
1. 原文:
iPhone Development: OpenGL ES From the Ground Up, Part 2: A Look at Simple Drawing
2. 翻譯:
從零開始學習OpenGL ES之二 – 簡單繪圖概述
3. Developer's Note: Protocol & Delegate
簡單繪圖之一: 繪圖架構
A. 說明
1. 為了儘量接近原始文章的架構, 因此需要使用到 Delegate (委任) 的方式. 2. 先不使用 OpenGL ES 2, 而使用 OpenGL ES 1.
3. 目前主要有三個類別檔案: GLView, ViewController 與 AppDelegate,
功能調整如下:
a. GLView:
(1). 將定義一個 protocol: <GLViewDelegate>, 並新增一個將實作此 protocol
的變數 delegate
(2). <GLViewDelegate> protocol 宣告了二個需要被實作的方法:
// 用來設置 view
- (void)setupView:(GLView *)view;
// 這是最主要繪圖的地方
- (void)drawView:(GLView *)view;
(3). GLView 類別新增了以下的方法:
// 於繪圖前, 清除緩衝區內容
- (void)destroyFrameBuffer;
// 建立緩衝區內容, 並呼叫 delegate 的 setupView:
- (BOOL)createFrameBuffer;
// 呼叫 delegate 的 drawView: , 並實際將內容畫到螢幕上
- (void)drawView;
說明: 以上三個方法將藉由覆寫本身(GLView)的 layoutSubviews方法,
而依序自動被呼叫.
b. ViewController:
(1). 宣告 ViewController 類別, 必須遵循 <GLViewDelegate> protocol 的規範.
(2). ViewController 必須實作 <GLViewDelegate> protocol 所宣告的二個方法:
// 用來設置 view
- (void)setupView:(GLView *)view;
// 這是最主要繪圖的地方
- (void)drawView:(GLView *)view;
c. AppDelegate:
在 application:didFinishLaunchingWithOptions: 方法內, 將 GLView 實體
的 delegate 指向 ViewController 實體.
self.glView.delegate = self.viewController;
4. 整個繪圖架構流程大致如下:
步驟 01. AppDelegate => didFinishLaunchingWithOptions
步驟 02. GLView => layoutSubviews
步驟 03. GLView => destroyFrameBuffer
步驟 04. GLView => createFrameBuffer
步驟 05. ViewController => setupView:
步驟 06. GLView => drawView
步驟 07. ViewController => drawView:
-----------------------------------------------------------------------------------------------
B. 開啓 GLView.h 檔案, 修改如下:
#import <UIKit/UIKit.h>
//@add
#import <OpenGLES/EAGL.h>
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
#import "OpenGLESCommon.h"
#import "ConstantsAndMacros.h"
//@add for protocol
@protocol GLViewDelegate;
@interface GLView : UIView
{
//@add
EAGLContext *glContext;
//@add
GLint backingWidth;
GLint backingHeight;
GLuint viewRenderBuffer;
GLuint viewFrameBuffer;
GLuint depthRenderBuffer;
id<GLViewDelegate> delegate;
}
//@add
@property (nonatomic, strong) EAGLContext *glContext;
@property (assign) /* weak ref */ id <GLViewDelegate> delegate;
//@add
- (void)destroyFrameBuffer;
- (BOOL)createFrameBuffer;
- (void)drawView;
@end
//@add for protocol
@protocol GLViewDelegate
- (void)setupView:(GLView *)view;
- (void)drawView:(GLView *)view;
@end
-----------------------------------------------------------------------------------------------
#import "GLView.h"
@implementation GLView
//@add
@synthesize glContext = _glContext;
@synthesize delegate = _delegate;
//@add
- (EAGLContext *)glContext
{
if (_glContext == nil) {
//_glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
//@update
_glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
}
return _glContext;
}
....
//@update: comment it
/*
- (id)initWithFrame:(CGRect)frame
{
....
}
*/
....
//@add: overide
- (void)layoutSubviews
{
NSLog(@"step 02. GLView => layoutSubviews");
[EAGLContext setCurrentContext:self.glContext];
[self destroyFrameBuffer];
[self createFrameBuffer];
[self drawView];
}
//@add
- (void)destroyFrameBuffer
{
NSLog(@"step 03. GLView => destroyFrameBuffer");
glDeleteFramebuffersOES(1, &viewFrameBuffer);
viewFrameBuffer = 0;
glDeleteRenderbuffersOES(1, &viewRenderBuffer);
viewRenderBuffer = 0;
if(depthRenderBuffer)
{
glDeleteRenderbuffersOES(1, &depthRenderBuffer);
depthRenderBuffer = 0;
}
}
//@add
- (BOOL)createFrameBuffer
{
NSLog(@"step 04. GLView => createFrameBuffer");
// 從 UIView 取得 layer (CALayer), 向下轉型成 CAEAGLLayer.
// 在此為安全的, 因為 layerClass 方法已被覆寫)
CAEAGLLayer *eaglLayer = (CAEAGLLayer*) super.layer;
// 直接使用 OpenGL 設定不透明度
eaglLayer.opaque = YES;
// 定義: 渲染(render)與幅(frame)緩衝區(buffer)
glGenFramebuffersOES(1, &viewFrameBuffer);
glGenRenderbuffersOES(1, &viewRenderBuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFrameBuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderBuffer);
[self.glContext renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:eaglLayer];
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;
}
/**** 以上此段非必要 ****/
// GO: step 05. ViewController => setupView:
[self.delegate setupView:self];
return YES;
}
//@add
- (void)drawView
{
NSLog(@"step 06. GLView => drawView");
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFrameBuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderBuffer);
// GO: step 07. ViewController => drawView:
[self.delegate drawView:self];
[self.glContext presentRenderbuffer:GL_RENDERBUFFER_OES];
}
....
-----------------------------------------------------------------------------------------------
D. 開啓 ViewController.h 檔案, 修改如下:
#import <UIKit/UIKit.h>
//@add
#import "GLView.h"
//@interface ViewController : UIViewController
//@update
@interface ViewController : UIViewController <GLViewDelegate>
{
}
@end
-----------------------------------------------------------------------------------------------
E. 開啓 ViewController.m 檔案, 修改如下:
....
//@add for <GLViewDelegate> method
-(void)setupView:(GLView *)view
{
NSLog(@"step 05. ViewController => setupView:");
const GLfloat zNear = 0.01, zFar = 1000.0, fieldOfView = 45.0;
GLfloat size;
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);
glLoadIdentity();
}
//@add for <GLViewDelegate> method
- (void)drawView:(GLView *)view
{
NSLog(@"step 07. ViewController => drawView:");
// Draw code here
glClearColor(0.5f, 0.5f, 0.5f, 1); // 將顏色定義為灰色
glClear(GL_COLOR_BUFFER_BIT); // 執行清除操作
}
....
//@update: comment it
/*
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
*/
....
-----------------------------------------------------------------------------------------------
F. 開啓 AppDelegate.m 檔案, 修改如下:
....
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
/*
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
*/
//@update
NSLog(@"step 01. AppDelegate => didFinishLaunchingWithOptions");
CGRect screenBounds = [[UIScreen mainScreen] bounds];
self.window = [[UIWindow alloc] initWithFrame:screenBounds];
self.viewController = [[ViewController alloc] init];
self.glView = [[GLView alloc] initWithFrame:screenBounds];
self.window.rootViewController = viewController;
self.viewController.view = self.glView;
//@add for delegate
self.glView.delegate = self.viewController;
[self.window addSubview:self.viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
....
-----------------------------------------------------------------------------------------------
G. 編譯並執行
step 01. AppDelegate => didFinishLaunchingWithOptions
OpenGLESBegin[3779:fb03] step 02. GLView => layoutSubviews
OpenGLESBegin[3779:fb03] step 03. GLView => destroyFrameBuffer
OpenGLESBegin[3779:fb03] step 04. GLView => createFrameBuffer
OpenGLESBegin[3779:fb03] step 05. ViewController => setupView:
OpenGLESBegin[3779:fb03] step 06. GLView => drawView
OpenGLESBegin[3779:fb03] step 07. ViewController => drawView:
-----------------------------------------------------------------------------------------------
H. 備註
1. 很多 code 原本應該是由 template 產生的, 但是找不到原始可用的 template,
所以變成自行 coding, 因此缺少了許多的說明; 目前先將重心放在畫圖本身.
2. 以後畫圖的 code, 幾乎都是寫在 ViewController.m 裡的 drawView: 內.
//@add for <GLViewDelegate> method
- (void)drawView:(GLView *)view
{
NSLog(@"step 07. ViewController => drawView:");
// Draw code here
....
}
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。