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: