Processing で絵を描こう

# Processing で絵を描こう

ちょっとプログラムを使って図形描画をしたくなったので、簡単にかける仕組みはないかと探して、Processingに行き着いた。

勉強がてら、ポイントとサンプルをまとめました。
なお、最新版の Processing3 を使っているので、適宜インストールはしてください。


## Processing とは

Processing は、グラッフィック描画などが柔軟・簡便にできるように設計されたプログラム言語であり、またそれを実行させるための統合開発環境（IDE）でもある。

https://processing.org/



## 何ができるの？

- プログラムコードで、絵が描けます[^1]。
- IDE環境でもあるので、プログラムをIDE上のエディタに書いて、実行結果をすぐ見れます。
- 矩形や円、ドットや線など、図形の描画が可能です。
    - 描画エリアを３次元として3Dなオブジェクトの描画もできます。
- イベントのキャッチ（マウスやキーボード入力）なども行え、インタラクティブなビジュアルアートの作成も可能。
- 作成した画像のpngなどへの出力が可能です。
    - デザイナではないプログラマにとって、時には重宝するでしょう。
- [p5.jsといったJavascriptライブラリ](https://p5js.org/)もあり、発展性もあり。

[^1]: 昔話で恐縮だがBASIC(Visual Basicじゃないよ）も似たような感じで、簡単なコードでちょっとした画像描画ができた。そしてそれを色々応用しながらゲームなどを作ってたりして、プログラムやアルゴリズムを学んだのだった（遠い目）。そういうBASICに似た懐かしさも感じられるProcessingである。

### 言語的な特徴

- 関数型のプログラム言語。
    - あらかじめ言語で用意されている組み込み関数で描画。
        - 関数は[動的バインディング](https://ja.wikipedia.org/wiki/%E3%83%80%E3%82%A4%E3%83%8A%E3%83%9F%E3%83%83%E3%82%AF%E3%83%90%E3%82%A4%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0)なので、文法が引数に決まる。
    - 自分で任意の関数も定義可能。
- Javaをベースにした[DSL](https://ja.wikipedia.org/wiki/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E5%9B%BA%E6%9C%89%E8%A8%80%E8%AA%9E)なので、文法はほぼJavaです。
    - 1つの命令に`;`が必要。 
    - `,` を使った、複数命令の記述も可能。
- 変数の型あり。Javaのプリミティブな型に加えて、color型が定義されています。
    - [int - 32ビット整数 -2147483648～2147483647](https://processing.org/reference/int.html)
    - [long - 64ビット整数(-9223372036854775808～9223372036854775807)](https://processing.org/reference/long.html)

    - [float - 32ビット単精度浮動小数点数](https://processing.org/reference/float.html)
    - [double - 64ビット倍精度浮動小数点数](https://processing.org/reference/double.html)
    - [boolean - 真偽型(`true` / `false`)](https://processing.org/reference/boolean.html)
    - [byte - 8ビット整数(-128～127)](https://processing.org/reference/byte.html)
    - [char - 16ビットUnicode文字(\u0000～\uFFFF)](https://processing.org/reference/char.html)
    - [color](https://processing.org/reference/color_datatype.html)
        - `color()` で定義するか、`#RRGGBB` で定義可能。
    - 型変換には、`int()`などの型変換関数を用いる。
- 制御構文はシンプル
    - ループ処理として、 `for`, `while`
    - 判断処理として、 `if`, `switch~case`
- 日本語処理も可能
    - テキストエディタのフォントは日本語が表示できるものに設定を（Osakaなど）

## 基本

まずはサンプルコードを。

``````java:sample_of_setup()
int x = 0;    // x座標初期値

/*
 * 初期化
 */
void setup() {
  size(200, 200);
  background(0);
  noStroke();
  fill(102);
}

/*
 * 描画
 */
void draw() {
  rect(x, 10, 2, 80); 
  x = x + 1;
  println("x = ", x);    // デバッグ
}
```

### コメント

Javaと同じです。

```java
/*
複数行コメント
*/
// 行末までコメント
```

### コンソールへの出力

Javascriptでいうところの`console.log()`に当たるのが`print`と`println`。`println`だと自動的に改行が入る。結果はコンソール・エリアに出力される。デバッグにどうぞ。

```java
println("Hello, World!!");
```
### コード

プログラムコードは、頭から順番に処理される。
下記で説明する `setup()` や `draw()` などを使って基本動作を定義することも可能だが、これらの関数を使わなくても実行可能である。

### setup() と draw()

`setup()` と `draw()` は、言語で定義された初期化関数と描画実行関数である。

`setup()` では、実行時に１回呼ばれる。`size()`や`fullScreen()`、`background()`など、ディスプレイ・ウィンドウの属性や初期背景色などの初期化処理を行うと良い。

`draw()` は１フレームごとに呼ばれる。実際に描画関数を読んで何かを描かせる。Processingは、`draw()`関数の処理が終わった時点で描画を行う。

どちらも `void` 型の関数とする。
上記サンプルを実行すると、停止（:white_square_button:）が押され続けるまで、`println`が実行されるのがわかるだろう。（描画内容は途中から同じ結果になってしまうので変化なしに見えてしまうが）

[リファレンス： setup()](https://processing.org/reference/setup_.html)
[リファレンス： draw()](https://processing.org/reference/draw_.html)

### size() と fullScreen()

ディスプレイ・ウィンドウの属性（幅と高さ）を設定する。
`setup()` を用いる場合は、この関数内の一番最初に書かなければならない。
また、Processing3からは全画面表示用の `fullScreen()` が用意されている。これらはいずれかのみ指定可能。

[リファレンス： size()](https://processing.org/reference/size_.html)
[リファレンス： fullScreen()](https://processing.org/reference/fullScreen_.html)

### loop() と noLoop()

```java:sample_of_loop()
void setup() {
  size(200, 200);
  noLoop();  // draw() をループさせない
}

float x = 0;

void draw() {
  background(204);
  x = x + .1;
  if (x > width) {
    x = 0;
  }
  line(x, 0, x, height); 
}

void mousePressed() {
  loop();  // マウス押し込みで draw() をループ
}

void mouseReleased() {
  noLoop();  // マウスをリリースで draw() を非ループ
}
```

`draw()` のループは、`loop()` と `noLoop()` を使って初期化時、また（イベントハンドラなどを使って）実行時に制御できる。

[リファレンス： loop(), noLoop()](https://processing.org/reference/loop_.html)


### 色の設定

#### 色モデル

RGB色モデルと[HSB色モデル](https://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93)が用意されている[^2]。これを `colorModel()` で初期化する。

[リファレンス： colorModel()](https://processing.org/reference/colorMode_.html)

[^2]: RGBはCSSなどでも慣れ親しんでいる赤、緑、青の３原色を指定するモデルで、HSB（HSVとも）は色相と飽和度（鮮やかさ）と明度（白黒割合）のモデルである。ざっくりいうと、前者は原色の配色割合のモデルで、後者は色味・鮮やかさ・明度の度合いのモデルである。

#### color型とcolor()

color型が定義されていて、色情報を変数として持てる。定義する場合には、CSS方式の`#RRGGBB` で代入するか、組み込み関数 `color()` を用いる。

```java:sample_of_color
color col1 = #FF8800;               // オレンジ
color col2 = color(255,0,0);        // 赤
color col3 = color(255,0,0,128);    // 半透明の赤
background(col1);
```
[リファレンス： color型](https://processing.org/reference/color_datatype.html)
[リファレンス： color()](https://processing.org/reference/color_.html)

#### 背景色の設定

`background()` によって設定する。`setup()` の中で初期配色として設定ができ、また、`draw()`の中でフレーム毎に呼ぶことも可能。

```java:sample_of_background()
int r=0, g=0, b=0;

void setup() {
  size(200, 200);
  background(color(r,g,b));
}

void draw() {
  r = (r+1) & 255;
  g = (g+2) & 255;
  b = (b-3) & 255;
  background(color(r,g,b));
}
```

#### 色と線の太さの設定

```java:sample_of_coloring_and_stroke_weight
stroke(color(0,0,255));      // 線の色
strokeWeight(4);             // 線の太さ(pixel)
fill(color(128,128,255));    // 塗りつぶし色
rect(20, 20, 60, 60);
```

線や矩形、円などの外郭の線の色を `stroke()` で設定する。 `noStroke()` で線なし指定も可能。
線の太さは、 `strokeWeight()` で設定する。デフォルトは `1` である。
塗りつぶし色は、 `fill()` で設定する。 `noFill()` で塗りつぶしなし指定も可能。

[リファレンス： stroke()](https://processing.org/reference/stroke_.html)
[リファレンス： strokeWeight()](https://processing.org/reference/strokeWeight_.html)
[リファレンス： fill()](https://processing.org/reference/fill_.html)

## 画像の描画

　display windowへ図形を描画する。便利なことに、2D座標系と3D座標系の２つの座標系に対応している。

### 点を打つ： point()

2D、3Dのどちらの座標系でも利用可能。

```java:sample_of_point
void setup() {
  size(200, 200);
  background(255);
}

void draw() {
  float x = random(0, width);    // width はシステム変数でdisplay windowの幅
  float y = random(0, height);   // height もシステム変数でdisplay windowの高さ
  int col = int(random(0,255));
  stroke(col);
  strokeWeight(2);
  point(x,y);
}
```
[リファレンス： point()](https://processing.org/reference/point_.html)

### 線を引く： line()

2D、3Dのどちらの座標系でも利用可能。

```java:sample_of_line
int r1=0, g1=0, b1=255;
int r2=0, g2=255, b2=0;

size(200, 200);
background(0);

for ( int i=0; i<width; i= i+10 ){
  stroke(color(r1,g1,b1));
  line(0, i, i, height);
  g1 += 20;
  
  stroke(color(r2,g2,b2));
  line(i,0,width,i);
  b2 += 20;
}
```

[リファレンス： line()](https://processing.org/reference/line_.html)

### 四角形を描く： rect()

2D座標系で使う。`line()`と違って、第３、第４引数は、座標ではなく幅と高さなので注意。
第５引数を与えることで、角を丸めることもできる。

```java:sample_of_rect
boolean is_opening = true;
int win_height = 0;
int WIN_HEIGHT_MAX = 10;

void setup() {
  size(320,240);
  stroke(color(255,255,255));
  strokeWeight(3);
  fill(0,0,255);
}

void draw() {
  if ( is_opening ){
    if ( win_height < WIN_HEIGHT_MAX ){
      clear();
      rect(20,20,280,20*win_height++,8);
    } else {
      is_opening = false;
      noLoop();
    }
  } else {
    if ( win_height >= 0 ){
      background(0);
      rect(20,20,280,20*win_height--,8);
    } else {
      is_opening = true;
      clear();
      noLoop();
    }
  }
}

void mousePressed() {
  loop();
}
```

[リファレンス：　rect()](https://processing.org/reference/rect_.html)

#### 円・楕円を描く： ellipse()

2D座標系で利用可能。

```java:sample_of_ellipse
int t=0;

void setup() {
  frameRate(30);
  size(200,200);
  background(0);
}

void draw() {
  clear();
  float y = 50+pow(t-10,2);
  float w = 100+pow(t-10,2);
  t = (t < 20)? (t+1): 0;
  put_circle(y,w);
}

/*
 * 自前な関数（サブルーチン）
 */
void put_circle(float y, float w){
  color col = color((255-t*10)&255,0,0);
  ellipse(100,y,w,100);
}
```
[リファレンス： ellipse()](https://processing.org/reference/ellipse_.html)

#### 文字を描く： text()

2D、3Dのどちらの座標系でも利用可能。

```java:sample_of_text
size(300,200);
textSize(32);        // pixcel
fill(0, 128, 128);
text("Hello, World!", 20, 30); 
```

[リファレンス： text()](https://processing.org/reference/text_.html)