SPOUTでopenFramewoksの映像をvvvvに送信

#概要
vvvvでopenFrameworksやProcessingからの映像を受け取って
出力したいという場合、SPOUT(http://spout.zeal.co/) を使います。
MacでいうところのSyphon(http://syphon.v002.info/) ですね。
SPOUTを使うことで他の言語で生成した映像をvvvvで受信したり、
逆にvvvvで作った映像をopenFrameworksなどに送ることがが可能になります。

この記事ではopenFrameworksで生成した映像をSPOUTを使って送信しvvvvで受信する方法を説明します。

#全体図
システムの構成は以下になります。
![WS000754.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/81b414e7-8da6-f35c-7dcc-104c63c3d2c4.jpeg)

送信側のopenFrameworksではSPOUTのDLLを使って映像を送信し、
受信側のvvvvではSpout_Receiver.v4pを使って映像を受信します。
vvvvは映像の送信も受信も簡単なんですがopenFrameworksはちょっと面倒でした。
（私がopenFrameworksにあまり詳しくないからかもですが。）

#準備　SPOUTのダウンロードとインストール
Spoutのダウンロードは http://spout.zeal.co/ のDownloadをクリックし
SpoutSetup_V2.004-beta.zipを入手します。

![WS000731.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/775768cf-ea30-03a1-81ed-41f39395f8f7.jpeg)

ZIPファイルを任意のフォルダに解凍しSpoutSetup_V2.004-beta.exeを実行すると
インストールが始まります。
インストール先はどこでもOKです。展開されたファイルを使うだけなので。
（※イントールの画像は抜粋です。）

![WS000732.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/6b1e5c85-634a-ef19-cf29-f6da3b65da06.jpeg)
![WS000733.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/4eee1827-a724-9f56-d050-aa0b86dec45b.jpeg)
![WS000734.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/35a46dbc-7558-beb6-6578-715742c4a8fa.jpeg)
![WS000736.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/8e0737c4-f52d-3672-96f2-3b890b94e4f9.jpeg)

インストール先のフォルダを確認するとSpout2のフォルダが以下のように展開されています。

![WS000738.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/2a8f13e5-bed9-9346-216c-c78dbc8836ba.jpeg)

この後に使うのは送信側がSpout2/SPOUTSDK/SpoutSDK/Binaries にあるSpout2.dll、Spout2.lib、SpoutDLL.hです。

![WS000741.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/247da5af-227b-2d9d-52c6-9090dbae701f.jpeg)


受信側はSpout2/VVVV/Receiver/DirectX 9(11でもOK）にあるパッチファイルになります。

![WS000756.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/648eb94b-5a14-ac66-b756-f2a233d9eaff.jpeg)

openFrameworksの実装については、\Spout2\SPOUTSDK\SpoutSDK\SPOUTDLL\cbSpoutExample\srcのソースをコピペし使います。
これらの場所を覚えておいてください。

![WS000757.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/809bb24d-0493-635d-b355-74c4ec720997.jpeg)


#openFrameworks（0.9.0）でのSPOUT（Sender)の設定(Visual Studio 2015編)
openFrameworksでは新しいプロジェクトを作成した状態から説明します。
openFrameworksはとっかかりは　http://yoppa.org/ をみればすべて書いてますのでそちらを参考にしてください。偉大です。

次にSpoutを使うための準備をします。Spout2.dll、Spout2.libをopenFrameworksのプロジェクトのbinフォルダにコピーします。
また、SpoutDLL.hをsrcフォルダにコピーします。

SpoutDLL.h　をプロジェクトに追加します。
SolutionExplorerのsrcで右クリックし、Add>Existing Item で先ほど配置したSpoutDLL.hを選択すればOKです。
![WS000746.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/5a799cba-3b38-a896-80c3-8086c8b10646.jpeg)

こんな感じでSolutionExplorerにSpoutDLL.hが追加されます。

![WS000759.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/f733dc51-a3d7-37fe-70c4-ce4b111bc46e.jpeg)


次にSpout2.lib　をLinkerに追加します。
Project>Vs2015Test(※プロジェクト名）PropertiesでPropertyPagesを開き
LinkerのInputを選択しAdditional Dependenciesで<Edit>を選択し「.\bin\Spout2.lib」を
テキストボックスに記載し、OKをクリックします。

![WS000758.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/207ad6d8-e1d7-e6dd-9bc5-31e1e829e615.jpeg)

![WS000752.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/0566c87a-ffe5-8c02-fdd9-88e05ab9d390.jpeg)

これで準備は整いました。

#ofApp.hの実装

次に実装です。
main.cppは特別編集は必要ありません。
ofApp.hではSpoutDLL.hをインクルードします。

```
#include "SpoutDLL.h" // for Spout2 dll
```

また、ofApp.cppで使う変数を定義しておきます。
ソースはインストール先の\Spout2\SPOUTSDK\SpoutSDK\SPOUTDLL\cbSpoutExample\src\ofApp.hの一部をコピペすればよいです。

```
void exit();
bool InitGLtexture(GLuint &texID, unsigned int width, unsigned int height);
char sendername[256];			// Shared memory name
GLuint sendertexture;			// Local OpenGL texture used for sharing
bool bInitialized;			// Initialization result
ofImage myTextureImage;			// Texture image for the 3D demo
float rotX, rotY;
```

#ofApp.cppの実装
次にofApp.cppの実装です。
\Spout2\SPOUTSDK\SpoutSDK\SPOUTDLL\cbSpoutExample\src\ofApp.cppを参考に
必要なコードをコピペします。
まずはnamespaceを記載します。

```
// ====== SPOUT =====
using namespace Spout2;
```

次にsetup()の実装ですが以下のコードをサンプルからコピペします。
sendernameの文字列はvvvvと共通の文字列にする必要がありますが
適当でOKです。

```
// ====== SPOUT =====
bInitialized = false;		        // Spout sender initialization
strcpy(sendername, "CB Spout Sender");	// Set the sender name
ofSetWindowTitle(sendername);			// show it on the title bar
										// Create an OpenGL texture for data transfers
sendertexture = 0; // make sure the ID is zero for the first time
InitGLtexture(sendertexture, ofGetWidth(), ofGetHeight());
// Set the window icon from resources
//SetClassLong(GetActiveWindow(), GCL_HICON, (LONG)LoadIconA(GetModuleHandle(NULL), MAKEINTRESOURCEA(IDI_ICON1)));
// ===================
```

次にdraw()の実装です。

こちらは、SPOUTで送信したい範囲を
CreateSenderとSendTextureで囲む形になります。

```
//--------------------------------------------------------------
void ofApp::draw(){

    char str[256];
    ofSetColor(255);

    // ====== SPOUT =====
    // A render window must be available for Spout initialization and might not be
    // available in "update" so do it now when there is definitely a render window.
    if (!bInitialized) {
        bInitialized = CreateSender(sendername, ofGetWidth(), ofGetHeight()); // Create the sender
    }
    // ===================
    //ここから

    ofDrawCircle(100.0, 100.0, 10.0, 15.0);

    //ここまでが送信される。
    // ====== SPOUT =====
    if (bInitialized) {

        if (ofGetWidth() > 0 && ofGetHeight() > 0) { // protect against user minimize

                                                     // Grab the screen into the local spout texture
            glBindTexture(GL_TEXTURE_2D, sendertexture);
            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, ofGetWidth(), ofGetHeight());
            glBindTexture(GL_TEXTURE_2D, 0);

            // Send the texture out for all receivers to use
            SendTexture(sendertexture, GL_TEXTURE_2D, ofGetWidth(), ofGetHeight());

            //ここからの映像は送信されないのでUIとかを表示させてもいいかも

            // Show what it is sending
            ofSetColor(255);
            sprintf(str, "Sending as : [%s]", sendername);
            ofDrawBitmapString(str, 20, 20);

            // Show fps
            sprintf(str, "fps: %3.3d", (int)ofGetFrameRate());
            ofDrawBitmapString(str, ofGetWidth() - 120, 20);

        }
    }
    // ===================
}
```

あとはwindowResized、exit、InitGLtextureをサンプルからコピペして上書きすると
完了です。

```
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h) {
	// ====== SPOUT =====
	// Update the sender texture to receive the new dimensions
	// Change of width and height is handled within the SendTexture function
	if (w > 0 && h > 0) // protect against user minimize
		InitGLtexture(sendertexture, w, h);

}

//--------------------------------------------------------------
void ofApp::exit() {

	// ====== SPOUT =====
	ReleaseSender(); // Release the sender

}

// ====== SPOUT =====
bool ofApp::InitGLtexture(GLuint &texID, unsigned int width, unsigned int height)
{
	if (texID != 0) glDeleteTextures(1, &texID);

	glGenTextures(1, &texID);
	glBindTexture(GL_TEXTURE_2D, texID);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glBindTexture(GL_TEXTURE_2D, 0);

	return true;
}
```

ちょっと難しいのは最初のSpoutDLL.libの設定とか配置ですかね。。。
結構苦労しました。
コンパイルエラーの連続ですわ。
実装はコピペでいいので特に問題はないですかね。

#vvvvでSPOUT（Reviever)
次に受信側のvvvvの実装です。こちらはすこぶる簡単。
Spout2/VVVV/Receiver/DirectX 9/DX9_ReceiverExample.v4pを実行し、Spout_Receiverの
SpoutSenderNameの文字列を送信側の文字列を同じにするだけで受信できます。
今回はサンプルと同じく「CB Spout Sender」に変更してます。
vvvvではTextureが受信できるのであとはFullscreenQuadをかましてRendererにつなげれば
openFrameworksからの映像をvvvvで表示できます。
私は、vvvvでは手軽にエフェクトを変更したり出来るのでメインの映像はopenFrameworksでつくって
エフェクトとか画像の切り替えはvvvvでやるみたいな使い方をしてます。
全部vvvvでやればいいじゃないかって話ですが、まだまだ未熟で描きたい絵がvvvvで描けないので。
あと、openFramewoksでshaderを使った映像をvvvvに送るみたいな使い方をしてます。
するとGLSLSandBoxみたいなGLSLの映像もvvvvで扱えるようになるので。
（HLSLに移植したらいいじゃないって話ではありますが・・・。）

実装はこんな感じです。折角なんでopenFrameworksのHelloWorldともいえる（かどうかは知らんが）
3DPrimitivesExampleの映像をvvvvに送信して表示してみましょう。
vvvvのエフェクトをかけて最終的に出力してます。

![WS000760.JPG](https://qiita-image-store.s3.amazonaws.com/0/100682/ebe7e22a-331a-077d-c414-7387599d1371.jpeg)

こんな感じで、openFrameworksの映像をvvvvに送れるわけです。
ただ、送信側のウィンドウを最小化すると映像が止まってしまうとか、
送信側のウィンドウはプレビュー的に小さくして実際に送る映像は1280×800に
したいんだけどなーという感じがあるんですが解決方法がわからない。
SPOUT、oFに詳しい人がいたら教えてください。

#まとめ
vvvvがかなりマニアックなのにもかかわらず、さらにマニアックなSPOUTについての記事を書きました。需要は無いかもしれませんが、Windows環境ではSyphonは使えないので、openFrameworksのコンテンツをvvvvで活用したい人（そんな人いるかしら・・・）なんかのお役に立てれば幸いです。
どちらかというとopenFrameworksの記事ですか？みたいな話しもありますが・・・（汗
最終的にはvvvvを使ってるので良しとｼﾃｸﾀﾞｻｲ。

あと、手さぐりで書いているので、SPOUT導入の正当なやりかたじゃないような気がしてます。
色々、ご指摘いただけると幸いです。また、質問があればどうぞ。

要望があればサンプルコードをGitHubにあげる・・・かもですが、SPOUTのサンプルで事足りる気もしてます。。。