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.
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):
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_WRAP, D3DTADDRESS_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.
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φ.
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:
Ukazatel na zdrojovou texturu (IDirect3D8Texture*)
Ukazatel na zdrojov² obdΘlnφk, ze kterΘho se vykresluje
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φ.
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.
Reßlnß hodnota ·hlu v radißnech, o kter² se sprite otoΦφ (podle st°edu urΦenΘho p°edchßzejφcφm parametrem).
Ukazatel na 2D vektor urΦujφcφ polohu spritu na monitoru.
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².
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φ.
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.