Nov 25, 2008

MPRTest : 円筒・円錐を追加


 
直方体の他に、
  • 円筒 (Cylinder)
  • 円錐 (Cone)
  • 球 (Sphere)
を追加しました。円筒・円錐それぞれのサポート写像には GJK アルゴリズムで使用するものをそのまま利用しています。 Gino van den Bergen 氏の著作が参考になります。
凸多面体同士の交差判定/接触点情報の算出を行う Minkowski Portal Refinement (MPR) アルゴリズム の実験プログラムです。

Nov 16, 2008

MPRTest


任意の凸多面体同士の交差判定/接触点情報の算出ができるという Minkowski Portal Refinement (MPR) アルゴリズム の実験プログラムです。




とりあえず直方体同士の交差判定のみ実装してあります。 MPR自体は接触点情報(※接触法線等)も算出可能です。詳細は Game Programming Gems 7 や XenoCollide (著者本人のサポートページ)で。
GJK(+EPA)アルゴリズムと同等の用途に利用でき、なおかつわかりやすくて数値計算的にシンプルでロバストであるというのが謳い文句です。流行るでしょうか。

Sep 23, 2008

Yellow Dog Linux on PS3 で GL Excess / Ruby


暇なので Yellow Dog Linux on PS3 を整備して遊んでいました。 以下に GL Excess / Ruby を動かすまでの作業をメモしておきます。
  • root で作業してください。
  • Yellow Dog Linux 6.0 は PS3 にインストール済みであるとします。
まずは /etc/X11/xorg.conf を編集。 GLX 拡張をロードするため、"Module" セクションに次のように追記します:
Section "Module"
       Load  "dbe"
       Load  "extmod"
       Load  "fbdevhw"
       Load  "freetype"
       Load  "type1"
       #Load   "dri"
       Load  "glx"  # ←この行を追記
EndSection
X Window が起動中の場合、編集終了後にを再起動を (Ctrl+Alt+Backspace)。まだ起動していないなら startx を。問題なく起動することを確認してください。
次に freeglut のインストール。パッケージ化されているのですぐに終了します:
[root@localhost ~] yum install freeglut
...
[root@localhost ~] yum install freeglut-devel
続いて Ruby 1.9.0-4 をビルド&インストール。すでに Ruby 1.8.5 がインストールされているので、ここでは Ruby 1.9 の関連プログラムが ruby19 や gem19 といった名前となるよう、--program-suffix で指定しています:
[root@localhost tmp] wget ftp://ftp.ruby-lang.org/pub/ruby/ruby-1.9.0-4.tar.bz2
...
[root@localhost tmp] tar xvjf ruby-1.9.0-4.tar.bz2
...
[root@localhost tmp] cd ruby-1.9.0-4
...
[root@localhost ruby-1.9.0-4] ./configure --program-suffix=19
...
[root@localhost ruby-1.9.0-4] make && make install
ここまでで /usr/local/bin/ruby19 や /usr/local/bin/gem19 などが利用できるようになっています。 あとは ruby-opengl のインストール。ソースパッケージのダウンロード、ビルド、拡張ライブラリのインストールが自動的に実行されます:
[root@localhost ~] gem19 install ruby-opengl
GL Excess / Ruby を動かしてみます。一般ユーザーに戻って作業しても OK です。
[lt140@localhost tmp] wget http://sites.google.com/site/ltsevenscore/archives/glxsruby-20091223.7z
...
[lt140@localhost tmp] 7z x glxsruby-20091223.7z
...
[lt140@localhost tmp] cd glxsruby
...
[lt140@localhost glxsruby] ruby19 glxs.rb -s 9
写真は PS3 上の X Window で動く GL Excess / Ruby。 GPU Acceleration が効かないので遅いです。酔狂もいいところ。 ちなみにディスプレイは BRAVIA 。遊び道具をありがとうございます>ソニーグループ御中



Yellow Dog Linux 6.0 on PS3 : 設定等のメモ


ランレベルは 5 から 3 に変更

/etc/inittab を開いて、
id:5:initdefault:
となっている行を以下に変更する:
id:3:initdefault:

Fluxbox ウィンドウマネージャを導入

メインメモリ 256MB のマシンに Enlightenment, GNOME は厳しいので。
[root@localhost tmp] wget http://prdownloads.sourceforge.net/fluxbox/fluxbox-1.0.0.tar.bz2
...
[root@localhost tmp] tar xvjf fluxbox-1.0.0.tar.bz2
...
[root@localhost tmp] cd fluxbox-1.0.0
...
[root@localhost fluxbox-1.0.0] ./configure
...
[root@localhost fluxbox-1.0.0] make && make install
...
インストール終了後は ~/.Xclients に以下の 1 行を記述する:
/usr/local/bin/fluxbox
これで startx 直後に Fluxbox が起動される。

各種サービスを off に

サーバ用途として利用するつもりがないので、 sendmail などの不要なサービスを起動しないように設定:
[root@localhost ~] chkconfig --level 35 sendmail off
...
DHCP で取得した情報が上書きされてしまうように見えたので、 NetworkManager, NetworkManagerDispatcher も起動しないように設定。
[root@localhost ~] chkconfig --level 35 NetworkManager off
...
[root@localhost ~] chkconfig --level 35 NetworkManagerDispatcher off
...

ゲーム OS での再起動は ps3-boot-game-os

[root@localhost ~]$ /usr/sbin/ps3-boot-game-os

Aug 8, 2008

Ruby/SDL をビルド


素の Ruby/SDL を Visual C++ 2008 Express Edition でビルドするまでのメモです。 TTF や draw_line などを使用しているサンプルは動きませんのでご注意を。

用意するもの

  • Visual C++ 2008 (Express Edition SP1)
  • OpenGL
    • include : c:/Program Files/Microsoft SDKs/Windows/v6.0A/Include
    • lib : c:/Program Files/Microsoft SDKs/Windows/v6.0A/Lib
  • DirectX SDK
SDL のビルドに必要です。March 2009 を利用しました。
D:\tmp>ruby -v
ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-mswin32_90]
d:/ruby19 にインストール & d:/ruby19/bin にパス設定済みとします。

