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