/*
[構成プロパティ]-[VC++ ディレクトリ]
[インクルード ディレクトリ]
C:\Program Files\Microsoft DirectX SDK (February 2010)\Include
[ライブラリ ディレクトリ]
C:\Program Files\Microsoft DirectX SDK (February 2010)\Lib\x86
Unicode文字セット
*/
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#include <d3d9.h>
#include <d3dx9.h>
#include <stdio.h>
#define SAFE_RELEASE(x) { if (x) { x->Release(); x = NULL; } }
#define CLASS_NAME TEXT("Shader1")
#define WINDOW_NAME TEXT("Shader1")
// 頂点定義
struct CUSTOMVTX {
float x, y, z; // 頂点位置
DWORD color; // 頂点カラー
};
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)
// 関数プロトタイプ宣言
void Trace(LPCTSTR format, ...);
HWND CreateWnd(HINSTANCE hInstance);
HRESULT InitDirect3D(HWND hWnd);
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// 外部変数構造体
static struct {
LPDIRECT3D9 pD3D;
LPDIRECT3DDEVICE9 pD3DDev;
IDirect3DVertexBuffer9 *pVertex;
IDirect3DVertexDeclaration9 *pDec;
IDirect3DVertexShader9 *pShaderHandler;
} g;
//==============================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
MSG msg;
msg.wParam = 0;
// ウィンドウの作成
HWND hWnd = CreateWnd(hInstance);
if (hWnd == NULL) {
return 0;
}
// Direct3Dの初期化
HRESULT hr = InitDirect3D(hWnd);
if (FAILED(hr)) {
goto Exit;
}
ShowWindow(hWnd, nCmdShow);
// メッセージループ
float c = 0.0f;
float addcolor[4]; // 頂点カラー(RGB)に足す値
do {
Sleep(1);
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
DispatchMessage(&msg);
} else {
// Direct3Dの処理
g.pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0);
g.pD3DDev->BeginScene();
// 描画
c += 0.005f; // 足す値
addcolor[0] = addcolor[1] = addcolor[2] = c;
g.pD3DDev->SetVertexShaderConstantF(4, addcolor, 1);
g.pD3DDev->SetStreamSource(0, g.pVertex, 0, sizeof (CUSTOMVTX));
g.pD3DDev->SetVertexDeclaration(g.pDec);
g.pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
g.pD3DDev->EndScene();
g.pD3DDev->Present(NULL, NULL, NULL, NULL);
}
} while (msg.message != WM_QUIT);
Exit:
SAFE_RELEASE(g.pShaderHandler);
SAFE_RELEASE(g.pDec);
SAFE_RELEASE(g.pVertex);
SAFE_RELEASE(g.pD3DDev);
SAFE_RELEASE(g.pD3D);
return msg.wParam;
}
//------------------------------------------------------------------------------
void Trace(LPCTSTR format, ...)
{
va_list arg_ptr;
TCHAR buffer[256];
int size;
va_start(arg_ptr, format);
size = _vsnwprintf_s(buffer, _TRUNCATE, format, arg_ptr);
va_end(arg_ptr);
OutputDebugString(buffer);
if (size < 0) {
OutputDebugString(L"...\n");
}
}
//------------------------------------------------------------------------------
HWND CreateWnd(HINSTANCE hInstance)
{
// ウィンドウクラスの登録
WNDCLASSEX wcx;
ZeroMemory(&wcx, sizeof wcx);
wcx.cbSize = sizeof wcx;
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = MainWndProc;
wcx.hInstance = hInstance;
wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
// wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcx.lpszClassName = CLASS_NAME;
if (RegisterClassEx(&wcx) == 0) {
return NULL;
}
// ウィンドウの作成
HWND hWnd = CreateWindow(
CLASS_NAME, WINDOW_NAME,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0,
NULL, NULL, hInstance, NULL);
return hWnd;
}
//------------------------------------------------------------------------------
HRESULT InitDirect3D(HWND hWnd)
{
// Direct3Dの初期化
g.pD3D = Direct3DCreate9(D3D_SDK_VERSION);
HRESULT hr = (g.pD3D) ? S_OK : E_FAIL;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof d3dpp);
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // 0
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; // 0
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // 1
d3dpp.Windowed = TRUE; // windowed / full-screen
d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; // 0
if (SUCCEEDED(hr)) {
hr = g.pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g.pD3DDev);
}
// 頂点の設定(小さな長方形)
static const CUSTOMVTX v[] = {
{-1.0f, -1.0f, 0.0f, 0xff0000ff},
{+1.0f, -1.0f, 0.0f, 0xffff0000},
{+1.0f, +1.0f, 0.0f, 0xff00ff00},
{-1.0f, +1.0f, 0.0f, 0xffffffff},
};
// 頂点バッファ作成と頂点情報の書き込み
if (SUCCEEDED(hr)) {
hr = g.pD3DDev->CreateVertexBuffer(sizeof v, D3DUSAGE_WRITEONLY, CUSTOMFVF,
D3DPOOL_MANAGED, &g.pVertex, NULL);
}
VOID *pData;
if (SUCCEEDED(hr)) {
hr = g.pVertex->Lock(0, sizeof v, &pData, 0);
}
if (SUCCEEDED(hr)) {
memcpy_s(pData, sizeof v, v, sizeof v);
hr = g.pVertex->Unlock();
}
// 頂点データ宣言(シェーダに伝える)
static const D3DVERTEXELEMENT9 VtxElem[] = {
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
D3DDECL_END()
};
if (SUCCEEDED(hr)) {
hr = g.pD3DDev->CreateVertexDeclaration(VtxElem, &g.pDec);
}
// シェーダバージョンの確認
if (SUCCEEDED(hr)) {
D3DCAPS9 caps;
hr = g.pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
Trace(L"VertexShaderVersion=%#x\n", caps.VertexShaderVersion);
Trace(L"PixelShaderVersion=%#x\n", caps.PixelShaderVersion);
}
// シェーダ命令配列定義
static const char VShader[] =
"vs_1_1\n"
"dcl_position v0\n"
"dcl_color v1\n"
"m4x4 oPos, v0, c0\n" // 頂点に変換行列を掛け算
"add oD0, v1, c4\n"; // 頂点カラーに定数を足し算して出力
// シェーダ命令のコンパイル
ID3DXBuffer *pShader = NULL;
ID3DXBuffer *pError = NULL;
if (SUCCEEDED(hr)) {
hr = D3DXAssembleShader(VShader, sizeof VShader - 1,
NULL, NULL, 0, &pShader, &pError);
}
// シェーダハンドラの生成
if (SUCCEEDED(hr)) {
hr = g.pD3DDev->CreateVertexShader(
(DWORD *)(pShader->GetBufferPointer()), &g.pShaderHandler);
}
SAFE_RELEASE(pError);
SAFE_RELEASE(pShader);
// 変換行列の設定
D3DXMATRIX mat, matView, matProj;
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3(0,0,5), &D3DXVECTOR3(0,0,0), &D3DXVECTOR3(0,1,0));
D3DXMatrixPerspectiveFovLH(&matProj, 0.785398163f, 480.0f / 640.0f, 0.1f, 10000.0f);
D3DXMatrixMultiply(&mat, &matView, &matProj);
// 変換行列を転置して定数レジスタc0~c3に登録する
D3DXMatrixTranspose(&mat, &mat);
if (SUCCEEDED(hr)) {
hr = g.pD3DDev->SetVertexShaderConstantF(0, (float *)&mat, 4);
}
// 頂点シェーダに切り替え
if (SUCCEEDED(hr)) {
hr = g.pD3DDev->SetVertexShader(g.pShaderHandler);
}
return hr;
}
//------------------------------------------------------------------------------
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}