ひと筆描きです

https://dl.getdropbox.com/u/264798/clojure_girl.jpg

↓これがすごくステキだったので、じぶんも試しにこういうテイストのものをやってみようかなと思い珍幹線でひと筆描き風スケッチ。

http://f.hatena.ne.jp/rakawa/20090926234604

しかもせっかくなのでclojureで。ちなみにp5をclojureからつかうのはこれがはじめて。

(import '(processing.core PApplet PImage))
(import '(javax.swing JFrame))

(def pic (ref nil))
(def black (ref nil))

(defn girl []
  (let [#^JFrame f (new JFrame "clojure girl")
        #^PApplet p (proxy [PApplet] []
            (setup []
                   (doto this 
                     (.size 499 502)
                     (.background 255))
                   (dosync 
                     (ref-set pic (.loadImage this "girl.jpg"))
                     (ref-set black (.color this 0 0 0)))
                   (let [#^PApplet app this
                         width (. this width)
                         height (. this height)] 
                     (dotimes [i 30] 
                       (doto app
                         (.smooth)
                         (.noStroke)
                         (.fill @black)
                         (.triangle 
                           (.random app (float width))
                           (.random app (float height))
                           (.random app (float (/ width 2)))
                           (.random app (float (/ height 2)))
                           (.random app (float (/ width 3)))
                           (.random app (float (/ height 3))))))
                     (dotimes [w width] 
                       (dotimes [h height] 
                         (if (= (.get app w h) @black) 
                           (do 
                             ;(println (aget (.pixels @pic) (+ (* h width) w)))
                             (.set app w h (aget (.pixels @pic) (+ (* h width) w))))))))))]
    (.init p)
    (doto f 
      (.add p) 
      (.pack) 
      (.setVisible true)
      (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE))))
(girl)

まだまだリファクタらないと残念なかんじ。triangleとか相当残念。「on Lisp」とかLOLとかでいわれてるようにボトムアップしていくのがlispの礼儀なのでこの状態でコード載せちゃうってのもどーかとは思うんですけど…

しかしサンプルコードではわからなかったようなことがいろいろと見えてきた気がする。たとえばtype hintつけるだけで速度が全然ちがうとか。

…つか笑うぐらいにレンダリングのスピードが遅いw ボトルネックはなんとなく見えてます。java arrayをゴニョる「aget」っぽい。
タイミングよくclojureのMLにもこんな話が出てたので詳しく見てみるつもり。

ちなみに中身的にはある特定の色で図形を描いて、あとからキャンバスの位置ピクセルに該当する画像のピクセルを置いてあげるという方向なんですが、groovyでやるとこんなかんじかな。

特定の色で図形を描く

  def mask = {
    background(255)
    smooth()
    
    30.times{i->
      def(x1,y1,x2,y2,x3,y3) = [random(width),random(height),random(width)/2,random(height)/2,random(width)/3,random(height)/3]
      noStroke()
      fill(black)
      triangle(x1 as Float,y1 as Float,x2 as Float,y2 as Float,x3 as Float,y3 as Float)
    }
  }

該当するピクセルをあてこむ

def applyImg = {
    width.times{w->
      height.times{h->
        def pos = h*width+w
        def c = get(w,h)
        if(c==black){
          set(w,h,pic.pixels[pos])
        }
      }
    }
  }

1.6からできるようになった多重代入のおかげで、triangleとかquadとかbezierとか座標をたくさんつっこむものはすごく書きやすくなった。
ただclojure書いてたせいか、schemeのlet*みたいなことできるかなとアタマをよぎったのでやってみたよ。

ちなみにschemeのlet*とはこういうやつ。

(let* ((i 1) (j (+ i 2)))
        (* i j))

すなわち変数定義内で直前に定義したものが参照できるって挙動。

def(i,j,k) = [1, i+1, i+j]
[i, j, k].each(){
  println it
}

Caught: groovy.lang.MissingPropertyException: No such property: i for class: xxxx

ダメでした…