Gauche-gl (2)

read book

挑発する少女小説 なんて本を読んだ。幼児の時は、白雪姫みたいなおとぎ話、年代が上ると、小公女みたいな、少女小説に興味が移る。この少女小説を大人の視点でみたらどうなるってのが、この本の内容。

女性誌の人気投票で上位に入った、若草物語、ハイジ、赤毛のアン、あしながおじさん、秘密の花園、大草原の小さな家、ふたりのロッテ等が、俎上に登っていた。オイラーは、こんな類、生まれてこの方、一度も読んだ事ないぞ。まあ、普通の男性は、そうだよな。

これたの物語には、幾つかの共通性があるとの著者は言う。A.主人公はみな、おてんば娘。B.主人公の多くは、みなしご。C.友情が恋愛を凌駕する。D.少女期からの卒業が仕込まれている。そうである。

ひとつ、ハイジ(アルプスの少女ハイジ)をみてみる。家庭教師のコマーシャルに出てくるあの子だ。なんで、家庭教師のCMなの? 解説を読んで疑問が氷解した。

この小説は、2部構成だったとか。最初の部は、ハイジの修行と遍歴時代。次は、ハイジは学んだ事を役立てるって風。

山で暮らす祖父に引き取られ、アルプスを満喫。将来の事を思った叔母は、フランクフルトの大富豪の、足の悪いクララの話相手にと言う事で、都会へ出稼ぎを強いる。

ここで山娘は、文字を驚異的にスピードで覚えてしまう。出稼ぎが留学になったとな。でも、山を忘れられず、夢遊病者のようになってしまう。そこで、山に戻る事になる。 謝礼たっぷりと学力を身につけてね。

やぎ飼いの少年、ペーターに文字を教えてあげる。これを捉えて家庭教師のCMになったんだな。

やがて、クララ一行が山へ遊びに来る。その頃のスイスは鉄道も引かれて、観光地として絶賛売出し中。山の空気は美味しいわって、ハイジは観光大使顔負けだな。

あとは、ペーターの意地悪で、クララの車椅子が壊され、それを機にクララは歩けるようになる。

都会と田舎、富豪と貧乏、資本主義社会をどう生きるかってのが、大人の小説の読み方だと著者はまとめていた。

こんな調子で、他の人気作品も解説されてた、100分で名著ってのがあるけど、200分で、9冊分を楽しめた。

OpenGL in OpenBSD

前回やったGauche-glは、大正解であった。豊富なサンプル(しかも詳しいコメント付)に助けられて、大いに勉強がはかどる。が、残念な事に、OpenBSDではgaucheがサポートされていない。

そこで、少しむくれて、素直なOpenGLを試してみる事にした。デフォでXが入っているしね。と、思ったら、GL/gult.h が無いぞと言われた。有名なんだけどな。調べてみたら、grafics/freegultってパッケージになってた。

それ用のMakefileを用意したよ。

CFLAGS = -I/usr/X11R6/include -I/usr/local/include
LDLIBS = -L/usr/X11R6/lib -L/usr/local/lib -lglut -lGLU -lGL -lXmu -lXi -lXext -lX11 -lm -lpthread
a.out: z.c
        $(CC) $(CFLAGS) z.c $(LDLIBS)

手始めに、バージョン等を表示するやつを、移植って程の事はないけど、作ってみた。

#include <GL/glut.h>
#include <stdio.h>

void display(void) { }

int main(int argc, char *argv[]) {
  glutInit(&argc, argv);
  glutCreateWindow(argv[0]);
  glutDisplayFunc(display);
  printf("GL_RENDERER     = %s\n", glGetString(GL_RENDERER) );
  printf("GL_VERSION      = %s\n", glGetString(GL_VERSION) );
  printf("GL_VENDOR       = %s\n", glGetString(GL_VENDOR) );
  printf("GL_EXTENSIONS   = %s\n", glGetString(GL_EXTENSIONS) );
  glutMainLoop();
  return 0;
}

関数名がキャメルケースなってるの、schemeから来た人には不便だなあ。

