0001: // ----------------------------------------------------------------------------
0002: //
0003: // main.cpp - ウィンドウズメイン部分
0004: // 
0005: // Copyright (c) 2001 if (if@kun.desu.ne.jp)
0006: // All Rights Reserved.
0007: //
0008: // ----------------------------------------------------------------------------
0009: 
0010: #define STRICT
0011: #include <stdio.h>
0012: #include <windows.h>
0013: #include <d3d8.h>
0014: #include <d3dx8.h>
0015: 
0016: #include "resource.h"
0017: #include "main.h"
0018: #include "draw.h"
0019: #include "font.h"
0020: #include "load.h"
0021: #include "rigidbody.h"
0022: 
0023: // ----------------------------------------------------------------------------
0024: // オブジェクト
0025: // ----------------------------------------------------------------------------
0026: static LPDIRECT3D8              s_lpD3D = NULL;
0027: static LPDIRECT3DDEVICE8        s_lpD3DDEV = NULL;
0028: static D3DPRESENT_PARAMETERS    s_d3dpp;
0029: static bool                     s_end;      // 終了フラグ
0030: static HINSTANCE                shInstApp;
0031: static bool     sZoom = false;
0032: 
0033: static CMyFont sFont;
0034: extern CMyMesh  mesh;
0035: extern DWORD    gVs;
0036: extern DWORD    gEdge;
0037: extern D3DXVECTOR4  rot;
0038: 
0039: // 光源の方向
0040: extern D3DXVECTOR4      lrot;
0041: void SetLight(LPDIRECT3DDEVICE8 lpD3DDEV, D3DXVECTOR4 *pRot);
0042: 
0043: // ----------------------------------------------------------------------------
0044: // プロトタイプ宣言
0045: // ----------------------------------------------------------------------------
0046: int PASCAL WinMain(HINSTANCE hInst,HINSTANCE hPrev,char *CmdLine,int CmdShow);
0047: LRESULT CALLBACK MsgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
0048: LRESULT CALLBACK MyDlgProc(HWND hDlgWnd, UINT msg, WPARAM wp, LPARAM lp);
0049: HRESULT InitD3D( HWND hWnd );           // DirectX の初期化
0050: static void fps_disp();
0051: 
0052: // ----------------------------------------------------------------------------
0053: // Name: WinMain()
0054: // Desc: Windows アプリケーションはここから始まる
0055: //-----------------------------------------------------------------------------
0056: int PASCAL WinMain(HINSTANCE hInst,HINSTANCE hPrev,char *CmdLine,int CmdShow)
0057: {
0058:     s_end = 0;
0059:     shInstApp = hInst;
0060:     // ウインドウの作成
0061:     RECT    rect;
0062:     SetRect(&rect, 0, 0, WIDTH, HEIGHT);
0063:     DWORD   style = (FULLSCREEN) ? WS_POPUP :(WS_CAPTION|WS_SYSMENU|WS_BORDER|WS_MINIMIZEBOX);
0064:     AdjustWindowRect(&rect, style, FALSE);  // ウィンドウスタイルを設定したときの、ウィンドウの大きさを調べる
0065:     int width  = rect.right - rect.left;
0066:     int height = rect.bottom - rect.top;    
0067:     
0068:     WNDCLASS wc;
0069:     ZeroMemory(&wc, sizeof(WNDCLASS));
0070:     wc.hbrBackground    = (HBRUSH)GetStockObject(BLACK_BRUSH);
0071:     wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
0072:     wc.hInstance        = hInst;
0073:     wc.lpfnWndProc      = MsgProc;
0074:     wc.lpszMenuName     = (char*)IDR_MENU;
0075:     wc.lpszClassName    = CAPTION;
0076:     if(RegisterClass(&wc) == 0) return 0; //ウィンドウ作成に使用できる新しいウィンドウクラスを作成する。
0077:     
0078:     HWND hWnd = CreateWindow(CAPTION        // 登録されているクラス名
0079:                             ,CAPTION        // ウィンドウ名
0080:                             ,style          // ウィンドウスタイル
0081:                             ,CW_USEDEFAULT  // ウィンドウの横方向の位置
0082:                             ,CW_USEDEFAULT  // ウィンドウの縦方向の位置
0083:                             ,width          // ウィンドウの幅
0084:                             ,height         // ウィンドウの高さ
0085:                             ,NULL           // 親ウィンドウまたはオーナーウィンドウのハンドル
0086:                             ,NULL           // メニューハンドルまたは子ウィンドウ ID
0087:                             ,hInst          // アプリケーションインスタンスのハンドル
0088:                             ,NULL           // ウィンドウ作成データ
0089:                             );
0090:     if(hWnd == NULL) return 0;
0091:     
0092:     // Direct3D の初期化
0093:     if(SUCCEEDED(InitD3D(hWnd))){
0094:         
0095:         sFont.Init(s_lpD3DDEV, 12, 24);
0096: 
0097:         if(FAILED(InitRender(s_lpD3DDEV))) s_end = true;
0098:         
0099:         ShowWindow(hWnd, SW_SHOW);
0100:         UpdateWindow(hWnd);
0101:     
0102:         // メインループ
0103:         MSG msg;
0104:         while (!s_end)
0105:         {
0106:             if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
0107:                 // メッセージの処理
0108:                 TranslateMessage(&msg);
0109:                 DispatchMessage(&msg);
0110:             }else{
0111:                 // Direct3D の描画
0112:                 // バックバッファと Z バッファをクリア
0113:                 s_lpD3DDEV->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0x50,0x6e,0xbf),1.0f,0);
0114:                 // シーン開始
0115:                 s_lpD3DDEV->BeginScene();
0116:                 
0117:                 Render(s_lpD3DDEV); // 描画などの処理
0118:                 fps_disp();         // fpsの描画
0119:                 
0120:                 // シーン終了
0121:                 s_lpD3DDEV->EndScene();
0122:                 if (FAILED(s_lpD3DDEV->Present(NULL,NULL,NULL,NULL)))
0123:                     s_lpD3DDEV->Reset(&s_d3dpp);// バックバッファをプライマリバッファにコピー
0124:             }
0125:         }
0126:     }
0127:     
0128:     // 終了
0129:     CleanRender(s_lpD3DDEV);
0130:     RELEASE(s_lpD3DDEV);
0131:     RELEASE(s_lpD3D);
0132:     
0133:     return 0;
0134: }
0135: //-----------------------------------------------------------------------------
0136: // Name: InitD3D()
0137: // Desc: Direct3D の初期化
0138: //-----------------------------------------------------------------------------
0139: HRESULT InitD3D( HWND hWnd )
0140: {
0141:     // Direct3D オブジェクトを作成
0142:     if (NULL == (s_lpD3D = Direct3DCreate8(D3D_SDK_VERSION))){
0143:         MessageBox(NULL,"Direct3D の作成に失敗しました。",CAPTION,MB_OK | MB_ICONSTOP);
0144:         return E_FAIL;
0145:     }
0146: 
0147:     // 現在の画面モードを取得
0148:     D3DDISPLAYMODE d3ddm;
0149:     if( FAILED( s_lpD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) ) return E_FAIL;
0150: 
0151:     // Direct3D 初期化パラメータの設定
0152:     ZeroMemory(&s_d3dpp, sizeof(D3DPRESENT_PARAMETERS));
0153:     s_d3dpp.BackBufferCount = 1;
0154:     if (FULLSCREEN){
0155:         s_d3dpp.Windowed = FALSE;
0156:         s_d3dpp.BackBufferWidth = WIDTH;
0157:         s_d3dpp.BackBufferHeight = HEIGHT;
0158:     }else{
0159:         s_d3dpp.Windowed = TRUE;
0160:         s_d3dpp.BackBufferWidth = 0;
0161:         s_d3dpp.BackBufferHeight = 0;
0162:     }
0163:     // ウインドウ : 現在の画面モードを使用
0164:     s_d3dpp.BackBufferFormat = d3ddm.Format;
0165:     s_d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
0166:     s_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
0167:     s_d3dpp.hDeviceWindow = hWnd;
0168:     // Z バッファの自動作成
0169:     s_d3dpp.EnableAutoDepthStencil = TRUE;
0170:     s_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
0171:  
0172:     D3DCAPS8 caps;
0173:     s_lpD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
0174:     
0175:     if(caps.VertexShaderVersion < D3DVS_VERSION(1,0)){
0176:         //vertex shader 1.0 をhwサポートしない場合はD3DCREATE_SOFTWARE_VERTEXPROCESSINGする必要があります
0177:         if(FAILED(s_lpD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&s_d3dpp,&s_lpD3DDEV))){
0178:             if(FAILED(s_lpD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF,hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE,&s_d3dpp,&s_lpD3DDEV))){
0179:                 return FALSE;
0180:             }
0181:         }
0182:     }else{
0183:         // デバイスの作成 - T&L HAL
0184:         if (FAILED(s_lpD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING,&s_d3dpp,&s_lpD3DDEV))){
0185:             // 失敗したので HAL で試行
0186:             if (FAILED(s_lpD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&s_d3dpp,&s_lpD3DDEV))){
0187:                 // 失敗したので REF で試行
0188:                 if (FAILED(s_lpD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&s_d3dpp,&s_lpD3DDEV))){
0189:                     // 結局失敗した
0190:                     MessageBox(NULL,"Direct3D の初期化に失敗しました。",CAPTION,MB_OK | MB_ICONSTOP);
0191:                     return E_FAIL;
0192:                 }
0193:             }
0194:         }
0195:     }
0196:     
0197:     return S_OK;
0198: }
0199: /*-------------------------------------------
0200:     ウィンドウ処理
0201: --------------------------------------------*/
0202: LRESULT CALLBACK MsgProc(HWND hWnd, UINT msg, UINT wParam, LONG lParam)
0203: {
0204:     static long prevX = 0;
0205:     static long prevY = 0;
0206:     static int sizeMoving = FALSE;
0207:     static wVertexShaderOld = IDM_DIFFUSE;
0208:     long x,y,dx,dy;
0209:     D3DXMATRIX m;
0210:     D3DXVECTOR3 v;
0211: 
0212:     switch(msg){
0213:         break;
0214:     case WM_LBUTTONDOWN:
0215:         prevX = (lParam << 16) >> 16;
0216:         prevY = lParam >> 16;
0217:         SetCapture(hWnd);
0218:         break;
0219:     case WM_LBUTTONUP:
0220:         ReleaseCapture();
0221:         break;
0222:     case WM_MOUSEMOVE:
0223:         x = (lParam << 16) >> 16;
0224:         y = lParam >> 16;
0225:         dx = x - prevX;
0226:         dy = y - prevY;
0227:         if(wParam & MK_LBUTTON){
0228:             if(sZoom){
0229:                 if(dy+dx != 0){
0230:                     D3DXVECTOR4 v = view.GetEye();
0231:                     v.z += 0.005f*v.z*dy;
0232:                     view.SetEye(v);
0233:                 }
0234:             }else{
0235:                 bool chg = false;
0236:                 if(dx != 0){
0237:                     rot.y -= 0.01f*dx; chg = true;
0238:                 }
0239:                 if(dy != 0){
0240:                     rot.x -= 0.01f*dy; chg = true;
0241:                 }
0242:             }
0243:         }else if(wParam & MK_RBUTTON){
0244:             if(dx != 0){
0245:                 lrot.y -= 0.005f*dx;
0246:             }
0247:             if(dy != 0){
0248:                 lrot.x -= 0.005f*dy;
0249:             }
0250:             if(dy != 0 || dx != 0) SetLight(s_lpD3DDEV, &lrot);
0251:         }
0252:         prevX = x;
0253:         prevY = y;
0254:         break;
0255:     case WM_KEYUP:
0256:         switch(wParam){
0257:         case VK_SHIFT:
0258:             sZoom = false;
0259:             break;
0260:         }
0261:         break;
0262:     case WM_KEYDOWN:
0263:         switch(wParam){
0264:         case VK_ESCAPE:
0265:         case VK_F12:
0266:             // 終了要求
0267:             s_end = true;
0268:             return 1;
0269:         case VK_SHIFT:
0270:             sZoom = true;
0271:             break;
0272:         default:
0273:             MyMsgProc(wParam);
0274:             break;
0275:         }
0276:         break;
0277:     case WM_COMMAND:
0278:         switch(LOWORD(wParam)){
0279:         case FILE_MENU_OPEN:
0280:             {
0281:             char filename[1024];
0282:             OPENFILENAME ofn;
0283:             filename[0] = '\0';
0284: 
0285:             ZeroMemory(&ofn,sizeof(ofn));
0286:             ofn.lStructSize = sizeof(ofn);
0287:             ofn.hwndOwner = hWnd;
0288:             ofn.hInstance = shInstApp;
0289:             ofn.lpstrFilter = ".X Files (.x)\0*.x\0";
0290:             ofn.lpstrTitle = "Load X-File";
0291:             ofn.lpstrFile = filename;
0292:             ofn.nMaxFile = 1024;
0293:             ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
0294:             if(GetOpenFileName(&ofn)){
0295:                 if(mesh.Load(s_lpD3DDEV, filename)){
0296:                     InvalidateRect(hWnd,NULL,TRUE);
0297:                 }
0298:             }
0299:             }
0300:             break;
0301:         case FILE_MENU_EXIT:
0302:             s_end = true;
0303:             return 1;
0304:             break;
0305:         case FILE_MENU_ABOUT:// バージョン情報
0306:             DialogBox(shInstApp, MAKEINTRESOURCE(IDD_ABOUT_DIALOG), hWnd, (DLGPROC)MyDlgProc);
0307:             break;
0308:         case IDM_DIFFUSE:
0309:         case IDM_SPECULAR:
0310:         case IDM_TEX_SPEC:
0311:         case IDM_METAL:
0312:         case IDM_HEMI:
0313:         case IDM_HEMI_AMB:
0314:         case IDM_HEMI_SPEC:
0315:         case IDM_SOFT:
0316:             gVs = wParam-IDM_DIFFUSE;
0317:             CheckMenuItem(GetMenu(hWnd), wVertexShaderOld, MF_UNCHECKED);
0318:             CheckMenuItem(GetMenu(hWnd), wParam,MF_CHECKED);
0319:             wVertexShaderOld = wParam;  
0320:             break;
0321:         case IDM_EDGE:// 輪郭抽出
0322:             gEdge = 1-gEdge;
0323:             CheckMenuItem(GetMenu(hWnd), wParam, gEdge?MF_CHECKED:MF_UNCHECKED);
0324:             break;
0325:         default:
0326:             break;
0327:         }
0328:         break;
0329:     case WM_CLOSE:                  // ×ボタンを押した
0330:         s_end = true;
0331:         return 1;
0332:         break;
0333:     default:
0334:         return DefWindowProc(hWnd,msg,wParam,lParam);
0335:     }
0336:     return 0L;
0337: }
0338: // ----------------------------------------------------------------------------
0339: // Name: set_fps()
0340: // Desc: フレーム数の表示
0341: //-----------------------------------------------------------------------------
0342: static void fps_disp()
0343: {
0344:     static DWORD    last = timeGetTime();
0345:     static DWORD    frames = 0;
0346:     static char     buf[256] = "";
0347:     DWORD           current;
0348:     
0349:     current = timeGetTime();
0350:     frames++;
0351:     
0352:     if(500 <= current - last) {// 0.5秒後とに更新
0353:         float dt = (float)(current - last) / 1000.0f;
0354:         float fps = (float)frames / dt;
0355:         last = current;
0356:         frames = 0;
0357:         sprintf(buf, "%.02f fps", fps);
0358:     }
0359:     sFont.Print(buf, 0,0);
0360: }
0361: // ----------------------------------------------------------------------------
0362: // Name: MyDlgProc
0363: // Desc: バージョン情報のプロシージャ
0364: //-----------------------------------------------------------------------------
0365: LRESULT CALLBACK MyDlgProc(HWND hDlgWnd, UINT msg, WPARAM wp, LPARAM lp)
0366: {
0367:     switch (msg) {
0368:     case WM_INITDIALOG:
0369:         return FALSE;
0370:     case WM_COMMAND:
0371:         switch (LOWORD(wp)) {
0372:             case IDOK:
0373:                 EndDialog(hDlgWnd, IDOK);
0374:                 break;
0375:             default:
0376:                 return FALSE;
0377:         }
0378:     default:
0379:         return FALSE;
0380:     }
0381:     return TRUE;
0382: }
0383: