開発環境 Microsoft Visual Studio Express 2013 for Windows Desktop
実行環境 Microsoft Windows 8.1 (64bit)
プロジェクトの種類 Visual C++/Win32/Win32 プロジェクト
プロジェクト名 DxMandelbrot
アプリケーションの種類 Windows アプリケーション
追加のオプション 空のプロジェクト、SDLチェック

参考

DxMandelbrot.cpp
#pragma comment(lib, "d3d11")
#pragma comment(lib, "d3dcompiler")
 
#include <d3d11.h>
#include <d3dcompiler.h>
 
#include <DirectXColors.h>
using namespace DirectX;
 
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
 
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
 
struct CustomVertex {
	XMFLOAT2 Position;
	XMFLOAT2 UV;
};
 
// 外部変数
ID3D11Device *pDevice;
ID3D11DeviceContext *pDeviceContext;
IDXGISwapChain *pSwapChain;
ID3D11RenderTargetView *pRenderTargetView;
ID3D11InputLayout *pVertexLayout;
ID3D11Buffer *pVertexBuffer;
ID3D11Buffer *pConstBuffer;
 
ID3D11VertexShader *pVertexShader;
ID3D11PixelShader *pPixelShader;
 
double offsetx;
double offsety;
double zoom = 4;
XMFLOAT4 center;
 
// 関数プロトタイプ宣言
HWND InitWnd(HINSTANCE hInstance, int nCmdShow);
HRESULT InitDevice(HWND hWnd);
HRESULT CompileShaderFromFile(LPCTSTR pFileName, LPCSTR pEntrypoint, LPCSTR pTarget, ID3DBlob **ppCode);
HRESULT CreateShaderBuffer();
void Render();
void CleanupDevice();
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
//==============================================================================
 
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
	// ウィンドウ初期化
	HWND hWnd = InitWnd(hInstance, nCmdShow);
	if (hWnd == NULL) {
		return 0;
	}
 
	// デバイス初期化
	if (FAILED(InitDevice(hWnd))) {
		return 0;
	}
 
	// メインループ
	MSG msg = { 0 };
	while (msg.message != WM_QUIT) {
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else {
			// 描画
			Render();
		}
	}
 
	// デバイスのクリーンアップ
	CleanupDevice();
 
	return msg.wParam;
}
 
HWND InitWnd(HINSTANCE hInstance, int nCmdShow)
{
	WNDCLASSEX wc;
	ZeroMemory(&wc, sizeof wc);
	wc.cbSize = sizeof wc;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.lpszClassName = L"DxMandelbrot";
	RegisterClassEx(&wc);
 
	DWORD dwStyle = WS_OVERLAPPEDWINDOW ^ WS_MAXIMIZEBOX ^ WS_THICKFRAME;
	RECT rc = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
	AdjustWindowRect(&rc, dwStyle, FALSE);
 
	HWND hWnd = CreateWindow(
		wc.lpszClassName, L"DxMandelbrot", dwStyle,
		CW_USEDEFAULT, 0, rc.right - rc.left, rc.bottom - rc.top,
		NULL, NULL, hInstance, NULL);
 
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
 
	return hWnd;
}
 
