OpenGL ESテンプレート(3)~GLFunViewControllerクラス(2)

2012. 02. 07
3)クラスエクステンション

@interface GLFunViewController ()
@property (nonatomic, retain) EAGLContext *context;
@property (nonatomic, assign) CADisplayLink *displayLink;
- (BOOL)loadShaders;
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file;
- (BOOL)linkProgram:(GLuint)prog;
- (BOOL)validateProgram:(GLuint)prog;
@end

ソースファイル内にある『@interface ~ () ... @end』はカテゴリの一種であるクラスエクステンションと呼ばれるもので、カテゴリ名を指定せずにクラスの実装部に記述するカテゴリです。

クラスエクステンションの特徴は次の2点です。

・宣言したメソッドは実装しなければならない(実装漏れを防ぐことができる)
・ヘッダファイルに記述しないメソッドを作成できる(プライベートなメソッドの実現)

(『Co2er/クラスエクステンション(class extensions)』や『詳解 Objective-C 2.0』(最新版『詳解 Objective-C 2.0 第3版』)の『09-01 カテゴリ』にある項目『クラスエクステンション』参照)

自動生成されるものに実装漏れの心配は無いでしょうし、個人制作ならプライベートなメソッドにする必要性もあまり感じませんが、宣言されているメソッドが記述順序で前後して呼び出されていることから、少なくともカテゴリでメソッドの宣言をする必要はあります。

プロパティ)

2つのプロパティを宣言していますが、EAGLContextクラスのプロパティcontextはretain(保持)していますが、CADisplayLinkクラスのプロパティdisplayLinkはassign(代入、非保持)になっています。

CADisplayLinkクラスのリファレンスを見ると、CADisplayLinkオブジェクトはタイマーオブジェクトで、実行ループがディスプレイリンクを保持するとあります。

したがってdisplayLinkをassignにしている理由は、『A-Liaison BLOG/NSTimerは基本的にretainせずassignでよい』で説明されているNSTimerと同様に、ターゲットであるself(ビューコントローラ)がretainされてしまうと都合が悪いからのようです。

実際deallocメソッドではEAGLContextのプロパティだけreleaseしており、また実行ループからディスプレイリンクを削除するinvalidateメソッドはstopAnimationメソッドに記述され、stopAnimationメソッドはviewWillDisappear:メソッド、つまりビューが非表示になった時点で実行されるようになっています。

インスタンスメソッド)

ここで宣言されている4つのメソッドは、OpenGL ES 2.0に対応するGLSL用のメソッドで、OpenGL ES 1.1の場合は使用されません。

loadShaders:プログラマブルシェーダの初期化メソッド

compileShader:type:file::シェーダプログラムのコンパイルメソッド

linkProgram::シェーダプログラムのリンクメソッド

validateProgram::シェーダプログラムの検証メソッド


4)プロパティの実装

@synthesize animating, context, displayLink;

ヘッダファイルで宣言しているanimatingと、ソースファイル(クラスエクステンション)で宣言しているcontextとdisplayLinkプロパティを実装しています。

ヘッダファイルではもう一つanimationFrameIntervalプロパティがありますが、こちらは@synthesizeによる簡易実装ではなく、別途手動でアクセサを実装しています。


5)awakeFromNibメソッド

- (void)awakeFromNib
{
    EAGLContext *aContext = [[EAGLContext alloc]
     initWithAPI:kEAGLRenderingAPIOpenGLES2];

    if (!aContext)
    {
        aContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
    }

    if (!aContext)
        NSLog(@"Failed to create ES context");
    else if (![EAGLContext setCurrentContext:aContext])
        NSLog(@"Failed to set ES context current");

    self.context = aContext;
    [aContext release];

    [(EAGLView *)self.view setContext:context];
    [(EAGLView *)self.view setFramebuffer];

    if ([context API] == kEAGLRenderingAPIOpenGLES2)
        [self loadShaders];

    animating = FALSE;
    animationFrameInterval = 1;
    self.displayLink = nil;
}

awakeFromNibメソッドは、nibファイルから全てのオブジェクトを読み込んでインスタンスの初期化が完了した後に呼び出されるもので、(nibファイルで設定していない)それ以外の初期化を記述します。

具体的には、

