PVRToolsの使い方


SDKのサンプルの **SDK_3.2\Examples\05_IntroducingPVRTools**のOpenGLES2.0版(**OGLES2**)を使います。

## 必要なヘッダファイル
２つのSDK用のヘッダをインクルードします。

```C++
#include "PVRShell.h"
#include "OGLES2Tools.h"
```

## GLSLにおけるシェーダーのattribute変数とuniform変数
- **attribute**変数は、親プログラムから頂点シェーダーに頂点ごとの値を渡すために使われます。
- **uniform**変数は、親プログラムから頂点シェーダーやフラグメントシェーダーにグローバルな値を渡すために使われます。
- **varying**変数は、頂点シェーダーからフラグメントシェーダーに値を渡すために使われます。

| プロジェクト | 頂点シェーダー | フラグメントシェーダー | 用途 |
|:-------------------|:--------:|:--------:|:--------|
| default | R/W | R/W | |
| const | R/W | R/W | |
| attribute | R | X | CPUから頂点ごとに渡す変数 |
| uniform | R | R | CPUから渡すグローバル変数 |
| varying | W | R | 頂点シェーダーからフラグメントシェーダーに渡す変数 |


ここではPVRToolsで使用されている変数を定義しています。

```C++
// attribute変数
enum EVertexAttrib {
    VERTEX_ARRAY,
    TEXCOORD_ARRAY,
    eNumAttribs
};
const char* g_aszAttribNames[] = {
    "inVertex",
    "inTexCoord"
};

// uniform変数
enum EUniform {
    eMVPMatrix,
    eNumUniforms
};
const char* g_aszUniformNames[] = {
    "MVPMatrix"
};

```

## シェーダーのソースファイルとバイナリファイル名の指定

PVRToolsを使用すると、シェーダーのソースはプログラム埋め込みではなく、外部ファイルから読み込めます。バイナリを直接ロードもできますが、ここでは親プログラム内でソースをコンパイルしてバイナリを作成しています。

- **.fsh** ・・・フラグメントシェーダーのソース
- **.fsc** ・・・フラグメントシェーダーのバイナリ
- **.vsh** ・・・頂点シェーダーのソース
- **.vsh** ・・・頂点シェーダーのバイナリ

```C++
// フラグメントシェーダーソース
const char c_szFragShaderSrcFile[]	= "FragShader.fsh";
// フラグメントシェーダーバイナリ
const char c_szFragShaderBinFile[]	= "FragShader.fsc";
// 頂点シェーダーソース
const char c_szVertShaderSrcFile[]	= "VertShader.vsh";
// 頂点シェーダーバイナリ
const char c_szVertShaderBinFile[]	= "VertShader.vsc";
```

## テクスチャファイル名の指定

```C++
// PVR テクスチャファイル
const char c_szTextureFile[]		= "Image.pvr";
```

## クラス定義

**PVRShell**を継承したクラスを作成します。

```C++
class OGLES2IntroducingPVRTools : public PVRShell
{
	// テキストを表示するためのPrint3Dクラス
	CPVRTPrint3D	m_Print3D;

	// テクスチャハンドル
	GLuint	m_uiTexture;

	// VBO ハンドル
	GLuint m_ui32Vbo;

	// 頂点のストライド(間隔)
	unsigned int m_ui32VertexStride;

	// 頂点シェーダー、フラグメントシェーダーのハンドル
	GLuint m_uiVertexShader, m_uiFragShader;

	// シェーダープログラムとuniform変数の位置を合わせたグループ
	struct
	{
		GLuint uiId;
		GLuint auiLoc[eNumUniforms];
	}
	m_ShaderProgram;

public:
	virtual bool InitApplication();
	virtual bool InitView();
	virtual bool ReleaseView();
	virtual bool QuitApplication();
	virtual bool RenderScene();
};

```

## InitApplicationメンバー関数の実装
レンダリングコンテキストが作成される前に、PVRShellから一度だけ呼び出されます。外部モジュールやメッシュなどに依存しない変数を初期化します。レンダリングコンテキストがロストしても再び呼び出されることはありません。

