libGDXの基礎２０ シザーテストを使う

#シザーテストとは

シザーテストとは描画範囲を狭める機能です。矩形を指定することができます。

シザーテスト自体は扱いは簡単なのでOpenGL直に触ることが容易なlibGDXを利用する限りは単純なものならそのまま使ってもかまわないです。

一応libGDXにも用意されています。そのままではなくほんの少しだけ高機能なもの、シザースタックです。

#シザースタックとは

シザースタックはシザーテストの矩形をスタックのように積み上げる機能です。Andの論理演算のように複数の矩形が重なっている部分のみ描画されます。

サンプルとして256x256の画像を描画してみます。

##画像を描画する

基礎２とほぼ同じコードです。

```java
public class MainListener20 extends ApplicationAdapter{
    SpriteBatch batch;
    Texture texture;

    @Override
    public void create() {
        batch = new SpriteBatch();
        texture = new Texture("enemy.png");
    }

    @Override
    public void resize(int w, int h) {
    }

    @Override
    public void render() {
        Gdx.gl.glClearColor(0, 0, 0.2f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        
        
        batch.begin();
        batch.draw(texture, 0, 0);
        batch.end();
        
    }

    
    public static void main(String[] args) {
        new LwjglApplication(new MainListener20(), "libGdxTest", 256, 256);
    }

}
```

実行結果
![20170226-1.png](https://qiita-image-store.s3.amazonaws.com/0/46371/abdf80ae-3cf6-ae4c-4cb9-64c30cb4230e.png)


##Y方向を半分切り取る

```java
    @Override
    public void render() {
        Gdx.gl.glClearColor(0, 0, 0.2f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        
        ScissorStack.pushScissors(new Rectangle(0, 0, 256, 128));
        
        batch.begin();
        batch.draw(texture, 0, 0);
        batch.end();
        
        
        ScissorStack.popScissors();
    }
```

実行結果
![20170226-2.png](https://qiita-image-store.s3.amazonaws.com/0/46371/510c4018-9256-0f89-6c5f-dce86e5dc111.png)



##X方向を半分切り取る

```java
    @Override
    public void render() {
        Gdx.gl.glClearColor(0, 0, 0.2f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        
        ScissorStack.pushScissors(new Rectangle(0, 0, 128, 256));
        
        batch.begin();
        batch.draw(texture, 0, 0);
        batch.end();
        
        
        ScissorStack.popScissors();
    }
```

実行結果
![20170226-3.png](https://qiita-image-store.s3.amazonaws.com/0/46371/0b3c5eb2-7686-00d3-f3cc-4a8b373c3540.png)



##両方スタックに乗せる

```java

    @Override
    public void render() {
        Gdx.gl.glClearColor(0, 0, 0.2f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        
        ScissorStack.pushScissors(new Rectangle(0, 0, 256, 128));
        ScissorStack.pushScissors(new Rectangle(0, 0, 128, 256));
        
        batch.begin();
        batch.draw(texture, 0, 0);
        batch.end();
        
        
        ScissorStack.popScissors();
        ScissorStack.popScissors();
    }
```

実行結果
![20170226-4.png](https://qiita-image-store.s3.amazonaws.com/0/46371/d013b757-5f12-461b-b5dc-ee555f322002.png)


今回のような単純な描画ではあまりスタックの意味がないですが、階層構造を持つ画面などではスタックが活躍します。Scene2Dのような場合ですね。


#Scene2Dでシザースタックを使う

Scene2Dではさらに上位のAPIとしてActor自体がメソッドを持っています。
メソッドはそれぞれclipBegin()とclipEnd()です。

シザーテストという名前ではなくクリッピングというより上位の概念名にしていますが、中身は同じです。シザースタックを利用しています。
引数なしのclipBegin()をよびだすとそのコンポーネントのサイズでクリッピングされます。座標系はそのActorのローカル座標になります。
シザースタックを直接使う場合は座標変換がめんどくさいのでScene2Dを使う場合はこちらを使うのが良いでしょう。また、こちらはオブジェクトプーリングされていますので上のようなサンプルコードと違い、Rectangleが使いまわされるためGC負荷が上がりません。できるだけこちらをつかいましょう。

また、Scene2Dに限りませんが、Scene2Dで特に発覚しやすいのが描画タイミングです。あくまでも描画をする時にシザーテストが行われます。batch.draw()等を呼び出しただけではまだ描画されていません。flushやendなどをシザーテストの開始前と描画後に入れるようにしましょう。