DirectX(D3D11.1)再入門 Texture

気が変わったのでTextureを先にやる。
[今回のコード](https://github.com/ousttrue/MinTriangle/tree/Texture)

これもD3DX無き世界でどうするかとなるのだけどWindowsのWindowsImagingComponent略してWICを使ってみる。

```hlsl:今回のシェーダー
Texture2D diffuseTexture;
SamplerState diffuseTextureSampler;

struct VS_IN
{
    float4 Position: POSITION;
    float4 Color: COLOR;
    float2 Tex: TEXCOORD0;
};

struct VS_OUT
{
    float4 Position: SV_POSITION;
    float4 Color: COLOR;
    float2 Tex: TEXCOORD0;
};

typedef VS_OUT PS_IN;

//cbuffer buffer
//{
	float4x4 ModelMatrix;
//};

VS_OUT vsMain(VS_IN input)
{
    VS_OUT Output;
    Output.Position = mul(input.Position, ModelMatrix);
    Output.Color = input.Color;
    Output.Tex = input.Tex;
    return Output;    
}

float4 psMain(PS_IN input) : SV_TARGET
{
    float4 texel = diffuseTexture.Sample(diffuseTextureSampler, input.Tex);
    return input.Color * texel;
}
```

Texture2D(ShaderResourceView)とSamplerStateが増えてTextureの参照座標Texが頂点属性に追加になった。

```hlsl:増えた
// 定義
Texture2D diffuseTexture;
SamplerState diffuseTextureSampler;

struct VS_IN
{
    float4 Position: POSITION;
    float4 Color: COLOR;
    float2 Tex: TEXCOORD0; // 増えた
};

struct VS_OUT
{
    float4 Position: SV_POSITION;
    float4 Color: COLOR;
    float2 Tex: TEXCOORD0; // 増えた
};

// 使う
    float4 texel = diffuseTexture.Sample(diffuseTextureSampler, input.Tex);
```

# プログラム側
デバイスからID3D11Texture2Dを作って、ID3D11Texture2DからID3D11ShaderResourceView(SRV)を作る。
SamplerStateも作る。
作ったSRVをデバイスコンテキストにセットする。
SamplerStateはセットしなくてもデフォルトのものが使われる(分かりにくい)。
謎のimageutil::ImageはWICから画像を読み込んだもの。次節で。

```cpp:テクスチャクラス
class Texture
{
    Microsoft::WRL::ComPtr<ID3D11Texture2D> m_texture;
    Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> m_srv; // これがhslslのtexture2Dになる
    Microsoft::WRL::ComPtr<ID3D11SamplerState> m_sampler; // これがhlslのSamplerStateになる

public:
	bool Initialize(const Microsoft::WRL::ComPtr<ID3D11Device> &device
            , const std::shared_ptr<imageutil::Image> &image)
	{
		D3D11_TEXTURE2D_DESC desc;
		desc.Width = image->Width();
		desc.Height = image->Height();
		desc.MipLevels = 1;
		desc.ArraySize = 1;
		desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		desc.SampleDesc.Count = 1;
		desc.SampleDesc.Quality = 0;
		desc.Usage = D3D11_USAGE_DEFAULT;
		desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
		desc.CPUAccessFlags = 0;
		desc.MiscFlags = 0;

		D3D11_SUBRESOURCE_DATA initData;
		initData.pSysMem = image->Pointer();
		initData.SysMemPitch = image->Stride();
		initData.SysMemSlicePitch = image->Size();

		auto hr = device->CreateTexture2D(&desc, &initData, &m_texture);
		if (FAILED(hr)){
			return false;
		}

		D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc = {};
		SRVDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		SRVDesc.Texture2D.MipLevels = 1;

		hr = device->CreateShaderResourceView(m_texture.Get(), &SRVDesc, &m_srv);
		if (FAILED(hr))
		{
			return false;
		}

        D3D11_SAMPLER_DESC samplerDesc;
        samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
        samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
        samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
        samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
        samplerDesc.MipLODBias = 0.0f;
        samplerDesc.MaxAnisotropy = 1;
        samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
        samplerDesc.BorderColor[0] = 0;
        samplerDesc.BorderColor[1] = 0;
        samplerDesc.BorderColor[2] = 0;
        samplerDesc.BorderColor[3] = 0;
        samplerDesc.MinLOD = 0;
        samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

        // Create the texture sampler state.
        hr = device->CreateSamplerState(&samplerDesc, &m_sampler);
        if(FAILED(hr))
        {
            return false;
        }

		return true;
	}

    void Set(const Microsoft::WRL::ComPtr<ID3D11DeviceContext> &deviceContext)
    {
        deviceContext->PSSetShaderResources(0, 1, m_srv.GetAddressOf());
        //deviceContext->PSSetSamplers(0, 1, m_sampler.GetAddressOf());
    }
};
```

# WICで画像をロード

```cpp:imageutil
	#pragma once
	#include <memory>
	#include <string>
	#include <vector>
	#include <wrl/client.h>


	struct IWICImagingFactory;

	namespace imageutil {

	class Image
	{
		std::vector<unsigned char> m_buffer;
		int m_width;
		int m_height;
		int m_pixelBytes;

	public:
		Image(int w, int h, int pixelBytes);
		int Width()const{ return m_width; }
		int Stride()const{ return m_width*m_pixelBytes; }
		int Height()const{ return m_height; }
		unsigned char* Pointer(){ return m_buffer.empty() ? nullptr : &m_buffer[0]; }
		size_t Size()const{ return m_buffer.size(); }
	};

	class Factory
	{
		IWICImagingFactory *m_factory;

	public:
		Factory();
		~Factory();
		std::shared_ptr<Image> Load(const std::wstring &path);
	};

	}
```

```cpp:使う
	auto wicFactory = std::make_shared<imageutil::Factory>();
        // 画像をロードする
        auto image=wicFactory->Load(textureFile);
        if(image){
            // テクスチャを作る
            if (!m_texture->Initialize(pDevice, image)){
                return false;
            }
        }
```

WICによる画像のロードはCOMプログラミングでございます。

```cpp:WIC
    IWICImagingFactory *m_factory;
    HRESULT hr = CoCreateInstance(
        CLSID_WICImagingFactory,
        nullptr,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&m_factory)
        );

    // decoder作ってファイルを渡す
    Microsoft::WRL::ComPtr<IWICBitmapDecoder> decoder;
    HRESULT hr = m_factory->CreateDecoderFromFilename(path.c_str(), 0
            , GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder);
    if(FAILED(hr)){
        return nullptr;
    }

    // decoderからframeを取得
    Microsoft::WRL::ComPtr<IWICBitmapFrameDecode> frame;
    hr = decoder->GetFrame(0, &frame);
    if(FAILED(hr)){
        return nullptr;
    }

    // フレームからサイズとピクセルフォーマットとデータを得る
    UINT width, height;
    hr = frame->GetSize( &width, &height );
    if(FAILED(hr)){
        return nullptr;
    }

    assert( width > 0 && height > 0 );

	// Determine format
	WICPixelFormatGUID pixelFormat;
	hr = frame->GetPixelFormat(&pixelFormat);
	if (FAILED(hr)){
		return nullptr;
	}

	if (pixelFormat != GUID_WICPixelFormat32bppRGBA){
        // 変換する
        Microsoft::WRL::ComPtr<IWICFormatConverter> FC;
        hr = m_factory->CreateFormatConverter(&FC);
        if(FAILED(hr)){
            return nullptr;
        }

        hr = FC->Initialize(frame.Get(), GUID_WICPixelFormat32bppRGBA
                , WICBitmapDitherTypeErrorDiffusion
                , 0, 0, WICBitmapPaletteTypeCustom);
        if(FAILED(hr)){
            return nullptr;
        }

		// copy
		auto image=std::make_shared<Image>(width, height, 4);
		FC->CopyPixels(0, image->Stride(), image->Size(), image->Pointer());
		return image;
	}
	else{
		// copy
		auto image = std::make_shared<Image>(width, height, 4);
		frame->CopyPixels(0, image->Stride(), image->Size(), image->Pointer());
		return image;
	}

```

WICで大概の画像(tgaは無かった)はロードできる。
GetPixelFormatで画素のフォーマットを得てID3D11Textureで使いやすい形に変換しましょうということであります。
要するにGUID_WICPixelFormat32bppRGBA以外をDXGI_FORMAT_R8G8B8A8_UNORMに相当するGUID_WICPixelFormat32bppRGBAに変換してやるといいのではないか。

![ss.png](https://qiita-image-store.s3.amazonaws.com/0/59664/af3a080e-d33c-ef99-07d1-74a31746b387.png)

次回、賢いコンスタントバッファ。予定。

# 参考
* [How to: Initialize a Texture From a File](http://msdn.microsoft.com/en-us/library/windows/desktop/ff476904(v=vs.85).aspx)
* [Windows Imaging Component の基礎](http://msdn.microsoft.com/ja-jp/magazine/cc500647.aspx)