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: }