全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1099
推到 Plurk!
推到 Facebook!

[推薦] C++ template類TFVFProperties及其在DX8中的應用

 
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-08-14 15:34:24 IP:61.218.xxx.xxx 未訂閱

C template類TFVFProperties及其在DX8中的應用

說明:介紹了C template類TFVFProperties及類TFVFDeclGen的實現 by: 方泓 資料來源:http://www.cpp3d.com/articles/show.asp?aid=104 參考網頁:http://www.cpp3d.com/ 介紹 DX8中的FVF(Flexible Vertex Format Flags)是用來描述在單個數據流里交錯存儲的頂點內容, 它是用一個整形數(DWORD)來表示,更多關于FVF的說明,可以在DX8 SDK文檔[1]中找到。 從FVF的值我們就可以知道此FVF所表示的一些基本屬性。如果我們在編譯時間就知道了這個值,那麼我們甚至在編譯時間就可以知道並利用這些屬性,由此我們可以做一些有趣的應用。但是如何才能在編譯時間就得到這些屬性呢 ? 實現 C 中的template機制就能實現上面所說的目標,這種稱為C Meta Programming的方法是C template的一種有趣而且也有一定實用價值的應用,對此有興趣的人可以讀讀Todd Veldhuizen的著名文章[2]。 在這里我引進一個名為TFVFProperties template類(或結構),它的template參數就是FVF值,這個類非常的單純,就是根據此FVF值在編譯時間算出一些基本屬性,並將這些基本屬性信息保存在里面待用,這樣我們在編譯時就能得到指定FVF中所包含的屬性信息,我們可以利用這些屬性來做一些有趣的應用。 這個類的實現不算很複雜,下面我就直接將實現列在下面: template struct TFVFProperties { BOOST_STATIC_CONSTANT(DWORD, sc_dwFVF = t_dwFVF); private: BOOST_STATIC_CONSTANT(int, _sc_nDummy = 1); public: BOOST_STATIC_CONSTANT(bool, sc_bHasPosition = ((t_dwFVF & D3DFVF_POSITION_MASK) != 0)); BOOST_STATIC_CONSTANT(bool, sc_bHasRHW = ((t_dwFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)); BOOST_STATIC_CONSTANT(bool, sc_bHasWeights = ((t_dwFVF & D3DFVF_POSITION_MASK) >= D3DFVF_XYZB1)); BOOST_STATIC_CONSTANT(bool, sc_bHasMatrixIndices = ((t_dwFVF & D3DFVF_LASTBETA_UBYTE4) != 0)); BOOST_STATIC_CONSTANT(int, sc_nWeights = sc_bHasWeights ? (sc_bHasMatrixIndices ? (t_dwFVF - D3DFVF_XYZB1 & D3DFVF_POSITION_MASK) >> 1 : ((t_dwFVF - D3DFVF_XYZB1 & D3DFVF_POSITION_MASK) >> 1) 1) : _sc_nDummy); BOOST_STATIC_CONSTANT(bool, sc_bHasNormal = ((t_dwFVF & D3DFVF_NORMAL) != 0)); BOOST_STATIC_CONSTANT(bool, sc_bHasPointSize = ((t_dwFVF & D3DFVF_PSIZE) != 0)); BOOST_STATIC_CONSTANT(bool, sc_bHasDiffuse = ((t_dwFVF & D3DFVF_DIFFUSE) != 0)); BOOST_STATIC_CONSTANT(bool, sc_bHasSpecular = ((t_dwFVF & D3DFVF_SPECULAR) != 0)); BOOST_STATIC_CONSTANT(bool, sc_bHasTexCoords = ((t_dwFVF & D3DFVF_TEXCOUNT_MASK) != 0)); BOOST_STATIC_CONSTANT(int, sc_nTexCoords = ((t_dwFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT)); // D3DFVF_TEXCOORDSIZEx #define _M_DIM_TEX(mCoordIndex)\ (0x1432 >> (((t_dwFVF >> ((mCoordIndex - 1) * 2 16)) & 0x03) * 4)) & 0x0F BOOST_STATIC_CONSTANT(int, sc_nDimTex1 = _M_DIM_TEX(1) ? _M_DIM_TEX(1) : _sc_nDummy); BOOST_STATIC_CONSTANT(int, sc_nDimTex2 = _M_DIM_TEX(2) ? _M_DIM_TEX(2) : _sc_nDummy); BOOST_STATIC_CONSTANT(int, sc_nDimTex3 = _M_DIM_TEX(3) ? _M_DIM_TEX(3) : _sc_nDummy); BOOST_STATIC_CONSTANT(int, sc_nDimTex4 = _M_DIM_TEX(4) ? _M_DIM_TEX(4) : _sc_nDummy); BOOST_STATIC_CONSTANT(int, sc_nDimTex5 = _M_DIM_TEX(5) ? _M_DIM_TEX(5) : _sc_nDummy); BOOST_STATIC_CONSTANT(int, sc_nDimTex6 = _M_DIM_TEX(6) ? _M_DIM_TEX(6) : _sc_nDummy); BOOST_STATIC_CONSTANT(int, sc_nDimTex7 = _M_DIM_TEX(7) ? _M_DIM_TEX(7) : _sc_nDummy); BOOST_STATIC_CONSTANT(int, sc_nDimTex8 = _M_DIM_TEX(8) ? _M_DIM_TEX(8) : _sc_nDummy); #undef _M_DIM_TEX private: BOOST_STATIC_CONSTANT(bool, _sc_bIsValid = sc_bHasPosition && (sc_bHasNormal || sc_bHasDiffuse || sc_bHasSpecular || sc_bHasTexCoords) && ! (sc_bHasRHW && (sc_bHasNormal || sc_bHasWeights))); M_CAssert(sc_nTexCoords <= 8); M_CAssert(_sc_bIsValid); }; 由此類的實現可以看出,象sc_bHasPosition這樣的bool值屬性的獲取是非常簡單的,只要將FVF值與D3DFVF_POSITION_MASK相與看是否為0就可以得到了。一些屬性數值的取得較為複雜一些,如sc_nWeights, sc_nDimTex* 等,不過相信只要仔細看DX8SDK的文檔[1]可以得到解答,在此我不再說明。 應用 下面我們來看TFVFProperties的一個簡單應用:根據FVF自動生成Vertex shader的declaration token數組,我們可以用下面這個template類來做這項工作: template struct TFVFDeclGen { BOOST_STATIC_CONSTANT(DWORD, e_StreamNumber = t_dwStreamNumber); public: static const DWORD sm_adwDecl[D3DVSDE_NORMAL2 2 1]; }; template const DWORD TFVFDeclGen::sm_adwDecl[] = { D3DVSD_STREAM(e_StreamNumber), TFVFProperties::sc_bHasPosition ? D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3) : D3DVSD_NOP(), TFVFProperties::sc_bHasWeights ? D3DVSD_REG(D3DVSDE_BLENDWEIGHT, (TFVFProperties::sc_nWeights == 1) ? D3DVSDT_FLOAT1 : (TFVFProperties::sc_nWeights == 2) ? D3DVSDT_FLOAT2 : (TFVFProperties::sc_nWeights == 3) ? D3DVSDT_FLOAT3 : (TFVFProperties::sc_nWeights == 4) ? D3DVSDT_FLOAT4 : D3DVSDT_FLOAT4) : D3DVSD_NOP(), TFVFProperties::sc_bHasMatrixIndices ? D3DVSD_REG(D3DVSDE_BLENDINDICES, D3DVSDT_UBYTE4) : D3DVSD_NOP(), TFVFProperties::sc_bHasNormal ? D3DVSD_REG(D3DVSDE_NORMAL, D3DVSDT_FLOAT3) : D3DVSD_NOP(), TFVFProperties::sc_bHasPointSize ? D3DVSD_REG(D3DVSDE_PSIZE, D3DVSDT_FLOAT1) : D3DVSD_NOP(), TFVFProperties::sc_bHasDiffuse ? D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR) : D3DVSD_NOP(), TFVFProperties::sc_bHasSpecular ? D3DVSD_REG(D3DVSDE_SPECULAR, D3DVSDT_D3DCOLOR) : D3DVSD_NOP(), #define _M_GenTexureDecl(mN, mN_1)\ TFVFProperties::sc_nTexCoords >= ##mN\ ? D3DVSD_REG(D3DVSDE_TEXCOORD##mN_1,\ (D3DVSDT_FLOAT1 TFVFProperties::sc_nDimTex##mN - 1))\ : D3DVSD_NOP() _M_GenTexureDecl(1, 0), _M_GenTexureDecl(2, 1), _M_GenTexureDecl(3, 2), _M_GenTexureDecl(4, 3), _M_GenTexureDecl(5, 4), _M_GenTexureDecl(6, 5), _M_GenTexureDecl(7, 6), _M_GenTexureDecl(8, 7), #undef _M_GenTexureDecl D3DVSD_NOP(), // D3DVSDE_POSITION2 D3DVSD_NOP(), // D3DVSDE_NORMAL2 D3DVSD_END() }; 代碼很容易理解,在這我不加解說了。這樣的話我們在編譯時就能求出數組的值,省了一點點運行開銷,這個方法我去年底曾經在cpp3d的論壇上簡單說過,也有朋友認為這數組可能是運行時才算出的,所以我還寫了一個最簡單的試驗程序在VC6 SP5下驗証了一下: { ... const DWORD dwFVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; printf("%X\n%X-%X-%X-%X\n%X-%X-%X-%X\n%X-%X-%X-%X\n%X-%X-%X-%X-%X\n%X\n" , TFVFDeclGen::m_adwDecl[0], ...); ... } 用IDA反匯編出來的代碼可以清楚的看到生成的declaration 數組: 可見在這些值並非在運行時才計算出的。 ; Segment type: Pure data _rdata segment para public 'DATA' use32 assume cs:_rdata ;org 4070DCh db 0 ; db 0 ; db 0 ; db 0 ; dword_4070E0 dd 20000000h ; DATA XREF: _main 76r dword_4070E4 dd 40020000h ; DATA XREF: _main 6Fr dword_4070E8 dd 0 ; DATA XREF: _main 68r dword_4070EC dd 0 ; DATA XREF: _main 62r dword_4070F0 dd 40020003h ; DATA XREF: _main 5Br dword_4070F4 dd 0 ; DATA XREF: _main 54r dword_4070F8 dd 0 ; DATA XREF: _main 4Er dword_4070FC dd 0 ; DATA XREF: _main 47r dword_407100 dd 40010007h ; DATA XREF: _main 40r dword_407104 dd 0 ; DATA XREF: _main 3Ar dword_407108 dd 0 ; DATA XREF: _main 33r dword_40710C dd 0 ; DATA XREF: _main 2Cr dword_407110 dd 0 ; DATA XREF: _main 26r dword_407114 dd 0 ; DATA XREF: _main 1Fr dword_407118 dd 0 ; DATA XREF: _main 18r dword_40711C dd 0 ; DATA XREF: _main 12r dword_407120 dd 0 ; DATA XREF: _main Br dword_407124 dd 0 ; DATA XREF: _main 5r dword_407128 dd 0FFFFFFFFh ; DATA XREF: _mainr 下面我們來看看如何使用這個類的代碼示例: class CD3DVertexShader { .... public: #define M_FVF2Decl(mFVF) meta::TType2Type >() template inline bool Create(TWrapDecl, const DWORD* pVSCode) { return Create(TWrapDecl::TOriginalType::sm_adwDecl, pVSCode); } inline bool Create(const DWORD* pdwDecl, const DWORD* pVSCode) { DWORD dwUsage = 0L; if (CD3DRenderDevice::Instance()->IsSoftwareVertexProcessing()) dwUsage |= D3DUSAGE_SOFTWAREPROCESSING; // Create the vertex shader return SUCCEEDED(CD3DRenderDevice::Instance()->CreateVertexShader(...); } ... }; const DWORD c_dwFVF0 = D3DFVF_XYZ | D3DFVF_DIFFUSE; const DWORD c_dwFVF1 = D3DFVF_XYZ | D3DFVF_DIFFUSE; const DWORD c_dwFVF2 = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1, const DWORD c_dwFVF3 = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1; ... { ... // Create the vertex shader m_VS0.Create(M_FVF2Decl(c_dwFVF0), dwSimple0VertexShader); m_VS1.Create(M_FVF2Decl(c_dwFVF1), dwSimple1VertexShader); m_VS2.Create(M_FVF2Decl(c_dwFVF2), dwSimple2VertexShader); m_VS3.Create(M_FVF2Decl(c_dwFVF3), dwSimple3VertexShader); ... } 這里需要提醒的是,declaration是提供給shader使用的,用來表達輸入數值的秩序,所以記得你的shader代碼得到輸入數據要和它一致。 對比D3DX中的D3DXDeclaratorFromFVF()方法,這種方法在編譯時生成數組,沒什麼運行開銷。但是需要FVF是一個編譯時知道的常量。而D3DXDeclaratorFromFVF()則是運行期間生成declaration數組的,有一點點運行開銷,但是FVF不必是常量。對比實際中更常用的直接定義declaration數組,好處是比較方便,不需要定義,但不能用于一些特殊情況,而且有多個Stream時就用不上了,而直接定義則有很大的靈活性,所以在實用中可以幾種方法一起使用。 總結 本文介紹了一個C template類TFVFProperties及其實現,並介紹它的一個具體應用,生成靜態Vertex Shader的declaration數組,可以在某些情況下簡化編程,但要注意在使用上有一些限制。 下一篇我將介紹應用TFVFProperties的一個更為複雜的應用。 注釋 [1] Microsoft Corp., Microsoft DirectX 8.1 SDK. Microsoft Visual C Documentation Homepage, Microsoft Corp., 2001. [2] Todd Veldhuizen. "Template Metaprograms.", C Report, 7, May, pp 36-43, 1995. 時間就是金錢---[ 發問前請先找找舊文章]
系統時間:2024-04-20 15:21:03
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!