cl-openglでグラフィックス

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


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

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

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

replを起動して。

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

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

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

```cl: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)))

```

```cl:gltest.lisp

(load "glib.lisp")

(defun user-init ())

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

(defun user-display ())

```

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

```cl
(load "gltest.lisp")
(main)
```
![sample1.png](https://qiita-image-store.s3.amazonaws.com/0/74246/d54bd5ce-78d5-bd30-23d0-05b0c3c99c48.png)

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

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

```cl
;; 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)))
```

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

```cl: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](https://qiita-image-store.s3.amazonaws.com/0/74246/365a6d1d-d978-f31a-1b83-4dcd7efd195b.png)

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

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

```cl
;; 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))
```

```cl
(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](https://qiita-image-store.s3.amazonaws.com/0/74246/908ce205-78ba-bc97-82e2-86f417959ac5.png)

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

さあ、あなたの目にトドメを刺しましょう (￣ー￣)ﾆﾔﾘｯ 

```cl
;; 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](https://qiita-image-store.s3.amazonaws.com/0/74246/88169cd9-743c-d877-e089-29c0af5dd6a5.png)

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

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


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

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

* [Common Lisp用の軽量グラフィックスライブラリ「Mir」を作りました](https://qiita.com/kedama17/items/6da66d9a295bce97c71d)