WPFとDirect3D9Exの連携 --- テクスチャ貼り付け
下記記事にて三角形を描画するところまで実装しました。
WPFとDirect3D9Exの連携 --- 三角形描画 - 何でもプログラミング
今回はさらにテクスチャを貼り付けを実装してみたいと思います。
本記事で利用している、CreateVertexShader、CreatePixelShader、CreateVertexBufferは上記記事を、
CliComPtr、AssertHR、CreateDevice、CreateRenderTargetは下記記事を参照してください。
WPFとDirect3D9Exの連携 --- 導入 - 何でもプログラミング
Texture作成
X8R8G8B8フォーマットで作成しています。(byte列ではBGRA)
CPU側から書き込むため、D3DPOOL_SYSTEMMEMを指定しています。
CComPtr<IDirect3DTexture9> CreateTexture(IDirect3DDevice9Ex* device, int width, int height, const byte* pixels) { CComPtr<IDirect3DTexture9> texture; AssertHR(device->CreateTexture( width, height, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &texture.p, NULL)); D3DLOCKED_RECT lockedRect; AssertHR(texture->LockRect(0, &lockedRect, NULL, D3DLOCK_DISCARD)); for (int y = 0; y < height; ++y) memcpy((byte*)lockedRect.pBits + y * lockedRect.Pitch, pixels + y * 4 * width, 4 * width); AssertHR(texture->UnlockRect(0)); return texture; }
Renderer作成
入力データからテクスチャを作成し、ターゲット全画面にレンダリングしています。
struct Vertex { static const DWORD FVF = D3DFVF_XYZ | D3DFVF_TEX1; FLOAT X, Y, Z; FLOAT U, V; }; public ref class Renderer { public: property IntPtr Surface { IntPtr get() { return IntPtr(_surface); } } Renderer(int width, int height, array<byte>^ pixels) { _device = CreateDevice(); _surface = CreateRenderTarget(_device, width, height); // Shader作成 std::string vertexCode = "struct VS_OUTPUT { \n" " float4 Position : POSITION; \n" " float2 Texcoord : TEXCOORD0; \n" "}; \n" "VS_OUTPUT main( \n" " float4 position : POSITION, \n" " float2 texcoord : TEXCOORD0) { \n" " VS_OUTPUT output = (VS_OUTPUT)0; \n" " output.Position = position; \n" " output.Texcoord = texcoord; \n" " return output; \n" "} \n"; _vertexShader = CreateVertexShader(_device, vertexCode); std::string pixelCode = "Texture2D texture0 : register(t0); \n" "SamplerState texture0Sampler { \n" " Filter = MIN_MAG_MIP_POINT; \n" " AddressU = Clamp; \n" " AddressV = Clamp; \n" "}; \n" "float4 main(float2 texcoord : TEXCOORD0) : COLOR { \n" " return texture0.Sample(texture0Sampler, texcoord); \n" "} \n"; _pixelShader - CreatePixelShader(_device, pixelCode); // VertexBuffer作成 std::vector<Vertex> vertices = { { -1.0f, 1.0f, 0.5f, 0.0f, 0.0f }, { 1.0f, 1.0f, 0.5f, 1.0f, 0.0f }, { 1.0f, -1.0f, 0.5f, 1.0f, 1.0f }, { -1.0f, -1.0f, 0.5f, 0.0f, 1.0f }, }; _vertexBuffer = CreateVertexBuffer(_device, vertices); // Texture作成 pin_ptr<byte> pixelsPtr = &pixels[0]; _texture = CreateTexture(_device, width, height, pixelsPtr); // 描画準備 AssertHR(_device->SetRenderTarget(0, _surface)); AssertHR(_device->SetFVF(Vertex::FVF)); AssertHR(_device->SetStreamSource(0, _vertexBuffer, 0, sizeof(Vertex))); AssertHR(_device->SetVertexShader(_vertexShader)); AssertHR(_device->SetPixelShader(_pixelShader)); AssertHR(_device->SetTexture(0, _texture)); // 描画 AssertHR(_device->BeginScene()); AssertHR(_device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2)); AssertHR(_device->EndScene()); } private: CliComPtr<IDirect3DDevice9Ex> _device; CliComPtr<IDirect3DSurface9> _surface; CliComPtr<IDirect3DVertexShader9> _vertexShader; CliComPtr<IDirect3DPixelShader9> _pixelShader; CliComPtr<IDirect3DVertexBuffer9> _vertexBuffer; CliComPtr<IDirect3DTexture9> _texture; };
WPF側
XamlとCreateD3DImageは下記記事のものを利用します。
WPFとDirect3D9Exの連携 --- 導入 - 何でもプログラミング
C#側に、画像ファイルを読み込んでRendererを作成する部分を追加します。
var src = new BitmapImage(new Uri("Parrots.bmp", UriKind.Relative)); int width = src.PixelWidth; int height = src.PixelHeight; byte[] pixels = new byte[4 * width * height]; src.CopyPixels(pixels, 4 * width, 0); var renderer = new Renderer(width, height, pixels); image.Source = CreateD3DImage(width, height, renderer.Surface);