ob$ ./a.out
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
GL_RENDERER     = Intel(R) HD Graphics 520
GL_VERSION      = 1.4 (4.6.0 - Build 27.20.100.8854)
GL_VENDOR       = Intel
GL_EXTENSIONS   = GL_ARB_depth_texture .... GL_SUN_multi_draw_arrays

仮想マシンで動いていて、VcXsrvを使うと、インテル入ってるって嬉しい事になるのか。 libGLが出す不機嫌なエラーは有名みたいだ。WSLでgnuplotを動かすとlibGL errorになる

USBに入れたモバイルOpenBSDが有った事を思い出した。こいつをdual bootしてたi386なマシンに刺して、起動してみた。

GL_RENDERER     = Mesa DRI Mobile Intel(TM) GM45 Express Chipset (CTG)
GL_VERSION      = 2.1 Mesa 20.0.8
GL_VENDOR       = Intel Open Source Technology Center
GL_EXTENSIONS   = GL_ARB_multisample ... GL_EXT_demote_to_helper_invocation

ほぉー、OpenBSDだと、ちゃんとハードを使ってくれているのね。FreeBSDは、このあたりがリナに依存してるみたいで、まだ実現出来ていない。10月中旬にupgradeされるであろう、portsに期待って所だな。

~/.local/share/Xorg/Xorg.0.log から抜粋

[   373.078] (II) Loading /usr/X11R6/lib/modules/drivers/modesetting_drv.so
[   373.084] (II) Module modesetting: vendor="X.Org Foundation"
[   373.084]    compiled for 1.20.10, module version = 1.20.10
[   373.084]    Module class: X.Org Video Driver
[   373.084]    ABI class: X.Org Video Driver, version 24.1
[   373.084] (II) modesetting: Driver for Modesetting Kernel Drivers: kms
[   373.084] (WW) Falling back to old probe method for modesetting
[   373.098] (II) modeset(0): using default device
[   373.102] (II) modeset(0): Creating default Display subsection in Screen section
        "Default Screen Section" for depth/fbbpp 24/32
[   373.102] (==) modeset(0): Depth 24, (==) framebuffer bpp 32
[   373.102] (==) modeset(0): RGB weight 888
[   373.102] (==) modeset(0): Default visual is TrueColor
[   373.102] (II) Loading sub module "glamoregl"
[   373.102] (II) LoadModule: "glamoregl"
[   373.106] (II) Loading /usr/X11R6/lib/modules/libglamoregl.so
[   373.154] (II) Module glamoregl: vendor="X.Org Foundation"
[   373.154]    compiled for 1.20.10, module version = 1.0.1
[   373.154]    ABI class: X.Org ANSI C Emulation, version 0.4
[   373.537] (II) modeset(0): glamor X acceleration enabled on Mesa DRI Mobile Intel(TM) GM45 Express Chipset (CTG)
[   373.537] (II) modeset(0): glamor initialized

kmsって、リナ方式なのかな。そんなの無いのでデフォルトのドライバーを選んでいるのか。それで、ちゃんとハードを認識してる。そんな頑張らなくてもいいよって事かな。ちゃんとバックライトのコントロールも有効に動くしね(xbacklight = 60)。

四元数による回転

前回、Cフラフラ語で厚い本の回転をやったな。取り敢えず、どんな値に変数が設定されたか、1回実行した後の結果をgdbでプローブしてみた。

初期値は、次の通り。 x=22 y=17 z=5 回転角度90度、回転軸はy

(gdb) p ppp
$1 = {t = 0, x = -4.9999999999999947, y = 17, z = 22}
(gdb) p th
$2 = 1.5707963267948966
(gdb) p qqq
$3 = {t = 0.70710678118654757, x = 0, y = 0.70710678118654746, z = 0}
(gdb) p rrr
$4 = {t = 0.70710678118654757, x = -0, y = -0.70710678118654746, z = -0}

同じ事をGauche-glに備えつけられている、Quaternionsでやってみる。設定は、上記と同じ(コードに埋め込んでいる)