- CPVRTResourceFileは、リソースファイルのためのヘルパークラスです。
- リソースファイルは、実行ファイルと同じ位置かプロットフォームに依存した読み込みパス上においてください。
- クラスに読み込みパスを指定します。
- cppモジュールにファイルをラップして、直接実行ファイルにリンクすることもできます。
- PVRShellGet()関数がNULL関数ポインタを返す場合は、外部ファイルを何もロードしないことを意味します。

ここではパスは使いません。ディスク上のファイルは「メモリファイル」で上書きされます。

```C++
bool OGLES2IntroducingPVRTools::InitApplication()
{
	// コンテンツファイルの読み込みパスを取得し設定する。
	CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));

	// ロードする外部ファイルのロード、解放関数を取得し設定する。
	CPVRTResourceFile::SetLoadReleaseFunctions(PVRShellGet(prefLoadFileFunc), PVRShellGet(prefReleaseFileFunc));
	return true;
}
```

## QuitApplicationメンバー関数の実装
実行終了直前に、PVRShellから一度だけ呼び出されます。レンダリングコンテキストがロストしても呼び出されることはありません。

ここでは何もしません。

## InitViewメンバー関数の実装
レンダリングコンテキストの初期化や変更後に、PVRShellから呼び出されます。テクスチャや頂点バッファなどレンダリングコンテキストに依存する変数を初期化します。

### Print3Dを使う
Print3Dを使う場合は、文字列の向きや大きさを決めます。それぞれのパラメータを **PVRShellGet()**関数に設定して値を取得します。取得した値を使って、 **SetTextures()**関数で向きや大きさを設定します。

- **prefIsRotated** ・・・回転しているかどうかを取得できます。
- **prefFullScreen** ・・・・フルスクリーン状態かどうかを取得できます。
- **prefWidth**, **prefHeight** ・・・画面の幅と高さを取得できます。

ここでは三角形の頂点を作成し、テクスチャを用意しています。

```C++
	// 文字列を回転すべきかどうかを決める。
	bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);

	// 向きと大きさを設定する。
	if(m_Print3D.SetTextures(0, PVRShellGet(prefWidth), PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
	{
		PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
		return false;
	}
```

### 画面のクリア色の設定
クリアする関数を呼び出した時、設定した色で画面がクリアされます。

```C++
	// 画面クリアに使う色を設定します。
	glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
```

### テクスチャのロード
テクスチャーをロードするには、**PVRTTextureLoadFromPVR()**関数を使います。
- １番目のパラメータ・・・ファイル名
- ２番目のパラメータ・・・テクスチャハンドルを受け取るポインタ
- ３番目のパラメータ・・・エラーメッセージのための、 **CPVRTString**
また、フィルターの設定には ** glTexParameteri()**関数を使います。設定がない場合はOpenGL ESのデフォルトの値が使われます。ミップマップのないテクスチャにミップマップフィルタを指定するとエラーになります。

```C++
	if(PVRTTextureLoadFromPVR(c_szTextureFile, &m_uiTexture) != PVR_SUCCESS)
	{
		PVRShellSet(prefExitMessage, "ERROR: Cannot load the texture\n");
		return false;
	}

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
```

### バイナリシェーダーの準備
- **CPVRTResourceFile()**関数でリソースをメモリにロードします。

```C++
	CPVRTResourceFile VertexShaderSrcFile(c_szVertShaderSrcFile);
	CPVRTResourceFile VertexShaderBinFile(c_szVertShaderBinFile);
```
- **IsOpen()**関数でバイナリファイルが開かれていないかなどのチェック後、ソースをコンパイルします。
- **PVRTShaderLoadBinaryFromMemory()**は、バイナリシェーダーをロードします。引数は、バイナリシェーダーとシェーダーのサイズ、タイプ、バイナリフォーマットです。成功すると、新しいバイナリシェーダーのハンドルが５番目の引数として得られます。失敗するとエラー文字列が返ります。
- バイナリシェーダーがロードできない場合だけ、ソースをコンパイルします。
- **PVRTShaderLoadSourceFromMemory()**は、ソースシェーダーをロードします。引数は、ソースコードとタイプです。成功すると、新しいバイナリシェーダーのハンドルが３番目の引数として得られます。失敗するとエラー文字列が返ります。
- **PVRTLoadAndCompileShaderFromFile()**関数で外部ファイルからロードし、コンパイルすることもできます。
- **PVRTCreateProgram()**関数でシェーダープログラムオブジェクトを作成します。引数は、シェーダプログラムのIDと頂点シェーダー、フラグメントシェーダー、attrubute変数名、attribute列挙です。成功すると、新しいプログラムのハンドルが１番目の引数として得られます。失敗するとエラー文字列が返ります。

```C++
	// 頂点シェーダーを作成する。
	CPVRTString ErrorStr;
	// バイナリシェーダーをロードする。
	if (!VertexShaderBinFile.IsOpen() ||
		(PVRTShaderLoadBinaryFromMemory(
			VertexShaderBinFile.DataPtr(), 
			VertexShaderBinFile.Size(),
			GL_VERTEX_SHADER, 
			GL_SGX_BINARY_IMG,
			&m_uiVertexShader,
			&ErrorStr) != PVR_SUCCESS))
	{
		// バイナリシェーダーがないのでソースシェーダーを使用する。
		CPVRTString vertexShaderSrc((const char*) VertexShaderSrcFile.DataPtr(), VertexShaderSrcFile.Size());

		if (!VertexShaderSrcFile.IsOpen() ||
			(PVRTShaderLoadSourceFromMemory(
				vertexShaderSrc.c_str(), 
				GL_VERTEX_SHADER, 
				&m_uiVertexShader,
				&ErrorStr) != PVR_SUCCESS))
		{
			PVRShellSet(prefExitMessage, ErrorStr.c_str());
			return false;
		}
	}

	// フラグメントシェーダーを作成する。
	if (PVRTShaderLoadFromFile(
			c_szFragShaderBinFile,
			c_szFragShaderSrcFile,
			GL_FRAGMENT_SHADER,
			GL_SGX_BINARY_IMG,
			&m_uiFragShader,
			&ErrorStr) != PVR_SUCCESS)
	{
		PVRShellSet(prefExitMessage, ErrorStr.c_str());
		return false;
	}

	// シェーダープログラムオブジェクトを作成する。
	if (PVRTCreateProgram(
		&m_ShaderProgram.uiId,
		m_uiVertexShader,
		m_uiFragShader,
		g_aszAttribNames,
		eNumAttribs,
		&ErrorStr) != PVR_SUCCESS)
	{
		PVRShellSet(prefExitMessage, ErrorStr.c_str());
		return false;
	}

	// uniform変数の位置を保存する。
	for (int i = 0; i < eNumUniforms; ++i)
	{
		m_ShaderProgram.auiLoc[i] = glGetUniformLocation(m_ShaderProgram.uiId, g_aszUniformNames[i]);
	}
```

### 三角形のVBOを作成します。

```C++
	// インターリーブによる頂点データ
	GLfloat afVertices[] = {-0.4f,-0.4f,0.0f,	// 座標
							 0.0f,0.0f ,		// UV
							 0.4f,-0.4f,0.0f,
							 1.0f,0.0f ,
							 0.0f,0.4f ,0.0f,
							 0.5f,1.0f};

	// バッファを作成する。
	glGenBuffers(1, &m_ui32Vbo);

	// 頂点の座標３つのfloat値とUVの２つのfloat値から１つの頂点の大きさを計算する。
	m_ui32VertexStride = 5 * sizeof(GLfloat);

	// VBOをバッファとしてバインド(結合)する。
	glBindBuffer(GL_ARRAY_BUFFER, m_ui32Vbo);

	// バッファにデータをセットする。
	glBufferData(GL_ARRAY_BUFFER, 3 * m_ui32VertexStride, afVertices, GL_STATIC_DRAW);

	// VBOを一旦アンバインドする。
	glBindBuffer(GL_ARRAY_BUFFER, 0);
```

