Gauche, c-wrapper, SDL_ttfを使用してテキスト表示する例

http://konbu.s13.xrea.com/lib/lang/scheme/showtext.scm
コマンドラインで渡された文字列を表示する簡単な例。同じディレクトリにsdl_helper.c(c-wrapperのexample/sdlにあるもの)と、SDL_ttfが開けるフォントデータをfont.ttfとして置いてください。あとutf-8環境用。utf-8じゃなかったら、TTF_RenderUTF8としてるところをTTF_RenderTextにすればいいかなたぶん。

% ./showtext.scm hogehoge

とかやると600x480の画面にhogehogeと書かれたものが表示される。fontが日本語はいってりゃ日本語も表示できる。

% ls
font.ttf  sdl_helper.c  showtext.scm*
% cwcompile showtext.scm
% ls
font.ttf      sdllib.o    sdllib.stub    sdllib_head.o  sdllib_tail.o
sdl_helper.c  sdllib.so*  sdllib_head.c  sdllib_tail.c  showtext.scm*

こうしてcwcompileしておくとc-loadにかかる時間が短かくなるらしいです。けどたぶんこのプログラムぐらいだと違いあんまわからんかな。

#!/usr/bin/env gosh
(use c-wrapper)
;; cwcompile はここを読む
(c-load '("SDL.h" "SDL_ttf.h" "stdio.h" "stdlib.h" "sdl_helper.c")
        :cppflags-cmd "sdl-config --cflags"
        :libs-cmd "sdl-config --libs; echo '-lSDL_ttf'"
        :import (list (lambda (header sym)
                        (#/\/SDL\/.*\.h$/ header))
                      'NULL
                      'run_sdl_main)
        :compiled-lib "sdllib")

;; 適当に決め打ち
(define *screen-w* 600)
(define *screen-h* 480)
(define *font-path* "font.ttf") ; SDL_ttfはTTFフォント以外も開けたかも
(define *font-size* 100)

(define (make-rect x y w h)
  (let ((rect (make <SDL_Rect>)))
    (set! (ref rect 'x) x)
    (set! (ref rect 'y) y)
    (set! (ref rect 'w) w)
    (set! (ref rect 'h) h)
    rect))

(define (make-color r g b)
  (let ((color (make <SDL_Color>)))
    (set! (ref color 'r) r)
    (set! (ref color 'g) g)
    (set! (ref color 'b) b)
    color))

(define COLOR_BLACK (make-color 0 0 0))
(define COLOR_WHITE (make-color 255 255 255))

(define (wait-event)
  (define event (make <SDL_Event>))
  (define (run-event)
    (let ((sym (ref* event 'key 'keysym 'sym)))
      (cond
        ((or (= sym SDLK_ESCAPE) (= sym SDLK_q)) #t)
        (else #f))))
  (let poll-event ()
    (SDL_Delay 10)
    (if
      (and
        (> (SDL_PollEvent (ptr event)) 0)
        (= SDL_KEYDOWN (ref event 'type))
        (run-event))
      #t
      (poll-event))))

(define (make-printer font-path font-size)
  (let
    ((bgrect (make-rect 0 0 *screen-w* *screen-h*))
     (font (TTF_OpenFont font-path font-size)))
    (if (null-ptr? font) ; ちゃんとしたフォント開けてるかチェック
      ;; 開けてなかったらエラーメッセージ表示するクロージャを返す
      (lambda (text)
        (print (format "cannot open ~s" font-path)))
      ;; 開けてたらSDL画面を開く。
      ;; そして開いたフォントを使って画面にテキストを書きこみ、
      ;; イベント待ちループにはいるクロージャを返す
      (let
        ((screen (SDL_SetVideoMode *screen-w* *screen-h* 16 SDL_HWSURFACE)))
        (lambda (text)
          (let
            ((line (TTF_RenderUTF8 font text COLOR_BLACK COLOR_WHITE)))
            (SDL_FillRect screen (ptr bgrect) -1)
            (SDL_UpdateRect screen 0 0 *screen-w* *screen-h*)
            (SDL_BlitSurface line NULL screen (ptr (make-rect 0 0 0 0)))
            (SDL_Flip screen))
          (wait-event))))))

(define (show-text text)
  (SDL_Init SDL_INIT_VIDEO)
  (TTF_Init)
  ;; テキスト表示するクロージャを作成し、そのクロージャにtextを渡して実行
  (let ((printer (make-printer *font-path* *font-size*)))
    (printer text))
  (TTF_Quit)
  (SDL_Quit))

(define (sdl-main argc argv)
  ;; 1つ目の引数をshow-textに渡す
  (show-text (cast <string> (ref argv 1)))
  0)

(define (main args)
  ;; 引数があればrun_sdl_mainに渡す
  ;; run_sdl_mainはsdl_helperの方で定義したもの。内部でsdl-mainを呼ぶ
  (unless (null? (cdr args))
          (run_sdl_main (length args) args sdl-main)))

; (main '("spres.scm" "show text"))

Cに書きかえてみた

http://konbu.s13.xrea.com/lib/lang/c/showtext.c
やってることは同じ。さすがにSDLの関数とか呼ぶだけだったらCの方がみじかく済むな。

test