;; qu
(use gl.math3d)

(define book (quatf 22 17 5 0))
(define th (* 90 (/ 3.14159265358  180.0)))
(define qu (make-quatf (vector4f 0 1 0) th))
(define out (quatf-transform qu book))

非常にすっきりだ。本の実体は、22x17x5。0は実部になるけど、今回は関係ない。 thは、回転角のラジアン表現。quは、正規化された回転表現。最後は、回転実施。共役をわざわざ用意する必要は無い。

gosh> book
#,(quatf 22 17 5 0)
gosh> th
1.5707963267899998
gosh> qu
#,(quatf 0 0.707107 0 0.707107)
gosh> out
#f32(4.999999046325684 17.0 -22.0 0.0)

最後の0.0も無視してください。例によって極性違いは、座標の定義の違いだな。

なお、上記で、度をラジアンに変換する時、わざわざ(/ 3.1415 180.0)なんてしてるけど、 あらかじめ(use math.const)しとけば、pi/180 なんて言う定数が使える。gaucheな人は、甘やかされていますよ。特に電気屋さんね。2piなんてのも定義されてる。(* 2pi f L)って素直に書けるのが嬉しいぞ。

backend of Quatf

ユーザーレベルの使いかたは分った。で、その裏側はどうなってる。

src/math3d-lib.stub

(define-cproc quatf (x::<real> y::<real> z::<real> w::<real>) Scm_MakeQuatf)

(define-cproc make-quatf (&optional vec (angle::<real> 0))
  (if (SCM_UNBOUNDP vec)
    (result (Scm_MakeQuatf 0.0 0.0 0.0 1.0))
    (let* ([q::float*])
      (SCM_MATH3D_X3FP q vec)
      (let* ([sint::double (sin (/ angle 2.0))]
             [cost::double (cos (/ angle 2.0))])
        (result (Scm_MakeQuatf (* sint (aref q 0))
                               (* sint (aref q 1))
                               (* sint (aref q 2))
                               cost))))))

(define-cproc quatf-transform (quat::<quatf> v)
  (let* ([d::float*] [r::(.array float [4])])
    (SCM_MATH3D_X4FP d v)
    (Scm_QuatfTransformv r (SCM_QUATF_D quat) d)
    (cond [(SCM_VECTOR4FP v) (result (Scm_MakeVector4fv r))]
          [(SCM_POINT4FP v)  (result (Scm_MakePoint4fv r))]
          [else (result (Scm_MakeF32VectorFromArray 4 r))])))

define-cprocって何だろう? scheme語で定義したC言語の種と言った所かな。マニュアルによると、C言語の作成機械みたい。

9.3 ‘gauche.cgen’ - Cコードの生成
=================================

Gauche本体の多くの部分は、Gauche自身、もしくはS式ベースのDSLで書かれてい
ます。 これらのコードはビルド中にCソースに変換され、Cコンパイラで コンパ
イルされます。 ‘gauche.cgen’モジュールおよびそのサブモジュールは、
Gaucheビルドプロセスが使っているこの機能を一般にも使えるように公開するも
のです。

 * Cソースファイルを生成するgauche.cgen.unit
 * Schemeリテラルを生成するgauche.cgen.literals
 * SchemeとCの間の変換   gauche.cgen.type
 * S式で書くC            gauche.cgen.cise
 * スタブの生成          gauche.cgen.stub

世間一般に提供されてるFFIより自由度の高いしくみ。今回のようにモジュールの作成にも使える。但し、ダイナミックに実行中にという訳ではない。

モジュール作成時のログを見ると

make[1]: Entering directory '/tmp/Gauche-gl-0.6/src'
"/usr/bin/gauche-package" compile --verbose \
   :
   libgauche-math3d gauche-math3d.c math3d-lib.stub
   :
gcc  -shared -o libgauche-math3d.so 'gauche-math3d.o' 'math3d-lib.o' \
 -lgauche-0.97 -ldl -lcrypt -lrt -lm  -lpthread

Scm_MakeQuatf ってどこで定義されてる? gauche-math3d.cにあった。

ScmObj Scm_MakeQuatf(float x, float y, float z, float w)
{
    ScmQuatf *v = SCM_NEW(ScmQuatf);
    SCM_SET_CLASS(v, SCM_CLASS_QUATF);
    SCM_QUATF_D(v) = ALLOC_FV(4);
    SCM_QUATF_D(v)[0] = x;
    SCM_QUATF_D(v)[1] = y;
    SCM_QUATF_D(v)[2] = z;
    SCM_QUATF_D(v)[3] = w;
    return SCM_OBJ(v);
}

マクロが多用されてるけど、これが実体だ。C言語を見たい人とscheme言語を見たい人の要求を、同時に満しているぞ。

gauche-package

今迄気にした事は無かったんだけど、gaucheにもパッケージを作るための支援機構が用意されてる。rubyで言う所のgemだな。

sakae@deb:~$ gauche-package help
Usage: gauche-package <command> [options] <args> ...
Commands:
  install         - Fetch, extract, configure, make & install
  build           - Fetch, extract, configure & make
  reconfigure     - Show configure options of <package>
  list            - List known installed packages
  make-gpd        - Make gpd file (called from the configure script)
  compile         - Compile and link an extension module from sources
  generate        - Generate template source tree for a new Gauche extension
  make-tarball    - Create tarball of the package for distribution.
  help            - Show detailed help of <command>
Type 'gauche-package help <command>' for detailed help of each command.

どうやら、雛形も簡単に作ってくれるみたい。

sakae@deb:/tmp$ gauche-package generate mine
sakae@deb:/tmp$ ls mine
configure*        Makefile.in  mine.h        mine.scm     test.scm
configure-compat  mine.c       minelib.stub  package.scm

でも、ここから先は部外者立入禁止っぽい雰囲気だな。知らない人が手を出すと、火傷しそう。 頭の隅に記憶しておきましょ。

世の中には、元気な人が沢山おられるようで、 Gauche:Packages こんなに作成例が公開されてた。まだgemのように本当に沢山ある訳ではないので、専用のレポジトリィーが有るわけではない。

gl関係

math3dを見てきた訳だけど、これは作者様のいわば描き下ろし作品。本命は既にあるC言語で活躍中のlibgl.so等を、gaucheから利用出来るようにする事だ。

FreeBSDでコンパイルして、ログを眺めてみる。都合の良い事に、debianではnoteと称する警告が多数出てきてたけど、FreeBSDでは皆無だったよ。

"/usr/local/bin/gosh" ./gen-syms.scm
"/usr/local/bin/gosh" ./glstate.scm -o gettype-sizes.c gettype
"/usr/local/bin/gosh" ./gen-ptrs.scm
"/usr/local/bin/gauche-package" compile --verbose \
  :
  libgauche-gl gauche-gl.c gl-syms.c gl-lib.stub glu-lib.stub glext-lib.stub
"/usr/local/bin/gauche-package" compile --verbose \
  :
  libgauche-glut gauche-glut.c glut-lib.stub

gauche-packageコマンドは、xxx.so ファイルを作るために必要なファイル類を指定してるっぽい。上の例だと、libgauche-gl.soとlibgauche-glut.soの2つが作成されるんだな。

gen-syms.scm, gen-ptrs.scmは、gauche.cgenを使って、ヘッダーファイルとかを生成してるんだな。

複雑過ぎて、やはり手が出ないな。

HOWTO-precompile.adoc

すっかりコードを見るのを諦めて、Gauche/docs/の中を探索。サフィックスがadocと言う見慣れないファイル群を発見。HOWTOって接頭語で、さそってるよ。色々有ったけど、面白そうなやつをば。

スクリプトを走らせると、ソースが解析され内部コードに変換される。この解析を事前にやっておこうと言う例。

sakae@deb:/tmp/t$ cat >greet.scm
(define-module greet
  (export greeting))
(select-module greet)

(define *message* '("Hello, " ".  How are you?"))

(define (greeting who)
  #"~(car *message*)~|who|~(cadr *message*)")
sakae@deb:/tmp/t$ gosh precomp -e greet.scm
sakae@deb:/tmp/t$ ls
greet.c  greet.sci  greet.scm

プリコンパイルすると、2つのファイルが自動作成される。

sakae@deb:/tmp/t$ cat greet.sci
;; generated automatically.  DO NOT EDIT
#!no-fold-case
(define-module greet (export greeting))
(select-module greet)
(dynamic-load "greet")

モジュールを定義して、それをロードする小さなスクリプト。

sakae@deb:/tmp/t$ wc greet.c
 154  543 7668 greet.c

もう一つは、モジュールの内容をC言語に変換したもの。内容は省略して行数だけ確認。

sakae@deb:/tmp/t$ gauche-package compile greet greet.c
sakae@deb:/tmp/t$ ls
greet.c  greet.o  greet.sci  greet.scm  greet.so*

モジュールと言えば、gauche-packageの出番。最終的にsoファイルが作成された。このあたりは、上でgaucle-glをやったのと一緒だね。

sakae@deb:/tmp/t$ gosh -I. -fload-verbose
;;Loading /usr/share/gauche-0.97/0.9.10/lib/gauche/interactive/init.scm...
;;  Loading /usr/share/gauche-0.97/0.9.10/lib/gauche/interactive.scm...
(use greet)
;;Loading ./greet.sci...
;;  Dynamically Loading ./greet.so...
(greeting "John")
;;Loading /usr/share/gauche-0.97/0.9.10/lib/gauche/pputil.scm...
;;  Loading /usr/share/gauche-0.97/0.9.10/lib/util/match.scm...
;;    Dynamically Loading /usr/lib/gauche-0.97/0.9.10/i686-pc-linux-gnu/util--match.so...
;;  Loading /usr/share/gauche-0.97/0.9.10/lib/gauche/procedure.scm...
"Hello, John.  How are you?"

作成されたモジュールのテスト。普通は、正規の場所にモジュールをインストールして、初めて使えるようになる。けど、-I. で今居るdirも検索パスに追加。出来上がったモジュールの使用宣言してから、モジュール内の関数を実行。ここまでがテストの時間だな。

後はこれを実社会で使えるようにインストールする必要がある。それらをトレースしてもいいんだけど、余白の無駄になりそうなんで、同ファイルを参照あれ。 もっと実用っぽいのも紹介されてるぞ。

libffi

世間一般に流行してるやつ。よく名前だけは聞くよ。 libffi

cffi を学ぶ(4) C のライブラリを使う LISP用だけど、OpenGLを扱っていたので、参考になるな。

そして普通の人なら、rubyでしょ。 ffiを使ってCの関数をRubyから呼び出す とか、 ruby-ffi (slide)なんかがある。

あの人も本腰を入れるのかな。 Gauche:FFIとか Gauche:FFIと型表現

Gauche:c-wrapper

c-wrapper LL-Gongでさっそうと登場。懐しいですーーーう。

Gauche:c-wrapper関連

debianなら、gauche-c-wrapper ってパッケージになってる。実例をあげる。

sakae@deb:/tmp/c-wrapper-0.6.1/examples/stdio$ cat hello.scm
(use c-wrapper)

(c-load-library "libc")
(c-include "stdio.h")

(define (main args)
  (let ((fp (fopen "greeting.txt" "w")))
    (fprintf fp "Hello, %s\n" "world")
    (fclose fp))

  (printf "greeting.txt is created.\n")
  0)

libcにある有名な関数を呼び出してしまおうと言うschemeなコードだ。

sakae@deb:/tmp/c-wrapper-0.6.1/examples/stdio$ gosh hello.scm
greeting.txt is created.
sakae@deb:/tmp/c-wrapper-0.6.1/examples/stdio$ cat greeting.txt
Hello, world

素晴しいけど、リナだけの専売特許だな。FreeBSDではコンパイルに失敗。ひょっとしたらgccを使うとか、リナのエミュレーション・モードを動かせばなんとかなるかも知れないけど。。。


This year's Index

Home