scheme-users.jp Scheme-users.jp

こちらのブログに加えて新しいLISPブログ始めました!

このブログと同じくLISPのことしか書かないブログになる予定です。

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を入れていたドライブが飛びました ( ̄〜 ̄;)

新しい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. DreamweaverやXcodeのように設定を書き出すプログラムから必要な設定を動いているうちに引き出します。

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の間に入れてファイルをコピー。

コピーしたファイルを開こうとすると「次のディスクイメージは開けませんでした、理由:レガシーイメージを変換する必要があります」となるのだが、この変換は標準のディスクユーティリティのイメージ->変換が面倒を見てくれた。

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

開発機にMac OS X Lionをインストールしました。Xcode 4.1を使うにはLionが必須なのですよ・・・パーテションを分けてSnow Leopardとdual bootにしていますが、なかなか安定している印象です。

いつものごとく古いLispマシンのメーリングリストを漁っていたところDO&というものの提案メールを発見しました。

Date: Wednesday, 21 April 1982, 20:15-EST
From: levitt at MIT-AI, zvona at MIT-AI
Sender: Zvona at MIT-AI
Subject: LMLIB;DO&
To: info-lispm at MIT-AI

DO& is an interation macro with many of the features of LOOP and a
LISPy syntax similar to DO*.  User-definable keywords allow common
iterative constructs -- like CDRing down a list, CONSing a new list,
or counting -- to be implemented more simply and readably.  Automatic
generation of end tests makes the DO/DO* end-test form unnecessary.

The programs below, equivalent to common LISP functions, give a feel for
DO& style:

(defun length (list)
  (do& ((i &count0)
	(l &pop list &return i))))

(defun reverse (list)
  (do& ((elt &pop list &return accum)
	(accum &push elt))))

(defun listarray (array)
  (do& ((elt &aref array
	     &return (nreverse list))
	(list &push elt))))

(defun remq (item list)
  (do& ((a &pop list &return (nreverse out))
	(out &push a
	     &only-if (neq a item)))))

DO& allows most relevant information to appear within the
variable specifications, improving program clarity, and doing
away with the need for formulaic and complex bodies.

DO& has evolved over more than two years and reimplemented many times.
The rough corners have been worn off, and we now believe the current
implementation is clean enough for general release.

DO& is documented in detail in LMLIB;DO&DOC.  Bugs to BUG-DO&@AI;
users may wish to add themselves to INFO-DO&.

Here is a partial comparison of features of DO& and LOOP.  It is
perhaps not perfectly impartial.  Also, many of the features of LOOP
which DO& lacks could be added if there were demand for them.

DO& syntax is a natural extension of DO*.  LOOP is a non-LISPy
sublanguage.  Partly as a consequence, it is easier to determine
the scope of DO& keywords than that of LOOP keywords.  Since
keywords all begin with ``&'' it is easy to separate them from
non-keywords.  The simplicity of DO& syntax makes it trivial to
learn and often immediately understandably by non-users.  Also it
indents better than LOOP in Zmacs.

LOOP and DO& have roughly comparable numbers predefined iteration
keywords.  The sets are not identical; LOOP has a package mapping
keyword, and DO& has one for mapping over plists.  In any case, both
make it relatively easy to define your own keywords, so exactly which
keywords are defined by default is not very important.

LOOP supports parallel binding; DO& does not.  Of course you can
always use an extra variable to get the same effect.

DO& guarantees that variables have sensible values at all times; LOOP
does not.  In particular, in a LOOP epilogue, the values of iteration
variables may be undefined, whereas in a DO& &RETURN form, they are
always defined and take on the obvious value.

Both LOOP and DO& achieve package independence by using pname equality
in looking for keywords.

LOOP supports destructuring; DO& does not.  DO& generates automatic
dummy variables when none is supplied in a variable specification;
LOOP does not.

LOOP does more code optimization than DO& does.

DO& has many other features that are described in detail in DO&DOC.

LOOPマクロに対する対抗馬としては、最初期のものではないかと思いますが、LOOPで良く言われている問題点が既に述べられています。

面白そうなのでDO&のソースがどこかに落ちてないか探してみたのですが、残念ながらみつけることはできませんでした。

ということで、適当にサンプルコードが動く程度のものを作ってみました。

適当に考えながら作成していましたが、途中で面倒になったので、fare-matcherでやっつけることに。

しかし、サンプルコードの範囲だけではどういう動作なのかはちょっと分からないなという感じです…。

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

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

CLでSRFIな日々ですが、今回は、SRFI-30 ネスト可能な複数行コメントです。

ずばりのCLの、#| #| ...|# |# と同じなので、CLはSRFI-30対応済なのです。

とりあえず、レポジトリを作成してからソースを読んだりしているため、意味のないリポジトリを作成してしまいました。まあ良いかなと。

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

f:id:fujita-y:20110711132029p:image

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でグリグリ回るようになるのです :)

f:id:fujita-y:20110711143223p:image

古いLispMのメーリングリスト(info-lispm@mit-ai)を眺めていて発見した、新機能の告知メッセージ

Date: 15 JUN 1980 0023-EDT
From: RMS at MIT-AI (Richard M. Stallman)
Subject: Incompatible change to PROG
To: INFO-LISPM at MIT-AI

Soon PROG will bind all the variables in parallel
instead of sequentially.  This only makes a difference
if you have initializations which depend on other
variables bound by the same PROG.

If you want to bind variables sequentially, use PROG*,
which is presently the same as PROG and will not change.

Old QFASL files will continue to work as before.
The change takes effect only when the program is recompiled.

I plan to create LET* and DO*, which will both do sequential
binding like PROG*, at some time in the future.

これだけでは、PROGの変数が直列に束縛されるものをPROG*にしたのがRMSかどうかははっきりしませんが、LET*はRMSの創案かもしれないですね。

おおー、RMSかー、などと思ってしまいました。こんなことに関心がある人も少ないかと思いますが。

第2回自然言語処理勉強会@東京 - ATND
「n㌘超入門」的な(出席者のレベルを考えたら誰得な)発表をしてきたのでメモ。
発表資料(PDF)はこちら

@y_benjoの発表を聞きながら書いたp.200の実証コード(scheme):
ネットからアーカイブファイルを拾って解凍する時に、
% unzip http://incanter.org/downloads/incanter-latest.zip
とか
% tar zxvf http://prdownloads.sourceforge.net/gauche/Gauche-0.9.tgz
とか書いたらダウンロードから解凍まで面倒みてくれないかな…そろそろURLをファイル名と同等に扱えてもいい頃だよねと。
シェルがやってくれればいいんですが、何かいいやつ知りませんか?

手元でさっと書いてみたのは、例えば $HOME/bin あたりを環境変数PATHで最初に読まれるようにしといて、そこに みたいなスクリプトを unzip とか tar という名前で仕込んでみたりとか。(chmod +x しておく必要があります)

96.2%がJava。あとawkとかシェルスクリプトとか少々。

powered by Outputz.

【C.M.ビショップ「パターン認識と機械学習(PRML)」読書会の情報はこちら

(とりあえずハブエントリ)

PRML(パターン認識と機械学習) Hackathon #2 を開催しました。参加者8名。

幹事の都合で集まりにくい日になってしまって申し訳ありません。

公式タグはPRMLhackathon

続きを読む

Incanterは、Clojureベースの、統計計算とグラフィックスのためのR言語風プラットフォーム、であります

Incanter - Data Sorcery

  • PRML hackathon#2Processingを使ったビジュアライズに挑戦しようとしていて
  • Processing使うならClojureかなと思ってClojureにも挑戦しようとしていて
  • Chaton Clojureに行ったらmaking(※まきんぐ)さんにIncanterを勧められた、であります
  • ClojureもProcessingもユーザ歴1日目ですが… やってみます
  • これで勝つる!

短編小説レベル

原稿用紙 51.1 枚(20,440 文字)


λ成分が足りない…

powered by Outputz.

shiroさんに教わったのでメモっておきます

;;; from shiro
(defun gauche-info-index (topic)
  (interactive
   (list (read-string
	  (concat "Gauche help topic : ")
          (current-word))))
  (switch-to-buffer-other-window (get-buffer-create "*info*"))
  (info "/usr/share/info/gauche-refe.info.gz")
;;(info "/usr/local/share/info/gauche-refe.info.gz") ;;うちは/usr/local/

  (Info-index topic))

;;(define-key global-map "\C-xH" 'gauche-info-index) ;; original
(define-key global-map "\C-x\C-j" 'gauche-info-index) ;; naoya_t

キーバインドは C-x H だとシフト押すのが面倒なので、うちでは C-x C-j に移しました。(キーバインドは皆さんのお好みで!)

調べたい関数名の後でC-x C-jするとinfoが引けます。これは便利。

去年ちょっとだけ参加したTLE (Time Limit Exceeded)に今年は最初から参加。とは言っても仕事の合間にちょこちょこと。

  • PALIN1 (Super Palindrome - 1; 問題文): 58.7356 / 100
     // n^n%p。要128bit演算
  • PALIN2 (Super Palindrome - 2; 問題文): 111.6 / 150
     // これは簡易版
  • PREP (The Preprocessor Problem; 問題文): 5.6684 / 100
     // これは浜地さんの出題だそうです
     // cpp(プリプロセッサ)でfizzbuzz。あとでじっくり考えたい
  • CARM (Carmichael Numbers; 問題文): 3.2305 / 100
     // 自作Bignumが遅くてTLE(文字通りの)との闘い
  • COMP (Compress the Text/Image; 問題文): 76.973 / 100
     // tsubosakaさんさすがと思った
  • SHORTEN (Play with Code; 問題文): 18.2888 / 100
     // コードちゃんと読んでないので時間あればもっと取れたはず
  • KEY (Key to C; 問題文): 69.4118 / 100
     // 問題の意味がわからず悩んだ
  • CQUINE (Chain Quine!; 問題文): 94.2466 / 200
     // quineが書けただけで満足っす

(追記:恥ずかしいコードへのリンクを貼りました)

とりあえず通るコードを考えてsubmit x 8で最速全問通過(別にボーナスは無い)。しかしその後の詰めの能力は低いので順位は上がらず。瞬間最高順位は2位。

最終結果は438.1527点で19位。別枠でランキングのあるインド人トップより辛うじて上だけどそんなの関係ない。これはインドを舞台にした日本人同士の闘い。

パズル的にはとても面白かったけれどやはりゴルフ力が全然ないので、渋谷から10分のゴルフ場で鍛えるなどしたいです。

おまけ:副次的効果

gistに貼ってるだけだと忘れそうなのでここにもメモっとく。

「プログラミングErlang」の§12.2 に、ErlangからCの関数を利用する方法があるので、同等なインターフェイスを書けば

(define (twice x) (* 2 x))
(define (sum x y) (+ x y))

のようなScheme(Gauche)の関数も呼び出せる。

Eshell V5.7.4  (abort with ^G)
1> c(example1).
{ok,example1}
2> example1:start().
<0.39.0>
3> example1:twice(48). 
96
4> example1:sum(17,25).
42
...
続きを読む
S式を1つも書いてない…
2010/2/8 の Outputz
原稿用紙 36.7枚(14,676文字)

powered by Outputz.

【C.M.ビショップ「パターン認識と機械学習(PRML)」読書会の情報はこちら

8章後半~9章の最初@サイボウズラボにて

 §8.4 グラフィカルモデルにおける推論

   マルコフ連鎖、因子グラフ

 §9.1 K-meansクラスタリング

次回読書会は3/7(日) サイボウズ・ラボにて§9.2~§10.1。

予約(※キャンセル待ち状態!)はATNDから。

Interpolative coding - tsubosakaの日記 より。

長さと出てくる値の最小値、最大値が分かっている狭義単調増加な自然数のリストを圧縮する方法の話。

最小値1、最大値20、長さ7の数列 [ 3, 8, 9, 11, 12, 13, 17 ] が17ビットに圧縮されるらしい。試してみたい。

まずはC++に翻訳しつつ写経。(Scheme編はこちら

続きを読む

Schemeでも写経してみたの巻。C++編はこちら

#;'(べ、べつにS式で書かないと理解できないわけじゃないんだからね)

(define (lg x) (integer-length (- x 1)))

(define (interpolative-encode L L-length lo hi)
  (define (binary-encode x low high result)
    (let* ([range (+ (- high low) 1)]
           [bnum (lg range)]
           [enc (- x low)])
      (let loop ((i (- bnum 1)) (result result))
        (if (< i 0) result
            (loop (- i 1) (cons (if (logbit? i enc) 1 0) result))))))
  (define (iter f lo hi left right result)
    (cond [(= f 0) result]
          [(= f 1) (binary-encode (vector-ref L left) lo hi result)]
          [else
           (let* ([h (quotient f 2)]
                  [m (vector-ref L (+ left h))]
                  [f1 h]
                  [f2 (- f h 1)])
             (iter f2 (+ m 1) hi (+ left h 1) right
                   (iter f1 lo (- m 1) left (+ left h)
                         (binary-encode m (+ lo f1) (- hi f2) result))))]))
  (let1 L-length (vector-length L)
  (reverse! (iter L-length lo hi 0 L-length '())))


(define (interpolative-decode L L-length lo hi input-stream)
  (define (binary-decode low high iter)
    (let* ([range (+ (- high low) 1)]
           [bnum (lg range)])
      (let loop ((i 0) (dec 0) (iter iter))
        (if (= i bnum)
            (values (+ low dec) iter)
            (let1 b (car iter)
              (loop (+ i 1) (+ (* dec 2) (car iter)) (cdr iter)))))))
  (define (iter f lo hi left right input-stream)
    (cond [(= f 0) input-stream]
          [(= f 1)
           (receive (m stream) (binary-decode lo hi input-stream)
             (vector-set! L left m)
             stream)]
          [else
           (let* ([h (quotient f 2)]
                  [f1 h]
                  [f2 (- f h 1)])
             (receive (m stream) (binary-decode (+ lo f1) (- hi f2) input-stream)
               (vector-set! L (+ left h) m)
               (iter f2 (+ m 1) hi (+ left h 1) right
                     (iter f1 lo (- m 1) left (+ left h) stream))))]))
  (iter L-length lo hi 0 L-length input-stream))

(define (main args)
  (let* ([L #(3 8 9 11 12 13 17)]
         [lo 1]
         [hi 20]
         [L-length (vector-length L)]
         [Ldec (make-vector L-length)]) ; 結果格納用vec
    (print "original: " L)
    (let1 encoded-bitstream (interpolative-encode L L-length lo hi)
      (format #t "encoded (~d bits): ~a\n" (length encoded-bitstream) encoded-bitstream)
      (interpolative-decode Ldec L-length lo hi encoded-bitstream)
      (print "decoded: " Ldec))))

結果

original: #(3 8 9 11 12 13 17)
encoded (17 bits): (0 1 1 1 1 1 0 0 1 0 0 0 0 0 0 1 1)
decoded: #(3 8 9 11 12 13 17)

17bitに圧縮後、ちゃんと復号できて一安心。

こんな便利なものがあるなんて知らずに生きていた(恥)

Function: info symbol

Gaucheのinfoドキュメント中から、 symbolで指定される手続きか構文要素の定義を含んでいるページを表示します。 infoドキュメントは、もし環境変数INFOPATHが定義されていればそこに示されるディレクトリ中から探され、そうでなければgoshのライブラリディレクトリから推測されるディレクトリ中から探されます。infoドキュメントが見付からなかったり、見付かってもsymbolがIndexページ中に無かった場合はエラーとなります。つまり、この手続きはinfoファイルがインストールされていないと動作しません。

現在の出力ポートが端末である場合、infoドキュメントの該当ページはページングプログラムを用いて表示されます。環境変数PAGERが指定されていればそれを用い、そうでなければコマンドサーチパスからless及びmoreをこの順で探します。いずれも見付からなかった場合や、出力ポートが端末ではない場合には、単にページがそのまま出力されます。

この手続きのセッション中での最初の呼び出しは、infoファイルをパーズするために多少時間がかかります。

info - gauche.interactive

unfoldの引数の順番に迷った時とか、REPLから

gosh> (info 'unfold)

と打てば

10.2.5 List fold, unfold & map
------------------------------

...
... (foldとかreduceとかの定義) 
...

 -- Function: unfold p f g seed &optional tail-gen
     [SRFI-1] Fundamental recursive list constructor.  Defined by the
     following recursion.

          (unfold p f g seed tail-gen) ==
             (if (p seed)
                 (tail-gen seed)
                 (cons (f seed)
                       (unfold p f g (g seed))))
     That is, P determines where to stop, G is used to generate
     successive seed value from the current seed value, and F is used
     to map each seed value to a list element.
...

qを打てばまたREPLに戻って来られる。これは便利。

久々にMeCabを使いたくなったのでGauche-mecabをインストールしたい(が少しはまった)のでメモ。

1. ビルドはGauche-0.9でもSnow Leopardでも行けるっぽい。

  • CFLAGS='-arch i386' LDFLAGS='-arch i386' ./configure とかしなくても可か

2. ビルドはできるが make check で失敗する。

  • /usr/lib/にある、Snow Leopardに元々入ってる?MeCabを見に行ってしまうため。
mecab-lib.$(SOEXT): $(srcdir)/mecab-lib.scm
    $(GENCOMP) --ext-module=text/mecab.scm $(srcdir)/mecab-lib.scm
    $(GAUCHE_PACKAGE) compile \
      --local=$(LOCAL_PATHS) --ldflags='-L/usr/local/lib' --libs='-lmecab' --verbose mecab-lib mecab-lib.c

のようにldflagsでなんとかすれば良いレベル。