DirectX (26.)

Je tu dalÜφ pokraΦovßnφ kurzu o Direct3D! V prvnφ Φßsti dneÜnφ lekce se budeme podrobn∞ji v∞novat texturovßnφ objekt∙ v 3D scΘn∞. V druhΘ sekci ud∞lßme takovou menÜφ p°φpravu pro p°φÜtφ lekci, kde se budu v∞novat optimalizacφm p°i vykreslovßnφ. P°idßme tedy do projektu nov² projekt Input, kter² vyu₧ijeme pro ovlßdßnφ kamery pou₧itΘ v p°φÜtφ lekci.

26.1. Texturovßnφ 2

26.1.2. Adresovacφ re₧imy

Ve 21. lekci DirectX jsme si n∞co mßlo o texturovßnφ pov∞d∞li. ╪ekli jsme si, ₧e objekt, na kter² chceme nanΘst texturu musφ b²t slo₧en z vertex∙ obsahujφcφ alespo≥ jednu sadu texturov²ch sou°adnic. TakΘ jsme si pov∞d∞li, jak tyto sou°adnice fungujφ. Rozsah hodnot je obyΦejn∞ od 0.0 do 1.0. Hodnotami mimo tento rozsah m∙₧eme vytvo°it n∞kterΘ specißlnφ efekty. Tak zvan²m adresovacφm re₧imem (texture address mode) urΦφme, jak²m zp∙sobem se textura nanßÜφ v t∞chto specißlnφch p°φpadech.
V D3D existujφ 4 adresovacφ re₧imy (AR):

  1. Wrap AR
  2. Mirror AR
  3. Clamp AR
  4. Border color AR

Adresovacφ re₧im nastavφme pomocφ metody SetTextureStageState(), kterß mß t°i parametry: Φφslo stage (o stage u₧ jsme si n∞co mßlo povφdali a vφce se dovφte dßle v tΘto lekci), parametr, kter² chceme m∞nit (v naÜem p°φpad∞ D3DTSS_ADDRESSU, D3DTSS_ADDRESSV nebo D3DTSS_ADDRESSW - znamenß to, ₧e m∙₧eme pro ka₧d² sm∞r nastavit jin² adresovacφ re₧im) a nakonec zadßvßme hodnotu:  D3DTADDRESS_WRAPD3DTADDRESS_MIRROR, D3DTADDRESS_CLAMP nebo D3DTADDRESS_BORDER.

1. Wrap AR

Pokud nastavφte tento adresovacφ re₧im, textura se nanese p°esn∞ tak jak bychom Φekali. Pokud nap°φklad zadßte sou°adnice pro Φtverec tak, ₧e prvnφ vertex mß (0.0, 0.0), druh² (0.0, 3.0), t°etφ (3.0, 0.0) a Φtvrt² (3.0, 3.0), nanese se textura nßsledovn∞:

Textura se tedy nanese t°ikrßt v obou sm∞rech a nep°evracφ se.

2. Mirror AR

P°edpoklßdejme stejn² Φtverec jako p°edchßzejφcφm p°φklad∞. Zde se prvnφ °ada nanese stejn∞, druhß se zrcadlov∞ otoΦφ a t°etφ je zase stejnß. Nastavili jsme zrcadlenφ i ve svislΘm sm∞ru, tak₧e i sloupce jsou otoΦeny.

Kdybychom nastavili pouze vodorovnΘ zrcadlenφ pomocφ parametru D3DTSS_ADDRESSU, otoΦila by se jen prost°edφ °ada a vÜechno ostatnφ by z∙stalo jako v prvnφm p°φpad∞.

3. Clamp AR

Nynφ pou₧ijeme stejn² Φtverec, ale jinou texturu. Tento re₧im pracuje tak, ₧e jednou se nanese textura, jak bychom Φekali a na zbytek Φtverce se roztßhnou okrajovΘ pixely textury:

A op∞t lze nastavit tento re₧im v jednom sm∞ru, tak₧e k rozta₧enφ pak dojde nap°φklad jen ve svislΘm sm∞ru a ve vodorovnΘm se m∙₧e textura opakovat nebo zrcadlit.

4. Border color AR

