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