・レンダリングコンテキストの生成
・生成したコンテキストを現在のコンテキストに設定(EAGLViewクラスのsetContext:メソッド)
・フレームバッファオブジェクトの生成と設定(EAGLViewクラスのsetFramebufferメソッド)
・(OpenGL ES 2.0の場合)シェーダの初期化(loadShadersメソッド)
・アニメーションパラメータの設定

を行っています。

レンダリングコンテキストの生成)

initWithAPI:メソッドでOpenGL ES 2.0用(kEAGLRenderingAPIOpenGLES2)の仮のレンダリングコンテキストを生成します。

2.0用のコンテキストが生成できなかった場合は、同メソッドでOpenGL ES 1.1用(kEAGLRenderingAPIOpenGLES1)の仮のレンダリングコンテキストaContextを生成します。

どちらのバージョンでもレンダリングコンテキストが生成できなかった場合は、エラーログを出力します。

また成功した場合、setCurrentContext:メソッドで生成したレンダリングコンテキストを現在のコンテキストに設定できなかった場合もエラーログを出力します。

生成できた仮のコンテキストaContextを現在のコンテキストに設定できた場合はプロパティcontextに設定し、仮のコンテキストは破棄します。

コンテキストの設定)

EAGLViewクラスのsetContext:メソッドは、ビューコントローラが新たに生成したコンテキストと、ビューの持つ既存のコンテキストが同じものかを確認し、異なる場合は新たなコンテキストをビューの現在のコンテキストとして置換します。
(詳細は後述します)

フレームバッファの生成と設定)

EAGLViewクラスのsetFramebufferメソッドは、EAGLViewクラスのcreateFramebufferメソッドを使用して、フレームバッファと色レンダバッファの生成とバインド、そしてフレームバッファへレンダバッファのアタッチを行い、ビューポートの設定を行います。
(詳細は後述します)

シェーダの初期化)

レンダリングコンテキストがOpenGL ES 2.0用の場合、GLFunViewControllerクラスのloadShadersメソッドを使用して、頂点シェーダとフラグメントシェーダの初期化を行います。

アニメーションパラメータの設定)

animatingはアニメーションが行われているかを示すブール値のフラグで、初期状態としてFALSE(アニメーション停止)を指定しています。

animationFrameIntervalはアニメーションのフレーム間隔の指定に用いる定数で、初期状態として1(60FPS)を指定しています。

displayLinkはディスプレイリンクオブジェクトで、初期状態ではnil(空)を指定します。


6)deallocメソッド

- (void)dealloc
{
    if (program)
    {
        glDeleteProgram(program);
        program = 0;
    }

    // Tear down context.
    if ([EAGLContext currentContext] == context)
        [EAGLContext setCurrentContext:nil];

    [context release];

    [super dealloc];
}

deallocメソッドは、現在のコンテキストに設定されているレンダリングコンテキストの削除と、OpenGL ES 2.0のレンダリングコンテキストの場合はプログラムオブジェクトの削除を行います。

プログラムオブジェクトが存在する場合はglDeleteProgramで削除します。

レンダリングコンテキストはcurrentContextメソッドで保持しているコンテキストが現在のコンテキストかどうかを判定し、そうであればsetCurrentContext:メソッドでnilを指定して現在のコンテキストを解放します。

その後、レンダリングコンテキストオブジェクトも解放します。

glDeleteProgram

void glDeleteProgram(GLuint program);

プログラムオブジェクトを削除します。

glDeleteProgramは、メモリを解放し、programによって指定されたプログラムオブジェクトに関連付けられた名前を無効にします。

このコマンドは、事実上glCreateProgramへの呼び出しの効果を無効にします。

プログラムオブジェクトが現在のレンダリング状態の一部として使用されている場合、削除用のフラグが立てられますが、レンダリングコンテキストの現在の状態の一部でなくなるまで削除されません。

削除するプログラムオブジェクトがアタッチされたシェーダオブジェクトを持つ場合、それらのシェーダオブジェクトは自動的にデタッチされますが、事前にglDeleteShaderへの呼び出しによって既に削除用のフラグが立てられていない限り削除されません。

programが値0の場合は無視されます。

プログラムオブジェクトが削除フラグを持っているかどうかを判断するには、引数にprogramとGL_DELETE_STATUSを渡してglGetProgramivを呼び出します。

