#include <windows.h>
#include <d3d9.h> // DirectXGraphicsコアライブラリ
#include <d3dx9.h> // DirectXGraphics拡張ライブラリ
#pragma comment(lib, “d3d9.lib”)
#pragma comment(lib, “d3dx9.lib”)
// Direct3Dデバイス
IDirect3DDevice9* d3dDevice;
// Direct3Dテクスチャ
IDirect3DTexture9* myTexture;
// Direct3Dテクスチャ
IDirect3DTexture9* dogTexture;
// Direct3Dテクスチャ
IDirect3DTexture9* mikuTexture;
// Direct3Dテクスチャ
IDirect3DTexture9* kyukyuTexture;
//アニメーション用のインデックス
int animIndex = 0;
//アニメーション用ウェイトカウンター
int animWaitCounter = 0;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
// テクスチャを読み込む関数
IDirect3DTexture9* LoadTexture(const char* path)
{
IDirect3DTexture9* texture = nullptr;
HRESULT hr;
hr = D3DXCreateTextureFromFileEx(
d3dDevice, // Direct3Dデバイス
path, // 画像のパス (ファイル名)
0, // 読み込む際の横幅 (単位はピクセル)
0, // 読み込む際の高さ (単位はピクセル)
1, // ミップレベル
0, // 使用方法
D3DFMT_UNKNOWN, // ピクセルフォーマット
D3DPOOL_DEFAULT, // どのメモリ上に読み込むか?
D3DX_FILTER_NONE, // 拡大縮小フィルター
D3DX_FILTER_NONE, // ミップフィルター
D3DCOLOR_ARGB(0, 0, 0, 0), // 透過色
nullptr, // 画像情報を受け取る変数のアドレス
nullptr, // カラーパレットを受け取るバッファ
&texture // テクスチャを受け取る変数のアドレス
);
if(hr < 0)
{
MessageBox(nullptr, “画像の読み込みに失敗しました”, “エラー”, MB_OK);
}
return texture;
}
// DirectXGraphicsを初期化する関数
void InitializeGraphics(HWND hWnd, int resolutionWidth, int resolutionHeight)
{
// Direct3Dオブジェクトの作成
IDirect3D9* d3d9;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if (d3d9 == nullptr)
{
// DirectXが使えない
MessageBox(nullptr, “DirectXが使用できません”, “エラー”, MB_OK);
}
// プレゼンテーションパラメーターを用意する
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.BackBufferWidth = resolutionWidth; // 裏画面の横幅
d3dpp.BackBufferHeight = resolutionHeight; // 裏画面の高さ
d3dpp.BackBufferCount = 1; // 裏画面の枚数
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // 裏画面のピクセルフォーマット
d3dpp.hDeviceWindow = hWnd;
d3dpp.Windowed = TRUE; // TRUE:ウィンドウモード FALSE:フルスクリーンモード
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.FullScreen_RefreshRateInHz = 0;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
d3dpp.Flags = 0;
// Direct3Dデバイスの作成
if (FAILED(d3d9->CreateDevice(0, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &d3dDevice)))
{
// 上記の条件では初期化できない
MessageBox(nullptr, “Direct3Dの初期化に失敗しました”, “エラー”, MB_OK);
}
// 1枚目の画像読み込み
myTexture = LoadTexture(“0142.jpg”);
// 2枚目の画像読み込み
dogTexture = LoadTexture(“k9img13_golden.jpg”);
// 3枚目の画像読み込み
mikuTexture = LoadTexture(“miku-tiled.png”);
// 4枚目の画像読み込み
kyukyuTexture = LoadTexture(“kyukyu.png”);
}
// ゲーム内の時間を進める為の処理を行う関数
void UpdateGameFrame()
{
animWaitCounter++;
if (animWaitCounter < 6)
{
//ウェイトカウンター
animWaitCounter = 0;
//次のコマへ進む
animIndex++;
//最後のコマを過ぎたら最初のコマに戻す
if (animIndex >= 4)
animIndex = 0;
}
}
//レッスン1: 2D画面上に三角形を1つ描画する
void Lesson1()
{
// 1つの頂点にはどんな情報を持たせる?
// ・位置(x,y,z) 2D/3D共に必須
// ・wの逆数(rhw) 2Dには必須
// ・法線(nx,ny,nz) オプション
// ・色(diffuse) オプション
// ・テクスチャ座標(u,v) オプション
struct VERTEX
{
float x, y, z;
float rhw;
};
// 頂点は「変数」ではなく「配列」で用意すること
// DirectX側の条件:頂点がメモリ上で連続している
// C言語では「配列」はメモリ上で連続していることが保証される
VERTEX vert[3];
vert[0].x = 0.0f; // ゲーム画面の左上を原点(0,0)とした時のX座標
vert[0].y = 0.0f; // ゲーム画面の左上を原点(0,0)とした時のY座標
vert[0].z = 0.0f; // zは奥行きを表す値
vert[0].rhw = 1.0f; // rhwはいつも0にしておくこと
vert[1].x = 1280.0f;
vert[1].y = 0.0f;
vert[1].z = 0.0f;
vert[1].rhw = 1.0f;
vert[2].x = 0.0f;
vert[2].y = 720.0f;
vert[2].z = 0.0f;
vert[2].rhw = 1.0f;
// 頂点1個分にはどんな情報が含まれているのかを
// Direct3Dデバイスに教える
d3dDevice->SetFVF(D3DFVF_XYZRHW);
// Direct3Dデバイスに頂点データを渡して描画してもらう
d3dDevice->DrawPrimitiveUP(
D3DPT_TRIANGLELIST, // プリミティブタイプ
1, // プリミティブ数
vert, // 頂点データ
sizeof(VERTEX) // 頂点1個分のサイズ(バイト数)
);
}
//レッスン2: 2D画面上に三角形を2つ描画する
void Lesson2()
{
struct VERTEX
{
float x, y, z;
float rhw;
};
VERTEX vert[6];
// 1つ目の三角形
vert[0].x = 200.0f;
vert[0].y = 100.0f;
vert[0].z = 0.0f;
vert[0].rhw = 1.0f;
vert[1].x = 800.0f;
vert[1].y = 100.0f;
vert[1].z = 0.0f;
vert[1].rhw = 1.0f;
vert[2].x = 200.0f;
vert[2].y = 500.0f;
vert[2].z = 0.0f;
vert[2].rhw = 1.0f;
// 2つ目の三角形
vert[3].x = 200.0f;
vert[3].y = 500.0f;
vert[3].z = 0.0f;
vert[3].rhw = 1.0f;
vert[4].x = 800.0f;
vert[4].y = 100.0f;
vert[4].z = 0.0f;
vert[4].rhw = 1.0f;
vert[5].x = 800.0f;
vert[5].y = 500.0f;
vert[5].z = 0.0f;
vert[5].rhw = 1.0f;
d3dDevice->SetFVF(D3DFVF_XYZRHW);
d3dDevice->DrawPrimitiveUP(
D3DPT_TRIANGLELIST,
2,
vert,
sizeof(VERTEX)
);
}
//レッスン3: 三角形に色を付ける
void Lesson3()
{
// 1つの頂点にはどんな情報を持たせる?
// ・位置(x,y,z) 2D/3D共に必須
// ・wの逆数(rhw) 2Dには必須
// ・法線(nx,ny,nz) オプション
// ・色(diffuse) オプション
// ・テクスチャ座標(u,v) オプション
struct VERTEX
{
float x, y, z;
float rhw;
D3DCOLOR diffuse;
};
// 頂点は「変数」ではなく「配列」で用意すること
// DirectX側の条件:頂点がメモリ上で連続している
// C言語では「配列」はメモリ上で連続していることが保証される
VERTEX vert[3];
vert[0].x = 0.0f; // ゲーム画面の左上を原点(0,0)とした時のX座標
vert[0].y = 0.0f; // ゲーム画面の左上を原点(0,0)とした時のY座標
vert[0].z = 0.0f; // zは奥行きを表す値
vert[0].rhw = 1.0f; // rhwはいつも0にしておくこと
vert[0].diffuse = D3DCOLOR_ARGB(255, 255, 0, 0); // 0~255
// vert[0].diffuse = D3DCOLOR_ARGB(α値, 赤, 緑, 青); // 0~255
vert[1].x = 1280.0f;
vert[1].y = 0.0f;
vert[1].z = 0.0f;
vert[1].rhw = 1.0f;
vert[1].diffuse = D3DCOLOR_ARGB(255, 0, 255, 0);
vert[2].x = 0.0f;
vert[2].y = 720.0f;
vert[2].z = 0.0f;
vert[2].rhw = 1.0f;
vert[2].diffuse = D3DCOLOR_ARGB(255, 0, 0, 255);
// 頂点1個分にはどんな情報が含まれているのかを
// Direct3Dデバイスに教える
d3dDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
// Direct3Dデバイスに頂点データを渡して描画してもらう
d3dDevice->DrawPrimitiveUP(
D3DPT_TRIANGLELIST, // プリミティブタイプ
1, // プリミティブ数
vert, // 頂点データ
sizeof(VERTEX) // 頂点1個分のサイズ(バイト数)
);
}
//レッスン4: 四角形にテクスチャを貼る
void Lesson4()
{
struct VERTEX
{
float x, y, z;
float rhw;
float u, v; // テクスチャ座標(u,v)
};
VERTEX vert[6];
// 1つ目の三角形
vert[0].x = 200.0f;
vert[0].y = 100.0f;
vert[0].z = 0.0f;
vert[0].rhw = 1.0f;
vert[0].u = 0.0f;
vert[0].v = 0.0f;
vert[1].x = 800.0f;
vert[1].y = 100.0f;
vert[1].z = 0.0f;
vert[1].rhw = 1.0f;
vert[1].u = 1.0f;
vert[1].v = 0.0f;
vert[2].x = 200.0f;
vert[2].y = 500.0f;
vert[2].z = 0.0f;
vert[2].rhw = 1.0f;
vert[2].u = 0.0f;
vert[2].v = 1.0f;
// 2つ目の三角形
vert[3].x = 200.0f;
vert[3].y = 500.0f;
vert[3].z = 0.0f;
vert[3].rhw = 1.0f;
vert[3].u = 0.0f;
vert[3].v = 1.0f;
vert[4].x = 800.0f;
vert[4].y = 100.0f;
vert[4].z = 0.0f;
vert[4].rhw = 1.0f;
vert[4].u = 1.0f;
vert[4].v = 0.0f;
vert[5].x = 800.0f;
vert[5].y = 500.0f;
vert[5].z = 0.0f;
vert[5].rhw = 1.0f;
vert[5].u = 1.0f;
vert[5].v = 1.0f;
d3dDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
// どのテクスチャを貼りたいのかをDirect3Dデバイスに教える
d3dDevice->SetTexture(0, dogTexture);
d3dDevice->DrawPrimitiveUP(
D3DPT_TRIANGLELIST,
2,
vert,
sizeof(VERTEX)
);
}
//DrowSprite関数: スプライトを画面に描画する関数
void DrowSprite(float dx, float dy, float dw, float dh, IDirect3DTexture9* texture, float sx, float sy, float sw, float sh, D3DCOLOR color)
{
D3DSURFACE_DESC desc;
texture->GetLevelDesc(0, &desc);
struct VERTEX
{
float x, y, z;
float rhw;
D3DCOLOR diffuse; //頂点カラー
float u, v; // テクスチャ座標(u,v)
};
VERTEX vert[6];
//サンプリングの関係で0.5ずつずらす
dx += 0.5f;
dy += 0.5f;
// 1つ目の三角形
vert[0].x = dx;
vert[0].y = dy;
vert[0].z = 0.0f;
vert[0].rhw = 1.0f;
vert[0].diffuse = color;
vert[0].u = sx / desc.Width;
vert[0].v = sy / desc.Height;
vert[1].x = dx + dw; // 右上X座標 = 左上X座標 + 四角形の横幅
vert[1].y = dy;
vert[1].z = 0.0f;
vert[1].rhw = 1.0f;
vert[1].diffuse = color;
vert[1].u = (sx + sw) / desc.Width;
vert[1].v = sy / desc.Height;
vert[2].x = dx;
vert[2].y = dy + dh;
vert[2].z = 0.0f;
vert[2].rhw = 1.0f;
vert[2].diffuse = color;
vert[2].u = sx / desc.Width;
vert[2].v = (sy + sh) / desc.Height;
// 2つ目の三角形
vert[3].x = dx;
vert[3].y = dy + dh;
vert[3].z = 0.0f;
vert[3].rhw = 1.0f;
vert[3].diffuse = color;
vert[3].u = sx / desc.Width;
vert[3].v = (sy + sh) / desc.Height;
vert[4].x = dx + dw;
vert[4].y = dy;
vert[4].z = 0.0f;
vert[4].rhw = 1.0f;
vert[4].diffuse = color;
vert[4].u = (sx + sw) / desc.Width;
vert[4].v = sy / desc.Height;
vert[5].x = dx + dw;
vert[5].y = dy + dh;
vert[5].z = 0.0f;
vert[5].rhw = 1.0f;
vert[5].diffuse = color;
vert[5].u = (sx + sw) / desc.Width;
vert[5].v = (sy + sh) / desc.Height;
d3dDevice->SetFVF(D3DFVF_XYZRHW |D3DFVF_DIFFUSE| D3DFVF_TEX1);
// どのテクスチャを貼りたいのかをDirect3Dデバイスに教える
d3dDevice->SetTexture(0, texture);
d3dDevice->DrawPrimitiveUP(
D3DPT_TRIANGLELIST,
2,
vert,
sizeof(VERTEX)
);
}
// ゲーム画面の描画を行う関数
// (この関数は1秒間に約60回呼び出される)
void DrawGame()
{
// 裏画面を塗りつぶす (1フレーム前の画面を消す)
d3dDevice->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, 100, 149, 237), 1.0f, 0);
// レンダリング開始
d3dDevice->BeginScene();
////////////////////////////////////////////
// ここで全てのポリゴンを描画する
////////////////////////////////////////////
// Lesson5(左上隅X座標, 左上隅Y座標, 横幅, 高さ, テクスチャ);
//Lesson5(50, 80, 300, 200, myTexture);
//Lesson5(200, 400, 200, 500, dogTexture);
DrowSprite(100, 50, 200 , 200, mikuTexture, 200 * animIndex, 0, 200, 200, D3DCOLOR_ARGB( 255, 255, 255, 255));
// レンダリング終了
d3dDevice->EndScene();
// 裏画面の内容を表画面にコピーする
d3dDevice->Present(nullptr, nullptr, nullptr, nullptr);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst,
LPSTR lpszCmdLine, int nCmdShow)
{
WNDCLASS myProg;
myProg.style = CS_HREDRAW | CS_VREDRAW;
myProg.lpfnWndProc = WndProc;
myProg.cbClsExtra = 0;
myProg.cbWndExtra = 0;
myProg.hInstance = hInstance;
myProg.hIcon = NULL;
myProg.hCursor = LoadCursor(NULL, IDC_ARROW);
myProg.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
myProg.lpszMenuName = NULL;
myProg.lpszClassName = “GameProgram1”;
if (!RegisterClass(&myProg))
return -1;
// クライアント領域のサイズが800×600になるように
// ウィンドウのサイズを計算する
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = 1280;
rect.bottom = 720;
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
// ウィンドウの横幅
int windowWidth = rect.right – rect.left;
// ウィンドウの高さ
int windowHeight = rect.bottom – rect.top;
// スクリーンのサイズを調べる
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
// ウィンドウのセンタリング (中央揃え)
// ウィンドウの左上隅X座標 = (スクリーンの横幅 – ウィンドウの横幅) / 2;
// ウィンドウの左上隅Y座標 = (スクリーンの高さ – ウィンドウの高さ) / 2;
int windowPosX = (screenWidth – windowWidth) / 2;
int windowPosY = (screenHeight – windowHeight) / 2;
HWND hWnd;
hWnd = CreateWindow(
myProg.lpszClassName,
“脱出ゲーム(仮)”,
WS_OVERLAPPEDWINDOW,
windowPosX,
windowPosY,
windowWidth,
windowHeight,
NULL,
NULL,
hInstance,
NULL);
// DirectXGraphicsの初期化
InitializeGraphics(hWnd, 1280, 720);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// メッセージループ
MSG msg;
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// ゲーム画面の描画
DrawGame();
// ゲーム内時間の更新
UpdateGameFrame();
}
}
return (msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, msg, wParam, lParam));
}
return 0;
}