HRESULT InitDevice(HWND hWnd)
{
	// ドライバータイプ
	D3D_DRIVER_TYPE DriverType[] = {
		D3D_DRIVER_TYPE_HARDWARE,
		D3D_DRIVER_TYPE_WARP,
		D3D_DRIVER_TYPE_REFERENCE,
	};
 
	// 機能レベル
	D3D_FEATURE_LEVEL FeatureLevels[] = {
		D3D_FEATURE_LEVEL_11_1,
		D3D_FEATURE_LEVEL_11_0,
//		D3D_FEATURE_LEVEL_10_1,
//		D3D_FEATURE_LEVEL_10_0,
	};
 
	// スワップチェインの設定
	DXGI_SWAP_CHAIN_DESC sd;
	ZeroMemory(&sd, sizeof sd);
	sd.BufferCount = 1;
	sd.BufferDesc.Width = WINDOW_WIDTH;
	sd.BufferDesc.Height = WINDOW_HEIGHT;
	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.OutputWindow = hWnd;
	sd.SampleDesc.Count = 1;
	sd.SampleDesc.Quality = 0;
	sd.Windowed = TRUE;
 
	// デバイスとスワップチェインを作成
	HRESULT hr;
	for (int i = 0; i < ARRAYSIZE(DriverType); i++) {
		D3D_FEATURE_LEVEL FeatureLevel;
		hr = D3D11CreateDeviceAndSwapChain(NULL, DriverType[i], NULL, 0,
			FeatureLevels, ARRAYSIZE(FeatureLevels), D3D11_SDK_VERSION, &sd,
			&pSwapChain, &pDevice, &FeatureLevel, &pDeviceContext);
		if (SUCCEEDED(hr)) break;
	}
	if (FAILED(hr)) {
		return hr;
	}
 
	// バックバッファを取得
	ID3D11Texture2D *pBackBuffer;
	hr = pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
 
	// レンダーターゲットを生成
	hr = pDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRenderTargetView);
	pBackBuffer->Release();
 
	// 出力マネージャにレンダーターゲットを設定
	pDeviceContext->OMSetRenderTargets(1, &pRenderTargetView, NULL);
 
	// ビューポートの設定
	D3D11_VIEWPORT vp;
	vp.Width = WINDOW_WIDTH;
	vp.Height = WINDOW_HEIGHT;
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;
	vp.TopLeftX = 0;
	vp.TopLeftY = 0;
 
	// デバイスコンテキストにビューポートを設定
	pDeviceContext->RSSetViewports(1, &vp);
 
	// 頂点シェーダをコンパイル
	ID3DBlob *pCode;
	if (FAILED(CompileShaderFromFile(L"shader.fx", "VS", "vs_5_0", &pCode))) {
		return E_FAIL;
	}
 
	// 頂点シェーダ生成
	hr = pDevice->CreateVertexShader(
		pCode->GetBufferPointer(), pCode->GetBufferSize(), NULL, &pVertexShader);
	if (FAILED(hr)) {
		return hr;
	}
 
	// 入力レイアウトの定義
	D3D11_INPUT_ELEMENT_DESC layout[] = {
		{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};
 
	// 入力レイアウトを生成
	hr = pDevice->CreateInputLayout(layout, ARRAYSIZE(layout),
		pCode->GetBufferPointer(), pCode->GetBufferSize(), &pVertexLayout);
	SAFE_RELEASE(pCode);
	if (FAILED(hr)) {
		return hr;
	}
 
	// 入力アセンブラ(input-assembler)に入力レイアウトを設定
	pDeviceContext->IASetInputLayout(pVertexLayout);
 
	// ピクセルシェーダをコンパイル
	hr = CompileShaderFromFile(L"shader.fx", "PS", "ps_5_0", &pCode);
	if (FAILED(hr)) {
		return hr;
	}
 
	// ピクセルシェーダ生成
	hr = pDevice->CreatePixelShader(
		pCode->GetBufferPointer(), pCode->GetBufferSize(), NULL, &pPixelShader);
	SAFE_RELEASE(pCode);
	if (FAILED(hr)) {
		return hr;
	}
 
	// 頂点の定義
	CustomVertex vertices[] = {
		{ XMFLOAT2(-1, 1), XMFLOAT2(0, 1) },// LU
		{ XMFLOAT2(1, 1), XMFLOAT2(1, 1) }, // RU
		{ XMFLOAT2(-1, -1), XMFLOAT2(0, 0) }, // LD
		{ XMFLOAT2(1, -1), XMFLOAT2(1, 0) }, // RD
	};
 
	// 頂点バッファの設定
	D3D11_BUFFER_DESC bd;
	ZeroMemory(&bd, sizeof bd);
	bd.ByteWidth = sizeof vertices;
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
 
	// サブリソースの設定
	D3D11_SUBRESOURCE_DATA InitData;
	ZeroMemory(&InitData, sizeof InitData);
	InitData.pSysMem = vertices;
 
	// 頂点バッファの生成
	hr = pDevice->CreateBuffer(&bd, &InitData, &pVertexBuffer);
	if (FAILED(hr)) {
		return hr;
	}
 
	// 入力アセンブラに頂点バッファを設定
	UINT stride = sizeof CustomVertex;
	UINT offset = 0;
	pDeviceContext->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);
 
	// ピクセルシェーダのシェーダ変数
	CreateShaderBuffer();
 
	// プリミティブの種類を設定
	pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
 
	return S_OK;
}
 
HRESULT CompileShaderFromFile(LPCTSTR pFileName, LPCSTR pEntrypoint, LPCSTR pTarget, ID3DBlob **ppCode)
{
	ID3DBlob *pErrorMsgs;
	HRESULT hr = D3DCompileFromFile(
		pFileName, NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, pEntrypoint, pTarget,
		0, 0, ppCode, &pErrorMsgs);
	return hr;
}
 