A mßme tu poslednφ mo₧n² re₧im, kter² mß mnoho spoleΦnΘho s p°edchßzejφcφm, proto pou₧ijeme stejnou texturu. Op∞t se nanese textura na pozice (0.0,0.0) a₧ (1.0,1.0) (jako bychom pou₧ili rozsah 0.0 a₧ 1.0) a na zbytek se nanese po₧adovanß barva! Na obrßzku vidφte tento re₧im v akci:

Barvu, kterß se pou₧ije v tomto p°φpad∞ nastavφme op∞t pomocφ metody SetTextureStageState(), ale pou₧ijeme parametr D3DTSS_BORDERCOLOR, poslednφ parametr je samotnß barva v RGBA formßtu.

Pokud nenastavφte explicitn∞ ₧ßdn² adresovacφ re₧im, je nastaven wrap AR! VÜechny popsanΘ re₧imy si ukß₧eme v p°φkladu na zßv∞r lekce.

26.1.2. Mφchßnφ textur

Princip

V dalÜφ Φßsti se budeme v∞novat technice zvanΘ mφchßnφ textur (angl. texture blending), kterß se Φasto pou₧φvß pro vytvo°enφ zajφmav²ch efekt∙. Zde se takΘ koneΦn∞ dozvφte, k Φemu je pot°eba vφce sad texturov²ch sou°adnic. V Direct3D m∙₧ete smφchat a₧ 8 textur najednou, zßrove≥ tφm tedy zoptimalizujete vykreslovßnφ scΘny - pro ka₧dou texturu se pou₧ije jinß sada sou°adnic. Mφchßnφm textur navφc m∙₧ete docφlit zajφmav²ch efekt∙ jako jsou stφny, r∙znΘ sv∞tla atd. D3D pou₧φvß pro mφchßnφ tzv. stupn∞ (angl. stages). O t∞ch u₧ tu byla takΘ °eΦ. P°i v²poΦtu se do ka₧dΘho stupn∞ posφlajφ dva parametry (nap°φklad ze zdrojovΘ textury) a na t∞chto argumentech se provede po₧adovanß operace. V²sledek se ulo₧φ do nßsledujφcφho stupn∞, tak₧e vznikß kaskßda:

BarevnΘ Üipky znamenajφ vstupnφ parametry ka₧dΘho stupn∞, Φernß Üipka je v²stup. Na obrßzku je vid∞t pou₧itφ Φty° stup≥∙, ale v D3D jich m∙₧ete pou₧φt a₧ osm (samoz°ejm∞ to zßle₧φ takΘ na tom, co dovede vßÜ hardware). Takto p∙vodnφ textura probublßvß p°es stage 0 a₧ 3. Na ka₧dΘ stage se mφchß s texturou nebo s barvou vertexu (zde se bere bu∩ difuznφ nebo specular slo₧ka viz. Argumenty).

V DirectX SDK 8.1 je p°φklad MFC Tex, kter² demonstruje vÜechny mo₧nΘ kombinace mφchßnφ textur. V programu m∙₧ete nastavit libovolnΘ argumenty a libovoln² operßtor pro ka₧d² stupe≥, zvolit texturu, barvu atd. Proto mφchßnφ textur nezahrnu do p°φkladu z dneÜnφ lekce, ale v budoucnu to jist∞ pou₧ijeme.

Argumenty

Ka₧dΘmu stupni  lze p°i°adit dva argumenty, kterΘ ovliv≥ujφ barevn² nebo alpha kanßl v²slednΘ textury (to znamenß, ₧e se bude pracovat s barvou textury nebo s alpha kanßlem). Uvedu zde argumenty, kterΘ budeme pozd∞ji pou₧φvat v naÜem programu:

D3DTA_CURRENT
- pou₧ije se v²sledek operace z p°edeÜlΘho stupn∞. Stupe≥ 0 nemß ₧ßdn² p°edchozφ, tudφ₧ mß tento argument stejn² v²znam jako D3DTA_DIFFUSE.

D3DTA_DIFFUSE
- pou₧ije se difuznφ barva interpolovanß od okolnφch vertex∙ (viz. prvnφ lekce, kde jsme m∞li troj·helnφk, jeho₧ vertexy m∞ly ka₧d² jinou barvu, pak byla barva pixel∙ mezi interpolovßna). Pokud vertexy neobsahujφ difuznφ slo₧ku, pou₧ije se hodnota 0xFFFFFFFF.

D3DTA_SPECULAR
- funguje stejn∞ jako p°edchßzejφcφ parametr, jen se pracuje se specular barvou vertex∙

D3DTA_TEXTURE
- jako argument se pou₧ije barva textury, kterß je nastavena pro tento stupe≥ pomocφ metody SetTexture()

D3DTA_TFACTOR
- jako argument se pou₧ije  vlastnφ hodnota (texture factor) p°edem zadanß pomocφ metody SetRenderState() s parametrem  D3DRS_TEXTUREFACTOR.

D3DTA_TEMP
- pomocn² registr, kam m∙₧ete ulo₧it v²sledek n∞jakΘ operace a pou₧φt ho nap°φklad v nßsledujφcφ stupni nebo i pozd∞ji! Pokud se rozhodnete pomocn² registr pou₧φvat, m∞li byste zjistit, zda-li ho cφlov² hardware podporuje pomocφ p°φznaku D3DPMISCCAPS_TSSARGTEMP.

Argumenty nastavφme pomocφ metody SetTextureStageState() s parametrem stupn∞ a hodnotou urΦujφcφ, kter² argument chceme zm∞nit. Tyto hodnoty jsou nßsledujφcφ: D3DTSS_COLORARG0, D3DTSS_COLORARG1, D3DTSS_COLORARG2, D3DTSS_ALPHAARG0, D3DTSS_ALPHAARG1, D3DTSS_ALPHAARG2 a D3DTSS_RESULTARG. P°ed chvilkou jsem °φkal, ₧e se do ka₧dΘho stupn∞ posφlajφ pouze dva parametry a tady mßme pro barevnou i pro alpha slo₧ku t°i argumenty!  T°etφ argument se nastavuje jen pro specißlnφ operace, kterΘ vy₧adujφ t°i parametry (drtivß v∞tÜina vy₧aduje pouze dva). Poslednφm parametrem D3DTSS_RESULTARG urΦφme, zda-li se v²sledek operace ulo₧φ pro nßsledujφcφ stupe≥ (D3DTA_CURRENT) nebo do pomocnΘho registru (D3RTA_TEMP). Poslednφ stupe≥ nesmφ mφt nastaven v²stup do pomocnΘho registru.
Nastaven² argument m∙₧ete zjistit metodou GetTextureStateState(). Tato metoda mß stejnΘ parametry, jen poslednφ parametr je ukazatel, na jeho₧ hodnotu se ulo₧φ v²sledek metody.

P°φklad:

Chceme-li nap°φklad nastavit, ₧e v²sledek 2. stupn∞ se mß ulo₧it do pomocnΘho registru, zavolßme metodu s parametry:

lpDevice->SetTextureStageState(2, D3DTSS_RESULTARG, D3RTA_TEMP);

Nebo, chceme-li smφchat texturu s barvou vertex∙, pou₧ijeme p°φkazy:

lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3RTA_TEXTURE);
lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3RTA_DIFFUSE);

Zkrßtka nastavφme jako vstupnφ parametry texturu a difuznφ barvu vertex∙. JeÜt∞ jsme samoz°ejm∞ nenastavili operaci, o t∞ch se dozvφte v dalÜφ Φßsti.

Dopl≥ujφcφ p°φznaky argument∙
- tyto parametry se mohou kombinovat s v²Üe uveden²mi hodnotami:

D3DTA_ALPHAREPLICATE
- zkopφruje se hodnota alpha kanßlu na vÜechny barevnΘ kanßly.

D3DTA_COMPLEMENT
- pou₧ije se dopl≥kovß hodnota argumentu. Nap°φklad je-li argument hodnota X, p°i v²poΦtu se pou₧ije hodnota 1 - X.

Operßtory

Implicitn∞ jsou vÜechny stupn∞ krom∞ prvnφho vypnuty tzn., ₧e nemajφ nastavenou operaci. Pokud pou₧φvßme pro r∙znΘ objekty r∙zn² poΦet stup≥∙, musφme nepot°ebnΘ stupn∞ vypnout (viz. dßle). Nemusφme ovÜem vypφnat vÜechny, staΦφ jen prvnφ nepou₧it², ostatnφ se pak rovn∞₧ nepou₧ijφ.

