0001: // ----------------------------------------------------------------------------
0002: //
0003: // draw.cpp - 描画部分
0004: // 
0005: // Copyright (c) 2001 if (if@edokko.com)
0006: // All Rights Reserved.
0007: //
0008: // ----------------------------------------------------------------------------
0009: #define STRICT
0010: 
0011: #include <windows.h>
0012: #include "main.h"
0013: #include "draw.h"
0014: #include "load.h"
0015: 
0016: LPDIRECT3DVERTEXBUFFER8 pMeshVB = NULL;
0017: LPDIRECT3DINDEXBUFFER8  pMeshIndex = NULL;
0018: D3DXATTRIBUTERANGE      *pSubsetTable = NULL;
0019: DWORD                   nMeshFaces = 0;
0020: DWORD                   nMeshVertices = 0;
0021: D3DMATERIAL8            *pMeshMaterials = NULL;     // メッシュの質感
0022: LPDIRECT3DTEXTURE8      *pMeshTextures  = NULL;     // メッシュのテクスチャー
0023: DWORD                   dwNumMaterials = 0L;        // マテリアルの数
0024: FLOAT                   MeshRadius;                 // メッシュの大きさ
0025: 
0026: DWORD                   hVertexShader=~0;           // モデルの描画
0027: DWORD                   hShadowVertexShader=~0;
0028: 
0029: 
0030: 
0031: // ----------------------------------------------------------------------------
0032: // 外部関数
0033: void InitBg(LPDIRECT3DDEVICE8 lpD3DDev);
0034: void DrawBg(LPDIRECT3DDEVICE8 lpD3DDev);
0035: void CleanBg(LPDIRECT3DDEVICE8 lpD3DDev);
0036: 
0037: 
0038: 
0039: // ----------------------------------------------------------------------------
0040: // Name: LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev)
0041: // Desc: X-Fileの読み込み
0042: //-----------------------------------------------------------------------------
0043: HRESULT LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev)
0044: {
0045:     LPD3DXMESH pMesh, pMeshOpt;
0046:     LPD3DXBUFFER pD3DXMtrlBuffer = NULL;
0047:     DWORD i;
0048:     HRESULT hr;
0049: 
0050:     hr = D3DXLoadMeshFromX(filename, D3DXMESH_MANAGED,
0051:                                 lpD3DDev, NULL,
0052:                                 &pD3DXMtrlBuffer, &dwNumMaterials,
0053:                                 &pMesh);
0054:     if(FAILED(hr)) return E_FAIL;
0055: 
0056:     //並び替えておく
0057:     pMesh->Optimize(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL, &pMeshOpt);
0058:     RELEASE(pMesh);
0059: 
0060:     //アトリビュートテーブル
0061:     pMeshOpt->GetAttributeTable(NULL,&dwNumMaterials);
0062:     pSubsetTable = new D3DXATTRIBUTERANGE[dwNumMaterials];
0063:     pMeshOpt->GetAttributeTable(pSubsetTable, &dwNumMaterials);
0064: 
0065:     // FVF変換
0066:     hr = pMeshOpt->CloneMeshFVF(pMeshOpt->GetOptions(), D3DFVF_VERTEX, lpD3DDev, &pMesh);
0067:     if(FAILED(hr)) return E_FAIL;
0068:     RELEASE(pMeshOpt);
0069:     D3DXComputeNormals(pMesh, NULL);
0070: 
0071:     //Vertex Bufferにコピーする
0072:     D3DVERTEX* pSrc;
0073:     D3D_CUSTOMVERTEX* pDest;
0074:     LPDIRECT3DINDEXBUFFER8 pSrcIndex;
0075:     WORD* pISrc;
0076:     WORD* pIDest;
0077: 
0078:     DWORD nMeshVertices = pMesh->GetNumVertices();
0079:     DWORD nMeshFaces = pMesh->GetNumFaces();
0080:     lpD3DDev->CreateVertexBuffer(nMeshVertices * sizeof(D3D_CUSTOMVERTEX),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_MANAGED,&pMeshVB);
0081:     lpD3DDev->CreateIndexBuffer(nMeshFaces * 3 * sizeof(WORD),0,D3DFMT_INDEX16,D3DPOOL_MANAGED,&pMeshIndex);
0082: 
0083:     LPDIRECT3DVERTEXBUFFER8 pVB;
0084:     pMesh->GetVertexBuffer(&pVB);
0085:     pVB->Lock(0,0,(BYTE**)&pSrc,0);
0086:     pMeshVB->Lock(0,0,(BYTE**)&pDest,0);
0087:     MeshRadius = 0.0f;
0088:     for(i=0;i<nMeshVertices;i++){
0089:         pDest->x = pSrc->x;
0090:         pDest->y = pSrc->y;
0091:         pDest->z = pSrc->z;
0092:         pDest->nx = pSrc->nx;
0093:         pDest->ny = pSrc->ny;
0094:         pDest->nz = pSrc->nz;
0095:         pDest->tu0 = pSrc->tu0;
0096:         pDest->tu0 = pSrc->tu0;
0097:         // サイズの計算
0098:         FLOAT radius = sqrtf( pSrc->x*pSrc->x + pSrc->y*pSrc->y + pSrc->z*pSrc->z );
0099:         if (MeshRadius < radius) MeshRadius = radius;
0100:         
0101:         pSrc += 1;
0102:         pDest += 1;
0103:     }
0104:     pVB->Unlock();
0105:     pVB->Release();
0106:     pMeshVB->Unlock();
0107: 
0108:     //インデックスのコピー
0109:     pMesh->GetIndexBuffer(&pSrcIndex);
0110:     pSrcIndex->Lock(0,0,(BYTE**)&pISrc,0);
0111:     pMeshIndex->Lock(0,0,(BYTE**)&pIDest,0);
0112:     CopyMemory(pIDest,pISrc,nMeshFaces * 3 * sizeof(WORD));
0113:     pSrcIndex->Unlock();
0114:     pMeshIndex->Unlock();
0115:     pSrcIndex->Release();
0116: 
0117:     // pD3DXMtrlBuffer から、質感やテクスチャーの情報を読み取る
0118:     D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
0119:     pMeshTextures = new LPDIRECT3DTEXTURE8[dwNumMaterials];
0120:     pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
0121: 
0122:     for(i = 0; i < dwNumMaterials; i++){
0123:         pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
0124:         pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;
0125:         hr = D3DXCreateTextureFromFile( lpD3DDev, 
0126:                                         d3dxMaterials[i].pTextureFilename, 
0127:                                         &pMeshTextures[i] );
0128:         if(FAILED(hr)) pMeshTextures[i] = NULL;
0129:     }
0130:     RELEASE(pD3DXMtrlBuffer);
0131:     
0132:     RELEASE(pMesh);
0133: 
0134:     return S_OK;
0135: }
0136: //-----------------------------------------------------------------------------
0137: // Name: InitRender()
0138: // Desc: Load the mesh and build the material and texture arrays
0139: //-----------------------------------------------------------------------------
0140: HRESULT InitRender(LPDIRECT3DDEVICE8 lpD3DDev)
0141: {
0142:     HRESULT hr;
0143: 
0144:     // モデルの読み込み
0145:     if ( FAILED(hr = LoadXFile("knot.x", lpD3DDev)) ) return hr;
0146:     
0147:     // バーテックスシェーダーを作成する
0148:     if ( FAILED(CVertexShaderMgr::Load(lpD3DDev, "vs.vsh",     &hVertexShader, dwDecl)) ) return hr;
0149:     if ( FAILED(CVertexShaderMgr::Load(lpD3DDev, "shadow.vsh",    &hShadowVertexShader, dwDecl)) ) return hr;
0150:     
0151:     // 背景部分の初期化
0152:     InitBg(lpD3DDev);
0153: 
0154:     // 不変なレジスタの設定
0155:     lpD3DDev->SetRenderState( D3DRS_ZENABLE, TRUE );
0156:     lpD3DDev->SetRenderState( D3DRS_LIGHTING,  FALSE );
0157:     lpD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE);
0158:     lpD3DDev->SetVertexShaderConstant(12, &D3DXVECTOR4(0.0f, 0.5f, 1.0f, 2.0f), 1);
0159: 
0160:     // デカール
0161:     lpD3DDev->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
0162:     lpD3DDev->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
0163:     lpD3DDev->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_NONE);
0164:     
0165:     return S_OK;
0166: }
0167: //-----------------------------------------------------------------------------
0168: // Name: Render()
0169: // Desc: Draws the scene
0170: //-----------------------------------------------------------------------------
0171: VOID DrawModel(LPDIRECT3DDEVICE8 lpD3DDev, BOOL bBg)
0172: {
0173:     D3DXMATRIX mVP,  mWorld, mView,  mProj;
0174:     D3DXMATRIX mVPL, mViewL, mProjL;
0175:     D3DXMATRIX  m;
0176:     D3DXVECTOR4 vl;
0177:     DWORD i;
0178:     
0179:     const D3DXVECTOR4 lightDir(1.0f, 1.0f, 0.5f, 0.0f);
0180:     const float shadow_scale = 10.0f;
0181: 
0182:     // 
0183:     // 通常レンダリング用の行列を作成
0184:     // 
0185:     // ビュー行列
0186:     D3DXVECTOR3 eye    = D3DXVECTOR3(0.0f,1.4f*MeshRadius,2.5f*MeshRadius);
0187:     D3DXVECTOR3 lookAt = D3DXVECTOR3(0.0f,  0.0f,  0.0f);
0188:     D3DXVECTOR3 up     = D3DXVECTOR3(0.0f,  1.0f,  0.0f);
0189:     D3DXMatrixLookAtLH(&mView, &eye, &lookAt, &up);
0190:     // 射影行列
0191:     D3DXMatrixPerspectiveFovLH(&mProj
0192:         , D3DXToRadian(60.0f)                       // 視野角
0193:         , (float)WIDTH/(float)HEIGHT                // アスペクト比
0194:         , 1.0f, 70.0f                               // 最近接距離,最遠方距離
0195:         );
0196:     
0197:     mVP = mView * mProj;
0198:     
0199: 
0200:     // 
0201:     // ライト方向からのレンダリング用の定数を作成
0202:     // 
0203:     D3DXVECTOR4 l_eye    = 30.0f*lightDir;
0204:     l_eye.w = 40.0f;
0205:     lpD3DDev->SetVertexShaderConstant(15,&l_eye, 1);
0206:     lpD3DDev->SetVertexShaderConstant(16,&D3DXVECTOR4(0,0,0,0.0001f), 1);
0207: 
0208:     //
0209:     // 外側もでる描画
0210:     //
0211:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG1,  D3DTA_DIFFUSE);
0212:     
0213:     int t = timeGetTime()%(314159*3);
0214:     D3DXMatrixTranslation(&m, MeshRadius, 0.05f*MeshRadius,0);
0215:     D3DXMatrixRotationY( &mWorld, t/1000.0f );
0216:     mWorld = m * mWorld;
0217:     
0218:     m = mWorld * mVP;
0219:     D3DXMatrixTranspose( &m ,  &m);
0220:     lpD3DDev->SetVertexShaderConstant(0,&m, 4);
0221: 
0222:     D3DXMatrixInverse( &m,  NULL, &mWorld);
0223:     D3DXVec4Transform(&vl, &lightDir, &m);
0224:     D3DXVec4Normalize(&vl, &vl);
0225:     vl[3] = 0.1f;// w成分は環境色の強さ
0226:     lpD3DDev->SetVertexShaderConstant(13, &vl, 1);
0227:     D3DXVec4Scale(&vl, &vl, shadow_scale);vl.w=0;
0228:     lpD3DDev->SetVertexShaderConstant(15, &vl, 1);
0229: 
0230:     lpD3DDev->SetStreamSource(0, pMeshVB, sizeof(D3D_CUSTOMVERTEX));
0231:     lpD3DDev->SetIndices(pMeshIndex,0);
0232:     
0233:     for(i=0;i<dwNumMaterials;i++){
0234:         //色をセット
0235:         D3DXVECTOR4 vl;
0236:         vl.x = pMeshMaterials[i].Diffuse.r;
0237:         vl.y = pMeshMaterials[i].Diffuse.g;
0238:         vl.z = pMeshMaterials[i].Diffuse.b;
0239:         lpD3DDev->SetVertexShaderConstant(14, &vl, 1);
0240: 
0241:         lpD3DDev->SetTexture(0,pMeshTextures[i]);
0242:         lpD3DDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 
0243:                                         pSubsetTable[i].VertexStart,
0244:                                         pSubsetTable[i].VertexCount,
0245:                                         pSubsetTable[i].FaceStart * 3,
0246:                                         pSubsetTable[i].FaceCount);
0247:     }
0248:     //
0249:     // モデル2
0250:     //
0251:     D3DXMatrixTranslation(&m, 0, 0.1f*MeshRadius, 0);
0252:     D3DXMatrixRotationY( &mWorld, -t/3000.0f );
0253:     mWorld=m*mWorld;
0254: 
0255:     m = mWorld * mVP;
0256:     D3DXMatrixTranspose( &m ,  &m);
0257:     lpD3DDev->SetVertexShaderConstant(0,&m, 4);
0258: 
0259:     D3DXMatrixInverse( &m,  NULL, &mWorld);
0260:     D3DXVec4Transform(&vl, &lightDir, &m);
0261:     D3DXVec4Normalize(&vl, &vl);
0262:     vl[3] = 0.1f;// w成分は環境色の強さ
0263:     lpD3DDev->SetVertexShaderConstant(13, &vl, 1);
0264:     D3DXVec4Scale(&vl, &vl, shadow_scale);vl.w=0;
0265:     lpD3DDev->SetVertexShaderConstant(15, &vl, 1);
0266:     
0267:     for(i=0;i<dwNumMaterials;i++){
0268:         //色をセット
0269:         D3DXVECTOR4 vl;
0270:         vl.x = pMeshMaterials[i].Diffuse.r;
0271:         vl.y = pMeshMaterials[i].Diffuse.g;
0272:         vl.z = pMeshMaterials[i].Diffuse.b;
0273:         lpD3DDev->SetVertexShaderConstant(14, &vl, 1);
0274: 
0275:         lpD3DDev->SetTexture(0,pMeshTextures[i]);
0276:         lpD3DDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 
0277:                                         pSubsetTable[i].VertexStart,
0278:                                         pSubsetTable[i].VertexCount,
0279:                                         pSubsetTable[i].FaceStart * 3,
0280:                                         pSubsetTable[i].FaceCount);
0281:     }
0282:     //
0283:     // 背景描画
0284:     // 
0285:     if(bBg){
0286:         D3DXMatrixScaling(&mWorld, 3.0f, 3.0f, 3.0f);
0287:         
0288:         m = mWorld * mVP;
0289:         D3DXMatrixTranspose( &m ,  &m);
0290:         lpD3DDev->SetVertexShaderConstant(0,&m, 4);
0291:         
0292:         lpD3DDev->SetVertexShaderConstant(13, &D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f), 1);
0293:         lpD3DDev->SetVertexShaderConstant(14, &D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f), 1);
0294:         lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG1,  D3DTA_TEXTURE);
0295:         DrawBg(lpD3DDev);
0296:     }
0297: }
0298: //-----------------------------------------------------------------------------
0299: // Name: Render()
0300: // Desc: Draws the scene
0301: //-----------------------------------------------------------------------------
0302: VOID Render(LPDIRECT3DDEVICE8 lpD3DDev)
0303: {
0304:     // 深度を初期化する
0305:     lpD3DDev->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL
0306:                     , D3DCOLOR_RGBA(0,0,0,0), 1.0f, 0L);
0307: 
0308:     // ------------------------------------------------------------------------
0309:     // 通常レンダリング
0310:     // ------------------------------------------------------------------------
0311:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLOROP,    D3DTOP_SELECTARG1);
0312:     lpD3DDev->SetVertexShader(hVertexShader);
0313:     DrawModel(lpD3DDev, 1);
0314: 
0315:     // ------------------------------------------------------------------------
0316:     // 影の作成
0317:     // ------------------------------------------------------------------------
0318:     lpD3DDev->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);// zバッファの更新無し
0319:     lpD3DDev->SetRenderState(D3DRS_STENCILENABLE, TRUE);// ステンシルバッファ使用
0320:     lpD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, 0);// 色は書かない
0321: 
0322:     lpD3DDev->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);// 常に合格
0323:     lpD3DDev->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);// z落ちはそのまま
0324:     lpD3DDev->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);
0325:     lpD3DDev->SetRenderState(D3DRS_STENCILREF, 1);// ステンシル基準値は1
0326:     lpD3DDev->SetRenderState(D3DRS_STENCILMASK, 0xffffffff);
0327:     lpD3DDev->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff);
0328:     lpD3DDev->SetVertexShader(hShadowVertexShader);
0329:     lpD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
0330:     DrawModel(lpD3DDev, 0);
0331:     
0332:     lpD3DDev->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_DECR);
0333:     lpD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
0334:     DrawModel(lpD3DDev, 0);
0335: 
0336:     lpD3DDev->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
0337:     lpD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
0338:     lpD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, 0xf);
0339: 
0340: 
0341:     // ------------------------------------------------------------------------
0342:     // 影の描画
0343:     // ------------------------------------------------------------------------
0344:     lpD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE);
0345:     lpD3DDev->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL);// ステンシルが0の時に描画
0346:     lpD3DDev->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);// ステンシル落ちは描画しない
0347:     lpD3DDev->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);// 描画時は何もしない
0348:     lpD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
0349:     lpD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
0350:     lpD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
0351:     lpD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); 
0352:     
0353:     {
0354:         typedef struct{
0355:             float   x, y, z, w;
0356:             DWORD   color;
0357:         } LVERTEX;
0358:         #define     FVF_LVERTEX         (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
0359:         lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG1,  D3DTA_DIFFUSE);
0360:         float size = 512.0f;
0361:         LVERTEX Vertex[4] = {
0362:             //  x   y  z rhw color
0363:             {   0,   0, 0, 1, D3DCOLOR_RGBA(0x0,0x0,0x0,0x80),},
0364:             {size,   0, 0, 1, D3DCOLOR_RGBA(0x0,0x0,0x0,0x80),},
0365:             {size,size, 0, 1, D3DCOLOR_RGBA(0x0,0x0,0x0,0x80),},
0366:             {   0,size, 0, 1, D3DCOLOR_RGBA(0x0,0x0,0x0,0x80),},
0367:         };
0368:         lpD3DDev->SetVertexShader( FVF_LVERTEX );
0369:         lpD3DDev->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, Vertex, sizeof( LVERTEX ) );
0370:     }
0371: 
0372:     // ------------------------------------------------------------------------
0373:     // 元に戻す
0374:     // ------------------------------------------------------------------------
0375:     lpD3DDev->SetRenderState(D3DRS_ZENABLE, TRUE);
0376:     lpD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE);
0377:     lpD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
0378: }
0379: //-----------------------------------------------------------------------------
0380: // メッシュオブジェクト削除
0381: //-----------------------------------------------------------------------------
0382: void DeleteMeshObject(void)
0383: {
0384:     DWORD i;
0385: 
0386:     if(pMeshVB == NULL) return;
0387: 
0388:     for(i=0; i<dwNumMaterials; i++){
0389:         RELEASE(pMeshTextures[i]);
0390:     }
0391:     delete[] pMeshTextures;
0392:     delete[] pMeshMaterials;
0393:     delete[] pSubsetTable;
0394: 
0395:     RELEASE(pMeshVB);
0396:     RELEASE(pMeshIndex);
0397: }
0398: //-----------------------------------------------------------------------------
0399: // Name: CleanRender()
0400: // Desc: 後始末
0401: //-----------------------------------------------------------------------------
0402: void CleanRender(LPDIRECT3DDEVICE8 lpD3DDev)
0403: {
0404:     CleanBg(lpD3DDev);
0405:     
0406:     CVertexShaderMgr::Release(lpD3DDev, &hShadowVertexShader);
0407:     CVertexShaderMgr::Release(lpD3DDev, &hVertexShader);
0408:     
0409:     DeleteMeshObject();
0410: }
0411: