0001: // ----------------------------------------------------------------------------
0002: //
0003: // draw.cpp - 描画部分
0004: //
0005: // Copyright (c) 2002 IMAGIRE Takashi (imagire@gmail.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: // モデル用
0017: LPDIRECT3DVERTEXBUFFER8 pMeshVB = NULL;
0018: LPDIRECT3DINDEXBUFFER8 pMeshIndex = NULL;
0019: D3DXATTRIBUTERANGE *pSubsetTable = NULL;
0020: DWORD nMeshFaces = 0;
0021: DWORD nMeshVertices = 0;
0022: D3DMATERIAL8 *pMeshMaterials = NULL; // メッシュの質感
0023: LPDIRECT3DTEXTURE8 *pMeshTextures = NULL; // メッシュのテクスチャー
0024: DWORD dwNumMaterials = 0L; // マテリアルの数
0025: FLOAT MeshRadius; // メッシュの大きさ
0026:
0027: // レンダリングテクスチャーの設定
0028: LPDIRECT3DTEXTURE8 pTexture;
0029: LPDIRECT3DSURFACE8 pTextureSurface;
0030: LPDIRECT3DSURFACE8 pBackbuffer = NULL;
0031:
0032:
0033: // 最後の一枚絵の描画用
0034: DWORD hVertexShader=~0;
0035: DWORD hPixelShader=~0;
0036: LPDIRECT3DVERTEXBUFFER8 pFinalVB = NULL;
0037: LPDIRECT3DINDEXBUFFER8 pFinalIB = NULL;
0038:
0039: typedef struct {
0040: float x,y,z;
0041: float tu,tv;
0042: }D3D_FINAL_VERTEX;
0043: #define D3DFVF_FINAL_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1)
0044:
0045: DWORD dwFinalDecl[] = {
0046: D3DVSD_STREAM(0),
0047: D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3 ), //D3DVSDE_POSITION, 0
0048: D3DVSD_REG(D3DVSDE_TEXCOORD0,D3DVSDT_FLOAT2 ), //D3DVSDE_TEXCOORD0, 7
0049: D3DVSD_END()
0050: };
0051:
0052:
0053: // ----------------------------------------------------------------------------
0054: // 外部関数
0055: void InitBg(LPDIRECT3DDEVICE8 lpD3DDev);
0056: void DrawBg(LPDIRECT3DDEVICE8 lpD3DDev);
0057: void CleanBg(LPDIRECT3DDEVICE8 lpD3DDev);
0058:
0059:
0060:
0061: // ----------------------------------------------------------------------------
0062: // Name: LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev)
0063: // Desc: X-Fileの読み込み
0064: //-----------------------------------------------------------------------------
0065: HRESULT LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev)
0066: {
0067: LPD3DXMESH pMesh, pMeshOpt;
0068: LPD3DXBUFFER pD3DXMtrlBuffer = NULL;
0069: DWORD i;
0070: HRESULT hr;
0071:
0072: hr = D3DXLoadMeshFromX(filename, D3DXMESH_MANAGED,
0073: lpD3DDev, NULL,
0074: &pD3DXMtrlBuffer, &dwNumMaterials,
0075: &pMesh);
0076: if(FAILED(hr)) return E_FAIL;
0077:
0078: //並び替えておく
0079: pMesh->Optimize(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL, &pMeshOpt);
0080: RELEASE(pMesh);
0081:
0082: //アトリビュートテーブル
0083: pMeshOpt->GetAttributeTable(NULL,&dwNumMaterials);
0084: pSubsetTable = new D3DXATTRIBUTERANGE[dwNumMaterials];
0085: pMeshOpt->GetAttributeTable(pSubsetTable, &dwNumMaterials);
0086:
0087: // FVF変換
0088: hr = pMeshOpt->CloneMeshFVF(pMeshOpt->GetOptions(), D3DFVF_VERTEX, lpD3DDev, &pMesh);
0089: if(FAILED(hr)) return E_FAIL;
0090: RELEASE(pMeshOpt);
0091: D3DXComputeNormals(pMesh, NULL);
0092:
0093: //Vertex Bufferにコピーする
0094: D3DVERTEX* pSrc;
0095: D3D_CUSTOMVERTEX* pDest;
0096: LPDIRECT3DINDEXBUFFER8 pSrcIndex;
0097: WORD* pISrc;
0098: WORD* pIDest;
0099:
0100: DWORD nMeshVertices = pMesh->GetNumVertices();
0101: DWORD nMeshFaces = pMesh->GetNumFaces();
0102: lpD3DDev->CreateVertexBuffer(nMeshVertices * sizeof(D3D_CUSTOMVERTEX),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_MANAGED,&pMeshVB);
0103: lpD3DDev->CreateIndexBuffer(nMeshFaces * 3 * sizeof(WORD),0,D3DFMT_INDEX16,D3DPOOL_MANAGED,&pMeshIndex);
0104:
0105: LPDIRECT3DVERTEXBUFFER8 pVB;
0106: pMesh->GetVertexBuffer(&pVB);
0107: pVB->Lock(0,0,(BYTE**)&pSrc,0);
0108: pMeshVB->Lock(0,0,(BYTE**)&pDest,0);
0109: MeshRadius = 0.0f;
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: // サイズの計算
0120: FLOAT radius = sqrtf( pSrc->x*pSrc->x + pSrc->y*pSrc->y + pSrc->z*pSrc->z );
0121: if (MeshRadius < radius) MeshRadius = radius;
0122:
0123: pSrc += 1;
0124: pDest += 1;
0125: }
0126: pVB->Unlock();
0127: pVB->Release();
0128: pMeshVB->Unlock();
0129:
0130: //インデックスのコピー
0131: pMesh->GetIndexBuffer(&pSrcIndex);
0132: pSrcIndex->Lock(0,0,(BYTE**)&pISrc,0);
0133: pMeshIndex->Lock(0,0,(BYTE**)&pIDest,0);
0134: CopyMemory(pIDest,pISrc,nMeshFaces * 3 * sizeof(WORD));
0135: pSrcIndex->Unlock();
0136: pMeshIndex->Unlock();
0137: pSrcIndex->Release();
0138:
0139: // pD3DXMtrlBuffer から、質感やテクスチャーの情報を読み取る
0140: D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
0141: pMeshTextures = new LPDIRECT3DTEXTURE8[dwNumMaterials];
0142: pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
0143:
0144: for(i = 0; i < dwNumMaterials; i++){
0145: pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
0146: pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;
0147: hr = D3DXCreateTextureFromFile( lpD3DDev,
0148: d3dxMaterials[i].pTextureFilename,
0149: &pMeshTextures[i] );
0150: if(FAILED(hr)) pMeshTextures[i] = NULL;
0151: }
0152: RELEASE(pD3DXMtrlBuffer);
0153:
0154: RELEASE(pMesh);
0155:
0156: return S_OK;
0157: }
0158: //-----------------------------------------------------------------------------
0159: // Name: InitRenderTexture()
0160: // Desc: レンダリングテクスチャー用の下準備
0161: //-----------------------------------------------------------------------------
0162: HRESULT InitRenderTexture(LPDIRECT3DDEVICE8 lpD3DDev)
0163: {
0164: HRESULT hr;
0165: DWORD i;
0166:
0167: // バーテックスシェーダーを作成する
0168: if( FAILED(hr=CVertexShaderMgr::Load(lpD3DDev, "final.vsh", &hVertexShader
0169: , dwFinalDecl)) ) return hr;
0170: if( FAILED(hr=CPixelShaderMgr::Load(lpD3DDev, "final.psh", &hPixelShader)))
0171: return hr;
0172:
0173: // 頂点バッファの作成
0174: D3D_FINAL_VERTEX *pDest;
0175: WORD *pIndex;
0176: hr = lpD3DDev->CreateVertexBuffer( 4 * sizeof(D3D_FINAL_VERTEX),
0177: D3DUSAGE_WRITEONLY, D3DFVF_FINAL_VERTEX, D3DPOOL_MANAGED,
0178: &pFinalVB );
0179: // 頂点をセットアップ
0180: pFinalVB->Lock ( 0, 0, (BYTE**)&pDest, 0 );
0181: for (i = 0; i < 4; i++) {
0182: pDest->x = (i == 0 || i == 1)?-1:(float)1;
0183: pDest->y = (i == 0 || i == 2)?-1:(float)1;
0184: pDest->z = 0.5f;
0185: pDest->tu = (i == 2 || i == 3)?1:(float)0;
0186: pDest->tv = (i == 0 || i == 2)?1:(float)0;
0187: pDest++;
0188: }
0189: pFinalVB->Unlock ();
0190: // インデックスをセットアップ
0191: hr = lpD3DDev->CreateIndexBuffer( 6 * sizeof(WORD),
0192: 0,
0193: D3DFMT_INDEX16, D3DPOOL_MANAGED,
0194: &pFinalIB );
0195: pFinalIB->Lock ( 0, 0, (BYTE**)&pIndex, 0 );
0196: pIndex[0] = 0; pIndex[1] = 1; pIndex[2] = 2;
0197: pIndex[3] = 1; pIndex[4] = 3; pIndex[5] = 2;
0198: pFinalIB->Unlock ();
0199:
0200: // 定数レジスタの設定
0201: float const inv_w = 1.0f / (float)WIDTH;
0202: float const inv_h = 1.0f / (float)HEIGHT;
0203: lpD3DDev->SetVertexShaderConstant(20, &D3DXVECTOR4 (-0.5f*inv_w, -0.5f*inv_h, 0.0f, 0.0f), 1);
0204: lpD3DDev->SetVertexShaderConstant(21, &D3DXVECTOR4 (+0.5f*inv_w, -0.5f*inv_h, 0.0f, 0.0f), 1);
0205: lpD3DDev->SetVertexShaderConstant(22, &D3DXVECTOR4 (-0.5f*inv_w, +0.5f*inv_h, 0.0f, 0.0f), 1);
0206: lpD3DDev->SetVertexShaderConstant(23, &D3DXVECTOR4 (+0.5f*inv_w, +0.5f*inv_h, 0.0f, 0.0f), 1);
0207:
0208: // -------------------------------------------------------------------------
0209: // 描画用テクスチャーを用意する
0210: // -------------------------------------------------------------------------
0211: D3DSURFACE_DESC Desc;
0212: LPDIRECT3DSURFACE8 lpZbuffer = NULL;
0213: if( FAILED(hr = lpD3DDev->GetRenderTarget(&pBackbuffer))) return hr;
0214: if( FAILED(hr = pBackbuffer->GetDesc( &Desc ))) return hr;
0215:
0216: // 深度バッファのサーフェスを確保する
0217: if( FAILED(hr = lpD3DDev->GetDepthStencilSurface( &lpZbuffer ))) return hr;
0218:
0219: // テクスチャーの生成
0220: if( FAILED(hr = lpD3DDev->CreateTexture(Desc.Width, Desc.Height, 1
0221: , D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8
0222: , D3DPOOL_DEFAULT, &pTexture))) return hr;
0223: // テクスチャーとサーフェスを関連づける
0224: if( FAILED(hr = pTexture->GetSurfaceLevel(0,&pTextureSurface))) return hr;
0225: // テクスチャー用の描画と深度バッファを関連付ける
0226: if( FAILED(hr = lpD3DDev->SetRenderTarget(pTextureSurface, lpZbuffer)))
0227: return hr;
0228:
0229: // 描画を元の画面に戻す
0230: lpD3DDev->SetRenderTarget(pBackbuffer, lpZbuffer );
0231:
0232: return S_OK;
0233: }
0234: //-----------------------------------------------------------------------------
0235: // Name: InitRender()
0236: // Desc: Load the mesh and build the material and texture arrays
0237: //-----------------------------------------------------------------------------
0238: D3DXVECTOR4 lightDir(1.0f, 1.0f, 0.5f, 0.0f);
0239:
0240: HRESULT InitRender(LPDIRECT3DDEVICE8 lpD3DDev)
0241: {
0242: HRESULT hr;
0243:
0244: // モデルの読み込み
0245: if ( FAILED(hr = LoadXFile("nsx.x", lpD3DDev)) ) return hr;
0246:
0247: // レンダリングテクスチャー用の初期化
0248: InitRenderTexture(lpD3DDev);
0249:
0250: // 背景部分の初期化
0251: InitBg(lpD3DDev);
0252:
0253: // 不変なレジスタの設定
0254: lpD3DDev->SetRenderState( D3DRS_ZENABLE, TRUE );
0255: for (DWORD i = 0; i < 4; ++i) {
0256: lpD3DDev->SetTextureStageState(i, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
0257: lpD3DDev->SetTextureStageState(i, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
0258: lpD3DDev->SetTextureStageState(i, D3DTSS_MIPFILTER, D3DTEXF_NONE);
0259: lpD3DDev->SetTextureStageState(i,D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
0260: lpD3DDev->SetTextureStageState(i,D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
0261: }
0262:
0263: // 光源の設定
0264: D3DLIGHT8 light;
0265: ZeroMemory( &light, sizeof(D3DLIGHT8) );
0266: light.Type = D3DLIGHT_DIRECTIONAL;
0267: light.Diffuse.r = 1.0f;
0268: light.Diffuse.g = 1.0f;
0269: light.Diffuse.b = 1.0f;
0270: D3DXVECTOR3 vecDir = D3DXVECTOR3(-lightDir.x, -lightDir.y, lightDir.z);
0271: D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir );
0272: lpD3DDev->SetLight( 0, &light );
0273: lpD3DDev->LightEnable( 0, TRUE );
0274: lpD3DDev->SetRenderState( D3DRS_AMBIENT, 0x00404040 );
0275:
0276: return S_OK;
0277: }
0278: //-----------------------------------------------------------------------------
0279: // Name: DrawModel()
0280: // Desc: Draw Models
0281: //-----------------------------------------------------------------------------
0282:
0283: VOID DrawModel(LPDIRECT3DDEVICE8 lpD3DDev)
0284: {
0285: D3DXMATRIX mWorld, mView, mProj, m;
0286: D3DXVECTOR4 vl;
0287: DWORD i;
0288:
0289: // ビュー行列
0290: D3DXVECTOR3 eye = D3DXVECTOR3(0.0f,18,30);
0291: D3DXVECTOR3 lookAt = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
0292: D3DXVECTOR3 up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
0293: D3DXMatrixLookAtLH(&mView, &eye, &lookAt, &up);
0294: lpD3DDev->SetTransform(D3DTS_VIEW, &mView);
0295:
0296: // 射影行列
0297: D3DXMatrixPerspectiveFovLH(&mProj
0298: ,60.0f*PI/180.0f // 視野角
0299: ,(float)WIDTH/(float)HEIGHT // アスペクト比
0300: ,0.01f,100.0f // 最近接距離,最遠方距離
0301: );
0302: lpD3DDev->SetTransform(D3DTS_PROJECTION, &mProj);
0303:
0304: //
0305: // 背景描画
0306: //
0307: D3DXMatrixScaling(&mWorld, 3.0f, 3.0f, 3.0f);
0308: lpD3DDev->SetTransform(D3DTS_WORLD, &mWorld);
0309: lpD3DDev->SetVertexShader( D3DFVF_VERTEX );
0310: DrawBg(lpD3DDev);
0311:
0312: //
0313: // 外側もでる描画
0314: //
0315: lpD3DDev->SetRenderState( D3DRS_LIGHTING, TRUE );
0316:
0317: lpD3DDev->SetStreamSource(0, pMeshVB, sizeof(D3D_CUSTOMVERTEX));
0318: lpD3DDev->SetIndices(pMeshIndex,0);
0319:
0320: int t = timeGetTime();
0321: D3DXMatrixTranslation(&m, 1.5f*MeshRadius, 0,0);
0322: D3DXMatrixRotationY( &mWorld, t/1000.0f );
0323: //D3DXMatrixRotationY( &mWorld, -0.2*PI/2 );
0324: mWorld = m * mWorld;
0325: lpD3DDev->SetTransform(D3DTS_WORLD, &mWorld);
0326:
0327: for(i=0;i<dwNumMaterials;i++){
0328: lpD3DDev->SetMaterial( &pMeshMaterials[i] );
0329: lpD3DDev->SetTexture(0,pMeshTextures[i]);
0330: lpD3DDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
0331: pSubsetTable[i].VertexStart,
0332: pSubsetTable[i].VertexCount,
0333: pSubsetTable[i].FaceStart * 3,
0334: pSubsetTable[i].FaceCount);
0335: }
0336: //
0337: // 内側もでる描画
0338: //
0339: D3DXMatrixRotationY( &mWorld, -t/3000.0f );
0340: //D3DXMatrixRotationY( &mWorld, -1.4f*PI/2 );
0341: lpD3DDev->SetTransform(D3DTS_WORLD, &mWorld);
0342:
0343: for(i=0;i<dwNumMaterials;i++){
0344: lpD3DDev->SetMaterial( &pMeshMaterials[i] );
0345: lpD3DDev->SetTexture(0,pMeshTextures[i]);
0346: lpD3DDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
0347: pSubsetTable[i].VertexStart,
0348: pSubsetTable[i].VertexCount,
0349: pSubsetTable[i].FaceStart * 3,
0350: pSubsetTable[i].FaceCount);
0351: }
0352: lpD3DDev->SetRenderState( D3DRS_LIGHTING, FALSE );
0353: }
0354: //-----------------------------------------------------------------------------
0355: // Name: Render()
0356: // Desc: Draw the scene
0357: //-----------------------------------------------------------------------------
0358: VOID Render(LPDIRECT3DDEVICE8 lpD3DDev)
0359: {
0360: LPDIRECT3DSURFACE8 lpZbuffer = NULL;
0361:
0362: lpD3DDev->GetDepthStencilSurface( &lpZbuffer );
0363:
0364: // テクスチャーに描画
0365: lpD3DDev->SetRenderTarget(pTextureSurface, lpZbuffer);
0366:
0367: lpD3DDev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_MODULATE);
0368: lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE);
0369: lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG2, D3DTA_DIFFUSE);
0370: lpD3DDev->SetTextureStageState(1,D3DTSS_COLOROP, D3DTOP_DISABLE);
0371: DrawModel(lpD3DDev);
0372:
0373: // 描画をバックバッファに戻す
0374: lpD3DDev->SetRenderTarget(pBackbuffer, lpZbuffer );
0375: for (DWORD i = 0; i < 4; i++) {
0376: lpD3DDev->SetTextureStageState(i, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
0377: lpD3DDev->SetTextureStageState(i, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
0378: lpD3DDev->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
0379: lpD3DDev->SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
0380: lpD3DDev->SetTexture( i, pTexture ); // テクスチャー
0381: }
0382:
0383: lpD3DDev->SetVertexShader(hVertexShader);
0384: lpD3DDev->SetPixelShader(hPixelShader);
0385: lpD3DDev->SetStreamSource( 0, pFinalVB, sizeof(D3D_FINAL_VERTEX) );
0386: lpD3DDev->SetIndices(pFinalIB,0);
0387: lpD3DDev->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 4, 0, 2 );
0388:
0389: lpD3DDev->SetPixelShader(0);
0390: lpD3DDev->SetTexture( 0, NULL);
0391: lpD3DDev->SetTexture( 1, NULL);
0392: lpD3DDev->SetTexture( 2, NULL);
0393: lpD3DDev->SetTexture( 3, NULL);
0394:
0395: #if 0
0396: // 描画した画面をテクスチャーとして描く
0397: {
0398: struct TLVERTEX
0399: {
0400: float x,y,z,rhw;
0401: float tu,tv;
0402: };
0403: #define FVF_TLVERTEX (D3DFVF_XYZRHW | D3DFVF_TEX1)
0404: lpD3DDev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1);
0405: lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE);
0406: lpD3DDev->SetTextureStageState(1,D3DTSS_COLOROP, D3DTOP_DISABLE);
0407: float scale = 64.0f;
0408: TLVERTEX Vertex[4] = {
0409: // x y z rhw tu tv
0410: { 0, 0,0, 1, 0, 0,},
0411: {scale, 0,0, 1, 1, 0,},
0412: {scale,scale,0, 1, 1, 1,},
0413: { 0,scale,0, 1, 0, 1,},
0414: };
0415: lpD3DDev->SetTexture( 0, pTexture );
0416: lpD3DDev->SetVertexShader( FVF_TLVERTEX );
0417: lpD3DDev->SetPixelShader(0);
0418: lpD3DDev->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, Vertex, sizeof( TLVERTEX ) );
0419: }
0420: #endif
0421: }
0422: //-----------------------------------------------------------------------------
0423: // メッシュオブジェクト削除
0424: //-----------------------------------------------------------------------------
0425: void DeleteMeshObject(void)
0426: {
0427: DWORD i;
0428:
0429: if(pMeshVB == NULL) return;
0430:
0431: for(i=0; i<dwNumMaterials; i++){
0432: RELEASE(pMeshTextures[i]);
0433: }
0434: delete[] pMeshTextures;
0435: delete[] pMeshMaterials;
0436: delete[] pSubsetTable;
0437:
0438: RELEASE(pMeshVB);
0439: RELEASE(pMeshIndex);
0440: }
0441: //-----------------------------------------------------------------------------
0442: // Name: CleanRender()
0443: // Desc: 後始末
0444: //-----------------------------------------------------------------------------
0445: void CleanRender(LPDIRECT3DDEVICE8 lpD3DDev)
0446: {
0447: CleanBg(lpD3DDev);
0448:
0449: RELEASE(pTextureSurface);
0450: RELEASE(pTexture);
0451: RELEASE(pBackbuffer);
0452:
0453: RELEASE(pFinalIB);
0454: RELEASE(pFinalVB);
0455: CPixelShaderMgr::Release(lpD3DDev, &hPixelShader);
0456: CVertexShaderMgr::Release(lpD3DDev, &hVertexShader);
0457:
0458: DeleteMeshObject();
0459: }
0460: