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: 
0015: void InitBg(LPDIRECT3DDEVICE8 lpD3DDev);
0016: void DrawBg(LPDIRECT3DDEVICE8 lpD3DDev, D3DXMATRIX &mV, D3DXMATRIX &mP );
0017: void CleanBg(LPDIRECT3DDEVICE8 lpD3DDev);
0018: 
0019: 
0020: LPDIRECT3DVERTEXBUFFER8 pMeshVB = NULL;
0021: LPDIRECT3DINDEXBUFFER8  pMeshIndex = NULL;
0022: D3DXATTRIBUTERANGE      *pSubsetTable = NULL;
0023: DWORD                   nMeshFaces = 0;
0024: DWORD                   nMeshVertices = 0;
0025: D3DMATERIAL8            *pMeshMaterials = NULL;     // メッシュの質感
0026: LPDIRECT3DTEXTURE8      *pMeshTextures  = NULL;     // メッシュのテクスチャー
0027: DWORD                   dwNumMaterials = 0L;        // マテリアルの数
0028: 
0029: DWORD                   hVertexShader=~0;
0030: 
0031: FLOAT                   MeshRadius;                 // メッシュの多さ
0032: 
0033: 
0034: 
0035: 
0036: 
0037: // ----------------------------------------------------------------------------
0038: // 頂点の定義
0039: 
0040: typedef struct {
0041:     float x,y,z;
0042:     float nx,ny,nz;
0043:     float tu0,tv0;
0044: }D3DVERTEX;
0045: #define D3DFVF_VERTEX       (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
0046: 
0047: typedef struct {
0048:     float x,y,z;
0049:     float nx,ny,nz;
0050:     float tu0,tv0;
0051: }D3D_CUSTOMVERTEX;
0052: #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL)
0053: 
0054: static DWORD dwDecl[] = {
0055:     D3DVSD_STREAM(0),
0056:     D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3 ),          //D3DVSDE_POSITION,  0
0057:     D3DVSD_REG(D3DVSDE_NORMAL,   D3DVSDT_FLOAT3 ),          //D3DVSDE_NORMAL,    3
0058:     D3DVSD_REG(D3DVSDE_TEXCOORD0,D3DVSDT_FLOAT2 ),          //D3DVSDE_TEXCOORD0, 7  
0059:     D3DVSD_END()
0060: };
0061: 
0062: // ----------------------------------------------------------------------------
0063: // Name: LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev)
0064: // Desc: X-Fileの読み込み
0065: //-----------------------------------------------------------------------------
0066: HRESULT LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev)
0067: {
0068:     LPD3DXMESH pMesh, pMeshOpt;
0069:     LPD3DXBUFFER pD3DXMtrlBuffer = NULL;
0070:     DWORD i;
0071:     HRESULT hr;
0072: 
0073:     hr = D3DXLoadMeshFromX(filename, D3DXMESH_MANAGED,
0074:                                 lpD3DDev, NULL,
0075:                                 &pD3DXMtrlBuffer, &dwNumMaterials,
0076:                                 &pMesh);
0077:     if(FAILED(hr)) return E_FAIL;
0078: 
0079:     //並び替えておく
0080:     pMesh->Optimize(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL, &pMeshOpt);
0081:     RELEASE(pMesh);
0082: 
0083:     //アトリビュートテーブル
0084:     pMeshOpt->GetAttributeTable(NULL,&dwNumMaterials);
0085:     pSubsetTable = new D3DXATTRIBUTERANGE[dwNumMaterials];
0086:     pMeshOpt->GetAttributeTable(pSubsetTable, &dwNumMaterials);
0087: 
0088:     // FVF変換
0089:     hr = pMeshOpt->CloneMeshFVF(pMeshOpt->GetOptions(), D3DFVF_VERTEX, lpD3DDev, &pMesh);
0090:     if(FAILED(hr)) return E_FAIL;
0091:     RELEASE(pMeshOpt);
0092:     D3DXComputeNormals(pMesh, NULL);
0093: 
0094:     //Vertex Bufferにコピーする
0095:     D3DVERTEX* pSrc;
0096:     D3D_CUSTOMVERTEX* pDest;
0097:     LPDIRECT3DINDEXBUFFER8 pSrcIndex;
0098:     WORD* pISrc;
0099:     WORD* pIDest;
0100: 
0101:     DWORD nMeshVertices = pMesh->GetNumVertices();
0102:     DWORD nMeshFaces = pMesh->GetNumFaces();
0103:     lpD3DDev->CreateVertexBuffer(nMeshVertices * sizeof(D3D_CUSTOMVERTEX),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_MANAGED,&pMeshVB);
0104:     lpD3DDev->CreateIndexBuffer(nMeshFaces * 3 * sizeof(WORD),0,D3DFMT_INDEX16,D3DPOOL_MANAGED,&pMeshIndex);
0105: 
0106:     LPDIRECT3DVERTEXBUFFER8 pVB;
0107:     pMesh->GetVertexBuffer(&pVB);
0108:     pVB->Lock(0,0,(BYTE**)&pSrc,0);
0109:     pMeshVB->Lock(0,0,(BYTE**)&pDest,0);
0110:     MeshRadius = 0.0f;
0111:     for(i=0;i<nMeshVertices;i++){
0112:         pDest->x = pSrc->x;
0113:         pDest->y = pSrc->y;
0114:         pDest->z = pSrc->z;
0115:         pDest->nx = pSrc->nx;
0116:         pDest->ny = pSrc->ny;
0117:         pDest->nz = pSrc->nz;
0118:         // サイズの計算
0119:         FLOAT radius = sqrtf( pSrc->x*pSrc->x + pSrc->y*pSrc->y + pSrc->z*pSrc->z );
0120:         if (MeshRadius < radius) MeshRadius = radius;
0121:         
0122:         pSrc += 1;
0123:         pDest += 1;
0124:     }
0125:     pVB->Unlock();
0126:     pVB->Release();
0127:     pMeshVB->Unlock();
0128: 
0129:     //インデックスのコピー
0130:     pMesh->GetIndexBuffer(&pSrcIndex);
0131:     pSrcIndex->Lock(0,0,(BYTE**)&pISrc,0);
0132:     pMeshIndex->Lock(0,0,(BYTE**)&pIDest,0);
0133:     CopyMemory(pIDest,pISrc,nMeshFaces * 3 * sizeof(WORD));
0134:     pSrcIndex->Unlock();
0135:     pMeshIndex->Unlock();
0136:     pSrcIndex->Release();
0137: 
0138:     // pD3DXMtrlBuffer から、質感やテクスチャーの情報を読み取る
0139:     D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
0140:     pMeshTextures = new LPDIRECT3DTEXTURE8[dwNumMaterials];
0141:     pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
0142: 
0143:     for(i = 0; i < dwNumMaterials; i++){
0144:         pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
0145:         pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;
0146:         hr = D3DXCreateTextureFromFile( lpD3DDev, 
0147:                                         d3dxMaterials[i].pTextureFilename, 
0148:                                         &pMeshTextures[i] );
0149:         if(FAILED(hr)) pMeshTextures[i] = NULL;
0150:     }
0151:     RELEASE(pD3DXMtrlBuffer);
0152:     
0153:     RELEASE(pMesh);
0154: 
0155:     return S_OK;
0156: }
0157: // ----------------------------------------------------------------------------
0158: // Name: LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev)
0159: // Desc: 頂点シェーダープログラムの読み込み
0160: //-----------------------------------------------------------------------------
0161: HRESULT LoadVertexShader(char* filename, LPDIRECT3DDEVICE8 lpD3DDev, DWORD *phVertexShader, const DWORD *dwDecl)
0162: {
0163:     HRESULT hr;
0164:     ID3DXBuffer *pshader;
0165:     
0166:     if ( FAILED(hr = D3DXAssembleShaderFromFile(filename, 0,NULL,&pshader,NULL)) ) return hr;
0167:     
0168:     hr = lpD3DDev->CreateVertexShader( dwDecl, (DWORD*)pshader->GetBufferPointer(), phVertexShader, 0 );
0169:     RELEASE(pshader);
0170:     if ( FAILED(hr) ) return hr;
0171:     
0172:     return S_OK;
0173: }
0174: //-----------------------------------------------------------------------------
0175: // Name: InitRender()
0176: // Desc: Load the mesh and build the material and texture arrays
0177: //-----------------------------------------------------------------------------
0178: HRESULT InitRender(LPDIRECT3DDEVICE8 lpD3DDev)
0179: {
0180:     HRESULT hr;
0181: 
0182:     // モデルの読み込み
0183:     if ( FAILED(hr = LoadXFile("nsx.x", lpD3DDev)) ) return hr;
0184:     
0185:     // バーテックスシェーダーを作成する
0186:     if ( FAILED(hr = LoadVertexShader("vs.vsh", lpD3DDev, &hVertexShader, dwDecl)) ) return hr;
0187: 
0188:     InitBg(lpD3DDev);
0189: 
0190:     lpD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE);
0191: 
0192:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLOROP,    D3DTOP_MODULATE);
0193:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG1,  D3DTA_TEXTURE);
0194:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG2,  D3DTA_DIFFUSE);
0195: 
0196:     lpD3DDev->SetVertexShader(hVertexShader);
0197:     lpD3DDev->SetVertexShaderConstant(12, &D3DXVECTOR4(0.0f, 0.5f, 1.0f, 2.0f), 1);
0198: 
0199:     // フォグの設定
0200:     float start = 0.0f;
0201:     float end   = 1.0f;
0202:     lpD3DDev->SetRenderState(D3DRS_FOGENABLE, TRUE);                // フォグ ブレンディングを有効にする。
0203:     lpD3DDev->SetRenderState(D3DRS_FOGCOLOR, 0x000000);             // フォグの色を設定する。
0204:     lpD3DDev->SetRenderState(D3DRS_FOGSTART, *((DWORD *)(&start))); // 0 からかかりはじめる
0205:     lpD3DDev->SetRenderState(D3DRS_FOGEND,   *((DWORD *)(&end)) );  // 1で完全に見えなくなる
0206: 
0207:     return S_OK;
0208: }
0209: 
0210: 
0211: //-----------------------------------------------------------------------------
0212: // Name: Render()
0213: // Desc: Draws the scene
0214: //-----------------------------------------------------------------------------
0215: VOID Render(LPDIRECT3DDEVICE8 lpD3DDev)
0216: {
0217:     DWORD cnt = timeGetTime()%10000;
0218:     float t = (float)cnt/1000.0f;
0219: 
0220:     float Near;
0221:     float Far;
0222:     float max = 100.0f;
0223: 
0224:     // 頂点シェーダーのフォグに関するパラメータ 
0225:     if(t < 3.0f){
0226:         // フェードイン
0227:         t /= 3.0f;
0228:         Near = max*(t-0.15f);
0229:         Far  = max*(t-0.0f);
0230:     }else
0231:     if( t < 5.0f){
0232:         // 明るい
0233:         Near = max-0.1f; 
0234:         Far  = max;
0235:     }else
0236:     if( t < 8.0f){
0237:         // フェードアウト
0238:         t = 8.0f-t;
0239:         t /= 3.0f;// これで、tは1.0fから0.0fと動くので、フェードインの逆になる
0240:         Near = max*(t-0.15f);
0241:         Far  = max*(t-0.0f);
0242:     }else{
0243:         // 暗い
0244:         Near = -0.1f;
0245:         Far  =  0.0f;
0246:     }
0247:     if(Far-Near<0.1f)Near=Far-0.1f;
0248:     lpD3DDev->SetVertexShaderConstant(16, &D3DXVECTOR4(-1.0f/(Far-Near), Far/(Far-Near), 0.0f, 0.0f), 1);
0249: 
0250:     D3DXMATRIX mWorld, mView, mProj, m;
0251: 
0252:     // ビュー行列
0253:     D3DXVECTOR3 eye    = D3DXVECTOR3(0.0f,MeshRadius,2.5f*MeshRadius);
0254:     D3DXVECTOR3 lookAt = D3DXVECTOR3(0.0f,  0.0f,  0.0f);
0255:     D3DXVECTOR3 up     = D3DXVECTOR3(0.0f,  1.0f,  0.0f);
0256:     // 通常表示
0257:     D3DXMatrixLookAtLH(&mView, &eye, &lookAt, &up);
0258:     D3DXMatrixPerspectiveFovLH(&mProj
0259:         ,60.0f*PI/180.0f                        // 視野角
0260:         ,(float)WIDTH/(float)HEIGHT             // アスペクト比
0261:         ,0.01f,100.0f                           // 最近接距離,最遠方距離
0262:         );
0263:     lpD3DDev->SetVertexShaderConstant(15, &D3DXVECTOR4(eye.x, eye.y, eye.z
0264:                                 , (float)sqrt(eye.x*eye.x+eye.y*eye.y+eye.z*eye.z)), 1);
0265:     
0266:     // 背景描画
0267:     DrawBg(lpD3DDev, mView, mProj);
0268: 
0269:     // 車の描画
0270:     D3DXMatrixRotationY( &mWorld, timeGetTime()/1000.0f );
0271:     D3DXMatrixRotationY( &mWorld, -2.5f );
0272:     
0273:     m = mWorld;
0274:     D3DXMatrixTranspose( &m ,  &m);
0275:     lpD3DDev->SetVertexShaderConstant(4,&m, 4);
0276: 
0277:     m = mWorld * mView * mProj;
0278:     D3DXMatrixTranspose( &m ,  &m);
0279:     lpD3DDev->SetVertexShaderConstant(0,&m, 4);
0280: 
0281:     D3DXMatrixInverse( &m,  NULL, &mWorld);
0282:     
0283:     // 光の強さ
0284:     D3DXVECTOR4 lightDir(0.5f, 1.0f, -0.5f, 0.0f);
0285:     D3DXVec4Normalize(&lightDir, &lightDir);
0286:     D3DXVec4Transform(&lightDir, &lightDir, &m);
0287:     lightDir[3] = 0.3f;// 環境光の強さ
0288:     lpD3DDev->SetVertexShaderConstant(13, &lightDir, 1);
0289: 
0290:     //メッシュの描画
0291:     lpD3DDev->SetStreamSource(0, pMeshVB, sizeof(D3D_CUSTOMVERTEX));
0292:     lpD3DDev->SetIndices(pMeshIndex,0);
0293:     for(DWORD i=0;i<dwNumMaterials;i++){
0294:         //色をセット
0295:         D3DXVECTOR4 vl( pMeshMaterials[i].Diffuse.r,
0296:                         pMeshMaterials[i].Diffuse.g,
0297:                         pMeshMaterials[i].Diffuse.b,
0298:                         0.0f);
0299:         lpD3DDev->SetVertexShaderConstant(14, &vl, 1);
0300:         lpD3DDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 
0301:                                         pSubsetTable[i].VertexStart,
0302:                                         pSubsetTable[i].VertexCount,
0303:                                         pSubsetTable[i].FaceStart * 3,
0304:                                         pSubsetTable[i].FaceCount);
0305:     }
0306: }
0307: //-----------------------------------------------------------------------------
0308: // メッシュオブジェクト削除
0309: //-----------------------------------------------------------------------------
0310: void DeleteMeshObject(void)
0311: {
0312:     DWORD i;
0313: 
0314:     if(pMeshVB == NULL) return;
0315: 
0316:     for(i=0; i<dwNumMaterials; i++){
0317:         RELEASE(pMeshTextures[i]);
0318:     }
0319:     delete[] pMeshTextures;
0320:     delete[] pMeshMaterials;
0321:     delete[] pSubsetTable;
0322: 
0323:     RELEASE(pMeshVB);
0324:     RELEASE(pMeshIndex);
0325: }
0326: //-----------------------------------------------------------------------------
0327: // Name: CleanRender()
0328: // Desc: 後始末
0329: //-----------------------------------------------------------------------------
0330: void CleanRender(LPDIRECT3DDEVICE8 lpD3DDev)
0331: {
0332:     CleanBg(lpD3DDev);
0333: 
0334:     DeleteMeshObject();
0335:     
0336:     if ( hVertexShader != ~0 ){
0337:         lpD3DDev->DeleteVertexShader( hVertexShader );
0338:         hVertexShader = ~0;
0339:     }
0340: }
0341: