DxLibで画像管理するクラスを作った件

DxLib Advent Calendar 2019の2日目の記事です。
[1日目：DXアーカイブの暗号化を強引に解除することは法に触れるのか？](https://qiita.com/Seiten_Minagawa/items/1ef198671da59ef85253) <- | 2日目：これ| -> [6日目：プログラミング教育フリーソフト第4位アプリをDXライブラリでAndroidアプリにした](https://qiita.com/danjiro/items/b43c8e21e38e88a3ff00)

今回DxLibで画像を管理してくれるクラスを作ったので公開します。

#実装
今回はSiv3Dのような構造で組んでいきます。

##ヘッダーファイル

```C++:Texture.h
#pragma once
#include "Vec2.h"
#include <string>


class Texture {
	int32 mGraphic = 0;
	char* mGraphicPath = nullptr;
	Vec2<int32> mGraphSize = { 0,0 };

	void Loader();

	void LoaderDiv(const char* Path, Vec2<int32>num, Array<DXLIB::Texture>* TextureArray);

	Texture(int32 Graphic, string Path, Vec2<int32> Size) 
		:mGraphic(Graphic), mGraphicPath(&Path[0]), mGraphSize(Size) {}

public:
	Texture() = default;

	Texture(const char* Path) { 
		std::string tmp(Path);
		mGraphicPath = &tmp[0];

		Loader();
	}

	Texture(char* Path) : mGraphicPath(Path) { Loader(); }
		
	Texture(std::string Path) { 
		mGraphicPath = &Path[0]; 
		Loader();
	}

	Texture(const char* Path, int32 XNum, int32 YNum, Array<Texture>* TextureArray) {
		std::string tmp(Path);
		mGraphicPath = &tmp[0];

		LoaderDiv(Path, Vec2<int32>( XNum, YNum ), TextureArray);
	}

	Vec2<int32> TextureSize() const { return mGraphSize; }

	bool isEmpty() const { return mGraphic == 0 || mGraphicPath == nullptr ; }

	void Draw(Vec2<int32> Pos);
		
	void DrawRotation(Vec2<int32> Pos, double Rate, double Angle);

	void DrawRect(Vec2<int32> TopPos, Vec2<int32> BottomPos);

	void Draw(Vec2<double> Pos);

	void DrawRotation(Vec2<double> Pos, double Rate, double Angle);

	void DrawRect(Vec2<double> TopPos, Vec2<double> BottomPos);

	void Draw(Vec2<float> Pos);

	void DrawRect(Vec2<float> TopPos, Vec2<float> BottomPos);

	void DrawRotation(Vec2<float> Pos, double Rate, double Angle);

	~Texture() {}
}
```

`Vec2.h`については[別途公開](https://github.com/legohasiri1025/legohasiri-/blob/master/Vec2.h)しておきます。また、`int32`などは`int32_t`のように`_t`を付けたものを`using`で定義してあるだけですので、ここでは省略します。
では上から順に紹介していきます。

- メンバ変数
    - `int32 mGraph`：グラフィックハンドルを保持する
    - `char* mGraphicPath`：画像のパスを保持する
    - `Vec2<int32>　ｍGraphSize`：画像の大きさを保持する。

- メンバ関数
    - `void Loder()`：画像を読み込む
    - `void LoderDiv()`：画像を分割読み込みする
    - `Texture(int32 Graphic, string Path, Vec2<int32> Size)`：Textureをグラフィックハンドル、パス、大きさで初期化する
    - `Texture()`：デフォルトコンストラクタ
    - `Texture(const char* Path)`：パスからテクスチャを作る
    - `Texture(const char* Path, int32 XNum, int32 YNum, Array<Texture>* TextureArray)`：画像を分割読み込みする。
    - `Vec2<int32> TextureSize()`：画像の大きさを返す
    - `bool isEmpty()`：画像が空かを返す
    - `void Draw(Vec2<int32> Pos)`：位置を指定して描画する
    - `void DrawRotation(Vec2<int32> Pos, double Rate, double Angle)`：拡大、回転させて描画する
    - `void DrawRect(Vec2<int32> TopPos, Vec2<int32> BottomPos)`：画像を矩形に変換して描画する
     - *残り6個は、上記のdouble,float版です。
    - `~Texture()`：デストラクタ(特に何もしない)
    
## メンバ関数の実装
### void Loder()
上から順に実装します。

```C++
void Texture::Loader() {

	Vec2<int32> Grsize;
	GetImageSize_File(mGraphicPath, &Grsize.x, &Grsize.y);//読み込む画像の大きさを取得
	mGraphic = LoadGraph(mGraphicPath);
		
	if (mGraphic == -1) {//読み込み失敗
		AppLogAdd("画像 %s が読み込めませんでした。\n", mGraphicPath);
	}
	mGraphSize = Grsize;
}
```

画像サイズとグラフィックハンドルを取得する関数です。主にコンストラクタ内で呼び出します。
`GetImageSize_File`は画像の大きさを返すDxLibの関数です。
`AppLogAdd`は文字列を`Log.txt`に書き出す関数です。必要なければ消しても構いません。また、ここに例外をスローするコードを組み込んでもよいかもしれません。

### void LoderDiv()

```C++
void Texture::LoaderDiv(const char* Path, Vec2<int32>num, Array<DXLIB::Texture>* TextureArray) {
	int32 *gr;
	size_t Grnum = num.x*num.y;
	gr = new int32[Grnum];
		
	Vec2<int32> Grsize;
	GetImageSize_File(Path, &Grsize.x, &Grsize.y);//読み込む画像の大きさを取得
	Grsize /= num;

	if (LoadDivGraph(Path, num.x*num.y, num.x, num.y, Grsize.x, Grsize.y, gr) == -1) {
		AppLogAdd("画像 %s の分割読み込みに失敗しました。\n", Path);
	}
	mGraphSize = Grsize;
	for (size_t i = 0; i < Grnum; i++) {
	//テクスチャのコピー
		TextureArray->push_back(Texture(gr[i], Path, mGraphSize));
	}
	delete[] gr;
}
```

基本的にはさっきの`Loder()`と同じです。
`LoadDivGraph`は画像の合計数、一つの大きさも必要になりますので、それらを求める必要があります。
もう少しスマートにかけそうな気もするけどめんどくさいので適宜書き直してください。編集リクエスト等受け付けます。

コンストラクタ、`TextureSize()` `isEmpty()`はヘッダーファイル内で定義しているので省略。


### void Draw()
```C++
void Texture::Draw(Vec2<int32> Pos) {
	if (DrawGraph(Pos.x, Pos.y, mGraphic, TRUE) == -1) {
		AppLogAdd("画像 %s の描画に失敗しました。\n", mGraphicPath);
	}
}
```
```C++
void Texture::Draw(Vec2<float> Pos) {
	if (DrawGraphF(Pos.x, Pos.y, mGraphic, TRUE) == -1) {
		AppLogAdd("画像 %s の描画に失敗しました。\n", mGraphicPath);
	}
}
```
```C++
void Texture::Draw(Vec2<double> Pos) {
	if (DrawGraphF(static_cast<float>(Pos.x), static_cast<float>(Pos.y), mGraphic, TRUE) == -1) {
		AppLogAdd("画像 %s の描画に失敗しました。\n", mGraphicPath);
	}
}
```
doubleの座標で描画することはできないので、floatにキャストする必要があります。floatでの描画はDrawGraphFになります。

### void DrawRotaion()
```C++
void Texture::DrawRotation(Vec2<int32> Pos, double Rate, double Angle) {
	if (DrawRotaGraph(Pos.x, Pos.y, Rate, Angle, mGraphic, TRUE) == -1) {
		AppLogAdd("画像 %s の描画に失敗しました。\n", mGraphicPath);
	}
}
```
```C++
void Texture::DrawRotation(Vec2<float> Pos, double Rate, double Angle) {
	if (DrawRotaGraphF(Pos.x, Pos.y, Rate, Angle, mGraphic, TRUE) == -1) {
		AppLogAdd("画像 %s の描画に失敗しました。\n", mGraphicPath);
	}
}
```
```C++
void Texture::DrawRotation(Vec2<double> Pos, double Rate, double Angle) {
	if (DrawRotaGraphF(static_cast<float>(Pos.x), static_cast<float>(Pos.y), Rate, Angle, mGraphic, TRUE) == -1) {
		AppLogAdd("画像 %s の描画に失敗しました。\n", mGraphicPath);
	}
}
```
特に解説はありません。

### DrawRect()
```C++
void Texture::DrawRect(Vec2<int32> TopPos, Vec2<int32> BottomPos) {
	if (DrawModiGraph(TopPos.x, TopPos.y, BottomPos.x, TopPos.y, BottomPos.x, BottomPos.y, TopPos.x, BottomPos.y, mGraphic, TRUE) == -1) {
		AppLogAdd("画像 %s の描画に失敗しました。\n", mGraphicPath);throw ERR_DRAW_GRAPH;
	}
}
```
```C++
void Texture::DrawRect(Vec2<float> TopPos, Vec2<float> BottomPos) {
	if (DrawModiGraphF(TopPos.x, TopPos.y, BottomPos.x, TopPos.y, BottomPos.x, BottomPos.y, TopPos.x, BottomPos.y, mGraphic, TRUE) == -1) {
		AppLogAdd("画像 %s の描画に失敗しました。\n", mGraphicPath);throw ERR_DRAW_GRAPH;
	}
}
```
```C++
void Texture::DrawRect(Vec2<double> TopPos, Vec2<double> BottomPos) {
	if (DrawModiGraphF(static_cast<float>(TopPos.x), static_cast<float>(TopPos.y), static_cast<float>(BottomPos.x), static_cast<float>(TopPos.y), static_cast<float>(BottomPos.x), static_cast<float>(BottomPos.y), static_cast<float>(TopPos.x), static_cast<float>(BottomPos.y), mGraphic, TRUE) == -1) {
		AppLogAdd("画像 %s の描画に失敗しました。\n", mGraphicPath);throw ERR_DRAW_GRAPH;
	}
}
```
解説はありません。

#使用例
```C++
Texture Hoge;
Hoge = Texture("hoge/hage/Hoge.png");//この書き方は警告が出るらしい

void Draw(){
	Hoge.Draw(64,32);
}
```
こうするときっとはげの画像が出るでしょうね。

#最後に
こうすればいいとか、バグがある、これも追加してほしいなどはコメント、編集リクエストで受け付けてます。
また、ライセンスはCC0です。自由に使用、改変して結構です。
[![CC0](https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg "CC0")](http://creativecommons.org/publicdomain/zero/1.0/deed.ja)
##更新履歴
- 2019/12/01 カレンダーへの登録、記事作成
- 2019/12/02 DxLib Advent Calendar 2019の2日目の記事として公開