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);
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: LPDIRECT3DSURFACE8      pBackbuffer = NULL;
0032: 
0033: LPDIRECT3DTEXTURE8      pTexture;
0034: LPDIRECT3DSURFACE8      pTextureSurface;
0035: 
0036: FLOAT                   MeshRadius;                 // メッシュの多さ
0037: 
0038: 
0039: 
0040: 
0041: 
0042: // ----------------------------------------------------------------------------
0043: // 頂点の定義
0044: 
0045: typedef struct {
0046:     float x,y,z;
0047:     float nx,ny,nz;
0048:     float tu0,tv0;
0049: }D3DVERTEX;
0050: #define D3DFVF_VERTEX       (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
0051: 
0052: typedef struct {
0053:     float x,y,z;
0054:     float nx,ny,nz;
0055:     float tu0,tv0;
0056: }D3D_CUSTOMVERTEX;
0057: #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
0058: 
0059: static DWORD dwDecl[] = {
0060:     D3DVSD_STREAM(0),
0061:     D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3 ),          //D3DVSDE_POSITION,  0
0062:     D3DVSD_REG(D3DVSDE_NORMAL,   D3DVSDT_FLOAT3 ),          //D3DVSDE_NORMAL,    3
0063:     D3DVSD_REG(D3DVSDE_TEXCOORD0,D3DVSDT_FLOAT2 ),          //D3DVSDE_TEXCOORD0, 7  
0064:     D3DVSD_END()
0065: };
0066: 
0067: // ----------------------------------------------------------------------------
0068: // 横軸をcosθとしたフレネルテクスチャーを作成する
0069: //       近似:(分布関数の影響により)H・N~1 のところしか効かない
0070: //              以上の近似から L・N~V・N になる
0071: //       pTexCoord->x : cosθ=H・N
0072: //       pTexCoord->y : L・N
0073: VOID MakeCookTorranceTexture(D3DXVECTOR4* pOut, D3DXVECTOR2 *pTexCoord, D3DXVECTOR2 *pTexelSize, LPVOID pData)
0074: {
0075:     float NH = pTexCoord->x;// cosθ=H・N
0076:     float NL = pTexCoord->y;// L・N
0077:     
0078:     // フレネル項
0079:     float n = 1.5f;
0080:     float c = NL;
0081:     float g = (float)sqrt(n*n+c*c-1.0f);
0082:     float F = 0.5*((g-c)*(g-c)/(g+c)*(g+c))*(1.0f+((c*(g+c)-1)*(c*(g+c)-1))/((c*(g-c)+1)*(c*(g-c)+1)));
0083: 
0084:     // Beckmann分布関数の近似
0085:     float m = 0.3f;
0086:     float D = (float)(exp(-(1.0f-NH*NH)/(m*m*NH*NH))/(4*m*m*NH*NH*NH*NH));
0087: 
0088:     // 幾何減衰率
0089:     float G = min(1.0f, 2.0f*NH);
0090: 
0091:     float rho = 1.0f*F*D*G/((NL));
0092:     rho = min(1.0f, rho);
0093:     rho = max(rho, 0.0f);
0094: 
0095:     pOut->x = rho;
0096:     pOut->y = rho;
0097:     pOut->z = rho;
0098:     pOut->w = 1.0f;
0099: }
0100: // ----------------------------------------------------------------------------
0101: // Name: LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev)
0102: // Desc: X-Fileの読み込み
0103: //-----------------------------------------------------------------------------
0104: HRESULT LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev)
0105: {
0106:     LPD3DXMESH pMesh, pMeshOpt;
0107:     LPD3DXBUFFER pD3DXMtrlBuffer = NULL;
0108:     DWORD i;
0109:     HRESULT hr;
0110: 
0111:     hr = D3DXLoadMeshFromX(filename, D3DXMESH_MANAGED,
0112:                                 lpD3DDev, NULL,
0113:                                 &pD3DXMtrlBuffer, &dwNumMaterials,
0114:                                 &pMesh);
0115:     if(FAILED(hr)) return E_FAIL;
0116: 
0117:     //並び替えておく
0118:     pMesh->Optimize(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL, &pMeshOpt);
0119:     RELEASE(pMesh);
0120: 
0121:     //アトリビュートテーブル
0122:     pMeshOpt->GetAttributeTable(NULL,&dwNumMaterials);
0123:     pSubsetTable = new D3DXATTRIBUTERANGE[dwNumMaterials];
0124:     pMeshOpt->GetAttributeTable(pSubsetTable, &dwNumMaterials);
0125: 
0126:     // FVF変換
0127:     hr = pMeshOpt->CloneMeshFVF(pMeshOpt->GetOptions(), D3DFVF_VERTEX, lpD3DDev, &pMesh);
0128:     if(FAILED(hr)) return E_FAIL;
0129:     RELEASE(pMeshOpt);
0130:     D3DXComputeNormals(pMesh, NULL);
0131: 
0132:     //Vertex Bufferにコピーする
0133:     D3DVERTEX* pSrc;
0134:     D3D_CUSTOMVERTEX* pDest;
0135:     LPDIRECT3DINDEXBUFFER8 pSrcIndex;
0136:     WORD* pISrc;
0137:     WORD* pIDest;
0138: 
0139:     DWORD nMeshVertices = pMesh->GetNumVertices();
0140:     DWORD nMeshFaces = pMesh->GetNumFaces();
0141:     lpD3DDev->CreateVertexBuffer(nMeshVertices * sizeof(D3D_CUSTOMVERTEX),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_MANAGED,&pMeshVB);
0142:     lpD3DDev->CreateIndexBuffer(nMeshFaces * 3 * sizeof(WORD),0,D3DFMT_INDEX16,D3DPOOL_MANAGED,&pMeshIndex);
0143: 
0144:     LPDIRECT3DVERTEXBUFFER8 pVB;
0145:     pMesh->GetVertexBuffer(&pVB);
0146:     pVB->Lock(0,0,(BYTE**)&pSrc,0);
0147:     pMeshVB->Lock(0,0,(BYTE**)&pDest,0);
0148:     MeshRadius = 0.0f;
0149:     for(i=0;i<nMeshVertices;i++){
0150:         pDest->x = pSrc->x;
0151:         pDest->y = pSrc->y;
0152:         pDest->z = pSrc->z;
0153:         pDest->nx = pSrc->nx;
0154:         pDest->ny = pSrc->ny;
0155:         pDest->nz = pSrc->nz;
0156:         pDest->tu0 = pSrc->tu0;
0157:         pDest->tu0 = pSrc->tu0;
0158:         // サイズの計算
0159:         FLOAT radius = sqrtf( pSrc->x*pSrc->x + pSrc->y*pSrc->y + pSrc->z*pSrc->z );
0160:         if (MeshRadius < radius) MeshRadius = radius;
0161:         
0162:         pSrc += 1;
0163:         pDest += 1;
0164:     }
0165:     pVB->Unlock();
0166:     pVB->Release();
0167:     pMeshVB->Unlock();
0168: 
0169:     //インデックスのコピー
0170:     pMesh->GetIndexBuffer(&pSrcIndex);
0171:     pSrcIndex->Lock(0,0,(BYTE**)&pISrc,0);
0172:     pMeshIndex->Lock(0,0,(BYTE**)&pIDest,0);
0173:     CopyMemory(pIDest,pISrc,nMeshFaces * 3 * sizeof(WORD));
0174:     pSrcIndex->Unlock();
0175:     pMeshIndex->Unlock();
0176:     pSrcIndex->Release();
0177: 
0178:     // pD3DXMtrlBuffer から、質感やテクスチャーの情報を読み取る
0179:     D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
0180:     pMeshTextures = new LPDIRECT3DTEXTURE8[dwNumMaterials];
0181:     pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
0182: 
0183:     for(i = 0; i < dwNumMaterials; i++){
0184:         pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
0185:         pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;
0186:         hr = D3DXCreateTextureFromFile( lpD3DDev, 
0187:                                         d3dxMaterials[i].pTextureFilename, 
0188:                                         &pMeshTextures[i] );
0189:         if(FAILED(hr)) pMeshTextures[i] = NULL;
0190:     }
0191:     RELEASE(pD3DXMtrlBuffer);
0192:     
0193:     RELEASE(pMesh);
0194: 
0195:     return S_OK;
0196: }
0197: // ----------------------------------------------------------------------------
0198: // Name: LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev)
0199: // Desc: 頂点シェーダープログラムの読み込み
0200: //-----------------------------------------------------------------------------
0201: HRESULT LoadVertexShader(char* filename, LPDIRECT3DDEVICE8 lpD3DDev, DWORD *phVertexShader, const DWORD *dwDecl)
0202: {
0203:     HRESULT hr;
0204:     ID3DXBuffer *pshader;
0205:     
0206:     if ( FAILED(hr = D3DXAssembleShaderFromFile(filename, 0,NULL,&pshader,NULL)) ) return hr;
0207:     
0208:     hr = lpD3DDev->CreateVertexShader( dwDecl, (DWORD*)pshader->GetBufferPointer(), phVertexShader, 0 );
0209:     RELEASE(pshader);
0210:     if ( FAILED(hr) ) return hr;
0211:     
0212:     return S_OK;
0213: }
0214: //-----------------------------------------------------------------------------
0215: // Name: InitRender()
0216: // Desc: Load the mesh and build the material and texture arrays
0217: //-----------------------------------------------------------------------------
0218: HRESULT InitRender(LPDIRECT3DDEVICE8 lpD3DDev)
0219: {
0220:     HRESULT hr;
0221: 
0222:     // モデルの読み込み
0223: //  if ( FAILED(hr = LoadXFile("ball.x", lpD3DDev)) ) return hr;
0224:     if ( FAILED(hr = LoadXFile("nsx.x", lpD3DDev)) ) return hr;
0225:     
0226:     // バーテックスシェーダーを作成する
0227:     if ( FAILED(hr = LoadVertexShader("vs.vsh", lpD3DDev, &hVertexShader, dwDecl)) ) return hr;
0228: 
0229:     // 描画用テクスチャーを用意する(2枚分)
0230:     if ( FAILED(hr = lpD3DDev->GetRenderTarget(&pBackbuffer))) return hr;
0231:     D3DSURFACE_DESC Desc;
0232:     if ( FAILED(hr = pBackbuffer->GetDesc( &Desc ))) return hr;
0233: 
0234:     // フレネル反射のテクスチャーを作る
0235:     if( FAILED(hr = lpD3DDev->CreateTexture(512, 512, 1 ,D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pTexture))) return hr;// テクスチャーの生成
0236:     if( FAILED(hr = D3DXFillTexture(pTexture, MakeCookTorranceTexture, NULL))) return hr;
0237: 
0238:     InitBg(lpD3DDev);
0239: 
0240:     lpD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE);
0241: 
0242:     return S_OK;
0243: }
0244: 
0245: struct TLVERTEX
0246: {
0247:     float x,y,z,rhw;
0248:     D3DCOLOR color;
0249:     float tu,tv;
0250: };
0251: #define FVF_TLVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
0252: 
0253: 
0254: //-----------------------------------------------------------------------------
0255: // Name: Render()
0256: // Desc: Draws the scene
0257: //-----------------------------------------------------------------------------
0258: VOID Render(LPDIRECT3DDEVICE8 lpD3DDev)
0259: {
0260:     static int cnt = 0;
0261:     ++cnt;
0262: 
0263:     D3DXMATRIX mWorld, mView, mProj, m;
0264: 
0265:     D3DXMatrixTranslation(&m, MeshRadius, 0,0);
0266:     D3DXMatrixRotationY( &mWorld, timeGetTime()/300.0f );
0267:     mWorld = m * mWorld;
0268:     
0269:     // ビュー行列
0270:     D3DXVECTOR3 eye    = D3DXVECTOR3(0.0f,MeshRadius,2.5f*MeshRadius);
0271:     D3DXVECTOR3 lookAt = D3DXVECTOR3(0.0f,  0.0f,  0.0f);
0272:     D3DXVECTOR3 up     = D3DXVECTOR3(0.0f,  1.0f,  0.0f);
0273:     // 通常表示
0274:     D3DXMatrixLookAtLH(&mView, &eye, &lookAt, &up);
0275:     D3DXMatrixPerspectiveFovLH(&mProj
0276:         ,60.0f*PI/180.0f                        // 視野角
0277:         ,(float)WIDTH/(float)HEIGHT             // アスペクト比
0278:         ,0.01f,100.0f                           // 最近接距離,最遠方距離
0279:         );
0280:     
0281:     // 背景描画
0282:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLOROP,    D3DTOP_MODULATE);
0283:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG1,  D3DTA_TEXTURE);
0284:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG2,  D3DTA_DIFFUSE);
0285:     lpD3DDev->SetTransform(D3DTS_VIEW,  &mView);
0286:     lpD3DDev->SetTransform(D3DTS_PROJECTION, &mProj);
0287:     DrawBg(lpD3DDev);
0288: 
0289:     // 車の描画
0290:     m = mWorld * mView * mProj;
0291:     D3DXMatrixTranspose( &m ,  &m);
0292:     lpD3DDev->SetVertexShaderConstant(0,&m, 4);
0293: 
0294:     D3DXMatrixInverse( &m,  NULL, &mWorld);
0295:     
0296:     // 光の強さ
0297:     D3DXVECTOR4 lightDir(0.5f, 1.0f, -0.5f, 0.0f);
0298:     D3DXVec4Normalize(&lightDir, &lightDir);
0299:     D3DXVec4Transform(&lightDir, &lightDir, &m);
0300:     lightDir[3] = 0.3f;// 環境光の強さ
0301:     lpD3DDev->SetVertexShaderConstant(13, &lightDir, 1);
0302:     // 視点
0303:     D3DXVECTOR4 view(0.0f,MeshRadius, 2.5f*MeshRadius, 0.0f);
0304:     D3DXVec4Transform(&view, &view, &m);
0305:     lpD3DDev->SetVertexShaderConstant(15, &view, 1);
0306: 
0307:     lpD3DDev->SetVertexShader(hVertexShader);
0308:     lpD3DDev->SetTexture( 0, pTexture );
0309:     lpD3DDev->SetTextureStageState(0,D3DTSS_ADDRESSU,    D3DTADDRESS_CLAMP);
0310:     lpD3DDev->SetTextureStageState(0,D3DTSS_ADDRESSV,    D3DTADDRESS_CLAMP);
0311:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLOROP,    D3DTOP_ADD);
0312:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG1,  D3DTA_TEXTURE);
0313:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG2,  D3DTA_DIFFUSE);
0314:     
0315:     //メッシュの描画
0316:     lpD3DDev->SetStreamSource(0, pMeshVB, sizeof(D3D_CUSTOMVERTEX));
0317:     lpD3DDev->SetIndices(pMeshIndex,0);
0318:     for(DWORD i=0;i<dwNumMaterials;i++){
0319:         //色をセット
0320:         D3DXVECTOR4 vl( pMeshMaterials[i].Diffuse.r,
0321:                         pMeshMaterials[i].Diffuse.g,
0322:                         pMeshMaterials[i].Diffuse.b,
0323:                         0.0f);
0324:         lpD3DDev->SetVertexShaderConstant(14, &vl, 1);
0325:         lpD3DDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 
0326:                                         pSubsetTable[i].VertexStart,
0327:                                         pSubsetTable[i].VertexCount,
0328:                                         pSubsetTable[i].FaceStart * 3,
0329:                                         pSubsetTable[i].FaceCount);
0330:     }
0331:     
0332: #if 1
0333:     // 描画した画面をテクスチャーとして描く
0334:     {
0335:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLOROP,    D3DTOP_SELECTARG1);
0336:     lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG1,  D3DTA_TEXTURE);
0337:         TLVERTEX Vertex[4] = {
0338:             // x  y  z rhw           color                     tu tv
0339:             {  0,  0,0, 1, D3DCOLOR_ARGB( 255, 255, 255, 255 ), 0, 0,},
0340:             { 64,  0,0, 1, D3DCOLOR_ARGB( 255, 255, 255, 255 ), 1, 0,},
0341:             { 64, 64,0, 1, D3DCOLOR_ARGB( 255, 255, 255, 255 ), 1, 1,},
0342:             {  0, 64,0, 1, D3DCOLOR_ARGB( 255, 255, 255, 255 ), 0, 1,},
0343:         };
0344:         lpD3DDev->SetTexture( 0, pTexture );
0345:         lpD3DDev->SetVertexShader( FVF_TLVERTEX );
0346:         lpD3DDev->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, Vertex, sizeof( TLVERTEX ) );
0347:     }
0348: #endif
0349: }
0350: //-----------------------------------------------------------------------------
0351: // メッシュオブジェクト削除
0352: //-----------------------------------------------------------------------------
0353: void DeleteMeshObject(void)
0354: {
0355:     DWORD i;
0356: 
0357:     if(pMeshVB == NULL) return;
0358: 
0359:     for(i=0; i<dwNumMaterials; i++){
0360:         RELEASE(pMeshTextures[i]);
0361:     }
0362:     delete[] pMeshTextures;
0363:     delete[] pMeshMaterials;
0364:     delete[] pSubsetTable;
0365: 
0366:     RELEASE(pMeshVB);
0367:     RELEASE(pMeshIndex);
0368: }
0369: //-----------------------------------------------------------------------------
0370: // Name: CleanRender()
0371: // Desc: 後始末
0372: //-----------------------------------------------------------------------------
0373: void CleanRender(LPDIRECT3DDEVICE8 lpD3DDev)
0374: {
0375:     CleanBg(lpD3DDev);
0376: 
0377:     DeleteMeshObject();
0378:     
0379:     if ( hVertexShader != ~0 ){
0380:         lpD3DDev->DeleteVertexShader( hVertexShader );
0381:         hVertexShader = ~0;
0382:     }
0383: 
0384:     RELEASE(pTexture);
0385:     RELEASE(pTextureSurface);
0386:     
0387:     RELEASE(pBackbuffer);
0388: }
0389: