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: const DWORD WIN_W       = 400;
0016: const DWORD WIN_H       =  80;
0017: const DWORD WIN_X       = (WIDTH - WIN_W)/2;
0018: const DWORD WIN_Y       = 30;
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: LPDIRECT3DTEXTURE8      pTexture  = NULL;           // エフェクト用のテクスチャー
0031: 
0032: // ----------------------------------------------------------------------------
0033: // 頂点の定義
0034: 
0035: typedef struct {
0036:     float x,y,z;
0037:     float nx,ny,nz;
0038:     float tu0,tv0;
0039: }D3DVERTEX;
0040: #define D3DFVF_VERTEX       (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
0041: 
0042: typedef struct {
0043:     float x,y,z;
0044:     float nx,ny,nz;
0045:     float tu0,tv0;
0046: }D3D_CUSTOMVERTEX;
0047: #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
0048: 
0049: DWORD dwDecl[] = {
0050:     D3DVSD_STREAM(0),
0051:     D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3 ),          //D3DVSDE_POSITION,  0
0052:     D3DVSD_REG(D3DVSDE_NORMAL,   D3DVSDT_FLOAT3 ),          //D3DVSDE_NORMAL,    3
0053:     D3DVSD_REG(D3DVSDE_TEXCOORD0,D3DVSDT_FLOAT2 ),          //D3DVSDE_TEXCOORD0, 7  
0054:     D3DVSD_END()
0055: };
0056: 
0057: // ----------------------------------------------------------------------------
0058: static void frame_back_init(LPDIRECT3DDEVICE8 lpD3DDEV);
0059: static void frame_back_draw(LPDIRECT3DDEVICE8 lpD3DDEV);
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);
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:     for(i=0;i<nMeshVertices;i++){
0111:         pDest->x = pSrc->x;
0112:         pDest->y = pSrc->y;
0113:         pDest->z = pSrc->z;
0114:         pDest->nx = pSrc->nx;
0115:         pDest->ny = pSrc->ny;
0116:         pDest->nz = pSrc->nz;
0117:         pDest->tu0 = pSrc->tu0;
0118:         pDest->tu0 = pSrc->tu0;
0119:         pSrc += 1;
0120:         pDest += 1;
0121:     }
0122:     pVB->Unlock();
0123:     pVB->Release();
0124:     pMeshVB->Unlock();
0125: 
0126:     //インデックスのコピー
0127:     pMesh->GetIndexBuffer(&pSrcIndex);
0128:     pSrcIndex->Lock(0,0,(BYTE**)&pISrc,0);
0129:     pMeshIndex->Lock(0,0,(BYTE**)&pIDest,0);
0130:     CopyMemory(pIDest,pISrc,nMeshFaces * 3 * sizeof(WORD));
0131:     pSrcIndex->Unlock();
0132:     pMeshIndex->Unlock();
0133:     pSrcIndex->Release();
0134: 
0135:     // pD3DXMtrlBuffer から、質感やテクスチャーの情報を読み取る
0136:     D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
0137:     pMeshTextures = new LPDIRECT3DTEXTURE8[dwNumMaterials];
0138:     pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
0139: 
0140:     for(i = 0; i < dwNumMaterials; i++){
0141:         pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
0142:         pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;
0143:         hr = D3DXCreateTextureFromFile( lpD3DDEV, 
0144:                                         d3dxMaterials[i].pTextureFilename, 
0145:                                         &pMeshTextures[i] );
0146:         if(FAILED(hr)) pMeshTextures[i] = NULL;
0147:     }
0148:     RELEASE(pD3DXMtrlBuffer);
0149:     
0150:     RELEASE(pMesh);
0151: 
0152:     return S_OK;
0153: }
0154: // ----------------------------------------------------------------------------
0155: // Name: LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDEV)
0156: // Desc: X-Fileの読み込み
0157: //-----------------------------------------------------------------------------
0158: HRESULT LoadVertexShader(char* filename, LPDIRECT3DDEVICE8 lpD3DDEV, DWORD *phVertexShader, const DWORD *dwDecl)
0159: {
0160:     HRESULT hr;
0161:     ID3DXBuffer *pshader;
0162:     
0163:     if ( FAILED(hr = D3DXAssembleShaderFromFile(filename, 0,NULL,&pshader,NULL)) ) return hr;
0164:     
0165:     hr = lpD3DDEV->CreateVertexShader( dwDecl, (DWORD*)pshader->GetBufferPointer(), phVertexShader, 0 );
0166:     RELEASE(pshader);
0167:     if ( FAILED(hr) ) return hr;
0168:     
0169:     return S_OK;
0170: }
0171: // ----------------------------------------------------------------------------
0172: // Name: Render()
0173: // Desc: ポリゴンの初期化
0174: //-----------------------------------------------------------------------------
0175: HRESULT InitRender(LPDIRECT3DDEVICE8 lpD3DDEV)
0176: {
0177:     HRESULT hr;
0178: 
0179:     // モデルの読み込み
0180:     if ( FAILED(hr = LoadXFile("nsx.x", lpD3DDEV)) ) return hr;
0181:  
0182:     // 虹色テクスチャーの読み込み
0183:     D3DXCreateTextureFromFileEx(lpD3DDEV, "light.bmp",0,0,0,0,D3DFMT_A8R8G8B8,
0184:                                 D3DPOOL_MANAGED, D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR,
0185:                                 0, NULL, NULL, &pTexture);
0186: 
0187: 
0188:     // バーテックスシェーダーを作成する
0189:     if ( FAILED(hr = LoadVertexShader("vs.vsh", lpD3DDEV, &hVertexShader, dwDecl)) ) return hr;
0190:     
0191:     // レンダリングの状態の設定
0192:     lpD3DDEV->SetRenderState( D3DRS_ZENABLE, TRUE);
0193:     
0194:     frame_back_init(lpD3DDEV);
0195:     return S_OK;
0196: }
0197: // ----------------------------------------------------------------------------
0198: // Name: Render()
0199: // Desc: ポリゴンの描画
0200: //-----------------------------------------------------------------------------
0201: void Render(LPDIRECT3DDEVICE8 lpD3DDEV)
0202: {
0203:     if(NULL == pMeshVB) return;
0204:     
0205:     D3DVIEWPORT8 viewport={WIN_X, WIN_Y, WIN_W, WIN_H, 0.0f, 0.0f};
0206:     D3DVIEWPORT8 viewport_bak;
0207:     lpD3DDEV->GetViewport(&viewport_bak);       //  元のビューポート矩形を取っておく
0208: 
0209:     lpD3DDEV->SetTextureStageState(0,D3DTSS_ADDRESSU,   D3DTADDRESS_CLAMP);
0210:     lpD3DDEV->SetTextureStageState(0,D3DTSS_COLOROP,    D3DTOP_SELECTARG1);
0211:     lpD3DDEV->SetTextureStageState(0,D3DTSS_COLORARG1,  D3DTA_TEXTURE);
0212:     lpD3DDEV->SetTextureStageState(0,D3DTSS_MAGFILTER,  D3DTEXF_LINEAR);
0213:     lpD3DDEV->SetTextureStageState(0,D3DTSS_MINFILTER,  D3DTEXF_LINEAR);
0214:     lpD3DDEV->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_MODULATE);
0215:     lpD3DDEV->SetTextureStageState(1,D3DTSS_COLORARG1,D3DTA_TEXTURE);
0216:     lpD3DDEV->SetTextureStageState(1,D3DTSS_COLORARG2,D3DTA_CURRENT);
0217:     lpD3DDEV->SetTextureStageState(1,D3DTSS_MAGFILTER,D3DTEXF_LINEAR);
0218:     lpD3DDEV->SetTextureStageState(1,D3DTSS_MINFILTER,D3DTEXF_LINEAR);
0219:     
0220:     for(int n = 0; n < 2; n++){
0221:         D3DXMATRIX mWorld, mView, mProj, m;
0222: 
0223:         D3DXMatrixRotationY( &mWorld, timeGetTime()/1000.0f );
0224:         
0225:         D3DXVECTOR3 eye, lookAt, up;
0226:         eye.x    = 0.0f; eye.y    = 10.0f; eye.z   = 30.0f;
0227:         lookAt.x = 0.0f; lookAt.y = 3.0f; lookAt.z = 0.0f;
0228:         up.x     = 0.0f; up.y     = 1.0f; up.z     = 0.0f;
0229:         if(1 == n){
0230:             // 窓で表示するときは、反対から見る
0231:             eye.z   = -30.0f;
0232:             D3DXMatrixLookAtLH(&mView, &eye, &lookAt, &up);
0233:             D3DXMatrixIdentity(&m);
0234:             m(0,0)=-1.0f;
0235:             mView = m * mView;
0236:             D3DXMatrixPerspectiveFovLH(&mProj
0237:                 ,20.0f*PI/180.0f                        // 視野角
0238:                 ,(float)WIN_W/(float)WIN_H              // アスペクト比
0239:                 ,0.01f                                  // 最近接距離
0240:                 ,100.0f                                 // 最遠方距離
0241:                 );
0242:         }else{
0243:             D3DXMatrixLookAtLH(&mView, &eye, &lookAt, &up);
0244:             D3DXMatrixPerspectiveFovLH(&mProj
0245:                 ,60.0f*PI/180.0f                        // 視野角
0246:                 ,(float)WIDTH/(float)HEIGHT             // アスペクト比
0247:                 ,0.01f                                  // 最近接距離
0248:                 ,100.0f                                 // 最遠方距離
0249:                 );
0250:         }
0251:         m = mWorld * mView * mProj;
0252:         D3DXMatrixTranspose( &m ,  &m);
0253:         lpD3DDEV->SetVertexShaderConstant(0,&m, 4);
0254: 
0255:         D3DXVECTOR4 lightDir(1.0f, 1.0f, 0.5f, 0.0f);
0256:         D3DXVec4Normalize(&lightDir, &lightDir);
0257:         D3DXMatrixInverse( &m,  NULL, &mWorld);
0258:         D3DXVec4Transform(&lightDir, &lightDir, &m);
0259:         lpD3DDEV->SetVertexShaderConstant(13, &lightDir, 1);
0260:         lpD3DDEV->SetVertexShaderConstant(12, D3DXVECTOR4(0.0f, 0.5f, 1.0f, 2.0f), 1);
0261: 
0262:         lpD3DDEV->SetTextureStageState(0,D3DTSS_COLOROP,    D3DTOP_SELECTARG1);
0263:         lpD3DDEV->SetTextureStageState(0,D3DTSS_COLORARG1,  D3DTA_TEXTURE);
0264:         lpD3DDEV->SetVertexShader(hVertexShader);
0265:         lpD3DDEV->SetTexture(0,pTexture);
0266: 
0267:         //メッシュの描画
0268:         lpD3DDEV->SetStreamSource(0, pMeshVB, sizeof(D3D_CUSTOMVERTEX));
0269:         lpD3DDEV->SetIndices(pMeshIndex,0);
0270:         for(DWORD i=0;i<dwNumMaterials;i++){
0271: #if 0 // 使えません
0272:             //色をセット
0273:             D3DXVECTOR4 vl;
0274:             vl.x = pMeshMaterials[i].Diffuse.r;
0275:             vl.y = pMeshMaterials[i].Diffuse.g;
0276:             vl.z = pMeshMaterials[i].Diffuse.b;
0277:             lpD3DDEV->SetVertexShaderConstant(14, &vl, 1);
0278: #endif
0279:             lpD3DDEV->SetTexture(1,pMeshTextures[i]);
0280:             lpD3DDEV->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 
0281:                                             pSubsetTable[i].VertexStart,
0282:                                             pSubsetTable[i].VertexCount,
0283:                                             pSubsetTable[i].FaceStart * 3,
0284:                                             pSubsetTable[i].FaceCount);
0285:         }
0286:         if(n==0){
0287:             frame_back_draw(lpD3DDEV);
0288:             lpD3DDEV->SetViewport(&viewport);           //  新しいビューポート矩形を設定する
0289:             lpD3DDEV->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
0290:         }else{
0291:             lpD3DDEV->SetViewport(&viewport_bak);           // ビューポート矩形を戻す
0292:             lpD3DDEV->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
0293:         }
0294:     }
0295:     
0296:     lpD3DDEV->SetTexture(0, NULL);
0297:     lpD3DDEV->SetTexture(1, NULL);
0298: }
0299: //-----------------------------------------------------------------------------
0300: // 下の画像がはみ出ないように塗りつぶす
0301: //-----------------------------------------------------------------------------
0302: LPDIRECT3DVERTEXBUFFER8 pFrameBackVB = NULL; // 頂点バッファに使うオブジェクト
0303: typedef struct{
0304:     FLOAT x, y, z, rhw;  // 位置
0305:     DWORD color;    // 色
0306: }FRAME_BACK_VERTEX;
0307: #define D3DFVF_FRAME_BACK_VERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
0308: //-----------------------------------------------------------------------------
0309: static void frame_back_init(LPDIRECT3DDEVICE8 lpD3DDEV)
0310: {
0311:     FRAME_BACK_VERTEX vertices[] = {
0312:         //     x,            y,         z,   rhw,                 color
0313:         {WIN_X      -1, WIN_Y      -1, 0.0f, 1.0f, D3DCOLOR_RGBA(0x00, 0xff, 0xff, 0xff), },
0314:         {WIN_X+WIN_W+1, WIN_Y      -1, 0.0f, 1.0f, D3DCOLOR_RGBA(0x00, 0xff, 0xff, 0xff), },
0315:         {WIN_X      -1, WIN_Y+WIN_H+1, 0.0f, 1.0f, D3DCOLOR_RGBA(0x00, 0xff, 0xff, 0xff), },
0316:         {WIN_X+WIN_W+1, WIN_Y+WIN_H+1, 0.0f, 1.0f, D3DCOLOR_RGBA(0x00, 0xff, 0xff, 0xff), },
0317:     };
0318:     RELEASE(pFrameBackVB);
0319:     if(FAILED(lpD3DDEV->CreateVertexBuffer( sizeof(vertices),0,
0320:                           D3DFVF_FRAME_BACK_VERTEX, D3DPOOL_DEFAULT, &pFrameBackVB))) return;
0321:     VOID* pVertices;
0322:     if(FAILED(pFrameBackVB->Lock( 0, sizeof(vertices), (BYTE**)&pVertices, 0))) return;
0323:     memcpy( pVertices, vertices, sizeof(vertices) );
0324:     pFrameBackVB->Unlock();
0325: }
0326: //-----------------------------------------------------------------------------
0327: static void frame_back_draw(LPDIRECT3DDEVICE8 lpD3DDEV)
0328: {
0329:     lpD3DDEV->SetRenderState( D3DRS_ZENABLE, FALSE);
0330:     
0331:     lpD3DDEV->SetTextureStageState(0,D3DTSS_COLOROP,    D3DTOP_SELECTARG1);
0332:     lpD3DDEV->SetTextureStageState(0,D3DTSS_COLORARG1,  D3DTA_DIFFUSE);
0333: 
0334:     lpD3DDEV->SetStreamSource( 0, pFrameBackVB, sizeof(FRAME_BACK_VERTEX) );
0335:     lpD3DDEV->SetVertexShader( D3DFVF_FRAME_BACK_VERTEX );
0336:     lpD3DDEV->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
0337:     
0338:     lpD3DDEV->SetRenderState( D3DRS_ZENABLE, TRUE);
0339: }
0340: //-----------------------------------------------------------------------------
0341: static void frame_back_clean()
0342: {
0343:     RELEASE(pFrameBackVB);
0344: }
0345: //-----------------------------------------------------------------------------
0346: // メッシュオブジェクト削除
0347: //-----------------------------------------------------------------------------
0348: void DeleteMeshObject(void)
0349: {
0350:     DWORD i;
0351: 
0352:     if(pMeshVB == NULL) return;
0353: 
0354:     for(i=0; i<dwNumMaterials; i++){
0355:         RELEASE(pMeshTextures[i]);
0356:     }
0357:     delete[] pMeshTextures;
0358:     delete[] pMeshMaterials;
0359:     delete[] pSubsetTable;
0360: 
0361:     RELEASE(pMeshVB);
0362:     RELEASE(pMeshIndex);
0363: }
0364: //-----------------------------------------------------------------------------
0365: // Name: CleanRender()
0366: // Desc: 後始末
0367: //-----------------------------------------------------------------------------
0368: void CleanRender(LPDIRECT3DDEVICE8 lpD3DDEV)
0369: {
0370:     DeleteMeshObject();
0371:     
0372:     if ( hVertexShader != ~0 ){
0373:         lpD3DDEV->DeleteVertexShader( hVertexShader );
0374:         hVertexShader = ~0;
0375:     }
0376:     
0377:     RELEASE(pTexture);
0378:     frame_back_clean();
0379: }
0380: