Pinball Tristan - Mac App Store版のテスト

Mac App StoreでPinball Tristanが承認されたのでpromo codeでダウンロードしてテスト。すると・・・

xpchelper reply message validation: sandbox creation failed: 1002
Code identity not in ACL for container ~/Library/Containers/com.littlewingpinball.Pinball-Tristan-OSX/Data
(if this is a self-signed app, see asctl(1) for how to resolve)

お叱りのお言葉が (((( ;゚Д゚)))
このメッセージが出るのは開発機のsandboxに開発中のバージョンが残っていたからで、この場合は~/Library/Containers/com.littlewingpinball.Pinball-Tristan-OSXを丸ごと消すだけで無事解決 (σ ゚ー゚)σ

Snow Leopardが飛ぶ日

Snow Leopardを入れていたドライブが飛びました ( ̄〜 ̄;)
新しいOSを入れてしばらくすると古いOSが飛ぶことが多いようなっていうのは気のせいでしょうかw
久しぶりに復旧作業をしたのでメモに残しておきます

1. まずインストールディスクで起動してディスクユーティリティで修復を試みる

多くのトラブルはこれで修復するのですが今回は駄目でした。こうなるとデータのサルベージが必要となります。

2. マシンの電源を入れて「ポーン」いう音を聞いたらCommand+Sを押しっぱなしにしてシングルモードで起動

シングルモードは通常の起動では途中で電源が切れてしまうような場合でも使えることが多いです。OS Xは起動ディスクに指定されたボリュームに問題があると、fsckで修復を数回試み、それで修復ができなかった場合は自動的にシャットダウンしているように見えます。シングルモードはfsckを行う前にプロンプトが出ているようです。

3. シングルモードのプロンプトが出たら"/sbin/mount -uw /"と打ち込む

これでマウントできれは嬉しいです。ディスクは破損した状態のままですが、とりあえず中のファイルを取り出すことができるようになります。できない場合は市販の修復ツールが必要になるかもしれません(´・ω・`)

4. 必要なファイルで重要度の高いもの(つまりラストバックアップに入っていない新しいファイル)をafpで別のMacに転送します(この状態でmount_afpは使えるのですがmount_smbとかは使えないようです)受側のMacのマシン名が"myMac"共有フォルダの名前が"crashsave"、それに接続するためのユーザー名が"foo"、パスワードが"bar"とすると、こんな具合で接続してcpでコピー

mkdir /Volumes/outlet
mount_afp afp://foo:bar@myMac/crashsave /Volumes/outlet
cp -R hoge /Volumes/outlet/hoge

5. HDがお釈迦になっても泣かなくてすむようになったならば、プロンプトにexitと打ち込んで、そのままMac OS Xを起動させてみます。ボリュームに問題があってもOS X本体が破損していなければ起動することが期待できます。

6. もし起動してもボリュームは壊れたままですから注意しましょう

7. DreamweaverXcodeのように設定を書き出すプログラムから必要な設定を動いているうちに引き出します。

8. 最後の最後にfsckで危険なオプションを使った修復を試みます・・・

9. ┐( ̄ヘ ̄)┌

10. 完全に論理構造が破壊されたので再フォーマット (σ ゚ー゚)σ

ああ懐かしのリソースフォーク

http://ja.wikipedia.org/wiki/リソースフォーク

Windows 2000 Serverの中のAppleShareボーリュームの中のDiskCopy 6.0フォーマットの.imgファイルの中にある天然記念物級に古いファイルをMac OS X 10.7 Lionに持ってこようとしたのだが・・・「次のディスクイメージは開けませんでした、理由:認識できません」となってしまった。

原因はFATフォーマットのUSBメモリを使ってコピーしたこと。リソースフォークが消えてしまったのだ。
そこで、AppleTalkがまだサポートされていたMac OS X 10.3 PantherをiCube G4で起動し、Windows 2000 ServerとMac OS X 10.7 Lionの間に入れてファイルをコピー。
コピーしたファイルを開こうとすると「次のディスクイメージは開けませんでした、理由:レガシーイメージを変換する必要があります」となるのだが、この変換は標準のディスクユーティリティのイメージ->変換が面倒を見てくれた。

今回は手持ちで全部繋がったからよかったけど、ちゃんと書き換えておかないとそろそろ切れそうで危ない (^_^;)

iPhone/iPadでゲームを開発しよう - その4

テスト用のプログラムですが、描画速度の変化が見やすいように動くようにしてみました :D

モデルを動かすには座標変換を行うための行列を使うことになるのですが、OpenGL ES2では行列関連のAPIがごっそり消えていますので必要なものはアプリで用意する必要があります。ここではPinball Tristan用に作った行列ライブラリを使う事にします。最小限の機能しかありませんが、この方が単純で読みやすいかもしれません :)

/*
 *  Matrix.h
 *
 *  Created by fujita-y
 *  Copyright 2010 LittleWing Co. Ltd. All rights reserved.
 *
 */

/*
    m[ 0] m[ 1] m[ 2] m[ 3]
    m[ 4] m[ 5] m[ 6] m[ 7]
    m[ 8] m[ 9] m[10] m[11]
    m[12] m[13] m[14] m[15]

    mm[0][0] mm[0][1] mm[0][2] mm[0][3]
    mm[1][0] mm[1][1] mm[1][2] mm[1][3]
    mm[2][0] mm[2][1] mm[2][2] mm[2][3]
    mm[3][0] mm[3][1] mm[3][2] mm[3][3]
*/

#pragma once
#ifndef __MATRIX_H__
#define __MATRIX_H__

#include <math.h>
#include <string.h>
#include <assert.h>

#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>

class Matrix4D {
public:

    union {
        GLfloat m[16];
        GLfloat mm[4][4];
    };

private:
    void clear() {
        m[ 0] = m[ 1] = m[ 2] = m[ 3] =
        m[ 4] = m[ 5] = m[ 6] = m[ 7] =
        m[ 8] = m[ 9] = m[10] = m[11] =
        m[12] = m[13] = m[14] = m[15] = 0.0f;
    }
    
    float normalize(float& x, float& y, float& z) {
        float d = sqrtf(x * x + y * y + z * z);
        if (d == 0.0f) return 0.0f;
        x /= d;
        y /= d;
        z /= d;
        return d;
    }
      
    bool lu_decomposition(Matrix4D& mat, int* idx) {
        for (int i = 0; i < 4; i++) idx[i] = i;        
        float weight[4];
        for (int i = 0; i < 4; i++) {
            float u = 0.0f;
            for (int j = 0; j < 4; j++) {
                float t = fabsf(mat.mm[i][j]);
                if (t > u) u = t;
            }
            if (u == 0.0f) return false;
            weight[i] = 1.0f / u;
        }
        for (int k = 0; k < 4; k++) {
            float u = fabsf(mat.mm[idx[k]][k]) * weight[idx[k]];
            int j = k;
            for (int i = k + 1; i < 4; i++) {
                int ii = idx[i];
                float t = fabsf(mat.mm[ii][k]) * weight[ii];
                if (t > u) {
                    u = t;
                    j = i;
                }
            }
            if (j != k) {
                int t = idx[j];
                idx[j] = idx[k];
                idx[k] = t;
            }
            int ik = idx[k];
            u = mat.mm[ik][k];
            if (u == 0.0) return false;
            for (int i = k + 1; i < 4; i++) {
                int ii = idx[i];
                float t = mat.mm[ii][k] / u;
                mat.mm[ii][k] = t;
                for (int j = k + 1; j < 4; j++) mat.mm[ii][j] -= mat.mm[ik][j] * t;
            }
        }
        return true;
    }

public:

    bool operator== (const Matrix4D& rhs) const { 
        return (this == &rhs) || (memcmp(m, rhs.m, sizeof(m)) == 0);
    }
    
    bool operator!= (const Matrix4D& rhs) const { 
        return (this != &rhs) && (memcmp(m, rhs.m, sizeof(m)) != 0);
    }

    void setTranspose(const Matrix4D& src) {
        assert(this != &src);
        m[ 0] = src.m[ 0];
        m[ 1] = src.m[ 4];
        m[ 2] = src.m[ 8];
        m[ 3] = src.m[12];
        m[ 4] = src.m[ 1];
        m[ 5] = src.m[ 5];
        m[ 6] = src.m[ 9];
        m[ 7] = src.m[13];
        m[ 8] = src.m[ 2];
        m[ 9] = src.m[ 6];
        m[10] = src.m[10];
        m[11] = src.m[14];
        m[12] = src.m[ 3];
        m[13] = src.m[ 7];
        m[14] = src.m[11];
        m[15] = src.m[15];
    }

    void setInverse(const Matrix4D& src) {
        assert(this != &src);
        Matrix4D lu(src);
        int idx[4];
        if (lu_decomposition(lu, idx)) {
            for (int k = 0; k < 4; k++) {
                for (int i = 0; i < 4; i++) {
                    int ii = idx[i];
                    float t = (ii == k) ? 1.0f : 0.0f;
                    for (int j = 0; j < i; j++) t -= lu.mm[ii][j] * mm[j][k];
                    mm[i][k] = t;
                }
                for (int i = 3; i >= 0; i--) {
                    int ii = idx[i];
                    float t = mm[i][k];
                    for (int j = i + 1; j < 4; j++) t -= lu.mm[ii][j] * mm[j][k];
                    mm[i][k] = t / lu.mm[ii][i];
                }
            }
            return;                    
        }
        setIdentity();           
    }
    
    void setMul(const Matrix4D& lhs, const Matrix4D& rhs) {
        assert(this != &lhs);
        assert(this != &rhs);
        for ( int i = 0; i < 4; i++ ) 
            for ( int j = 0; j < 4; j++ )
                mm[ i ][ j ] = lhs.mm[ 0 ][ j ] * rhs.mm[ i ][ 0 ]
                             + lhs.mm[ 1 ][ j ] * rhs.mm[ i ][ 1 ]
                             + lhs.mm[ 2 ][ j ] * rhs.mm[ i ][ 2 ]
                             + lhs.mm[ 3 ][ j ] * rhs.mm[ i ][ 3 ];
                    
    }    

    void setIdentity() {
        clear();
        m[0] = m[5] = m[10] = m[15] = 1.0f;
    }

    void setTranslate(GLfloat x, GLfloat y, GLfloat z) {
        setIdentity();
        m[12] = x;
        m[13] = y;
        m[14] = z;
    }
    
    void setRotate(GLfloat degree, GLfloat x, GLfloat y, GLfloat z) {
        float radian = degree * 3.141593f / 180.0f;
        float c = cos(radian);
        float s = sin(radian);
        normalize(x, y, z);
        m[ 0] = x * x + (1.0f - x * x) * c;
        m[ 1] = x * y * (1.0f - c) + z * s;
        m[ 2] = x * z * (1.0f - c) - y * s;
        m[ 3] = 0.0f;
        m[ 4] = x * y * (1.0f - c) - z * s;
        m[ 5] = y * y + (1.0f - y * y) * c;
        m[ 6] = y * z * (1.0f - c) + x * s;
        m[ 7] = 0.0f;
        m[ 8] = x * z * (1.0f - c) + y * s;
        m[ 9] = y * z * (1.0f - c) - x * s;
        m[10] = z * z + (1.0f - z * z) * c;
        m[11] = 0.0f;
        m[12] = 0.0f;
        m[13] = 0.0f;
        m[14] = 0.0f;
        m[15] = 1.0f;
    }

    void setScale(float x, float y, float z) {
        clear();
        m[ 0] = x;
        m[ 5] = y;
        m[10] = z;
        m[15] = 1.0f;
    }

    void setFrustum(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) {
        clear();
        m[ 0] = (2.0f * zNear) / (right - left);
        m[ 5] = (2.0f * zNear) / (top - bottom);
        m[ 8] = (right + left) / (right - left);
        m[ 9] = (top + bottom) / (top - bottom);
        m[10] = -(zFar + zNear) / (zFar - zNear);
        m[11] = -1.0f;
        m[14] = -(2.0f * zNear * zFar) / (zFar - zNear);
    }
    
    void setOrtho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) {
        clear();
        m[ 0] = 2.0f / (right - left);
        m[ 5] = 2.0f / (top - bottom);
        m[10] = -2.0f / (zFar - zNear);
        m[12] = -(right + left) / (right - left);
        m[13] = -(top + bottom) / (top - bottom);
        m[14] = -(zFar + zNear) / (zFar - zNear);
        m[15] = 1.0f;
    }

    void setLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx, GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy, GLfloat upz) {
        GLfloat z0 = eyex - centerx;
        GLfloat z1 = eyey - centery;
        GLfloat z2 = eyez - centerz;
        normalize(z0, z1, z2); 
        GLfloat y0 = upx;
        GLfloat y1 = upy;
        GLfloat y2 = upz;
        GLfloat x0 =  y1 * z2 - y2 * z1;
        GLfloat x1 = -y0 * z2 + y2 * z0;
        GLfloat x2 =  y0 * z1 - y1 * z0;
        y0 =  z1 * x2 - z2 * x1;
        y1 = -z0 * x2 + z2 * x0;
        y2 =  z0 * x1 - z1 * x0;
        normalize(x0, x1, x2);
        normalize(y0, y1, y2);        
        m[0] = x0;
        m[1] = y0;
        m[2] = z0;
        m[3] = 0.0;
        m[4] = x1;
        m[5] = y1;
        m[6] = z1;
        m[7] = 0.0;
        m[8] = x2;
        m[9] = y2;
        m[10] = z2;
        m[11] = 0.0;
        m[12] = 0.0;
        m[13] = 0.0;
        m[14] = 0.0;
        m[15] = 1.0;
        translate(-eyex, -eyey, -eyez);
    }

    void mul(const Matrix4D& rhs) {
        Matrix4D lhs(*this);
        setMul(lhs, rhs);
    }

    void scale(GLfloat x, GLfloat y, GLfloat z) {
        Matrix4D lhs(*this);
        Matrix4D rhs;
        rhs.setScale(x, y, z);
        setMul(lhs, rhs);
    }

    void rotate(GLfloat degree, GLfloat x, GLfloat y, GLfloat z) {
        Matrix4D lhs(*this);
        Matrix4D rhs;
        rhs.setRotate(degree, x, y, z);
        setMul(lhs, rhs);
    }

    void translate(GLfloat x, GLfloat y, GLfloat z) {
        Matrix4D lhs(*this);
        Matrix4D rhs;
        rhs.setTranslate(x, y, z);
        setMul(lhs, rhs);
    }

    void inverse() {
        Matrix4D lhs(*this);
        setInverse(lhs);
    }

    void transpose() {
        Matrix4D lhs(*this);
        setTranspose(lhs);
    }
    
    void lookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx, GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy, GLfloat upz) {
        Matrix4D lhs(*this);
        Matrix4D rhs;
        rhs.setLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz);
        setMul(lhs, rhs);
    }

};

struct Matrix3D {

    union {
        GLfloat m[9];
        GLfloat mm[3][3];
    };

    Matrix3D() {}

    Matrix3D(const Matrix4D& rhs) {
        m[0] = rhs.m[0];
        m[1] = rhs.m[1];
        m[2] = rhs.m[2];
        m[3] = rhs.m[4];
        m[4] = rhs.m[5];
        m[5] = rhs.m[6];
        m[6] = rhs.m[8];
        m[7] = rhs.m[9];
        m[8] = rhs.m[10];    
    }

    void set(const Matrix4D& rhs) {
        m[0] = rhs.m[0];
        m[1] = rhs.m[1];
        m[2] = rhs.m[2];
        m[3] = rhs.m[4];
        m[4] = rhs.m[5];
        m[5] = rhs.m[6];
        m[6] = rhs.m[8];
        m[7] = rhs.m[9];
        m[8] = rhs.m[10];    
    }

};

struct Vector3D {

    GLfloat vec[3];
    
    Vector3D() {}
    
    Vector3D(GLfloat v0, GLfloat v1, GLfloat v2) {
        vec[0] = v0;
        vec[1] = v1;
        vec[2] = v2;
    }
    
    void setMul(const Matrix3D& lhs, const Vector3D& rhs) {
        assert(this != &rhs);
        for ( int i = 0; i < 3; i++ )
            vec[i] = lhs.mm[0][i] * rhs.vec[0]
                   + lhs.mm[1][i] * rhs.vec[1]
                   + lhs.mm[2][i] * rhs.vec[2];
    }
    
    void setCrossProduct(const Vector3D& lhs, const Vector3D& rhs) {
        vec[0] = lhs.vec[1] * rhs.vec[2] - lhs.vec[2] * rhs.vec[1];
        vec[1] = lhs.vec[2] * rhs.vec[0] - lhs.vec[0] * rhs.vec[2];
        vec[2] = lhs.vec[0] * rhs.vec[1] - lhs.vec[1] * rhs.vec[0];
    }
    
    GLfloat magnitude() {
        return sqrtf(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
    }
    
    void normalize() {
        GLfloat m = 1.0 / magnitude();
        vec[0] *= m;
        vec[1] *= m;
        vec[2] *= m;
    }
    
    static GLfloat dotProduct(const Vector3D& lhs, const Vector3D& rhs) {
        return lhs.vec[0] * rhs.vec[0] + lhs.vec[1] * rhs.vec[1] + lhs.vec[2] * rhs.vec[2];
    }
    
};

struct Vector4D {

    GLfloat vec[4];

    Vector4D() {}
    
    Vector4D(GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {
        vec[0] = v0;
        vec[1] = v1;
        vec[2] = v2;
        vec[3] = v3;
    }
    
    void setMul(const Matrix4D& lhs, const Vector4D& rhs) {
        assert(this != &rhs);
        for ( int i = 0; i < 4; i++ )
            vec[i] = lhs.mm[0][i] * rhs.vec[0]
                   + lhs.mm[1][i] * rhs.vec[1]
                   + lhs.mm[2][i] * rhs.vec[2]
                   + lhs.mm[3][i] * rhs.vec[3];
    }
    
    GLfloat magnitude() {
        return sqrtf(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2] + vec[3] * vec[3]);
    }
    
    void normalize() {
        GLfloat m = 1.0 / magnitude();
        vec[0] *= m;
        vec[1] *= m;
        vec[2] *= m;
        vec[3] *= m;
    }

};

#endif

次にNotepadSampleViewController.mmに変更を加えます。NotepadSampleViewControllerの拡張子が.mmになっていることに注意してください。これはインポートするMatrix.hがC++で書いてあるのでObjective-C++でコンパイルしなければならないためです。

:

#import "Matrix.h" // これを上の方で追加

:

enum {
    UNIFORM_ROTATE, // 元のプログラムではUNIFORM_TRANSLATEとなっています
    NUM_UNIFORMS
};

:

- (void)drawFrame // 回転行列を計算してuniform変数に書き込むように書き換えます
{
    [(EAGLView *)self.view setFramebuffer];
    
    static GLfloat *vertices;
    const int numTriangles = 10000;
    const int numVertices = numTriangles * 3;
    const int numFloats = numVertices * 3;
    
    // ここで GLfloat *vertices に三角板のデータを用意します。作成するのは最初の一回だけです。
    if (vertices == NULL) {
        vertices = (GLfloat *)malloc(sizeof(GLfloat) * numFloats);
        for (int i = 0; i < numTriangles; i++) {
            GLfloat cx = random_zero_one() - 0.5;
            GLfloat cy = random_zero_one() - 0.5;
            GLfloat cz = random_zero_one() - 0.5;
            // vertex 1
            vertices[i * 9 + 0] = cx + random_delta();
            vertices[i * 9 + 1] = cy + random_delta(); 
            vertices[i * 9 + 2] = cz + random_delta();
            // vertex 2
            vertices[i * 9 + 3] = cx + random_delta();
            vertices[i * 9 + 4] = cy + random_delta(); 
            vertices[i * 9 + 5] = cz + random_delta();
            // vertex 3
            vertices[i * 9 + 6] = cx + random_delta();
            vertices[i * 9 + 7] = cy + random_delta(); 
            vertices[i * 9 + 8] = cz + random_delta();
        }
    }
    
    // モデルの回転行列をつくります
    static GLfloat x_degree;
    static GLfloat y_degree;
    if ((x_degree = x_degree + 1.0) > 360.0) x_degree -= 360.0;
    if ((y_degree = y_degree + 2.0) > 360.0) y_degree -= 360.0;
    Matrix4D rotate;
    rotate.setIdentity();
    rotate.rotate(x_degree, 1.0, 0.0, 0.0);
    rotate.rotate(y_degree, 0.0, 1.0, 0.0);

    glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glUseProgram(program);
    
    // uniform変数に回転行列をセット
    glUniformMatrix4fv(uniforms[UNIFORM_ROTATE], 1, GL_FALSE, rotate.m);

    glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, 0, 0, vertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    
    glDrawArrays(GL_TRIANGLES, 0, numVertices);
    
    [(EAGLView *)self.view presentFramebuffer];
}

:

    // uniforms[UNIFORM_TRANSLATE] = glGetUniformLocation(program, "translate");
    uniforms[UNIFORM_ROTATE] = glGetUniformLocation(program, "rotate"); // uniform変数の場所を取得

最後にバーテクスシェーダShader.vshを書き換えて回転行列を適用するようにします

uniform mat4 rotate; // モデルの回転行列
attribute vec4 position;
varying vec4 colorVarying;

void main()
{
    gl_Position = rotate * position; // 座標変換
    colorVarying = abs(position);
}

Xcode4のプロジェクトをダウンロードできるようにしましたので、どうぞお試しください :)
http://www.littlewing.jp/blog/NotepadSample_20110714.zip

iPhone/iPadでゲームを開発しよう - その3

まずは簡単にトライアングルを1万枚ほどレンダリングするサンプルプログラムを作ってみましょう :D

Xcode4のOpenGL ES Applicationテンプレートに以下の変更を行います。

== EAGLView.h

@interface EAGLView : UIView {
@private
    // The pixel dimensions of the CAEAGLLayer.
    GLint framebufferWidth;
    GLint framebufferHeight;
    
    // The OpenGL ES names for the framebuffer and renderbuffer used to render to this view.
    GLuint defaultFramebuffer, colorRenderbuffer;

    // @fujita-y 深度バッファ用定義をここに追加
    GLuint depthRenderbuffer; 
    // @fujita-y end
}

== EAGLView.m

- (void)createFramebuffer
{
    if (context && !defaultFramebuffer) {
        [EAGLContext setCurrentContext:context];
        
        // Create default framebuffer object.
        glGenFramebuffers(1, &defaultFramebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
        
        // Create color render buffer and allocate backing store.
        glGenRenderbuffers(1, &colorRenderbuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
        [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferWidth);
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &framebufferHeight);
        
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);

        // @fujita-y 深度バッファの作成をここに追加
        glGenRenderbuffers(1, &depthRenderbuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, framebufferWidth, framebufferHeight); 
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
        // @fujita-y end

        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
    }
}

- (void)deleteFramebuffer
{
    if (context) {
        [EAGLContext setCurrentContext:context];
        
        if (defaultFramebuffer) {
            glDeleteFramebuffers(1, &defaultFramebuffer);
            defaultFramebuffer = 0;
        }
        
        if (colorRenderbuffer) {
            glDeleteRenderbuffers(1, &colorRenderbuffer);
            colorRenderbuffer = 0;
        }
        
        // @fujita-y 深度バッファのデリートをここに追加
        if (depthRenderbuffer) {
            glDeleteRenderbuffers(1, &depthRenderbuffer);
            depthRenderbuffer = 0;
        }
        // @fujita-y end
        
    }
}

== notepad_sampleViewController.m(このファイル名は作成したプロジェクトの名前+"ViewController.m"になります)

// @fujita-y GLfloatの乱数その1
static GLfloat random_zero_one() // 0.0 .. 1.0
{
    return (float)rand() / (float)RAND_MAX;
}

// @fujita-y GLfloatの乱数その2
static GLfloat random_delta() // -0.025 .. 0.025
{
    return (random_zero_one() - 0.5) * 0.5;
}

// @fujita-y drawFrameを書き換え(OpenGL ES2必須)
- (void)drawFrame
{
    [(EAGLView *)self.view setFramebuffer];
    
    static GLfloat *vertices;
    const int numTriangles = 10000;
    const int numVertices = numTriangles * 3;
    const int numFloats = numVertices * 3;
    
    // ここで GLfloat *vertices に三角板のデータを用意します。作成するのは最初の一回だけです。
    if (vertices == NULL) {
        vertices = malloc(sizeof(GLfloat) * numFloats);
        for (int i = 0; i < numTriangles; i++) {
            GLfloat cx = random_zero_one() - 0.5;
            GLfloat cy = random_zero_one() - 0.5;
            GLfloat cz = random_zero_one() - 0.5;
            // vertex 1
            vertices[i * 9 + 0] = cx + random_delta();
            vertices[i * 9 + 1] = cy + random_delta(); 
            vertices[i * 9 + 2] = cz + random_delta();
            // vertex 2
            vertices[i * 9 + 3] = cx + random_delta();
            vertices[i * 9 + 4] = cy + random_delta(); 
            vertices[i * 9 + 5] = cz + random_delta();
            // vertex 3
            vertices[i * 9 + 6] = cx + random_delta();
            vertices[i * 9 + 7] = cy + random_delta(); 
            vertices[i * 9 + 8] = cz + random_delta();
        }
    }

    glClearColor(0.2f, 0.1f, 0.2f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glUseProgram(program);
    glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, 0, 0, vertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glDrawArrays(GL_TRIANGLES, 0, numVertices);
    
    [(EAGLView *)self.view presentFramebuffer];
}

== Shader.vsh

attribute vec4 position;
varying vec4 colorVarying;

void main()
{
    gl_Position = position;
    colorVarying = abs(gl_Position);
}

で、これをiPod touch 3Gで実行するとCoreAnimationのフレームレートが30fps・・・この段階では目眩のするような遅さです・・・が、最終的には下のような1万5千トライアングルのモデルにアンチエイリアスをかけても60fpsでグリグリ回るようになるのです :)