/*
#2 視点操作
プロジェクトのプロパティ
[構成プロパティ]-[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>
#include <time.h>
#define WIDTH(rect) ((rect).right - (rect).left)
#define HEIGHT(rect) ((rect).bottom - (rect).top)
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#define APP_NAME L"DxMesh"
#define CLIENT_W 640
#define CLIENT_H 480
struct Mesh {
ID3DXBuffer *pMat;
DWORD dwNumMat;
ID3DXMesh *pMesh;
};
// 関数プロトタイプ宣言
HRESULT InitD3D(HWND hWnd);
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void Render(HWND hWnd);
BOOL OnKeyDown(HWND hWnd, WPARAM wParam);
HRESULT OnSave(void);
// 外部変数構造体
static struct {
LPDIRECT3D9 pD3D; // Direct3D9
LPDIRECT3DDEVICE9 pDev; // レンダリングデバイス
LPD3DXFONT pFont; // フォント
Mesh cube;
Mesh axis;
float fDist; // 原点との距離
int nLat; // 緯度
int nLong; // 経度
} g;
//==============================================================================
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR lpCmdLine, int nCmdShow)
{
g.fDist = 75.0f;
g.nLat = 30;
g.nLong = 210;
// ウィンドウクラスの登録
WNDCLASSEX wcx;
ZeroMemory(&wcx, sizeof wcx);
wcx.cbSize = sizeof wcx;
wcx.lpfnWndProc = WndProc;
wcx.hInstance = hInstance;
wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
wcx.lpszClassName = APP_NAME;
if (RegisterClassEx(&wcx) == 0) {
return 0;
}
// ウィンドウサイズの計算
RECT rect;
SetRect(&rect, 0, 0, CLIENT_W, CLIENT_H);
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
// ウィンドウの作成
HWND hWnd = CreateWindow(
APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, WIDTH(rect), HEIGHT(rect),
NULL, NULL, hInstance, NULL);
if (hWnd == NULL) {
return 0;
}
// Direct3Dの初期化
if (FAILED(InitD3D(hWnd))) {
return 0;
}
// ウィンドウ表示
ShowWindow(hWnd, nCmdShow);
// メッセージループ
MSG msg;
do {
Sleep(1);
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
Render(hWnd);
}
} while (msg.message != WM_QUIT);
SAFE_RELEASE(g.cube.pMesh);
SAFE_RELEASE(g.axis.pMesh);
SAFE_RELEASE(g.pFont);
SAFE_RELEASE(g.pDev);
SAFE_RELEASE(g.pD3D);
return msg.wParam;
}
//------------------------------------------------------------------------------
HRESULT InitD3D(HWND hWnd)
{
// Direct3D
g.pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (g.pD3D == NULL) {
return E_FAIL;
}
// デバイス作成用のパラメタ
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof d3dpp);
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // モニタの設定と同じ
d3dpp.BackBufferCount = 0; // バックバッファの数 0->1
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; // マルチサンプリングしない
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // Direct3Dに任せる
d3dpp.hDeviceWindow = NULL; // カバーウィンドウ
d3dpp.Windowed = TRUE; // ウィンドウモード
d3dpp.EnableAutoDepthStencil = TRUE; // 深度バッファ自動管理
d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // 深度バッファフォーマット
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; // モニタの垂直回帰を待つ
// Direct3Dデバイスの作成
HRESULT hr = g.pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g.pDev);
// フォント
if (SUCCEEDED(hr)) {
hr = D3DXCreateFont(g.pDev, 40, 0, FW_HEAVY, 1, FALSE,
SHIFTJIS_CHARSET, OUT_TT_ONLY_PRECIS, ANTIALIASED_QUALITY,
FF_DONTCARE, L"MS Pゴシック", &g.pFont);
}
// 立方体メッシュ作成
if (SUCCEEDED(hr)) {
hr = D3DXLoadMeshFromX(L"C:\\tmp\\Cube2.x", D3DXMESH_MANAGED, g.pDev,
NULL, &g.cube.pMat, NULL, &g.cube.dwNumMat, &g.cube.pMesh);
}
// 軸メッシュ作成
if (SUCCEEDED(hr)) {
hr = D3DXLoadMeshFromX(L"C:\\tmp\\Axis.x", D3DXMESH_MANAGED, g.pDev,
NULL, &g.axis.pMat, NULL, &g.axis.dwNumMat, &g.axis.pMesh);
}
return hr;
}
//------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_KEYDOWN:
if (OnKeyDown(hWnd, wParam)) {
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
//------------------------------------------------------------------------------
void Render(HWND hWnd)
{
static int fps = 0;
static int frame = 0;
static time_t tmPrev = time(NULL);
if (IsIconic(hWnd)) return;
g.pDev->SetRenderState(D3DRS_ZENABLE, TRUE);
g.pDev->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
// 視点の設定
D3DXMATRIX mtxView;
float fRad = D3DXToRadian(g.nLat); // 緯度
float fPosY = sin(fRad) * g.fDist;
float fDist = cos(fRad) * g.fDist;
fRad = D3DXToRadian(g.nLong); // 経度
float fPoxX = sin(fRad) * fDist;
float fPoxZ = cos(fRad) * fDist;
D3DXMatrixLookAtLH(
&mtxView,
&D3DXVECTOR3(fPoxX, fPosY, fPoxZ),
&D3DXVECTOR3(0.0f, 0.0f, 0.0f),
&D3DXVECTOR3(0.0f, 1.0f, 0.0f));
g.pDev->SetTransform(D3DTS_VIEW, &mtxView);
D3DXMATRIX mtxProj;
D3DXMatrixPerspectiveFovLH(&mtxProj, D3DXToRadian(45),
(float)CLIENT_W / CLIENT_H, 0.1f, 100.0f);
g.pDev->SetTransform(D3DTS_PROJECTION, &mtxProj);
// ライトの設定
g.pDev->SetRenderState(D3DRS_LIGHTING, TRUE);
g.pDev->SetRenderState(D3DRS_AMBIENT, 0x007f7f7f);
D3DLIGHT9 light;
ZeroMemory(&light, sizeof light);
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 0.0f);
light.Ambient = D3DXCOLOR(0.5f, 0.5f, 0.5f, 0.0f);
light.Direction = D3DXVECTOR3(1.0f, -2.0f, 3.0f);
// light.Range = 1000.0f;
g.pDev->SetLight(0, &light);
g.pDev->LightEnable(0, TRUE);
// バックバッファのクリア
g.pDev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0x7f,0x7f,0xff), 1.0f, 0);
g.pDev->BeginScene();
D3DCOLORVALUE matAmb = {0.3f, 0.3f, 0.3f, 1.0f};
// D3DCOLORVALUE matDif = {1.0f, 0.0f, 0.0f, 1.0f}; // 元の色情報を上書き
D3DXMATRIX mtxWorld;
D3DXMatrixIdentity(&mtxWorld);
g.pDev->SetTransform(D3DTS_WORLD, &mtxWorld);
// 立方体描画
for (DWORD dw = 0; dw < g.cube.dwNumMat; dw++) {
D3DXMATERIAL *pMat = (D3DXMATERIAL *)g.cube.pMat->GetBufferPointer() + dw;
pMat->MatD3D.Ambient = matAmb;
// pMat->MatD3D.Diffuse = matDif;
g.pDev->SetMaterial(&pMat->MatD3D);
g.cube.pMesh->DrawSubset(dw);
}
// 軸描画
for (DWORD dw = 0; dw < g.axis.dwNumMat; dw++) {
D3DXMATERIAL *pMat = (D3DXMATERIAL *)g.axis.pMat->GetBufferPointer() + dw;
pMat->MatD3D.Ambient = matAmb;
// pMat->MatD3D.Diffuse = matDif;
g.pDev->SetMaterial(&pMat->MatD3D);
g.axis.pMesh->DrawSubset(dw);
}
// fps
TCHAR szBuf[32];
RECT rect;
time_t tmCurr = time(NULL);
if (tmCurr != tmPrev) {
fps = frame;
frame = 0;
tmPrev = tmCurr;
}
frame++;
SetRect(&rect, 0, 0, 50, 20);
swprintf_s(szBuf, L"time=%lld fps=%d", tmCurr, fps);
g.pFont->DrawText(NULL, szBuf, -1, &rect, DT_LEFT | DT_NOCLIP,
D3DCOLOR_ARGB(0xff,0xff,0xff,0xff));
// バックバッファを表画面に反映
g.pDev->EndScene();
g.pDev->Present(NULL, NULL, NULL, NULL);
}
//------------------------------------------------------------------------------
BOOL OnKeyDown(HWND hWnd, WPARAM wParam)
{
switch (wParam) {
case VK_LEFT:
g.nLong++;
break;
case VK_RIGHT:
g.nLong--;
break;
case VK_UP:
g.nLat++;
break;
case VK_DOWN:
g.nLat--;
break;
case VK_PRIOR: // Page Up
g.fDist -= 1.0f;
break;
case VK_NEXT: // Page Down
g.fDist += 1.0f;
break;
case 'S':
if (GetKeyState(VK_CONTROL) < 0) {
HRESULT hr = OnSave();
if (FAILED(hr)) {
MessageBox(hWnd, L"保存に失敗しました。", NULL, MB_OK);
} else {
MessageBox(hWnd, L"保存しました。", APP_NAME, MB_OK);
}
}
break;
case VK_ESCAPE:
DestroyWindow(hWnd);
break;
default:
return FALSE;
}
return TRUE;
}
//------------------------------------------------------------------------------
HRESULT OnSave(void)
{
HRESULT hr = D3DXSaveMeshToX(
L"C:\\tmp\\Cube2_2.x", g.cube.pMesh,
NULL, (D3DXMATERIAL *)&g.cube.pMat, NULL,
g.cube.dwNumMat, D3DXF_FILEFORMAT_TEXT);
return hr;
}