### 描画設定をします。
ここでは、カリングの指定をしています。

```C++
	// Enable culling
	glEnable(GL_CULL_FACE);
```

## ReleaseViewメンバー関数の実装
アプリケーション終了時やレンダリングコンテキスト変更時PVRShellから呼び出されます。

```C++
	// テクスチャを解放する。
	glDeleteTextures(1,&m_uiTexture);

	// 頂点バッファオブジェクトを解放する。
	glDeleteBuffers(1, &m_ui32Vbo);

	// Print3Dテクスチャを解放する。
	m_Print3D.ReleaseTextures();

	// OpenGLハンドルを解放する。
	glDeleteProgram(m_ShaderProgram.uiId);
	glDeleteShader(m_uiVertexShader);
	glDeleteShader(m_uiFragShader);

```

## RenderSceneメンバー関数の実装
メインレンダリングループ関数です。シェルは毎フレームこの関数を呼び出します。バッファ切り替えのためのglSwapBuffers()関数は自動的に呼びされますので、呼び出す必要はありません。また、重要なOSイベントも管理していますので、ユーザはこれらのイベントをPVRShellが提供する抽象レイヤからアクセスするようにします。

### 画面のクリア
色と深度バッファをクリアします。

- GL_COLOR_BUFFER_BIT・・・色バッファ
- GL_DEPTH_BUFFER_BIT・・・深度バッファ

```C++
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
```

### ポリゴンの描画

```C++
	// テクスチャをバインドする。
	glBindTexture(GL_TEXTURE_2D, m_uiTexture);

	// 使うシェーダープログラムを指定する。
	glUseProgram(m_ShaderProgram.uiId);

    // モデルビュー変換行列を作成する。
	PVRTMat4 mMVP = PVRTMat4::Identity();

    // 画面が回転していたらZ軸で回転する。
	if(PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen))
		mMVP = PVRTMat4::RotationZ(-1.57f);

    // 変換行列をシェーダーのuniform変数に渡す。
	glUniformMatrix4fv(m_ShaderProgram.auiLoc[eMVPMatrix], 1, GL_FALSE, mMVP.ptr());

    // VBOをバインドする。
	glBindBuffer(GL_ARRAY_BUFFER, m_ui32Vbo);

    // 頂点座標を指定する。
	glEnableVertexAttribArray(VERTEX_ARRAY);
	glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, m_ui32VertexStride, 0);

    // テクスチャ座標を指定する。
	glEnableVertexAttribArray(TEXCOORD_ARRAY);
	glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, m_ui32VertexStride, (void*) (sizeof(GLfloat) * 3));

	// インデックスなし三角形リストを描画する。
	glDrawArrays(GL_TRIANGLES, 0, 3);
```

### CPVRTPrint3Dオブジェクトによる文字列の描画

#### Print3D関数
任意の色で好きな位置に文字列を描画する関数。

- 引数 1: X座標 (スケール非依存、0 〜 100)
- 引数 2: Y座標 (fスケール非依存、0 〜 100)
- 引数 3: 文字列のスケーリング値
- 引数 4: 文字列の色 (0xAABBGGRR 形式)
- 引数 5: 書式付き文字列 (printfと同じ形式)

```C++
	m_Print3D.Print3D(8.0f, 30.0f, 1.0f, 0xFFAA4040, "example");
```

#### DisplayDefaultTitle関数
タイトルと説明を画面左上に描画します。また、PVRロゴ(ePVRTPrint3DLogoPVR)またはIMGロゴ(ePVRTPrint3DLogoIMG) または／両方 (ePVRTPrint3DLogoPVR | ePVRTPrint3DLogoIMG)を描画できます。NULLを指定するとロゴは描画されません。

```C++
	m_Print3D.DisplayDefaultTitle("IntroducingPVRTools", "Description", ePVRTPrint3DSDKLogo);
```

#### Flush関数
貯めこんだすべての文字列を描画します。

```C++
	m_Print3D.Flush();
```