Pokud nastavφte operaci pro urΦit² stupe≥, musφte takΘ zajistit sprßvnΘ parametry pro tento stupe≥. Chcete-li nastavit operaci (m∙₧ete pro barevn² nebo pro alpha kanßl), op∞t pou₧ijete metodu SetTextureStageState(), ale s parametrem D3DTSS_COLOROP nebo D3DTSS_ALPHAOP. Nßsleduje v²Φet operacφ (op∞t zde uvedu pouze ty, kterΘ budeme pou₧φvat):

D3DTOP_DISABLE
- tato hodnota samoz°ejm∞ nevyjad°uje ₧ßdnou operaci, jen urΦφ, ₧e v²stup tohoto stupn∞ je vypnut. Jak bylo zmφn∞no v²Üe, pokud je nap°φklad 3. stupe≥ vypnut, nßsledujφcφ stupn∞ se rovn∞₧ nepou₧ijφ.

D3DTOP_SELECTARG1
- operace pouze zkopφruje hodnotu argumentu 1 na v²stup. VhodnΘ nap°φklad pro 0. stupe≥, kdy₧ vstupnφ texturu nechceme upravovat, jen ji poslat do dalÜφho stupn∞ a tam nap°φklad smφchat s jinou texturou.

D3DTOP_SELECTARG2
- analogicky stejnΘ jako p°edchozφ parametr, jen pracujeme s druh²m parametrem. Nßsledujφ trochu zajφmav∞jÜφ operace.

D3DTOP_MODULATE
- modulace spoΦφvß v jednoduchΘm vztahu:

S = Arg1 x Arg2

Je to prostΘ nßsobenφ vstupnφch parametr∙.

D3DTOP_MODULATE2X
- modulace s dvojit²m zesv∞tlenφm:

S = (Arg1 x Arg2) << 1

V²sledek modulace je jeÜt∞ vynßsoben dv∞ma.

D3DTOP_MODULATE4X
- modulace se Φty°nßsobn²m zesv∞tlenφm:

S = (Arg1 x Arg2) << 2

V²sledek modulace je vynßsoben Φty°mi.

D3DTOP_ADD
- sΦφtßnφ vstupnφch parametr∙

S = Arg1 + Arg2

D3DTOP_ADDSIGNED
- sΦφtßnφ vstupnφch parametr∙ se zajiÜt∞nφm v²stupu v rozsahu -0,5 a₧ 0,5

S = Arg1 + Arg2 - 0,5

D3DTOP_ADDSIGNED2X
- v²sledek je stejn² jako p°edchozφ hodnota, navφc zde dojde k bitovΘmu posunu doleva Φili k nßsobenφ dv∞ma

S = (Arg1 + Arg2 - 0,5) << 1

D3DTOP_SUBTRACT
- odeΦφtßnφ druhΘho parametru od prvnφho

S = Arg1 - Arg2

D3DTOP_ADDSMOOTH
- seΦtenφ obou parametr∙ a potΘ odeΦtenφ jejich nßsobku

S = Arg1 + Arg2 - Arg1 x Arg2 = Arg1 + Arg2(1 - Arg1)

D3DTOP_BLENDDIFFUSEALPHA,D3DTOP_BLENDTEXTUREALPHA, D3DTOP_BLENDFACTORALPHA a D3DTOP_BLENDCURRENTALPHA
- tyto parametry jsou velice u₧iteΦnΘ! Mφchßnφ textury s pou₧itφm alpha informace bu∩ z alpha slo₧ek difuznφ barvy vertex∙ (D3DTOP_BLENDDIFFUSEALPHA) nebo se bere alpha z textury nastavenΘ v tomto stupni (D3DTOP_BLENDTEXTUREALPHA) nebo se vezme skalßrnφ hodnota (D3DTOP_BLENDFACTORALPHA - pou₧itφ viz. v²Üe) anebo se vezme alpha z p°edeÜlΘho stupn∞ (D3DTOP_BLENDCURRENTALPHA).

S = Arg1 x Alpha + Arg2 x (1 - Alpha)

Pomocφ poslednφ operace m∙₧eme bez problΘmu °φdit prolφnßnφ dvou textur bu∩ pomocφ faktoru nebo pomocφ alpha informace z vertex∙, tak₧e m∙₧ete docφlit postupnΘho prolφnßnφ a podobn∞.

P°φklad:

PokraΦujme ve v²Üe uvedenΘm p°φkladu a p°idejme operaci:

lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3RTA_TEXTURE);
lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3RTA_DIFFUSE);

lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE2X);

Takto vytvo°φme efekt, kde se nastavenß textura a barva vertex∙ moduluje tzn. nßsobφ! DoporuΦuji si zkusit v²Üe uveden² p°φklad obsa₧en² v DirectX SDK 8.0 i 9.0. K problΘmu texturovßnφ se jeÜt∞ jednou vrßtφme v n∞kterΘ z p°φÜtφch lekcφ.

26.2. Projekt Input a rozhranφ ID3DXSprite

V druhΘ Φßsti dneÜnφ lekce vlo₧φme nov² projekt Input. S tφmto projektem jsme se ji₧ n∞kolikrßt setkali v minul²ch lekcφch. Nynφ ho pou₧ijeme pro ovlßdßnφ kamery, ale to a₧ v p°φÜtφ lekci.. V∞tÜina projektu z∙stane nezm∞n∞nß, pouze pro vykreslovßnφ kurzoru pochopiteln∞ nem∙₧eme pou₧φt DirectDraw. Proto pou₧ijeme rozhranφ ID3DXSprite, kterΘ nahrazuje 2D sprite z DirectDraw.

Tento sprite vytvo°φme funkcφ knihovny D3DX D3DXCreateSprite(), kterß mß pouze dva parametry a to ukazatel na za°φzenφ a v²stupnφ parametr - samotn² ukazatel na rozhranφ spritu. Dßle pou₧ijeme ΦlenskΘ funkce Begin(), End() a Draw(). Metodou Begin() p°ipravφme za°φzenφ pro vykreslenφ spritu. Metodou End() naopak vykreslovßnφ ukonΦφme. Poslednφ uvedenß metoda Draw() mß °adu parametr∙ (podobn∞ jako funkce Blt() v DirectDraw), kterΘ si podrobn∞ji rozebereme:

  1. Ukazatel na zdrojovou texturu (IDirect3D8Texture*)

  2. Ukazatel na zdrojov² obdΘlnφk, ze kterΘho se vykresluje

  3. Ukazatel na 2D vektor urΦujφcφ m∞°φtko v x a y ose. Pokud je NULL, pou₧ije se vektor (1.0, 1.0), co₧ znamenß, ₧e m∞°φtko v²slednΘho obrßzku se nem∞nφ.

  4. Ukazatel na 2D vektor, kter²m m∙₧eme urΦit st°ed otßΦenφ (pokud pou₧ijeme nßsledujφcφ parametr). St°ed je brßn v∙Φi bodu 0.0, 0.0 samotnΘho spritu, co₧ je takΘ implicitnφ nastavenφ, pokud zadßte NULL.

  5. Reßlnß hodnota ·hlu v radißnech, o kter² se sprite otoΦφ (podle st°edu urΦenΘho p°edchßzejφcφm parametrem).

  6. Ukazatel na 2D vektor urΦujφcφ polohu spritu na monitoru.

  7. Barva spritu, kterou je zdrojovß textura modulovßna (viz. p°edchßzejφcφ Φßst lekce). M∙₧ete tak docφlit r∙zn²ch efekt∙.

Jak jsem zmφnil, my pou₧ijeme tento objekt pro kurzor. V p°edeÜlΘ verzi knihovny Input, jsme vytvo°ili t°φdu CCursor, kterß m∞la vlastnφ povrch CSurface. Nynφ to bude sprite ID3DXSprite a textura XTexture. Zde nastßvß nßsledujφcφ problΘm. Velikost textury je v₧dy nßsobkem dvou (16, 32, 64, 256 atd), tak₧e i kdy₧ mßme bitmapu o velikosti 320x200, bude vytvo°ena textura o velikosti 512x256 (nejbli₧Üφ vyÜÜφ formßt). Pokud se pak z tΘto textury sna₧φme vykreslovat nap°φklad animovan² kurzor, musφme peΦliv∞ p°epoΦφtat zdrojovΘ sou°adnice na sou°adnice v textu°e a potΘ v²sledn² obrßzek sprßvn∞ zv∞tÜit Φi zmenÜit, aby m∞l rozm∞r jako zdrojovß bitmapa. To nenφ v n∞kter²ch p°φpadech v∙bec mo₧nΘ, nebo¥ p°esnost integeru je omezena a zdrojov² obdΘlnφk je bohu₧el zadßvßn Φty°mi integer hodnotami. Z toho plynou docela vysokΘ po₧adavky na velikost zdrojovΘ bitmapy a na poΦet animaΦnφch krok∙. Ideßlnφ je nap°φklad p°φpad, kdy velikosti bitmapy a textury jsou stejnΘ (nap°φklad pokud mß bitmapa rozm∞ry 512x32 bude mφt i textura z tΘto bitmapy vytvo°enß stejnΘ rozm∞ry) a pak Üφ°ka tΘto textury je d∞litelnß poΦtem animaΦnφch krok∙. Zdß se to trochu slo₧itΘ, ₧e? Zkrßtka si zkuste vyd∞lit skuteΦnou Üφ°ku textury poΦtem animaΦnφch krok∙ a m∞la by vßm vyjφt Üφ°ka polφΦka (nap°φklad 32 pixel∙) nebo alespo≥ celΘ Φφslo. Je-li tedy textura Üirokß 1024 pixel∙ a chceme polφΦko 32 pixel∙, je vhodnΘ vytvo°it 32 animaΦnφch krok∙ (32 x 32  = 1024).

Podφvejme se na upravenou t°φdu CCursor:

class INPUT_API CCursor
{
    BOOL m_bInit;
    int m_iWidth;
    int m_iHeight;

    LPD3DXSPRITE m_d3dCursor;
    LPDIRECT3DDEVICE8 m_lpDevice;
    XTexture * m_lpTexture;

    int m_iPhase;
    int m_iSpeed;
    int m_nPhases;
    DWORD m_dwOldTime;

public:
    HRESULT Create(LPCSTR csIntPath, int cx, int cy, LPDIRECT3DDEVICE8 lpDevice);
    HRESULT Create(LPCSTR csIntPath, int cx, int cy, int nSpeed, int iPhases, LPDIRECT3DDEVICE8 lpDevice);
    HRESULT Update(D3DXVECTOR2* ptCursor);

public:
    CCursor();
    ~CCursor();
};

Zde se tΘm∞° nic nezm∞nilo. Jen p°ibyl atribut spritu a CSurface je vym∞n∞n za XTexture. Nakonec se trochu zm∞nily parametry u metod.

Zajφmav∞jÜφ budou metody Create() a Update():

HRESULT CCursor::Create(LPCSTR csIntPath, int cx, int cy, LPDIRECT3DDEVICE8 lpDevice)
{
    DWORD dwRet = 1;
    if(!m_bInit && lpDevice) {

        m_iWidth = cx;
        m_iHeight = cy;
        m_lpDevice = lpDevice;

      
 //
        // Try to create the sprite

        dwRet = D3DXCreateSprite(m_lpDevice, &m_d3dCursor);
        if(dwRet != ERROR_SUCCESS) {
            TRACE("Cannot create the sprite due", dwRet);
            return dwRet;
        }
      
 //        
      
 // Create texture
        m_lpTexture = new XTexture;
        dwRet = m_lpTexture->LoadTextureFromFile(csIntPath, lpDevice);
        if(dwRet != ERROR_SUCCESS) {
            ERR("Cannot create surface for cursor due", dwRet);
            return dwRet;
        }
        m_bInit = true;
        dwRet = ERROR_SUCCESS;
    }
    return dwRet;
}

Zde za prvΘ vytvß°φme objekt D3DXSprite a za druhΘ nahrßvßme textury z bitmapy. Zbytek metody je stejn².

HRESULT CCursor::Create(LPCSTR csIntPath, int cx, int cy, int iSpeed, int iPhases, LPDIRECT3DDEVICE8 lpDevice)
{
    DWORD dwRet = 1;
    if(!m_bInit) {
      
 //
        // Call standard creation

        dwRet = Create(csIntPath, cx, cy, lpDevice);
        if(dwRet == ERROR_SUCCESS) {
            m_iPhase = 0;
            m_iSpeed = iSpeed;
            m_nPhases = iPhases;
           
//
            // Ok

            m_bInit = true;
        }
    }
    return dwRet;
}

Druhß verze metody Create() pro vytvß°enφ animovan²ch kurzor∙ je trochu zjednoduÜenß, proto₧e mß jeden nov² parametr, kter² se d°φv poΦφtal uvnit° metody. Jednß se o parametr iPhases, kter² p°edstavuje poΦet animaΦnφch krok∙. Nejsme schopni toti₧ toto Φφslo spoΦφtat ze Üφ°ky textury, proto₧e toto Φφslo se m∙₧e odliÜovat od skuteΦnΘ Üφ°ky bitmapy.

HRESULT CCursor::Update(D3DXVECTOR2* ptCursor)
{
    CRect rcDest, rcSrc;
    DWORD dwRet = 1, newTime;
    int iHeight;
    D3DXVECTOR2 vecScaling(1.0f, 1.0f);
    if(m_bInit) {
  
     //
        // For static cursors

        if(m_nPhases == 0) {
       
    //
            // One static place

            rcSrc.top = 0;
            rcSrc.left = 0;
            rcSrc.right = m_iWidth;
            rcSrc.bottom = m_iHeight;
        }
  
     //
        // Compute move source rectangle

        else {
     
      //
            // Compute phase, increment phase if is time

            newTime = GetTickCount();
       
    //
            // Get time from last update

            if((newTime - m_dwOldTime) > (DWORD)m_iSpeed) {
               
//
                // If it right time, increment phase

                m_iPhase++;
                //
                // Check to overflow phases
                if(m_iPhase == m_nPhases) {
                    m_iPhase = 0;
                }
                //
                // Save time of last update
                m_dwOldTime = newTime;
            }
            // Compute width and height of each field on the texture
            iHeight = m_lpTexture->Height();
            double fWidth = double(m_lpTexture->Width()) / double(m_nPhases);
            //
            // Compute rectangle from current phase
            //
            // Static vertical postion
            rcSrc.top = 0;
            rcSrc.bottom = iHeight;
            // Variable horizontal pos.
            rcSrc.left = m_iPhase * fWidth;
            rcSrc.right = rcSrc.left + fWidth;
            vecScaling.x = double(m_nPhases * m_iWidth) / double(m_lpTexture->Width());
        }
        //
        // Blit cursor to back surface
        m_d3dCursor->Begin();
        dwRet = m_d3dCursor->Draw(m_lpTexture->GetTexture(), rcSrc, &vecScaling, NULL, NULL, ptCursor, -1);
        m_d3dCursor->End();
    }
    return dwRet;
}

Nakonec tu mßme metodu Update(), kterß kurzor vykreslφ. Metoda se op∞t liÜφ jen v n∞kolika maliΦkostech. Za prvΘ je t°eba spoΦφtat Üφ°ku polφΦka na textu°e. Tato hodnota se m∙₧e liÜit od Üφ°ky kurzoru, proto₧e Üφ°ka bitmapy a textury nemusφ b²t stejnß (viz. problΘm v²Üe). PotΘ m∙₧eme spoΦφtat zdrojov² obdΘlnφk a pou₧ijeme prßv∞ tuto Üφ°ku. Nakonec je pot°eba urΦit m∞°φtko v²slednΘho obrßzku tak, aby byl vykreslen² kurzor sprßvn∞ velik² (v naÜem p°φpad∞ Üirok²). JednoduÜe pod∞lφme Üφ°ku bitmapy a Üφ°ku textury. Pro ob∞ varianty kurzoru platφ poslednφ Φßst, samotnΘ vykreslenφ pomocφ metody Draw(). Metody Begin() a End() bychom zde volat ani nemuseli, nebo¥ jsou tyto metody volßny intern∞ v metod∞ Draw().

Zbytek projektu Input z∙stane stejn².

26.3. P°φklad

Na zßv∞r lekce trochu upravφme projekt Tester a vyzkouÜφme si adresovacφ re₧imy. Zahodφme trßvu z minulΘ lekce a vytvo°φme trochu zajφmav∞jÜφ texturu:

Vytvo°φme globßlnφ prom∞nnou, do kterΘ si budeme uklßdat aktußlnφ adresovacφ re₧im:

//
// Address mode
DWORD g_dwAddressMode;
 

Inicializace Φtverce bude vypadat takto:

g_Quad.Init(g_theDisplay.GetDevice(), "smile.bmp", 5, g_theDisplay.GetTextureFormat(), 4 * sizeof(VERTEX), 6 * sizeof(WORD), IB_WRITEONLY|VB_WRITEONLY);
g_Quad.Visible(FALSE);
g_dwAddressMode = D3DTADDRESS_WRAP;
FillBuffers();

Dßle musφme upravit metodu FillBuffers(), aby generovala sprßvnΘ texturovΘ sou°adnice:

pVertices[0].tu1 = 0.0f;
pVertices[0].tv1 = 0.0f;

pVertices[1].tu1 = 3.0f;
pVertices[1].tv1 = 0.0f;

pVertices[2].tu1 = 0.0f;
pVertices[2].tv1 = 3.0f;

pVertices[3].tu1 = 3.0f;
pVertices[3].tv1 = 3.0f;

Takto se textura bude opakovat 3x v obou sm∞rech. Na ·pln² zßv∞r upravφme metodu UpdateFrame():

// Get old addr mode
g_theDisplay.GetDevice()->GetTextureStageState(0, D3DTSS_ADDRESSU, &dwOldAdrMode);
//
// Change address mode
if(g_theInput.IsKeyDown(DIK_Q))
{
    g_dwAddressMode = D3DTADDRESS_WRAP;
}
if(g_theInput.IsKeyDown(DIK_W))
{
    g_dwAddressMode = D3DTADDRESS_MIRROR;
}
if(g_theInput.IsKeyDown(DIK_E))
{
    g_dwAddressMode = D3DTADDRESS_CLAMP;
}
if(g_theInput.IsKeyDown(DIK_R))
{
    g_dwAddressMode = D3DTADDRESS_BORDER;
    g_theDisplay.GetDevice()->SetTextureStageState(0, D3DTSS_BORDERCOLOR, 0x00FF0000); // red color
}
// Change address mode
g_theDisplay.GetDevice()->SetTextureStageState(0, D3DTSS_ADDRESSU, g_dwAddressMode);
g_theDisplay.GetDevice()->SetTextureStageState(0, D3DTSS_ADDRESSV, g_dwAddressMode);
g_Quad.Draw(D3DPT_TRIANGLELIST, 0, 4, 0, 2);
g_theDisplay.GetDevice()->SetRenderState(D3DRS_LIGHTING, TRUE);
// Restore addr modes
g_theDisplay.GetDevice()->SetTextureStageState(0, D3DTSS_ADDRESSU, dwOldAdrMode);
g_theDisplay.GetDevice()->SetTextureStageState(0, D3DTSS_ADDRESSV, dwOldAdrMode);

Za prvΘ je t°eba zjistit aktußlnφ texturovacφ re₧im, kter² na konci zase obnovφme. Dßle reagujeme na Φtve°ici klßves Q, W, E a R, pomocφ nich₧ p°epφnßme adresovacφ re₧imy. Nezapome≥te v₧dy definovat barvu u adresovacφho re₧imu D3DTADDRESS_BORDER. T∞sn∞ p°ed vykreslenφm Φtverce nastavφme nov² adresovacφ re₧im, Φtverec vykreslφme a obnovφme p∙vodnφ nastavenφ.

26.4. Zßv∞r

Jak bylo nakousnuto v ·vodu, v p°φÜtφ lekci se budeme zab²vat kamerou. Vytvo°φme novou t°φdu XCamera v projektu Display, kterß se bude starat o vÜechno kolem pohybu kamery v prostoru. A₧ budeme mφt kameru, budeme se moci pustit do slo₧it∞jÜφch vykreslovacφch operacφ. Mßm na mysli nap°φklad terΘn apod.

Ji°φ Formßnek