programがOpenGLで生成された値でない場合は、GL_INVALID_VALUEが発生します。

program:削除するプログラムオブジェクトを指定します。

currentContext

+ (EAGLContext *)currentContext

呼び出したスレッドの現在のレンダリングコンテキストを返します。

戻り値は呼び出したスレッドの現在のEAGLコンテキストです。


7)viewWillAppear:メソッド

- (void)viewWillAppear:(BOOL)animated
{
    [self startAnimation];

    [super viewWillAppear:animated];
}

viewWillAppear:メソッドはビューコントローラのビューが表示される時に呼び出されるメソッドで、ここではアニメーションを開始するstartAnimationメソッドの呼び出しを行っています。


8)viewWillDisappear:メソッド

- (void)viewWillDisappear:(BOOL)animated
{
    [self stopAnimation];

    [super viewWillDisappear:animated];
}

viewWillDisappear:メソッドはビューコントローラのビューが非表示になる時に呼び出されるメソッドで、ここではアニメーションを停止するstopAnimationメソッドの呼び出しを行っています。


9)viewDidUnloadメソッド

- (void)viewDidUnload
{
    [super viewDidUnload];

    if (program)
    {
        glDeleteProgram(program);
        program = 0;
    }

    // Tear down context.
    if ([EAGLContext currentContext] == context)
        [EAGLContext setCurrentContext:nil];
    self.context = nil;
}

viewDidUnloadメソッドはビューコントローラのビューがメモリから解放された時に呼び出されるメソッドで、deallocメソッドと同様に現在のコンテキストに設定されているレンダリングコンテキストと、OpenGL ES 2.0のレンダリングコンテキストの場合はプログラムオブジェクトの削除を行っています。


10)animationFrameIntervalメソッド

- (NSInteger)animationFrameInterval
{
    return animationFrameInterval;
}

animationFrameIntervalはヘッダファイルで宣言したプロパティのゲッタで、単にインスタンス変数animationFrameIntervalを返します。

インスタンス変数animationFrameIntervalは前述のawakeFromNibで初期化した後、後述するstartAnimationメソッドで変数として読み込まれるだけで、実際にはアクセサとしては使用されていません。
(フレーム間隔を任意に変更する機能が必要な場合のために用意されているものと思われます)


11)setAnimationFrameInterval:メソッド

- (void)setAnimationFrameInterval:(NSInteger)frameInterval
{
    /*
    Frame interval defines how many display frames must pass between each time the display
     link fires.
    The display link will only fire 30 times a second when the frame internal is two on a
     display that refreshes 60 times a second.
    The default frame interval setting of one will fire 60 times a second when the display
     refreshes at 60 times a second.
    A frame interval setting of less than one results in undefined behavior.
    */

    if (frameInterval >= 1)
    {
        animationFrameInterval = frameInterval;

        if (animating)
        {
            [self stopAnimation];
            [self startAnimation];
        }
    }
}

setAnimationFrameInterval:メソッドはヘッダファイルで宣言したプロパティのセッタで、アニメーションのフレーム間隔を設定します。

コメント文には、『フレーム間隔は、ディスプレイリンクが発動させる各時間の間に渡す必要がある表示フレーム数を定義します。ディスプレイリンクは1秒で60回更新するため、フレーム間隔が2の時は1秒で30回発動します。デフォルトのフレーム間隔の設定は1で、1秒で60回の表示を更新する場合、1秒あたり60回発動します。フレーム間隔の設定が1未満の場合の動作は未定義です。』と書かれており、引数frameIntervalが1未満の条件は記述されていません。

1以上の場合は引数frameIntervalをanimationFrameIntervalに設定し、フラグanimatingが有効な場合は一度stopAnimationで既存のアニメーションを停止した後で、startAnimationを呼び出しアニメーションを再開します。



参考文献

iOS OpenGL ESプログラミングガイド
 
OpenGL ES 2.0 Reference Pages

Co2er/クラスエクステンション(class extensions)

A-Liaison BLOG/NSTimerは基本的にretainせずassignでよい

EAGLContext Class Reference

詳解 Objective-C 2.0 第3版詳解 Objective-C 2.0 第3版
(2011/12/28)
荻原 剛志

商品詳細を見る






bose_soundsport_free
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
09 | 2017/10 | 11
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

bose_soundsport_free
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR