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: LPDIRECT3DVERTEXBUFFER8 pMeshVB = NULL;
0016: LPDIRECT3DINDEXBUFFER8  pMeshIndex = NULL;
0017: D3DXATTRIBUTERANGE      *pSubsetTable = NULL;
0018: DWORD                   nMeshFaces = 0;
0019: DWORD                   nMeshVertices = 0;
0020: D3DMATERIAL8            *pMeshMaterials = NULL;     // メッシュの質感
0021: LPDIRECT3DTEXTURE8      *pMeshTextures  = NULL;     // メッシュのテクスチャー
0022: DWORD                   dwNumMaterials = 0L;        // マテリアルの数
0023: 
0024: DWORD                   hVertexShader=~0;
0025: 
0026: LPDIRECT3DSURFACE8      pBackbuffer = NULL;
0027: 
0028: LPDIRECT3DTEXTURE8      pTexture[2];
0029: LPDIRECT3DSURFACE8      pTextureSurface[2];
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 | D3DFVF_TEX1)
0053: 
0054: 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:         pDest->tu0 = pSrc->tu0;
0119:         pDest->tu0 = pSrc->tu0;
0120:         // サイズの計算
0121:         FLOAT radius = sqrtf( pSrc->x*pSrc->x + pSrc->y*pSrc->y + pSrc->z*pSrc->z );
0122:         if (MeshRadius < radius) MeshRadius = radius;
0123:         
0124:         pSrc += 1;
0125:         pDest += 1;
0126:     }
0127:     pVB->Unlock();
0128:     pVB->Release();
0129:     pMeshVB->Unlock();
0130: 
0131:     //インデックスのコピー
0132:     pMesh->GetIndexBuffer(&pSrcIndex);
0133:     pSrcIndex->Lock(0,0,(BYTE**)&pISrc,0);
0134:     pMeshIndex->Lock(0,0,(BYTE**)&pIDest,0);
0135:     CopyMemory(pIDest,pISrc,nMeshFaces * 3 * sizeof(WORD));
0136:     pSrcIndex->Unlock();
0137:     pMeshIndex->Unlock();
0138:     pSrcIndex->Release();
0139: 
0140:     // pD3DXMtrlBuffer から、質感やテクスチャーの情報を読み取る
0141:     D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
0142:     pMeshTextures = new LPDIRECT3DTEXTURE8[dwNumMaterials];
0143:     pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
0144: 
0145:     for(i = 0; i < dwNumMaterials; i++){
0146:         pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
0147:         pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;
0148:         hr = D3DXCreateTextureFromFile( lpD3DDev, 
0149:                                         d3dxMaterials[i].pTextureFilename, 
0150:                                         &pMeshTextures[i] );
0151:         if(FAILED(hr)) pMeshTextures[i] = NULL;
0152:     }
0153:     RELEASE(pD3DXMtrlBuffer);
0154:     
0155:     RELEASE(pMesh);
0156: 
0157:     return S_OK;
0158: }
0159: // ----------------------------------------------------------------------------
0160: // Name: LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev)
0161: // Desc: 頂点シェーダープログラムの読み込み
0162: //-----------------------------------------------------------------------------
0163: HRESULT LoadVertexShader(char* filename, LPDIRECT3DDEVICE8 lpD3DDev, DWORD *phVertexShader, const DWORD *dwDecl)
0164: {
0165:     HRESULT hr;
0166:     ID3DXBuffer *pshader;
0167:     
0168:     if ( FAILED(hr = D3DXAssembleShaderFromFile(filename, 0,NULL,&pshader,NULL)) ) return hr;
0169:     
0170:     hr = lpD3DDev->CreateVertexShader( dwDecl, (DWORD*)pshader->GetBufferPointer(), phVertexShader, 0 );
0171:     RELEASE(pshader);
0172:     if ( FAILED(hr) ) return hr;
0173:     
0174:     return S_OK;
0175: }
0176: //-----------------------------------------------------------------------------
0177: // Name: InitRender()
0178: // Desc: Load the mesh and build the material and texture arrays
0179: //-----------------------------------------------------------------------------
0180: HRESULT InitRender(LPDIRECT3DDEVICE8 lpD3DDev)
0181: {
0182:     HRESULT hr;
0183: 
0184:     // モデルの読み込み
0185:     if ( FAILED(hr = LoadXFile("nsx.x", lpD3DDev)) ) return hr;
0186:     
0187:     // バーテックスシェーダーを作成する
0188:     if ( FAILED(hr = LoadVertexShader("vs.vsh", lpD3DDev, &hVertexShader, dwDecl)) ) return hr;
0189: 
0190:     // 描画用テクスチャーを用意する(2枚分)
0191:     if ( FAILED(hr = lpD3DDev->GetRenderTarget(&pBackbuffer))) return hr;
0192:     D3DSURFACE_DESC Desc;
0193:     if ( FAILED(hr = pBackbuffer->GetDesc( &Desc ))) return hr;
0194: 
0195:     LPDIRECT3DSURFACE8 lpZbuffer = NULL;
0196:     for( int i = 0; i < 2; i++ ){
0197:         if( FAILED(hr = lpD3DDev->CreateTexture(WIDTH,HEIGHT, 1 ,D3DUSAGE_RENDERTARGET, Desc.Format, D3DPOOL_DEFAULT, &pTexture[i]))) return hr;// テクスチャーの生成
0198:         if( FAILED(hr = pTexture[i]->GetSurfaceLevel(0,&pTextureSurface[i]))) return hr;        // テクスチャーとサーフェスを関連づける
0199:         if( FAILED(hr = lpD3DDev->GetDepthStencilSurface( &lpZbuffer ))) return hr;             // 深度バッファのサーフェスを確保する
0200:         if( FAILED(hr = lpD3DDev->SetRenderTarget(pTextureSurface[i], lpZbuffer ))) return hr;  // テクスチャー用の描画と深度バッファを関連付ける
0201: 
0202:         // 初期化としてテクスチャーを塗りつぶしておく
0203:         lpD3DDev->BeginScene();
0204:         lpD3DDev->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 
0205:                              D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
0206:         lpD3DDev->EndScene();
0207:     }
0208:     // 描画を元の画面に戻す
0209:     lpD3DDev->SetRenderTarget(pBackbuffer, lpZbuffer );
0210: 
0211:     return S_OK;
0212: }
0213: 
0214: struct TLVERTEX
0215: {
0216:     float x,y,z,rhw;
0217:     D3DCOLOR color;
0218:     float tu,tv;
0219: };
0220: #define FVF_TLVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
0221: 
0222: 
0223: //-----------------------------------------------------------------------------
0224: // Name: Render()
0225: // Desc: Draws the scene
0226: //-----------------------------------------------------------------------------
0227: VOID Render(LPDIRECT3DDEVICE8 lpD3DDev)
0228: {
0229:     LPDIRECT3DSURFACE8 lpZbuffer = NULL;
0230:     static int cnt = 0;
0231:     ++cnt;
0232: 
0233:     lpD3DDev->GetDepthStencilSurface( &lpZbuffer );
0234:     lpD3DDev->SetRenderTarget(pTextureSurface[cnt & 1], lpZbuffer );
0235: 
0236:     lpD3DDev->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,32,32), 1.0f, 0 );
0237: 
0238:     D3DXMATRIX mWorld, mView, mProj, m;
0239: 
0240:     D3DXMatrixTranslation(&m, MeshRadius, 0,0);
0241:     D3DXMatrixRotationY( &mWorld, timeGetTime()/300.0f );
0242:     mWorld = m * mWorld;
0243:     
0244:     // ビュー行列
0245:     D3DXVECTOR3 eye    = D3DXVECTOR3(0.0f,MeshRadius,2.5f*MeshRadius);
0246:     D3DXVECTOR3 lookAt = D3DXVECTOR3(0.0f,  0.0f,  0.0f);
0247:     D3DXVECTOR3 up     = D3DXVECTOR3(0.0f,  1.0f,  0.0f);
0248:     // 通常表示
0249:     D3DXMatrixLookAtLH(&mView, &eye, &lookAt, &up);
0250:     D3DXMatrixPerspectiveFovLH(&mProj
0251:         ,60.0f*PI/180.0f                        // 視野角
0252:         ,(float)WIDTH/(float)HEIGHT             // アスペクト比
0253:         ,0.01f,100.0f                           // 最近接距離,最遠方距離
0254:         );
0255: 
0256:     m = mWorld * mView * mProj;
0257:     D3DXMatrixTranspose( &m ,  &m);
0258:     lpD3DDev->SetVertexShaderConstant(0,&m, 4);
0259: 
0260:     D3DXVECTOR4 lightDir(1.0f, 1.0f, 0.5f, 0.0f);
0261:     D3DXVec4Normalize(&lightDir, &lightDir);
0262:     D3DXMatrixInverse( &m,  NULL, &mWorld);
0263:     D3DXVec4Transform(&lightDir, &lightDir, &m);
0264:     lightDir[3] = 0.3f;// 環境光の強さ
0265:     lpD3DDev->SetVertexShaderConstant(13, &lightDir, 1);
0266: 
0267:     //メッシュの描画
0268:     lpD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE);
0269:     lpD3DDev->SetVertexShader(hVertexShader);
0270:     lpD3DDev->SetStreamSource(0, pMeshVB, sizeof(D3D_CUSTOMVERTEX));
0271:     lpD3DDev->SetIndices(pMeshIndex,0);
0272:     for(DWORD i=0;i<dwNumMaterials;i++){
0273:         //色をセット
0274:         D3DXVECTOR4 vl;
0275:         vl.x = pMeshMaterials[i].Diffuse.r;
0276:         vl.y = pMeshMaterials[i].Diffuse.g;
0277:         vl.z = pMeshMaterials[i].Diffuse.b;
0278:         lpD3DDev->SetVertexShaderConstant(14, &vl, 1);
0279: 
0280:         lpD3DDev->SetTexture(0,pMeshTextures[i]);
0281:         lpD3DDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 
0282:                                         pSubsetTable[i].VertexStart,
0283:                                         pSubsetTable[i].VertexCount,
0284:                                         pSubsetTable[i].FaceStart * 3,
0285:                                         pSubsetTable[i].FaceCount);
0286:     }
0287:     
0288:     // 残像(位置フレーム前の画面を半透明で描く)
0289:     lpD3DDev->SetRenderState( D3DRS_ZENABLE, FALSE );
0290:     lpD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
0291:     lpD3DDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
0292:     lpD3DDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
0293:     lpD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
0294:     
0295:     lpD3DDev->SetTransform( D3DTS_VIEW, &mView );
0296:     lpD3DDev->SetTransform( D3DTS_PROJECTION, &mProj );
0297: 
0298:     TLVERTEX Vertex[4] = {
0299:         // x  y  z rhw           color                     tu tv
0300:         {  0,  0,0,1,D3DCOLOR_ARGB( 200, 255, 255, 255 ),0,0,},
0301:         {512,  0,0,1,D3DCOLOR_ARGB( 200, 255, 255, 255 ),1,0,},
0302:         {  0,512,0,1,D3DCOLOR_ARGB( 200, 255, 255, 255 ),0,1,},
0303:         {512,512,0,1,D3DCOLOR_ARGB( 200, 255, 255, 255 ),1,1,},
0304:     };
0305:     lpD3DDev->SetTexture( 0, pTexture[(cnt + 1)&1] );
0306:     lpD3DDev->SetVertexShader( FVF_TLVERTEX );
0307:     lpD3DDev->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, Vertex, sizeof( TLVERTEX ) );
0308: 
0309:     // 描画をバックバッファに戻す
0310:     lpD3DDev->GetDepthStencilSurface( &lpZbuffer );
0311:     lpD3DDev->SetRenderTarget(pBackbuffer, lpZbuffer );
0312:     lpD3DDev->SetRenderState( D3DRS_ZENABLE, TRUE );
0313:     lpD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE);
0314: 
0315:     // 描画した画面をテクスチャーとして描く
0316:     {
0317:         TLVERTEX Vertex[4] = {
0318:             // x  y  z rhw           color                     tu tv
0319:             {  0,  0,0, 1, D3DCOLOR_ARGB( 255, 255, 255, 255 ), 0, 0,},
0320:             {512,  0,0, 1, D3DCOLOR_ARGB( 255, 255, 255, 255 ), 1, 0,},
0321:             {512,512,0, 1, D3DCOLOR_ARGB( 255, 255, 255, 255 ), 1, 1,},
0322:             {  0,512,0, 1, D3DCOLOR_ARGB( 255, 255, 255, 255 ), 0, 1,},
0323:         };
0324:         lpD3DDev->SetTexture( 0, pTexture[cnt&1] );
0325:         lpD3DDev->SetVertexShader( FVF_TLVERTEX );
0326:         lpD3DDev->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, Vertex, sizeof( TLVERTEX ) );
0327:     }
0328: }
0329: //-----------------------------------------------------------------------------
0330: // メッシュオブジェクト削除
0331: //-----------------------------------------------------------------------------
0332: void DeleteMeshObject(void)
0333: {
0334:     DWORD i;
0335: 
0336:     if(pMeshVB == NULL) return;
0337: 
0338:     for(i=0; i<dwNumMaterials; i++){
0339:         RELEASE(pMeshTextures[i]);
0340:     }
0341:     delete[] pMeshTextures;
0342:     delete[] pMeshMaterials;
0343:     delete[] pSubsetTable;
0344: 
0345:     RELEASE(pMeshVB);
0346:     RELEASE(pMeshIndex);
0347: }
0348: //-----------------------------------------------------------------------------
0349: // Name: CleanRender()
0350: // Desc: 後始末
0351: //-----------------------------------------------------------------------------
0352: void CleanRender(LPDIRECT3DDEVICE8 lpD3DDev)
0353: {
0354:     DeleteMeshObject();
0355:     
0356:     if ( hVertexShader != ~0 ){
0357:         lpD3DDev->DeleteVertexShader( hVertexShader );
0358:         hVertexShader = ~0;
0359:     }
0360: 
0361:     for(int i = 0; i < 2; i++){
0362:         RELEASE(pTexture[i]);
0363:         RELEASE(pTextureSurface[i]);
0364:     }
0365:     RELEASE(pBackbuffer);
0366: }
0367: