CommonLisp
OpenGL
lisp

cl-openglでグラフィックス

Qiitaの記事をはじめて書きます。
どうぞ生暖かい目で見てやってください。

common lispでグラフィックスやりましょう。

使うのはcl-openglです、QuickLispを使ってインストールします。

まずはcl-openglをインストールしましょう。
cl-openglと一緒にcl-glutとcl-glutもインストールします。

replを起動して。

(ql:quickload :cl-opengl)
(ql:quickload :cl-glu)
(ql:quickload :cl-glut) 

とするとインストールされます。

画面にグラフィックを描画するための最低限のソースを書いていきます。

glib.lisp
;; Require libralies
(require 'asdf)
(require 'cl-opengl)
(require 'cl-glut)
(require 'cl-glu)

;; Parameters
(defvar *width* 500)
(defvar *height* 500)

;; USER FUNCTIONS
(defun user-display () ())
(defun user-init () ())
(defun user-idle () ())

;; Derived window class
(defclass main-window (glut:window) ()
    (:default-initargs :title "opengl test" :mode '(:double :rgb :depth) :width *width* :height *height*))

;; glut:display
;; Draw.
(defmethod glut:display ((window main-window))
    ;; Clear buffer
    (gl:clear :color-buffer :depth-buffer)

    ;; Draw shape
    ;;(glDisable GL_CULL_FACE)  
    (gl:shade-model :flat)
    (gl:normal 0 0 1)

    ;; user display process
    (user-display)

    ;; Swap buffer
    (glut:swap-buffers))

;; glut:idle
;; Application idle.
(defmethod glut:idle ((window main-window))
    ;; user idling process
    (user-idle)
    (glut:post-redisplay))

;; glut:reshape
(defmethod glut:reshape ((w main-window) width height)
    (gl:viewport 0 0 width height)
    (gl:load-identity)
    (glu:ortho-2d 0.0 *width* *height* 0.0))

;; glut-display
;; Draw.
(defmethod glut:display-window :before ((window main-window)) )

;; main
;; Main function (Program entry point).
(defun main ()
    ;; user initalization process
    (user-init)
    ;;(glut:special-func #'key-special)
    (glut:display-window (make-instance 'main-window)))

gltest.lisp
(load "glib.lisp")

(defun user-init ())

(defun user-idle ()
  (sleep (/ 1.0 60.0)))

(defun user-display ())

では実行してみましょう。

(load "gltest.lisp")
(main)

sample1.png

真っ黒な画面がでてきます。

さて、それではなにか描いてみましょう。
線分を描画する関数を定義します。

;; Draw 2D line.
(defun g2line (x y x2 y2)
    (gl:with-primitives :lines
        (gl:vertex x y 0.0)
        (gl:vertex x2 y2 0.0)))

そしてこんな感じにしてみます。

gltest.lisp
(load "glib.lisp")

(defun user-init ()
  (defparameter *theta* 0.0)
  (defparameter *length* 100.0)
  (defparameter *n* 500)
  (defparameter *pi-part* (/ (* 2.0 PI) *n*))
)

(defun user-idle ()
  (sleep (/ 1.0 60.0)))

(defun user-display ()
  (setf *theta* (+ *theta* 0.01))

  (mapcar 
    (lambda (n)
      (let ((rand-len (random 100)))
        (g2line (/ *width* 2.0)
                (/ *height* 2.0)
                (+ (/ *width* 2.0) (* (cos (+ *theta* (* n *pi-part*))) (+ *length* rand-len)))
                (+ (/ *height* 2.0) (* (sin (+ *theta* (* n *pi-part*))) (+ *length* rand-len))))))
    (iota *n*))
)


;; Draw 2D line.
(defun g2line (x y x2 y2)
    (gl:with-primitives :lines
        (gl:vertex x y 0.0)
        (gl:vertex x2 y2 0.0)))

;; iota
(defun iota (m &optional (n 0) (step 1))
  (if (>= n m)
    nil
    (cons n (iota m (+ n step) step))))

sample1.png

ええ、目がチカチカしますね。

線に色をつけるにはこんな感じにします。

;; Draw 2D line.
(defun g2linec (x y x2 y2 r g b)
    (gl:with-primitives :lines
        (gl:color r g b)
        (gl:vertex x y 0.0)
        (gl:vertex x2 y2 0.0))
        (gl:color 1.0 1.0 1.0))
(defun user-display ()
  (setf *theta* (+ *theta* 0.01))

  (mapcar 
    (lambda (n)
      (let ((rand-len (random 100)))
        (g2linec (/ *width* 2.0)
                 (/ *height* 2.0)
                 (+ (/ *width* 2.0) (* (cos (+ *theta* (* n *pi-part*))) (+ *length* rand-len)))
                 (+ (/ *height* 2.0) (* (sin (+ *theta* (* n *pi-part*))) (+ *length* rand-len)))
                 (random 1.0)
                 (random 1.0)
                 (random 1.0))))
    (iota *n*))
)

sample1.png

もう目がこわれてしまいそうです。

さあ、あなたの目にトドメを刺しましょう ( ̄ー ̄)ニヤリッ

;; draw filled rect
(defun g2fillrectc (x y x2 y2 r g b)
    (gl:with-primitives :polygon
        (gl:color r g b)
        (gl:vertex x y 0.0)
        (gl:vertex x2 y 0.0)
        (gl:vertex x2 y2 0.0)
        (gl:vertex x y2 0.0)
        (gl:color 1.0 1.0 1.0)))

(defun user-display ()
  (setf *theta* (+ *theta* 0.01))

  (g2fillrectc 0.0 0.0 *width* *height* 
               (random 1.0)
               (random 1.0)
               (random 1.0))

  (mapcar 
    (lambda (n)
      (let ((rand-len (random 100)))
        (g2linec (/ *width* 2.0)
                 (/ *height* 2.0)
                 (+ (/ *width* 2.0) (* (cos (+ *theta* (* n *pi-part*))) (+ *length* rand-len)))
                 (+ (/ *height* 2.0) (* (sin (+ *theta* (* n *pi-part*))) (+ *length* rand-len)))
                 (random 1.0)
                 (random 1.0)
                 (random 1.0))))
    (iota *n*))
)

sample1.png

画像ではわかんないですが、背景がぴかぴかしています。
もう眼球が取れそうです。

さて、今日はここまで。
ここまで読んでくださった皆様、ありがとうございました。

追記1
環境を書き忘れました。
OS:Windows 7 64bit
処理系:SBCL 1.2.15 x86

追記2
cl-openglを使ったグラフィックスライブラリをつくりました。
より手軽にグラフィックスを扱うことができます。