0001: // ----------------------------------------------------------------------------
0002: //
0003: // draw.cpp - 描画部分
0004: // 
0005: // Copyright (c) 2002 IF (imagire@gmail.com)
0006: // All Rights Reserved.
0007: //
0008: // ----------------------------------------------------------------------------
0009: #define STRICT
0010: 
0011: #include <windows.h>
0012: #include "Cg/cgD3D.h"
0013: #include "main.h"
0014: #include "load.h"
0015: #include "draw.h"
0016: 
0017: // ----------------------------------------------------------------------------
0018: // オブジェクト
0019: // ----------------------------------------------------------------------------
0020: // Cg 環境
0021: cgDirect3D cg;
0022: cgContextContainer * pCg = 0;
0023: 
0024: // モデル
0025: CMyMesh mesh;
0026: D3DXVECTOR4 position    = D3DXVECTOR4(0.0f, 0.0f, 0.0f, 1.0f);  // 位置
0027: D3DXVECTOR4 velosity    = D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f);  // 速度
0028: D3DXVECTOR4 angle       = D3DXVECTOR4(0.0f,-0.5f*D3DX_PI, 0.0f, 0.0f);  // 角度角速度
0029: D3DXVECTOR4 angler_vel  = D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f);  // 座標
0030: float       mouse[2]={150.f,200.f};
0031: D3DXVECTOR4 position1   = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);  // 位置
0032: 
0033: // 頂点シェーダー
0034: cgProgramContainer *pVs = 0;            // 頂点シェーダー
0035: cgBindIter * vertex_mat_iter = 0;       // ローカル/射影変換
0036: cgBindIter * mat0_iter = 0;             // 行列0
0037: cgBindIter * mat1_iter = 0;             // 行列1
0038: cgBindIter * diffuse_iter    = 0;       // 頂点色
0039: cgBindIter * light_iter      = 0;       // 光源方向
0040: // ピクセルシェーダー
0041: cgProgramContainer  *pPs = 0;           // ピクセルシェーダー
0042: cgBindIter * tex0_iter = 0;             // テクスチャー
0043: 
0044: // シェーダーに渡す
0045: cgVertexAttribute vertex_attributes[] = {
0046:     {4, "Position", 0},
0047:     {4, "Weight", 0},
0048:     {4, "Normal", 0},
0049:     {2, "Texcoord0", 0},
0050:     {0, 0, 0}
0051: };
0052: 
0053: // ----------------------------------------------------------------------------
0054: // カメラ
0055: CMyView view;
0056: 
0057: // ----------------------------------------------------------------------------
0058: // 外部関数
0059: void InitBg(LPDIRECT3DDEVICE8 lpD3DDev, cgContextContainer *pContextCntnr);
0060: void DrawBg(LPDIRECT3DDEVICE8 lpD3DDev, D3DXMATRIX &mVP);
0061: void CleanBg(LPDIRECT3DDEVICE8 lpD3DDev);
0062: 
0063: 
0064: //-----------------------------------------------------------------------------
0065: // Name: InitRender()
0066: // Desc: 初期化
0067: //-----------------------------------------------------------------------------
0068: HRESULT InitRender(LPDIRECT3DDEVICE8 lpD3DDev)
0069: {
0070:     // ==================================================
0071:     // プログラマぶるシェーダーを使えるようにする
0072:     // ==================================================
0073:     cg.AddFilePath("..");
0074:     pCg = cg.CreateContextContainer(lpD3DDev);
0075:     
0076:     // ==================================================
0077:     // モデルの読み込み
0078:     // ==================================================
0079:     mesh.Load(lpD3DDev, "arrow.x");
0080:     
0081:     // ==================================================
0082:     // 頂点シェーダー
0083:     // ==================================================
0084:     pVs = pCg->LoadCGProgramFromFile(
0085:         "vs.cg", "Vertex Shader", cgDX8VertexProfile, vertex_attributes);
0086:     
0087:     if (pVs == NULL) {
0088:         // エラー表示
0089:         const char * listing = pCg->GetLastListing();
0090:         if (listing == 0) listing = "Could not find cgc.exe.";
0091:         cg.NotePad("頂点シェーダープログラムの生成に失敗しました\n\n", listing);    // メモ帳に出力
0092: 
0093:         exit(1);    // 終了
0094:     }
0095: 
0096:     // 頂点データの反復子と、.cg ファイルの引数を関連付ける
0097:     vertex_mat_iter = pVs->GetParameterBindByName("worldviewproj_matrix");
0098:     mat0_iter       = pVs->GetParameterBindByName("m0");
0099:     mat1_iter       = pVs->GetParameterBindByName("m1");
0100:     light_iter      = pVs->GetParameterBindByName("light");
0101:     diffuse_iter    = pVs->GetParameterBindByName("diffuse");
0102: 
0103: //  cg.NotePad("", pVs->GetProgramObjectCode());    // 生成されたソースコードが表示される
0104: //  cg.NotePad("入力すべき頂点情報は次のとおりです:\n", pVs->GetVertexDeclaration());// 入力すべき頂点情報が表示される
0105: 
0106:     // ==================================================
0107:     // ピクセルシェーダー
0108:     // ==================================================
0109:     pPs = pCg->LoadCGProgramFromFile(
0110:         "ps.cg", "test", cgDX8PixelProfile);
0111: 
0112:     // テクスチャーの反復子と、.cg ファイルの引数を関連付ける
0113:     tex0_iter = pPs->GetTextureBindByName("tex0");
0114:     pPs->GetTexturePosition(tex0_iter);
0115: 
0116: //  cg.NotePad("", pPs->GetProgramObjectCode());// 生成されたソースコードが表示される
0117:    
0118:     // ==================================================
0119:     // 背景部分の初期化
0120:     // ==================================================
0121:     InitBg(lpD3DDev, pCg);
0122:     
0123:     // ==================================================
0124:     // 不変なレジスタの設定
0125:     // ==================================================
0126:     lpD3DDev->SetRenderState( D3DRS_ZENABLE, TRUE );
0127:     lpD3DDev->SetRenderState( D3DRS_LIGHTING,  FALSE );
0128:     lpD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE);
0129: 
0130:     // 光の向き
0131:     D3DXVECTOR4 lightDir(1.0f, 1.0f, 1.0f, 0.0f);
0132:     D3DXVec4Normalize(&lightDir, &lightDir);
0133:     lightDir[3] = 0.3f;// 環境光の強さ
0134:     pVs->SetShaderConstant( light_iter, &lightDir  );
0135: 
0136:     return S_OK;
0137: }
0138: 
0139: //-----------------------------------------------------------------------------
0140: // Name: FrameMove()
0141: // Desc: 矢印を動かす
0142: //-----------------------------------------------------------------------------
0143: VOID FrameMove(LPDIRECT3DDEVICE8 lpD3DDev, const D3DXMATRIX &mWS)
0144: {
0145:     float d;
0146: 
0147:     velosity.y -= 0.001f;   // 重力
0148:     velosity.x = min(max(velosity.x,-0.3f),0.3f);
0149:     velosity.y = min(max(velosity.y,-0.3f),0.3f);
0150:     velosity.z = min(max(velosity.z,-0.3f),0.3f);
0151:     velosity.y *= 0.99f;    // 抵抗
0152:     if(position.y < 0.01f){ // 摩擦
0153:         d = 0.99f*velosity.x;
0154:         if(-0.005f<d && d<+0.005f)d*=0.9f;
0155:         velosity.x = d;
0156:         d = 0.99f*velosity.z;
0157:         if(-0.005f<d && d<+0.005f)d*=0.9f;
0158:         velosity.z = d;
0159:     }
0160:     position += velosity;
0161: 
0162:     // 床の反射
0163:     if(position.y < 0.0f){
0164:         position.y = 0.0f;
0165:         velosity.y = -0.8f*velosity.y;
0166:     }
0167: 
0168:     if(position.y < 0.01f) angler_vel = 0.99f*angler_vel;   // 摩擦
0169:     angle += angler_vel;
0170: 
0171:     D3DXMATRIX m;
0172:     D3DXVECTOR4 v = D3DXVECTOR4(0,0,0,1);
0173:     D3DXVECTOR4 target;
0174:     static D3DXVECTOR4 vel = D3DXVECTOR4(0,0,0,0);
0175:     D3DXVec4Transform (&v, &v, &mWS);
0176:     D3DXMatrixInverse(&m, NULL, &mWS);
0177:     v.x = ( 2.0f*mouse[0]/ WIDTH-1.0f)*v[3];
0178:     v.y = (-2.0f*mouse[1]/HEIGHT+0.5f)*v[3];
0179:     D3DXVec4Transform (&target, &v, &m);
0180:     if(target.x < position1.x) vel.x -= 0.001f;
0181:     if(position1.x < target.x) vel.x += 0.001f;
0182:     if(target.y < position1.y) vel.y -= 0.001f;
0183:     if(position1.y < target.y) vel.y += 0.001f;
0184:     if(target.z < position1.z) vel.z -= 0.001f;
0185:     if(position1.z < target.z) vel.z += 0.001f;
0186:     
0187:     vel.x *= 0.99f;
0188:     vel.y *= 0.99f;
0189:     vel.z *= 0.99f;
0190:     
0191:     vel.x = min(max(vel.x,-0.1f),0.1f);
0192:     vel.y = min(max(vel.y,-0.1f),0.1f);
0193:     vel.z = min(max(vel.z,-0.1f),0.1f);
0194: 
0195:     if(target.x < position1.x && position1.x < target.x+vel.x) position1.x = target.x;
0196:     if(target.y < position1.y && position1.y < target.y+vel.y) position1.y = target.y;
0197:     if(target.z < position1.z && position1.z < target.z+vel.z) position1.z = target.z;
0198:     
0199:     if(position1.x < target.x && target.x+vel.x < position1.x) position1.x = target.x;
0200:     if(position1.y < target.y && target.y+vel.y < position1.y) position1.y = target.y;
0201:     if(position1.z < target.z && target.z+vel.z < position1.z) position1.z = target.z;
0202: 
0203:     position1 += vel;
0204: 
0205: }
0206: 
0207: //-----------------------------------------------------------------------------
0208: // Name: Render()
0209: // Desc: Draws the scene
0210: //-----------------------------------------------------------------------------
0211: VOID Render(LPDIRECT3DDEVICE8 lpD3DDev)
0212: {
0213:     D3DXMATRIX mWorld, mProj, m, m0, m1;
0214:     
0215:     // 射影行列
0216:     D3DXMatrixPerspectiveFovLH(&mProj
0217:         ,60.0f*D3DX_PI/180.0f                       // 視野角
0218:         ,(float)WIDTH/(float)HEIGHT             // アスペクト比
0219:         ,0.01f,100.0f                           // 最近接距離,最遠方距離
0220:         );
0221:     D3DXMATRIX mWS = view.Get() * mProj;
0222:     //
0223:     // 描画
0224:     // 
0225:     DrawBg(lpD3DDev, mWS);
0226: 
0227:     //
0228:     // モデル
0229:     // 
0230:     FrameMove(lpD3DDev, mWS); // 動かす
0231:     
0232:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLOROP,    D3DTOP_MODULATE);
0233:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG1,  D3DTA_TEXTURE);
0234:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG2,  D3DTA_DIFFUSE);
0235:     lpD3DDev->SetTextureStageState(1,D3DTSS_COLOROP,    D3DTOP_DISABLE);
0236: 
0237:     // プログラマぶるシェーダーを有効にする
0238:     pVs->SetShaderActive();
0239:     pPs->SetShaderActive();
0240:     
0241:     D3DXMatrixTranslation(&m0 , position.x, position.y, position.z);
0242:     D3DXMatrixRotationX(&m, angle.x );  m0 = m * m0;
0243:     D3DXMatrixRotationY(&m, angle.y );  m0 = m * m0;
0244:     D3DXMatrixRotationZ(&m, angle.z );  m0 = m * m0;
0245: 
0246:     D3DXMATRIX mT, mTi, mR;
0247:     D3DXVECTOR3 up = D3DXVECTOR3(0.0f,1.0f,0.0f);
0248:     D3DXVECTOR3 v = *(D3DXVECTOR3*)&position1-D3DXVECTOR3(0.0f,0.4f,0.0f);
0249:     D3DXVECTOR3 e1, e2, e3;
0250:     D3DXVec3Cross(&e1, &v,  &up);D3DXVec3Normalize(&e1,&e1);
0251:     D3DXVec3Cross(&e2, &e1, &v );D3DXVec3Normalize(&e2,&e2);
0252:     D3DXVec3Cross(&e3, &e1, &e2);D3DXVec3Normalize(&e3,&e3);
0253:     D3DXMatrixIdentity(&mR);
0254:     mR._11 = e1.x;  mR._12 = e1.y;  mR._13 = e1.z;
0255:     mR._21 =-e3.x;  mR._22 =-e3.y;  mR._23 =-e3.z;
0256:     mR._31 = e2.x;  mR._32 = e2.y;  mR._33 = e2.z;
0257:     D3DXMatrixTranslation(&mT , 0.0f, 1.0f, 0.0f);
0258:     D3DXMatrixTranslation(&mTi, 0.0f,-1.0f, 0.0f);
0259:     D3DXMatrixTranslation(&m1, position1.x, position1.y, position1.z);
0260:     m1 = mTi*mR*mT*m1;
0261: 
0262:     // 行列を設定
0263:     pVs->SetShaderConstant( vertex_mat_iter,D3DXMatrixTranspose( &m, &mWS )  );
0264:     pVs->SetShaderConstant( mat0_iter,      D3DXMatrixTranspose( &m, &m0 )  );
0265:     pVs->SetShaderConstant( mat1_iter,      D3DXMatrixTranspose( &m, &m1 )  );
0266: 
0267:     lpD3DDev->SetStreamSource(0, mesh.pVB, sizeof(D3D_CUSTOMVERTEX));
0268:     lpD3DDev->SetIndices(mesh.pIndex,0);
0269:     
0270:     for(DWORD i=0;i<mesh.dwNumMaterials;i++){
0271:         //色をセット
0272:         D3DXVECTOR4 vl(
0273:             mesh.pMaterials[i].Diffuse.r,
0274:             mesh.pMaterials[i].Diffuse.g,
0275:             mesh.pMaterials[i].Diffuse.b,
0276:             1.0f);
0277:         pVs->SetShaderConstant( diffuse_iter, &vl  );
0278:         pPs->SetTexture(tex0_iter, mesh.pTextures[i]);
0279: 
0280:         lpD3DDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 
0281:                                         mesh.pSubsetTable[i].VertexStart,
0282:                                         mesh.pSubsetTable[i].VertexCount,
0283:                                         mesh.pSubsetTable[i].FaceStart * 3,
0284:                                         mesh.pSubsetTable[i].FaceCount);
0285:     }
0286: 
0287: }
0288: //-----------------------------------------------------------------------------
0289: // Name: CleanRender()
0290: // Desc: 後始末
0291: //-----------------------------------------------------------------------------
0292: void CleanRender(LPDIRECT3DDEVICE8 lpD3DDev)
0293: {
0294:     CleanBg(lpD3DDev);
0295: 
0296:     mesh.Release();
0297: }
0298: //-----------------------------------------------------------------------------
0299: // 簡易カメラ設定
0300: static void set_camera(float cam_r, float cam_theta, float cam_phi, const D3DXVECTOR4 &cam_tr)
0301: {
0302:     D3DXVECTOR4 v = cam_tr;
0303:     view.SetLookAt(v);
0304:     v.z += cam_r * cos(cam_phi) * cos(cam_theta);
0305:     v.x += cam_r * cos(cam_phi) * sin(cam_theta);
0306:     v.y += cam_r * sin(cam_phi);
0307:     view.SetEye(v);
0308: }
0309: //-----------------------------------------------------------------------------
0310: // Name: MyMsgProc()
0311: // Desc: イベント処理
0312: //-----------------------------------------------------------------------------
0313: LRESULT CALLBACK MyMsgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
0314: {
0315:     static int  type = 0;   // 1:オブジェ制御 2:カメラ移動 2:オブジェ移動
0316:     // マウス位置
0317:     static long prevX = 0;
0318:     static long prevY = 0;
0319:     long x,y,dx,dy;
0320:     // カメラ
0321:     static D3DXVECTOR4 cam_tr = D3DXVECTOR4(0.0f, 0.5f, 0.0f, 0.0f);
0322:     static float cam_r      = 3.0f;
0323:     static float cam_theta  = 0.0f;
0324:     static float cam_phi    = 0.1f*D3DX_PI;
0325: 
0326:     switch(msg){
0327:     case WM_CREATE:
0328:         set_camera(cam_r, cam_theta, cam_phi, cam_tr);
0329:         break;
0330:     case WM_LBUTTONDOWN:
0331:     case WM_RBUTTONDOWN:
0332:         if(0==type)type = 1;
0333:         prevX = (lParam << 16) >> 16;
0334:         prevY = lParam >> 16;
0335:         if(WM_LBUTTONDOWN==msg&&type == 1){
0336:             mouse[0] = prevX;
0337:             mouse[1] = prevY;
0338:         }
0339:         // ボタンを押している間はマウスが出ても制御は持ったまま
0340:         SetCapture(hWnd);
0341:         break;
0342:     case WM_LBUTTONUP:
0343:     case WM_RBUTTONUP:
0344:         if(1==type)type = 0;
0345:         ReleaseCapture();
0346:         break;
0347:     case WM_MOUSEMOVE:
0348:         x = (lParam << 16) >> 16;
0349:         y = lParam >> 16;
0350:         dx = x - prevX;
0351:         dy = y - prevY;
0352:         switch(type){
0353:         case 1:// オブジェクト
0354:             if(wParam & MK_LBUTTON){
0355:                 mouse[0] = x;
0356:                 mouse[1] = y;
0357:             }else
0358:             if(wParam & MK_RBUTTON){
0359:                 velosity.y   -= 0.0020f*dy;
0360:                 angler_vel.y -= 0.0005f*dx;
0361:             }
0362:             break;
0363:         case 3:// オブジェクト移動
0364:             if(wParam & MK_RBUTTON){
0365:                 velosity.x -= 0.0001f*( dx * cos(cam_theta) - dy * sin(cam_theta));
0366:                 velosity.z += 0.0001f*( dx * sin(cam_theta) + dy * cos(cam_theta));
0367:             }
0368:             break;
0369:         case 2:// カメラ
0370:             if(wParam & MK_LBUTTON){
0371:                 if(dy != 0){
0372:                     cam_phi += 0.005f*dy;
0373:                     if( 0.499f*D3DX_PI<cam_phi)cam_phi = 0.499f*D3DX_PI;
0374:                     if(cam_phi<-0.499f*D3DX_PI)cam_phi =-0.499f*D3DX_PI;
0375:                     set_camera(cam_r, cam_theta, cam_phi, cam_tr);
0376:                 }
0377:                 if(dx != 0){
0378:                     cam_theta += 0.005f*dx;
0379:                     set_camera(cam_r, cam_theta, cam_phi, cam_tr);
0380:                 }
0381:             }else
0382:             if(wParam & MK_RBUTTON){
0383:                 cam_tr.x += 0.005f*( dx * cos(cam_theta) + dy * sin(cam_theta));
0384:                 cam_tr.z += 0.005f*(-dx * sin(cam_theta) + dy * cos(cam_theta));
0385:                 set_camera(cam_r, cam_theta, cam_phi, cam_tr);
0386:             }
0387:             break;
0388:         }
0389:         prevX = x;
0390:         prevY = y;
0391:         break;
0392:     case 0x020A:// WM_MOUSEWHEEL    // make がとおらなかったので直地指定
0393:         switch(type){
0394:         case 2:// カメラ
0395:             cam_r += 0.001f*(float)(short)HIWORD(wParam);
0396:             if(cam_r<=0.1f)cam_r = 0.1f;
0397:             set_camera(cam_r, cam_theta, cam_phi, cam_tr);
0398:             break;
0399:         }
0400:         break;
0401:     case WM_KEYDOWN:
0402:         switch(wParam){
0403:         case VK_SHIFT:
0404:             if(0==type)type = 2;
0405:             break;
0406:         case VK_CONTROL:
0407:             if(0==type)type = 3;
0408:             break;
0409:         default:
0410:             break;
0411:         }
0412:         break;
0413:     case WM_KEYUP:
0414:         switch(wParam){
0415:         case VK_SHIFT:
0416:         case VK_CONTROL:
0417:             if(2==type)type = 0;
0418:             if(3==type)type = 0;
0419:             break;
0420:         }
0421:         break;
0422:     }
0423: 
0424:     return 0L;
0425: }