ビルドとインストール

SDL
  • VisualC.zip を展開、SDL.sln を開いて Release ビルド。
  • dsound.h が無いとビルドエラー。⇒ 要 DirectX SDK
できあがった VisualC/SDL/Release/SDL.dll は d:/ruby19/bin にコピーしておきます。
Ruby/SDL
Makefile を書くのも面倒なので、sdl.so を作成するための新規プロジェクトを作成して対応します。
rubysdl-2.1.0 を展開したフォルダに 新規プロジェクトを作成します。ここでは `VCBuild' という名前にします。

DLL を作りたいのでそう選択します。空のプロジェクトに設定して、ソースコードの追加を後で行います。


既存の要素として Ruby/SDL のソースコードをプロジェクトに追加します。


プロジェクトのプロパティを設定する前に下準備をします。VCBuild フォルダの中に `sdl.so.def' という名前のテキストファイルを新規作成します。


内容はこちらの2行だけです:


ここから VCBuild プロジェクトのプロパティ設定を行います。ソリューション構成は Release にした 上で、まずは "C/C++ > 全般 > 追加のインクルード ディレクトリ" に以下のように記入します(各自の環境で適宜読み換えてください):


記入するのは SDL と Ruby のインクルードファイルが配置してある場所です。次に "C/C++ > プリプロセッサ > プリプロセッサの定義" に追記します:


ENABLE_OPENGL と追記しました。次は "リンカ > 全般 > 追加のライブラリ ディレクトリ" にパスを記入します:


SDL.lib, SDLmain.lib そして Ruby のエクスポートライブラリの場所を指定します。 次は "リンカ > 全般 > 出力ファイル" で名前を 'sdl.so' と明記します。


次は "リンカ > 入力 > 追加の依存ファイル" :


最後は "リンカ > コマンドライン > 追加のオプション" に sdl.so.def を使用するよう記入しておきます。


ビルドすると 'VCBuild/Release' に sdl.so が作成されます。


… Makefile 書くのとどっちが面倒だったろう?(^^;
それはそれとして、この DLL を含め、 Ruby/SDL のライブラリファイルを既定の場所へコピーしてインストール完了です。
  • VCBuild/Release/sdl.so
    • -> d:/ruby19/lib/ruby/site_ruby/1.9.1/i386-msvcr90 にコピー
  • lib/sdl.rb, lib/rubysdl_aliases.rb, lib/rubysdl_compatible.ver1.rb
    • -> d:/ruby19/lib/ruby/site_ruby/1.9.1/ にコピー
コマンドラインから実行:
D:\tmp\RubySDL\rubysdl-2.1.0\sample>ruby randrect.rb



今回ビルドしたのは素の SDL のみなので、フォントや高レベルの描画機能(draw_line, etc.)は 動作しませんのでご注意を。

Aug 3, 2008

Ruby 1.9.0-3 : インタプリタ DLL を C から呼ぶ例

(2010-08-29 追記 : 以下の記事は古くなっています。こちらが参考になるかもしれません。 http://sites.google.com/site/ltsevenscore/ruby/tips/interpreter_dll )


  • ruby_options が値を返すようになっている
  • ruby_run という関数がない
など、Rubyの初期化・実行に関する README.EXT の内容は現状に追いついていないようです。
そのようなわけで、Ruby 1.9 を外部から利用する方法を少し調べてみました。
  • アプリケーションに Ruby を組み込みたい
  • rubyw.exe に代わる前処理プログラムを作りたい
といったときに役立つかもしれません。
利用したのは Ruby 1.9.0-3です。 これを VC++ 2008 でビルドした msvcr90-ruby190.dll を C プログラムから利用してみます。
こちらがアプリケーションのソースコード。必要最小限のエントリーポイント を取得した後、インタプリタの初期化と実行に移っています。
UseRubyDLL.c:
#define WIN32_LEAN_AND_MEAN
#include 

#define APP_NAME                "UseRubyDLL.exe"
#define RUBY_DLL_NAME           "d:\\ruby19\\bin\\msvcr90-ruby190.dll"
#define RUBY_SCRIPT_NAME        "script.rb"

HINSTANCE ruby_dll;

/* from include/ruby/ruby.h */
void  (*ruby_init)( void );
void  (*ruby_sysinit)( int*, char*** );
void* (*ruby_options)( int, char** );
/* from include/ruby/intern.h */
void  (*ruby_init_loadpath)( void );
int   (*ruby_run_node)( void* );

void
WinMainCRTStartup()
{
    /* Dummy arguments for ruby_sysinit(). */
    int         sysinit_argc = 0;
    char**      sysinit_argv = NULL;

    /* Manually construct interpreter arguments. */
    int         app_argc = 3;
    char*       app_args[3];
    char**      app_argv = app_args;
    app_args[0] = APP_NAME;
    app_args[1] = RUBY_SCRIPT_NAME;
    app_args[2] = "See ya.";

    ruby_dll = LoadLibrary( RUBY_DLL_NAME );
    if ( ruby_dll )
    {
        ruby_sysinit       = (void (*)( int*, char*** ))GetProcAddress( ruby_dll, "ruby_sysinit" );
        ruby_init          = (void (*)( void ))GetProcAddress( ruby_dll, "ruby_init" );
        ruby_init_loadpath = (void (*)( void ))GetProcAddress( ruby_dll, "ruby_init_loadpath" );
        ruby_options       = (void* (*)( int, char** ))GetProcAddress( ruby_dll, "ruby_options" );
        ruby_run_node      = (int (*)( void* ))GetProcAddress( ruby_dll, "ruby_run_node" );

        ruby_sysinit( &sysinit_argc, &sysinit_argv );
        ruby_init();
        ruby_init_loadpath();

        ruby_run_node( ruby_options( app_argc, app_argv ) );

        /* NOTE: After the execution, +ruby_run_node+ automatically
           calls +ruby_cleanup+. So there's no need to explicitly call
           Ruby's finalizer here(otherwise cause disaster).
         */

        FreeLibrary( ruby_dll );
    }
}
上記の ruby_*() 系関数の利用方法は Ruby のソースコード(winmain.c, eval.c, etc.)から把握したものです。 当然ですがインタプリタ DLL の場所など、ハードコードした部分は適宜変更する必要があります。
アプリケーションから呼び出すスクリプトはこちら。インタプリタ DLL の場所 次第では、標準ライブラリ(ここでは matrix.rb)jの require に失敗しますの でご注意を。
script.rb:
require 'matrix'
File.open( 'result.txt', 'w' ) do |f|
  f.puts Time.now
  f.puts Vector[rand,100*rand,10000*rand]
  f << ARGV
end
ビルドによって生成された UseRubyDLL.exe を以下のように実行します。 script.rb は同じ場所にあるものとします。
$ ./UseRubyDLL
実行すると同じ場所に result.txt ができているはず。以下が結果の一例です。
result.txt(例)
2008-08-03 18:52:16 +0900
Vector[0.434646515113465, 27.44515575993, 9534.51425972162]
["See ya."]
ちなみにビルド用の Makefile はこちら。実行ファイルを小さくするため、あえて Cygwin gcc (gcc -mno-cygwin -mwindows) を利用してみました。
Makefile:
TARGET = UseRubyDLL.exe
SRC = $(TARGET:exe=c)
OBJ = $(TARGET:exe=o)

CC = gcc -mno-cygwin -mwindows
CFLAGS = -Wall -Os
LDFLAGS = -lkernel32 -nostdlib

all: $(TARGET)

$(TARGET): $(OBJ)
 $(CC) -o $(TARGET) $< $(LDFLAGS)
 strip $(TARGET)

clean:
 rm $(OBJ) $(TARGET)

.c.o:
 $(CC) $(CFLAGS) -c $<
手元での結果はこちら:
$ gcc --version
gcc (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


kazuwe@kazuwe-PC ~/UseRubyDLL
$ ls -l UseRubyDLL.exe
-rwxr-xr-x 1 kazuwe None 2560 Aug  3 18:58 UseRubyDLL.exe
ちょっと心配になるくらい小さくなるものですね :-)

参考

  • embedding Ruby 1.9.0 inside pthread
  • BDS2006(C++Builder)からRubyを使う (山本隆の開発日誌)

Jul 20, 2008

RMath

今年1月に書いておきながら、 そのまま忘れて半年放置していた 3D CG 向けの数学関数の拡張ライブラリを公開しておこうと思います。
RMath といいます。
RMath は行列(3x3,4x4)、ベクトル(3要素,4要素)、クォータニオンの各クラスを含んだ拡張ライブラリです。 デバッグ用に同じインタフェースを持った Ruby 実装版も同梱しています(RMath.rb)。
ライセンスは zlib/libpng としました。
リファレンスやサンプルが少ないので、それらの充実が当面の課題ですね。
(2009-12-26 URLを新しいものに修正しました)

Jul 6, 2008

takeown, icacls コマンド

Windows Vista での chown / chmod コマンドに相当するものです。
訳あって C ドライブの Vista (Home Premium) をインストールしなおしたところ、 以前から D ドライブ側に置いていたファイルへのアクセスに支障が出てしまいました。
具体的には:
  • 消せないファイルが多発。
  • Cygwin 系コマンドでの操作が軒並み ``Permission denied'' に。
OS からは別な(しかももう存在しない!)ユーザーの所有物とみなされているのが原因です。
この問題を次のようにして解決してみました。
1. コマンドプロンプトを「管理者として実行」する
``C:\Windows\System32\cmd.exe'' のアイコンを右クリックし、「管理者として実行(A)」で起動。

2. 作業するディレクトリに移動
ここでは ``D:\cygwin'' とします。
C:\Windows\system32>d:

D:\>cd cygwin

D:\cygwin>
3. ファイルの所有権を取得
takeown コマンドを実行します。 ``/f '' がファイル名の指定。``/r'' は再帰的に実行することを指定するものです。
D:\cygwin>takeown /f * /r

成功: ファイル (またはフォルダ): "D:\cygwin\bin" は現在ユーザー "lt140-PC\lt140" によって所有されています。

成功: ファイル (またはフォルダ): "D:\cygwin\cygdrive" は現在ユーザー "lt140-PC\lt140" によって所有されています。

成功: ファイル (またはフォルダ): "D:\cygwin\Cygwin.bat" は現在ユーザー "lt140-PC\lt140" によって所有されています。

成功: ファイル (またはフォルダ): "D:\cygwin\Cygwin.ico" は現在ユーザー "lt140-PC\lt140" によって所有されています。

成功: ファイル (またはフォルダ): "D:\cygwin\dev" は現在ユーザー "lt140-PC\lt140" によって所有されています。

...(以下略)
4. アクセス権を操作
icacls コマンドを実行します。 複雑なオプションを多数受け付ける高機能なコマンドですが、「ユーザーに指定したパス以下のフルコントロールを与える」のであれば ``icacls <パス名> /grant <ユーザー名>:F /t'' だけで終了です。 フルコントロール可能な状態にしたくない場所での実行には注意してください。その場合は ``:F'' とした部分を変更することになります。``icacls /?'' で詳細を確認してください。
D:\cygwin>icacls D:\cygwin /grant lt140:F /t
処理ファイル: D:\cygwin\bin
処理ファイル: D:\cygwin\cygdrive
処理ファイル: D:\cygwin\Cygwin.bat
処理ファイル: D:\cygwin\Cygwin.ico
処理ファイル: D:\cygwin\dev
処理ファイル: D:\cygwin\etc
処理ファイル: D:\cygwin\lib
処理ファイル: D:\cygwin\setup.exe
処理ファイル: D:\cygwin\tmp

...(以下略)
これで無事に読み書きできるようになりました。
…OS は忠実に自分の仕事をこなしているだけなのですが、自分がPCの管理者かつ唯一の利用者であるという状況では正直切ないですね。

Jun 8, 2008

マニフェスト関連


Visual C++ ファイルの再配布

Visual C++ ライブラリ DLL (MSVCR80.DLL など) に到達できた場合 (アプ
リケーションのローカル フォルダまたはシステム フォルダにインストール
されている場合など)、次のメッセージが表示されます。

R6034 An application has made an attempt to load the C runtime library incorrectly.

C/C++ 分離アプリケーションおよび side-by-side アセンブリのトラブルシューティング

すべての DLL がバイナリに埋め込まれたマニフェストを持つようにすることを
お勧めします。DLL が LoadLibrary 呼び出しで読み込まれる場合、外部マニフェストは
無視されます。

方法 : マニフェストを C/C++ アプリケーションに埋め込む

C/C++ アプリケーション (またはライブラリ) では、そのマニフェストを
最終的なバイナリに埋め込んでおくことをお勧めします。これにより、ほとんどの
シナリオで実行時の適切な動作が保証されます。

wxRuby2


wxWidgets の Ruby バインディング・ wxRuby というものを試そうとしてみました。 利用しているのは One-Click Ruby Installer 1.8.6-26。以下の作業は主に Cygwin Bash シェルで行っています。
インストールは RubyGems で楽勝でした。
$ gem.bat install wxruby
Bulk updating Gem source index for: http://gems.rubyforge.org
Building native extensions.  This could take a while...
Successfully installed wxruby-1.9.7-x86-mswin32-60
1 gem installed
wxRuby 1.9.7 の Windows 版バイナリがインストールされます。
それではさっそくサンプル起動!
$ ruby -rubygems d\:/ruby/lib/ruby/gems/1.8/gems/wxruby-1.9.7-x86-mswin32-60/samples/minimal/minimal.rb
しかしその瞬間、よくありがちなダイアログボックスが登場しました。
---------------------------
Microsoft Visual C++ Runtime Library
---------------------------
Runtime Error!

Program: d:\ruby\bin\ruby.exe

R6034
An application has made an attempt to load the C runtime library incorrectly.
Please contact the application's support team for more information.

---------------------------
OK   
---------------------------
そしてターミナルにはエラーメッセージが:
d:/ruby/lib/ruby/gems/1.8/gems/wxruby-1.9.7-x86-mswin32-60/lib/wxruby2.so: 1114: ダイナミック リンク ライブラリ (DLL) 初期化ルーチンの実行に失敗しました。
- d:/ruby/lib/ruby/gems/1.8/gems/wxruby-1.9.7-x86-mswin32-60/lib/wxruby2.so (LoadError)
from d:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
from d:/ruby/lib/ruby/gems/1.8/gems/wxruby-1.9.7-x86-mswin32-60/lib/wx.rb:12
from d:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:32:in `gem_original_require'
from d:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:32:in `require'
from d:/ruby/lib/ruby/gems/1.8/gems/wxruby-1.9.7-x86-mswin32-60/samples/minimal/minimal.rb:8
要するに wxruby2.so の LoadError だそうです。見に行きましょう。
$ cd d\:/ruby/lib/ruby/gems/1.8/gems/wxruby-1.9.7-x86-mswin32-60/lib/
$ ls
wx  wx.rb  wxruby2.exp  wxruby2.lib  wxruby2.so  wxruby2.so.manifest
む、wxruby2.so.manifest が。まさか。
$ strings wxruby2.so | grep manifest

$
埋 め 込 ま れ て な い
LoadLibrary される DLL の場合は外部マニフェストが無視されるそうです。最終的なバイナリファイルにはマニフェストの埋め込みが必要となります。
そのようなわけで Visual Studio のコマンドプロンプトから以下の作業をしました:
Setting environment for using Microsoft Visual Studio 2008 x86 tools.

D:\Programs\Microsoft Visual Studio 9.0\VC>cd D:\ruby\lib\ruby\gems\1.8\gems\wxruby-1.9.7-x86-mswin32-60\lib

D:\ruby\lib\ruby\gems\1.8\gems\wxruby-1.9.7-x86-mswin32-60\lib>mt -manifest wxruby2.so.manifest -outputresource:wxruby2.so;2
確かめてみましょう。元の Cygwin ターミナルから:
$ strings wxruby2.so | grep manifest
無事に埋め込まれた模様。ではあらためて!
$ ruby -rubygems d\:/ruby/lib/ruby/gems/1.8/gems/wxruby-1.9.7-x86-mswin32-60/samples/minimal/minimal.rb


うまくいきました。

May 18, 2008

メニューなどのテスト




Qtの各種機能を試してみました。前回のものではGLUTとの違いがわかりませんからね。
OpenGLによる描画とQtによる2Dオブジェクトの描画機能が併用できる、というのは強力だと思いました(画面右下のRubyロゴがそれ)。
中にはGLUTのソースコード(glut_teapot.c)から移植した 'teapot.rb' というものも入ってます。 GLUTから離れてティーポットが拝めなくなってしまったのが寂しかったものですから(^^;
アーカイブの展開後に
$ ruby -rubygems menutest.rb
…として起動してください。
動作に必要なものは以下の通り:

※menutest.rb: 利用したQtオブジェクトのリファレンス

May 15, 2008

glwidget.rb




QtのOpenGLサンプルにあるglwidget.cppを qt4-qtruby向けに書き直してみました。ruby-openglを併用しています。
これ単体で動くようにしてありますので、
$ ruby -rubygems glwidget.rb
…とすれば起動します。
動作に必要なものは以下の通りです:
コード:
require 'qt'
require 'opengl'

class GLWidget < Qt::GLWidget
  signals 'xRotationChanged(int)'
  signals 'yRotationChanged(int)'
  signals 'zRotationChanged(int)'

  slots 'setXRotation(int)'
  slots 'setYRotation(int)'
  slots 'setZRotation(int)'

  def initialize
    super
    @object = 0
    @xRot = 0
    @yRot = 0
    @zRot = 0
    @lastPos = Qt::Point.new

    @trolltechGreen = Qt::Color::fromCmykF( 0.40, 0.0, 1.0, 0.0 )
    @trolltechPurple = Qt::Color::fromCmykF( 0.39, 0.39, 0.0, 0.0 )
  end

  def destroy
    makeCurrent()
    glDeleteLists( @object, 1 )
  end

  def minimumSizeHint
    return Qt::Size.new( 50, 50 )
  end

  def sizeHint
    return Qt::Size.new( 400, 400 )
  end

  def setXRotation( angle )
    normalizeAngle( angle )
    if ( angle != @xRot )
      @xRot = angle
      emit xRotationChanged( angle )
      updateGL()
    end
  end

  def setYRotation( angle )
    normalizeAngle( angle )
    if ( angle != @yRot )
      @yRot = angle
      emit yRotationChanged( angle )
      updateGL()
    end
  end

  def setZRotation( angle )
    normalizeAngle( angle )
    if ( angle != @zRot )
      @zRot = angle
      emit zRotationChanged( angle )
      updateGL()
    end
  end

  def initializeGL
    qglClearColor( @trolltechPurple.dark() )
    @object = makeObject()
    glShadeModel( GL_FLAT )
    glEnable( GL_DEPTH_TEST )
    glEnable( GL_CULL_FACE )
  end

  def paintGL
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
    glLoadIdentity()
    glTranslated( 0.0, 0.0, -10.0)
    glRotated( @xRot / 16.0, 1.0, 0.0, 0.0 )
    glRotated( @yRot / 16.0, 0.0, 1.0, 0.0 )
    glRotated( @zRot / 16.0, 0.0, 0.0, 1.0 )
    glCallList( @object )
  end

  def resizeGL( width, height )
    # [NOTE] +qMin+ in the original code is a C++ Template Function.
    # Ref.: $(QTDIR)/src/corelib/global/qglobal.h
    #   template 
    #   inline const T &qMin(const T &a, const T &b) { if (a < b) return a; return b; }
    side = [width, height].min
    glViewport( (width - side) / 2, (height - side) / 2, side, side )

    glMatrixMode( GL_PROJECTION )
    glLoadIdentity()
    glOrtho( -0.5, +0.5, +0.5, -0.5, 4.0, 15.0 )
    glMatrixMode( GL_MODELVIEW )
  end

  def mousePressEvent( event ) # event : Qt::MouseEvent
    @lastPos = event.pos
  end

  def mouseMoveEvent( event ) # event : Qt::MouseEvent
    dx = event.x - @lastPos.x
    dy = event.y - @lastPos.y

    if ( event.buttons() & Qt::LeftButton.to_i )
      setXRotation( @xRot + 8 * dy )
      setYRotation( @yRot + 8 * dx )
    elsif ( event.buttons() & Qt::RightButton.to_i )
      setXRotation( @xRot + 8 * dy )
      setZRotation( @zRot + 8 * dx )
    end
    @lastPos = event.pos
  end

  def makeObject
    list = glGenLists( 1 )
    glNewList( list, GL_COMPILE )

    glBegin( GL_QUADS )

    x1 = +0.06
    y1 = -0.14
    x2 = +0.14
    y2 = -0.06
    x3 = +0.08
    y3 = +0.00
    x4 = +0.30
    y4 = +0.22

    quad( x1, y1, x2, y2, y2, x2, y1, x1 )
    quad( x3, y3, x4, y4, y4, x4, y3, x3 )

    extrude( x1, y1, x2, y2 )
    extrude( x2, y2, y2, x2 )
    extrude( y2, x2, y1, x1 )
    extrude( y1, x1, x1, y1 )
    extrude( x3, y3, x4, y4 )
    extrude( x4, y4, y4, x4 )
    extrude( y4, x4, y3, x3 )

    num_sectors = 200

    for i in 0...num_sectors do
      angle1 = (i * 2 * Math::PI) / num_sectors
      x5 = 0.30 * Math::sin( angle1 )
      y5 = 0.30 * Math::cos( angle1 )
      x6 = 0.20 * Math::sin( angle1 )
      y6 = 0.20 * Math::cos( angle1 )

      angle2 = ((i + 1) * 2 * Math::PI) / num_sectors
      x7 = 0.20 * Math::sin( angle2 )
      y7 = 0.20 * Math::cos( angle2 )
      x8 = 0.30 * Math::sin( angle2 )
      y8 = 0.30 * Math::cos( angle2 )

      quad( x5, y5, x6, y6, x7, y7, x8, y8 )

      extrude( x6, y6, x7, y7 )
      extrude( x8, y8, x5, y5 )
    end

    glEnd()

    glEndList()
    return list

  end

  def quad( x1,  y1,  x2,  y2,  x3,  y3,  x4,  y4 )
    qglColor( @trolltechGreen )

    glVertex3d( x1, y1, -0.05 )
    glVertex3d( x2, y2, -0.05 )
    glVertex3d( x3, y3, -0.05 )
    glVertex3d( x4, y4, -0.05 )

    glVertex3d( x4, y4, +0.05 )
    glVertex3d( x3, y3, +0.05 )
    glVertex3d( x2, y2, +0.05 )
    glVertex3d( x1, y1, +0.05 )

  end

  def extrude( x1,  y1,  x2,  y2 )
    qglColor( @trolltechGreen.dark(250 + (100 * x1).to_i) )

    glVertex3d( x1, y1, +0.05 )
    glVertex3d( x2, y2, +0.05 )
    glVertex3d( x2, y2, -0.05 )
    glVertex3d( x1, y1, -0.05 )
  end

  def normalizeAngle( angle )
    while ( angle < 0 ) do
      angle += 360 * 16
    end
    while ( angle > 360 * 16 ) do
      angle -= 360 * 16
    end
  end

end


#
# Application starts here.
#
begin
  a = Qt::Application.new(ARGV)

  w = GLWidget.new
  w.show

  a.exec
ensure
  w.destroy
end

Mar 8, 2008

GL Excess/Ruby : Scene 11 移植完了


Scene 11 はエンディングです。スタッフロールが流れます。

これで GL Excess 全12シーンの Ruby 移植ができたことになります。なんとかなるもんですね。
今後は
  • 全シーンをまとめたものを再パッケージ化
    • シーン個別での配布は廃止する
  • 特に遅い Scene 2, Scene 8 の一部を拡張ライブラリ化(「チート版」が適切かな?)
を予定しています。
GL Excess / Ruby のページも更新。 Scene 11 をダウンロードできるようにしておきました:
※ Scene 2 と 8 は動作が非常に遅くなってしまっています。 そこで glxsruby にもオリジナルと同様、更新のタイプステップを変更する機能が実装されています。 アプリケーション起動後に以下の操作を行ってください:
  • 'a' を押すと @step += 1 (更新速度アップ)
  • 'z' を押すと @step -= 1 (更新速度ダウン)
画面表示が遅い場合には、'a' をしばらく押しっぱなしにしておくと吉です。

Mar 2, 2008

GL Excess / Ruby : Scene 10 移植完了


Scene 10 です。これといって問題になるような部分はありませんでした。

このシーンで印象的なのはやはりレーザー効果ですが、本質的には GL_TRIANGLE_FAN だけでシンプルに実装されています。このようなことが勉強 できるのも、ソースコードが公開されているおかげですね。
GL Excess / Ruby のページも更新。 Scene 10 をダウンロードできるようにしておきました:
未実装のシーンは 11。とうとう残り 1 個になりました。
※ Scene 2 と 8 は動作が非常に遅くなってしまっています。 そこで glxsruby にもオリジナルと同様、更新のタイプステップを変更する機能が実装されています。 アプリケーション起動後に以下の操作を行ってください:
  • 'a' を押すと @step += 1 (更新速度アップ)
  • 'z' を押すと @step -= 1 (更新速度ダウン)
画面表示が遅い場合には、'a' をしばらく押しっぱなしにしておくと吉です。

Mar 1, 2008

RDフォーマット


Re: RDoc,RDフォーマットの公式文書はどこにあるのでしょうか

「仕様書」と呼ぶべきかどうかはともかくとして、Ruby自身の配布ファイル
の中に"lib/rdocs/README"というのが含まれています。公式のドキュメントの中で
は、これが一番良く書かれたものだと思います。

Module: RDoc

Rdoc is an application that produces documentation for one or more Ruby source files.

GL Excess / Ruby : Scene 8 移植


Scene 8 ですが…遅いっ。

原因は Scene 2 と 同様で、水面の表現に利用している 64x64 個のグリッドの更新が重荷になって います。描画の部分に頂点配列(glVertexPointer/glDrawArrays)を利用するよ うに書き直してみたりもしたのですが、有意な差が見られるほどの改善には至 りませんでした。
移植の最中に思い出しましたが、Ruby では !0 == false なのでした。
$ irb.bat
irb(main):001:0> some_value = 0
=> 0
irb(main):002:0> !some_value
=> false
irb(main):003:0> some_value==0
=> true
irb(main):004:0>
C/C++ によくあるイディオムの移植には注意が必要ですね。
GL Excess / Ruby のページも更新。 Scene 8 をダウンロードできるようにしておきました:
未実装のシーンは 10 と 11。残りは 2 個となりました。
※ Scene 2 と 8 は動作が非常に遅くなってしまっています。 そこで glxsruby にもオリジナルと同様、更新のタイプステップを変更する機能が実装されています。 アプリケーション起動後に以下の操作を行ってください:
  • 'a' を押すと @step += 1 (更新速度アップ)
  • 'z' を押すと @step -= 1 (更新速度ダウン)
画面表示が遅い場合には、'a' をしばらく押しっぱなしにしておくと吉です。。

Feb 17, 2008

GL Excess/Ruby : Scene 7 を移植


レンズフレアの効果がかっこいい Scene 7 です。

Scene 7 では 10x10x10 の多次元配列が登場しますが、次のように定義してみました:
@f_angle = Array.new(10) { Array.new(10) { Array.new(10) { 0.0 } } }
...
@f_angle[i][j][k] = (100*a + 10*b + c).to_f
他にも Hash と Array を組み合わせることで、もっときれいに記述することもできます:
ary = Hash.new
...
ary[[i,j,k]] = ... # ここで [i,j,k] が Array。
こちらの方が簡潔ですが、配列を参照するたびに Array のインスタンスが生成されてしまいます。今回のように速度が要求されるケースでは利用しない方が無難であると思います。
GL Excess / Ruby のページも更新。 Scene 7 をダウンロードできるようにしておきました:
未実装のシーンは 8, 10, 11 の 3 個となりました。

Feb 16, 2008

ruby-breakpoint, etc.


[ruby-list:44570] Re: Q: 動的デバッグ方法

> (1) 動的にデバッグモードに移るようなライブラリ関数はあります
>    でしょうか?

ruby-breakpointはどうでしょうか?
breakpointと書いた時点でirbに突入します。

RubyForge: ruby-breakpoint: Project Info

ruby-breakpoint lets you inspect and modify state, diagnose bugs,
patch applications and more all via IRB by simply doing a method
call at the place you want to investigate. It is no longer being
maintained. Please consider using ruby-debug instead.

RubyとCursesを使ったコンソールテキストエディタ

連載第二回目です。今回も引き続きRubyとCursesを使ったコンソールプログラムを作っていきます。

GL Excess / Ruby : Scene 6 の移植完了


結局、ロケットの形状データはオリジナル版と同様に配列ベタ持ちで使うことにしました。 パフォーマンスに深刻な影響が出ることもありませんでしたので。
あと実行終了後のクリーンアップ部分に glDeleteLists( @shiplist, 1 ) と追記。これってオリジナル版には見当らないのですが、大丈夫なんでしょうかね。

GL Excess / Ruby のページも更新。 Scene 6 をダウンロードできるようにしておきました:
未実装のシーンは 7, 8, 10, 11 の 4 個。

Feb 15, 2008

GL Excess/Ruby : Scene 6 の移植中


Scene 6 です。GL Excess で唯一、何らかのツールでモデリングされたジオメトリ(ロケットです)が登場します。 とりあえず、ロケット以外のもの全部を移植してしまいました。

ロケットの準備ができるまでの間、かわりに Teapot に飛んでもらうことにしました(^^;
オリジナル版ではモデルデータ(頂点情報とインデックス)を C の配列でベタ持ちしています。 Ruby ではこれをどのような形式で持つのがいいか、考え中です。
(案)
  • Marshal.dump で前処理しておいたバイト列を Marshal.load で復活
  • Array#pack/String#unpack

Feb 11, 2008

GL Excess / Ruby : Scene 5 を移植


バンプマッピングが印象的な Scene 5 です。最近主流のピクセル単位の処理で はないことから、負荷はそれほどでもありません。バンプマップの処理よりも、 燈台の炎を表現するパーティクルが負担になっている印象を受けます。

GL Excess / Ruby のページも更新。 Scene 5 をダウンロードできるようにしておきました:
未実装のシーンは 6, 7, 8, 10, 11 の 5 個です。

Feb 6, 2008

GL Excess / Ruby : Scene 1 を移植


GL Excess のオープニングである Scene 1 を移植しました。全然問題なしです。

GL Excess / Ruby のページも更新。 Scene 1 をダウンロードできるようにしておきました:
残りは 6 シーンになりました。未実装のシーンは 5, 6, 7, 8, 10, 11。大物ばかりですね。

Feb 4, 2008

GL Excess / Ruby : Scene 12 をサクッと移植、と思いきや


Scene 12 は GL Excess 全12シーンで一番短い行数のプログラムです(scene12.cppが281行)。

移植なんて一瞬だぜ、と思っていたら。
texture.rb で raw テクスチャの幅が正しく取れないケースがあることがわかりました。 Ruby 1.8 と 1.9 との間で、 String#to_i の挙動に違いがあることが原因のようです。
両方のバージョンで動かしたかったがために、次のようにして対処してみました:
texture.rb
major, minor, micro = RUBY_VERSION.scan( /\d+/ )

if ( major == "1" && minor == "8" )
  # for Ruby 1.8.
  width  = pow2( w[0].to_i - "0"[0].to_i )
  height = pow2( h[0].to_i - "0"[0].to_i )
else
  # for Ruby 1.9.
  width  = pow2( w[0].unpack("U")[0].to_i - "0"[0].unpack("U")[0].to_i )
  height = pow2( h[0].unpack("U")[0].to_i - "0"[0].unpack("U")[0].to_i )
end
普通であればどのようにして対処するべきところなのでしょうか?
GL Excess / Ruby のページも更新。 Scene 12 をダウンロードできるようにしておきました:

Feb 3, 2008

GL Excess / Ruby : Scene 4 を移植


パーティクルが多いように見えるので心配でしたが、特に問題なく移植できました。

GL Excess / Ruby のページも更新。 Scene 4 をダウンロードできるようにしておきました:

Feb 2, 2008

GL Excess / Ruby : Scene 3 を移植


シーン冒頭の山がせり上がってる部分については、ディスプレイリスト + glScalef() の組み合わせで書き直しました。計算の無駄を省いたおかげで、元となっている glxsglut に比べても遜色ない速度で動いてくれるようになりました。

そのようなわけで GL Excess / Ruby のページも更新。
移植済みのシーンは 2, 3, 9 。残りはあと 9 個です。

Jan 27, 2008

GL Excess / Ruby : Scene 2 を移植してみましたが…


オリジナルと同じ挙動が再現できていますが…遅い orz

200粒のパーティクルもキツそうですが、水面の波紋を表現するために 64x64個 の位置と法線を毎フレーム更新しているところが Ruby にはつらすぎます。
今なら頂点属性の時間発展はバーテックスシェーダにまかせてしまうところな のですが、オリジナルは 2001 年の作品。
負荷の大きい部分はわかりきっているので、そこだけを C の拡張モジュール化 してしまえば、処理速度は改善されるはずです。しかしそれで GL Excess / Ruby を名乗ってよいものなのでしょうか。悩み中です。

Jan 26, 2008

GL Excess / Ruby : ページを用意しました

ソースコードのライセンスは GPL Version 2 としています。オリジナ ル版のライセンスをそのまま引き継ぎました。
まだ Scene 9 しか移植していません。残りは 11 個! orz.

Jan 21, 2008


ruby-opengl で GLExcess

数学関数の拡張ライブラリを書くのにも少々飽きました。というか ruby-opengl で遊ぶつもりだったはずなのに、どんどん目的から離れてますね…
そのようなわけで、GLExcess の Ruby 移植をして遊ぶことにしました。 とりあえず癒し系の Scene 9 から。


ruby-opengl 自体は特に問題になることもなく移植できました。 それよりは元のソースコード(C++)の変数未初期化が原因で、パーティクルの挙動がオリジナル版と一致しないというバグに悩みました。
Ruby 1.8 と 1.9 での動作を確認しています。両者の比較をしてみるのも面白いかも。
そしてせっかく作った RMath ライブラリは一切使ってないわけですが何かorz

Jan 15, 2008

まだ拡張ライブラリ作成中


ruby-openglで遊ぶための数学関数ライブラリ・ RMath を作成中。とりあえず用意できたのはここまで:
  • RVec3/RVec4 : 3次元/4次元ベクトル
  • RMtx3/RMtx4 : 3x3/4x4正方行列
  • RQuat : クォータニオン
ちゃんと使い物になればいいのですけれどね。
Test::Unitでテストも書いてみています。テストを駆動するメソッド名を"test_..." としておけば、自動的に実行対象にしてくれるのが素敵です。 それにしても、「テストを書く順番が違う」と叱られそうですね。テストコードの書き方にも作法があるのでしょうけれど、便利な assert が使えるだけで私には十分です。
mkrf を利用したビルドも使ってみました。ソースディレクトリのルートにmkrf_conf.rbというファイルを作ります。
> more mkrf_conf.rb
require 'mkrf'
Mkrf::Generator.new( 'RMath' )
2行だけ。mkmfでの extconf.rb とほぼ同じです。あとは
> ruby mkrf_conf.rb
これで Rakefile が生成されます。あとは…
> rake -T  ← 定義済みタスクを確認
(in D:/RMath)
rake RMath.so  # Build this extension
rake clean     # Remove any temporary products.
rake clobber   # Remove any generated file.
rake install   # Install this extension
> rake
cl -nologo  -MD -Zi -O2b2xty-    -ID:/ruby19/include/ruby-1.9.0 -ID:/ruby19/incl
ude/ruby-1.9.0/i386-mswin32_90 -ID:/ruby19/lib/ruby/1.9.0/i386-mswin32_90 -ID:/r
uby19/lib/ruby/site_ruby/1.9.0 -I. -c RMathMtx3.c
RMathMtx3.c
...
これで OK、だといいのですが、マニフェストファイルの埋め込みには未対応のようです。最後にこうして完了:
> mt -manifest RMath.so.manifest -outputresource:RMath.so;2
Microsoft (R) Manifest Tool version 5.2.3790.2075
Copyright (c) Microsoft Corporation 2005.
...

Jan 13, 2008


ruby-opengl 0.60.0 : セットアップに再挑戦

追記: 以下の内容は古くなっています。こちらが役に立つかもしれません
VC++ 2008 版の Ruby 1.9.0 ができたので、ruby-opengl 0.60.0 のインストール。
  • GLUTのヘッダ・ライブラリは Windows SDK や Platform SDK で使える場所に配置しておきます。
  • rake や mkrf を最新版にしておきます。mkrf の 0.2.3 は Ruby 1.9.0 対応済みのバージョンです。
  > gem install mkrf
  Successfully installed mkrf-0.2.3
  1 gem installed
  Installing ri documentation for mkrf-0.2.3...
  Installing RDoc documentation for mkrf-0.2.3...
いきなり gem install ruby-opengl とやってしまうと、Ruby 1.8 版のバイナリがインストールされてしまうので注意。ソースアーカイブをいただいてきて作業します。
> wget http://rubyforge.org/frs/download.php/30282/ruby-opengl-0.60.0.gem
...
> gem install ruby-opengl-0.60.0.gem
  Building native extensions.  This could take a while...
  Successfully installed ruby-opengl-0.60.0
  1 gem installed
ではさっそく!
> ruby d:\ruby19\lib\ruby\gems\1.9.0\gems\ruby-opengl-0.60.0\examples\RedBook\teapots.rb

---------------------------
ruby.exe - コンポーネントが見つかりません
---------------------------
MSVCR90.dll が見つからなかったため、
このアプリケーションを開始できませんでした。
アプリケーションをインストールし直すとこの問題は解決される場合があります。
---------------------------
OK   
---------------------------
あらら。
案の定、できあがった各種 DLL にはマニフェストが埋め込まれていませんでした。というわけで後は手作業で、
  • gl.so
  • glu.so
  • glut.so
にマニフェストファイルを埋め込みます。ビルド時の中間ファイルがすべて残っているので、
> cd d:\ruby19\lib\ruby\gems\1.9.0\gems\ruby-opengl-0.60.0\ext\gl
> mt -manifest gl.so.manifest -outputresource:gl.so;2
> cd ..\glu
> mt -manifest glu.so.manifest -outputresource:glu.so;2
> cd ..\glut
> mt -manifest glut.so.manifest -outputresource:glut.so;2
> cd ..\..
> rake
  d:\ruby19\lib\ruby\gems\1.9.0\gems\ruby-opengl-0.60.0>rake
  (in d:/ruby19/lib/ruby/gems/1.9.0/gems/ruby-opengl-0.60.0)
  ruby mkrf_conf.rb
  call rake --nosearch
  (in d:/ruby19/lib/ruby/gems/1.9.0/gems/ruby-opengl-0.60.0/ext/gl)
  copy gl.so ..\..\lib
          1 個のファイルをコピーしました。
  ruby mkrf_conf.rb
  call rake --nosearch
  (in d:/ruby19/lib/ruby/gems/1.9.0/gems/ruby-opengl-0.60.0/ext/glu)
  copy glu.so ..\..\lib
          1 個のファイルをコピーしました。
  ruby mkrf_conf.rb
  call rake --nosearch
  (in d:/ruby19/lib/ruby/gems/1.9.0/gems/ruby-opengl-0.60.0/ext/glut)
  copy glut.so ..\..\lib
          1 個のファイルをコピーしました。
今度こそ!
> ruby d:\ruby19\lib\ruby\gems\1.9.0\gems\ruby-opengl-0.60.0\examples\RedBook\teapots.rb

うまく実行できました。

Jan 10, 2008

ruby-opengl 0.60.0 リリース


でてました。同じ日にこれが利用しているmkrf も 0.2.3 に。
One-Click Ruby Installer (Ruby 1.8.6) での利用は問題無しでした(Ruby 1.8向けのバイナリが自動的にインストールされるので)。
Ruby 1.9.0 の方は…、ちょっとうまくいきません。考えられる原因は多々ありまして、
  • target=mingw32 として Cygwin でビルドした私家版 Ruby 1.9.0 を使ってる
  • OS が VIsta (UAC有効)
  • ...
パス名の問題かもしれないですし、パーミッションに違反しているために必要なファイルにアクセスできていないのかもしれませんし。うん、問題が切り分けられない(笑
最近出た Visual C++ 2008 Express Edition をインストールしてあるので、私家版 Ruby もこれで作りなおしてしまった方が問題が少ないかもしれませんね。
あー、でも extconf.rb や mkrf が MS のビルド環境にどの程度適応していてくれているのか*1によって、これはこれでイバラの道かも。
*1  DLLへのマニフェスト埋め込みとか、GNUのツールにはないけ ど必須の手順がありますね。

Jan 7, 2008

Cygwin Package List

http://cygwin.com/packages/"Search Package List: " というテキストボックスにファイル名を入力して検索すると、そのファイル名 を含む Cygwin パッケージ名を教えてくれます。
例えば今日は svn を使おうとして 「"cygexpat-0.dll" というファイルが見付 からない」、というエラーが出ましたが、上記サイトで検索してみると、
Found 3 matches for cygexpat-0.dll.

  expat/expat-1.95.7-1 XML parser library written in C (development/documentation package)
  expat/expat-1.95.8-1 XML parser library written in C (development/documentation package)
  libexpat0/libexpat0-1.95.8-2 XML parser library written in C (runtime package)
という結果が出て、Expat のイン ストール状況を確認すればよいということがわかります。