HRESULT CreateShaderBuffer()
{
	center = { (float)offsetx, (float)offsety, (float)zoom, (float)WINDOW_HEIGHT / WINDOW_WIDTH };
 
	D3D11_BUFFER_DESC bd;
	bd.ByteWidth = sizeof center;
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	bd.StructureByteStride = 0;
 
	D3D11_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = &center;
	InitData.SysMemPitch = 0;
	InitData.SysMemSlicePitch = 0;
 
	HRESULT hr = pDevice->CreateBuffer(&bd, &InitData, &pConstBuffer);
	pDeviceContext->PSSetConstantBuffers(0, 1, &pConstBuffer);
	return hr;
}
 
void Render()
{
	// ビューをクリアする
	pDeviceContext->ClearRenderTargetView(pRenderTargetView, Colors::CornflowerBlue);
 
	// シェーダを設定して描画
	pDeviceContext->VSSetShader(pVertexShader, NULL, 0);
	pDeviceContext->PSSetShader(pPixelShader, NULL, 0);
 
	center = { (float)offsetx, (float)offsety, (float)zoom, (float)WINDOW_HEIGHT / WINDOW_WIDTH };
	pDeviceContext->UpdateSubresource(pConstBuffer, 0, NULL, &center, 0, 0);
 
	// 描画
	pDeviceContext->Draw(4, 0);
 
	// 描画結果を表示
	pSwapChain->Present(0, 0);
}
 
void CleanupDevice()
{
	// ステートをクリアし、デフォルト状態にする
	if (pDeviceContext) {
		pDeviceContext->ClearState();
		pDeviceContext->Flush();
	}
 
	SAFE_RELEASE(pVertexShader);
	SAFE_RELEASE(pPixelShader);
	SAFE_RELEASE(pConstBuffer);
	SAFE_RELEASE(pVertexBuffer);
	SAFE_RELEASE(pVertexLayout);
 
	SAFE_RELEASE(pRenderTargetView);
	SAFE_RELEASE(pSwapChain);
	SAFE_RELEASE(pDeviceContext);
	SAFE_RELEASE(pDevice);
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_KEYDOWN:
		switch (wParam)
		{
		case VK_ESCAPE:
			DestroyWindow(hWnd);
			break;
		case VK_UP:
			zoom *= 0.9;
			break;
		case VK_DOWN:
			zoom *= 1.1;
			break;
		case 'W':
			offsety += zoom * 0.1;
			break;
		case 'S':
			offsety -= zoom * 0.1;
			break;
		case 'A':
			offsetx -= zoom * 0.1;
			break;
		case 'D':
			offsetx += zoom * 0.1;
			break;
		}
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
 

プロジェクトには追加しない。
カレントディレクトリに置く。
shader.fx
float4 center : register(ps, c0);	// xy=Offset z=Zoom w=Aspect
 
struct VertexIn
{
	float2 Pos : POSITION;
	float2 UV : TEXCOORD;
};
 
struct VertexOut
{
	float4 ScreenPos : SV_Position;
	float2 UV : TEXCOORD;
};
 
VertexOut VS(VertexIn input)
{
	VertexOut output;
	output.ScreenPos = float4(input.Pos, 0, 1);
	output.UV = input.UV;
	return output;
}
 
float4 PS(VertexOut input) : SV_Target
{
	const double2 c = (input.UV - 0.5) * double2(1.0, center.w) * center.z + center.xy;
 
	double2 p = 0;
	int n;
	for (n = 0; n < 511 && dot(p, p) < 4.0; n++) {
		p = double2(p.x * p.x - p.y * p.y, 2.0 * p.x * p.y) + c;
	}
 
	float4 color;
	float u = (float)n / 1024.0;	// 0 <= u < 0.5
	switch (n % 4) {
	case 0:
		color.rgb = float3(1.0 - u, 1.0 - u, 0.5);
		break;
	case 1:
		color.rgb = float3(1.0 - u, 1.0 - u, 1.0 - u);
		break;
	case 2:
		color.rgb = float3(0.5, 1.0 - u, 1.0 - u);
		break;
	case 3:
		color.rgb = float3(0.5 - u, 0.5 - u, 0.5 - u);
		break;
	}
	color.a = 1.0;
	return color;
}
 
最終更新:2014年06月06日 09:48