0001: // ---------------------------------------------------------------------------- 0002: // 0003: // draw.cpp - 描画部分 0004: // 0005: // Copyright (c) 2002 imagire (imagire@gmail.com) 0006: // All Rights Reserved. 0007: // 0008: // ---------------------------------------------------------------------------- 0009: #define STRICT 0010: 0011: #include <windows.h> 0012: #include <stdio.h> 0013: #include "main.h" 0014: #include "draw.h" 0015: #include "load.h" 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: LPDIRECT3DTEXTURE8 pTexture = NULL; 0028: 0029: CMyView view; // カメラ 0030: 0031: const int RAND_ARRAY = 64; 0032: float rand_tbl[RAND_ARRAY][RAND_ARRAY]; 0033: 0034: 0035: // ---------------------------------------------------------------------------- 0036: // 外部関数 0037: void InitBg(LPDIRECT3DDEVICE8 lpD3DDev); 0038: void DrawBg(LPDIRECT3DDEVICE8 lpD3DDev); 0039: void CleanBg(LPDIRECT3DDEVICE8 lpD3DDev); 0040: 0041: 0042: 0043: // ---------------------------------------------------------------------------- 0044: // Name: LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev) 0045: // Desc: X-Fileの読み込み 0046: //----------------------------------------------------------------------------- 0047: HRESULT LoadXFile(char* filename, LPDIRECT3DDEVICE8 lpD3DDev) 0048: { 0049: LPD3DXMESH pMesh, pMeshOpt; 0050: LPD3DXBUFFER pD3DXMtrlBuffer = NULL; 0051: DWORD i; 0052: HRESULT hr; 0053: 0054: hr = D3DXLoadMeshFromX(filename, D3DXMESH_MANAGED, 0055: lpD3DDev, NULL, 0056: &pD3DXMtrlBuffer, &dwNumMaterials, 0057: &pMesh); 0058: if(FAILED(hr)) return E_FAIL; 0059: 0060: //並び替えておく 0061: pMesh->Optimize(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL, &pMeshOpt); 0062: RELEASE(pMesh); 0063: 0064: //アトリビュートテーブル 0065: pMeshOpt->GetAttributeTable(NULL,&dwNumMaterials); 0066: pSubsetTable = new D3DXATTRIBUTERANGE[dwNumMaterials]; 0067: pMeshOpt->GetAttributeTable(pSubsetTable, &dwNumMaterials); 0068: 0069: // FVF変換 0070: hr = pMeshOpt->CloneMeshFVF(pMeshOpt->GetOptions(), D3DFVF_VERTEX, lpD3DDev, &pMesh); 0071: if(FAILED(hr)) return E_FAIL; 0072: RELEASE(pMeshOpt); 0073: D3DXComputeNormals(pMesh, NULL); 0074: 0075: //Vertex Bufferにコピーする 0076: D3DVERTEX* pSrc; 0077: D3D_CUSTOMVERTEX* pDest; 0078: LPDIRECT3DINDEXBUFFER8 pSrcIndex; 0079: WORD* pISrc; 0080: WORD* pIDest; 0081: 0082: DWORD nMeshVertices = pMesh->GetNumVertices(); 0083: DWORD nMeshFaces = pMesh->GetNumFaces(); 0084: lpD3DDev->CreateVertexBuffer(nMeshVertices * sizeof(D3D_CUSTOMVERTEX),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_MANAGED,&pMeshVB); 0085: lpD3DDev->CreateIndexBuffer(nMeshFaces * 3 * sizeof(WORD),0,D3DFMT_INDEX16,D3DPOOL_MANAGED,&pMeshIndex); 0086: 0087: LPDIRECT3DVERTEXBUFFER8 pVB; 0088: pMesh->GetVertexBuffer(&pVB); 0089: pVB->Lock(0,0,(BYTE**)&pSrc,0); 0090: pMeshVB->Lock(0,0,(BYTE**)&pDest,0); 0091: // サイズの計算 0092: MeshRadius = 0.0f; 0093: float y[2];//min, max 0094: for(i=0;i<nMeshVertices;i++){ 0095: FLOAT radius = sqrtf( pSrc->x*pSrc->x + pSrc->y*pSrc->y + pSrc->z*pSrc->z ); 0096: if (MeshRadius < radius) MeshRadius = radius; 0097: if(i==0||pSrc->y<y[0]) y[0] = pSrc->y; 0098: if(i==0||y[1]<pSrc->y) y[1] = pSrc->y; 0099: pSrc++; 0100: pDest++; 0101: } 0102: pSrc -=nMeshVertices; 0103: pDest-=nMeshVertices; 0104: 0105: for(i=0;i<nMeshVertices;i++){ 0106: pDest->x = pSrc->x; 0107: pDest->y = pSrc->y; 0108: pDest->z = pSrc->z; 0109: pDest->nx = pSrc->nx; 0110: pDest->ny = pSrc->ny; 0111: pDest->nz = pSrc->nz; 0112: // 円柱座標でテクスチャを張る 0113: pDest->tu0 = 2*((float)atan2(pSrc->nz, pSrc->nx) / (2.0f*D3DX_PI) + 0.5f); 0114: pDest->tv0 = (y[1]-pSrc->y) / (y[1]-y[0]); 0115: 0116: pSrc ++; 0117: pDest++; 0118: } 0119: pVB->Unlock(); 0120: pVB->Release(); 0121: pMeshVB->Unlock(); 0122: 0123: //インデックスのコピー 0124: pMesh->GetIndexBuffer(&pSrcIndex); 0125: pSrcIndex->Lock(0,0,(BYTE**)&pISrc,0); 0126: pMeshIndex->Lock(0,0,(BYTE**)&pIDest,0); 0127: CopyMemory(pIDest,pISrc,nMeshFaces * 3 * sizeof(WORD)); 0128: pSrcIndex->Unlock(); 0129: pMeshIndex->Unlock(); 0130: pSrcIndex->Release(); 0131: 0132: // pD3DXMtrlBuffer から、質感やテクスチャーの情報を読み取る 0133: D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); 0134: pMeshTextures = new LPDIRECT3DTEXTURE8[dwNumMaterials]; 0135: pMeshMaterials = new D3DMATERIAL8[dwNumMaterials]; 0136: 0137: for(i = 0; i < dwNumMaterials; i++){ 0138: pMeshMaterials[i] = d3dxMaterials[i].MatD3D; 0139: pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse; 0140: hr = D3DXCreateTextureFromFile( lpD3DDev, 0141: d3dxMaterials[i].pTextureFilename, 0142: &pMeshTextures[i] ); 0143: if(FAILED(hr)) pMeshTextures[i] = NULL; 0144: } 0145: RELEASE(pD3DXMtrlBuffer); 0146: 0147: RELEASE(pMesh); 0148: 0149: return S_OK; 0150: } 0151: 0152: // ---------------------------------------------------------------------------- 0153: // CatmullRom スプライン 0154: // 0155: // 1 ┌ -1 3 -3 1┐┌ Pi-1 ┐ 0156: // xi(t) = ― [t3 t2 t 1]│ 2 -5 4 -1││ Pi │ 0157: // 2 │ -1 0 1 0││ Pi+1 │ 0158: // └ 0 2 0 0┘└ Pi+2 ┘ 0159: // ---------------------------------------------------------------------------- 0160: float CatmullRom(float x0, float x1, float x2, float x3, float t) 0161: { 0162: const D3DXMATRIX m( 0163: -1.0f/2.0f, 3.0f/2.0f, -3.0f/2.0f, 1.0f/2.0f, 0164: 2.0f/2.0f, -5.0f/2.0f, 4.0f/2.0f, -1.0f/2.0f, 0165: -1.0f/2.0f, 0.0f/2.0f, 1.0f/2.0f, 0.0f/2.0f, 0166: 0.0f/2.0f, 2.0f/2.0f, 0.0f/2.0f, 0.0f/2.0f 0167: ); 0168: 0169: float t2 = t*t; 0170: D3DXVECTOR4 vt(t2*t, t2, t, 1.f); 0171: 0172: D3DXVec4Transform(&vt, &vt, &m); 0173: 0174: return x0 * vt.x + x1 * vt.y + x2 * vt.z + x3 * vt.w; 0175: } 0176: // ---------------------------------------------------------------------------- 0177: float CatmullRomPatch(D3DXMATRIX &cp, float s, float t) 0178: { 0179: return CatmullRom( 0180: CatmullRom( cp._11, cp._12, cp._13, cp._14, s), 0181: CatmullRom( cp._21, cp._22, cp._23, cp._24, s), 0182: CatmullRom( cp._31, cp._32, cp._33, cp._34, s), 0183: CatmullRom( cp._41, cp._42, cp._43, cp._44, s), 0184: t); 0185: } 0186: // ---------------------------------------------------------------------------- 0187: float GetNoiseOctave(int octave, float frequency, float x, float y) 0188: { 0189: int ifrequency = (int)frequency; 0190: float t[2] = {frequency * x, frequency * y}; 0191: int no[2] = {(int)t[0], (int)t[1]}; 0192: 0193: int cp[2][4] = { 0194: { (RAND_ARRAY*((no[0]+0)%ifrequency)/ifrequency+octave)%RAND_ARRAY 0195: , (RAND_ARRAY*((no[0]+1)%ifrequency)/ifrequency+octave)%RAND_ARRAY 0196: , (RAND_ARRAY*((no[0]+2)%ifrequency)/ifrequency+octave)%RAND_ARRAY 0197: , (RAND_ARRAY*((no[0]+3)%ifrequency)/ifrequency+octave)%RAND_ARRAY}, 0198: { (RAND_ARRAY*((no[1]+0)%ifrequency)/ifrequency+octave)%RAND_ARRAY 0199: , (RAND_ARRAY*((no[1]+1)%ifrequency)/ifrequency+octave)%RAND_ARRAY 0200: , (RAND_ARRAY*((no[1]+2)%ifrequency)/ifrequency+octave)%RAND_ARRAY 0201: , (RAND_ARRAY*((no[1]+3)%ifrequency)/ifrequency+octave)%RAND_ARRAY}, 0202: }; 0203: 0204: D3DXMATRIX mCp( 0205: rand_tbl[cp[0][0]][cp[1][0]], 0206: rand_tbl[cp[0][1]][cp[1][0]], 0207: rand_tbl[cp[0][2]][cp[1][0]], 0208: rand_tbl[cp[0][3]][cp[1][0]], 0209: 0210: rand_tbl[cp[0][0]][cp[1][1]], 0211: rand_tbl[cp[0][1]][cp[1][1]], 0212: rand_tbl[cp[0][2]][cp[1][1]], 0213: rand_tbl[cp[0][3]][cp[1][1]], 0214: 0215: rand_tbl[cp[0][0]][cp[1][2]], 0216: rand_tbl[cp[0][1]][cp[1][2]], 0217: rand_tbl[cp[0][2]][cp[1][2]], 0218: rand_tbl[cp[0][3]][cp[1][2]], 0219: 0220: rand_tbl[cp[0][0]][cp[1][3]], 0221: rand_tbl[cp[0][1]][cp[1][3]], 0222: rand_tbl[cp[0][2]][cp[1][3]], 0223: rand_tbl[cp[0][3]][cp[1][3]]); 0224: 0225: return CatmullRomPatch( mCp, t[0]-(float)no[0], t[1]-(float)no[1]); 0226: } 0227: // ---------------------------------------------------------------------------- 0228: // テクスチャーを作成 0229: // ---------------------------------------------------------------------------- 0230: VOID MakTexture(D3DXVECTOR4* pOut, D3DXVECTOR2 *pTexCoord, D3DXVECTOR2 *pTexelSize, LPVOID pData) 0231: { 0232: const float PERSISTANCE = 1.0f/4; 0233: const int OCTAVES = 4; 0234: 0235: float shade = 0.0f; 0236: 0237: // 最大の振幅の大きさ 0238: float amplitude = 1.0f/(((float)pow( PERSISTANCE, OCTAVES ) - 1.f)/(PERSISTANCE - 1.f)); 0239: float frequency = 4.0; 0240: 0241: for(int i=0; i<OCTAVES ; i++){ 0242: shade += amplitude * GetNoiseOctave(i, frequency, pTexCoord->x, pTexCoord->y); 0243: 0244: amplitude *= PERSISTANCE; // 振幅は小さく 0245: frequency *= 2; // 周波数は高くなる 0246: } 0247: 0248: // 年輪ぽく加工する 0249: shade = 10*shade; // 10年分の輪 0250: shade = shade - (int)shade; // 小数部を取り出す 0251: 0252: // 色をつける 0253: pOut->x = 0.80f*shade; // 茶色っぽい色にする 0254: pOut->y = 0.36f*shade; 0255: pOut->z = 0.08f*shade; 0256: pOut->w = 1.0f; 0257: } 0258: 0259: //----------------------------------------------------------------------------- 0260: // Name: InitRender() 0261: // Desc: Load the mesh and build the material and texture arrays 0262: //----------------------------------------------------------------------------- 0263: HRESULT InitRender(LPDIRECT3DDEVICE8 lpD3DDev) 0264: { 0265: HRESULT hr; 0266: int i,j; 0267: 0268: // モデルの読み込み 0269: if ( FAILED(hr = LoadXFile("teapot.x", lpD3DDev)) ) return hr; 0270: 0271: // テクスチャーの作成 0272: for(i=0;i<RAND_ARRAY;i++) 0273: for(j=0;j<RAND_ARRAY;j++) 0274: rand_tbl[i][j] = (float)rand()/(float)RAND_MAX; 0275: if( FAILED(hr = lpD3DDev->CreateTexture(512, 512, 1 0276: , D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8 0277: , D3DPOOL_DEFAULT, &pTexture))) return hr; 0278: if( FAILED(hr = D3DXFillTexture(pTexture, MakTexture, NULL))) return hr; 0279: 0280: // 背景部分の初期化 0281: InitBg(lpD3DDev); 0282: 0283: // 不変なレジスタの設定 0284: lpD3DDev->SetRenderState( D3DRS_ZENABLE, TRUE ); 0285: lpD3DDev->SetRenderState( D3DRS_LIGHTING, FALSE ); 0286: lpD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE); 0287: 0288: lpD3DDev->SetTextureStageState(0,D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); 0289: lpD3DDev->SetTextureStageState(0,D3DTSS_MINFILTER, D3DTEXF_LINEAR ); 0290: 0291: return S_OK; 0292: } 0293: //----------------------------------------------------------------------------- 0294: // Name: Render() 0295: // Desc: Draws the scene 0296: //----------------------------------------------------------------------------- 0297: VOID Render(LPDIRECT3DDEVICE8 lpD3DDev) 0298: { 0299: D3DXMATRIX mWorld, mView, mProj; 0300: D3DXMATRIX m; 0301: DWORD i; 0302: 0303: // 0304: // レンダリング用の行列を作成 0305: // 0306: mView = view.Get(); 0307: 0308: // 射影行列 0309: D3DXMatrixPerspectiveFovLH(&mProj 0310: , D3DXToRadian(60.0f) // 視野角 0311: , (float)WIDTH/(float)HEIGHT // アスペクト比 0312: , 0.1f, 100.f // 最近接距離,最遠方距離 0313: ); 0314: lpD3DDev->SetTransform(D3DTS_VIEW, &mView); 0315: lpD3DDev->SetTransform(D3DTS_PROJECTION, &mProj); 0316: 0317: // 0318: // もでる描画 0319: // 0320: D3DXMatrixRotationY( &mWorld, 0 ); 0321: //D3DXMatrixRotationY( &mWorld, 1.4f*PI/2 ); // 撮影角度 0322: lpD3DDev->SetTransform(D3DTS_WORLD, &mWorld); 0323: 0324: lpD3DDev->SetVertexShader(D3DFVF_VERTEX); 0325: lpD3DDev->SetStreamSource(0, pMeshVB, sizeof(D3D_CUSTOMVERTEX)); 0326: lpD3DDev->SetIndices(pMeshIndex,0); 0327: lpD3DDev->SetTexture(0,pTexture); 0328: for(i=0;i<dwNumMaterials;i++){ 0329: lpD3DDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0330: pSubsetTable[i].VertexStart, 0331: pSubsetTable[i].VertexCount, 0332: pSubsetTable[i].FaceStart * 3, 0333: pSubsetTable[i].FaceCount); 0334: } 0335: 0336: // 0337: // 背景描画 0338: // 0339: D3DXMatrixScaling(&mWorld, 3.0f, 3.0f, 3.0f); 0340: D3DXMatrixTranslation(&m, 0, -1.0f*MeshRadius, 0); 0341: mWorld = mWorld * m; 0342: 0343: lpD3DDev->SetTransform(D3DTS_WORLD, &mWorld); 0344: DrawBg(lpD3DDev); 0345: 0346: #if 1 0347: //----------------------------------------------------------------------------- 0348: // でばっぐようにテクスチャを見る 0349: //----------------------------------------------------------------------------- 0350: { 0351: struct TLVERTEX 0352: { 0353: float x,y,z,rhw; 0354: float tu,tv; 0355: }; 0356: #define FVF_TLVERTEX (D3DFVF_XYZRHW | D3DFVF_TEX1) 0357: 0358: lpD3DDev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); 0359: lpD3DDev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); 0360: float scale = 128.0f; 0361: TLVERTEX Vertex[4] = { 0362: // x y z rhw tu tv 0363: { 0, 0,0, 1, 0, 0,}, 0364: {scale, 0,0, 1, 1, 0,}, 0365: {scale,scale,0, 1, 1, 1,}, 0366: { 0,scale,0, 1, 0, 1,}, 0367: }; 0368: lpD3DDev->SetTexture( 0, pTexture ); 0369: lpD3DDev->SetVertexShader( FVF_TLVERTEX ); 0370: lpD3DDev->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, Vertex, sizeof( TLVERTEX ) ); 0371: } 0372: #endif 0373: } 0374: //----------------------------------------------------------------------------- 0375: // メッシュオブジェクト削除 0376: //----------------------------------------------------------------------------- 0377: void DeleteMeshObject(void) 0378: { 0379: DWORD i; 0380: 0381: if(pMeshVB == NULL) return; 0382: 0383: for(i=0; i<dwNumMaterials; i++){ 0384: RELEASE(pMeshTextures[i]); 0385: } 0386: delete[] pMeshTextures; 0387: delete[] pMeshMaterials; 0388: delete[] pSubsetTable; 0389: 0390: RELEASE(pMeshVB); 0391: RELEASE(pMeshIndex); 0392: } 0393: //----------------------------------------------------------------------------- 0394: // Name: CleanRender() 0395: // Desc: 後始末 0396: //----------------------------------------------------------------------------- 0397: void CleanRender(LPDIRECT3DDEVICE8 lpD3DDev) 0398: { 0399: CleanBg(lpD3DDev); 0400: 0401: RELEASE(pTexture); 0402: 0403: DeleteMeshObject(); 0404: } 0405: //----------------------------------------------------------------------------- 0406: // カメラ設定 0407: //----------------------------------------------------------------------------- 0408: static void set_camera(float cam_r, float cam_theta, float cam_phi, const D3DXVECTOR4 &cam_tr) 0409: { 0410: D3DXVECTOR4 v = cam_tr; 0411: view.SetLookAt(v); 0412: v.z += cam_r * (float)cos(cam_phi) * (float)cos(cam_theta); 0413: v.x += cam_r * (float)cos(cam_phi) * (float)sin(cam_theta); 0414: v.y += cam_r * (float)sin(cam_phi); 0415: view.SetEye(v); 0416: } 0417: //----------------------------------------------------------------------------- 0418: // Name: MyMsgProc() 0419: //----------------------------------------------------------------------------- 0420: LRESULT CALLBACK MyMsgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) 0421: { 0422: static int type = 0; 0423: // マウスの位置 0424: static long prevX = 0; 0425: static long prevY = 0; 0426: long x,y,dx,dy; 0427: // カメラ 0428: static D3DXVECTOR4 cam_tr = D3DXVECTOR4(0.0f, 0.5f, 0.0f, 0.0f); 0429: static float cam_r = 4.0f; 0430: static float cam_theta = 0; 0431: static float cam_phi = 0.05f*D3DX_PI; 0432: 0433: switch(msg){ 0434: case WM_CREATE: 0435: set_camera(cam_r, cam_theta, cam_phi, cam_tr); 0436: break; 0437: case WM_LBUTTONDOWN: 0438: type=1; 0439: prevX = (lParam << 16) >> 16; 0440: prevY = lParam >> 16; 0441: SetCapture(hWnd); 0442: break; 0443: case WM_LBUTTONUP: 0444: type=0; 0445: ReleaseCapture(); 0446: break; 0447: case WM_MOUSEMOVE: 0448: x = (lParam << 16) >> 16; 0449: y = lParam >> 16; 0450: dx = x - prevX; 0451: dy = y - prevY; 0452: switch(type){ 0453: case 1:// camera 0454: if(wParam & MK_LBUTTON){ 0455: if(dy != 0){ 0456: cam_phi += 0.005f*dy; 0457: if( 0.499f*D3DX_PI<cam_phi)cam_phi = 0.499f*D3DX_PI; 0458: if(cam_phi<-0.499f*D3DX_PI)cam_phi =-0.499f*D3DX_PI; 0459: set_camera(cam_r, cam_theta, cam_phi, cam_tr); 0460: } 0461: if(dx != 0){ 0462: cam_theta += 0.005f*dx; 0463: set_camera(cam_r, cam_theta, cam_phi, cam_tr); 0464: } 0465: } 0466: break; 0467: } 0468: prevX = x; 0469: prevY = y; 0470: break; 0471: case 0x020A:// WM_MOUSEWHEEL 0472: cam_r += 0.001f*(float)(short)HIWORD(wParam); 0473: if(cam_r<=0.1f)cam_r = 0.1f; 0474: if(7.0f<cam_r)cam_r = 7.0f; 0475: 0476: set_camera(cam_r, cam_theta, cam_phi, cam_tr); 0477: break; 0478: } 0479: 0480: return 0L; 0481: }