<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Suomipelit.com &#187; opengl</title>
	<atom:link href="http://www.suomipelit.com/avainsana/opengl/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.suomipelit.com</link>
	<description>Pohjolan pelaava kansa</description>
	<lastBuildDate>Tue, 03 Aug 2010 07:26:56 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Pyglet &#8211; Asentaminen</title>
		<link>http://www.suomipelit.com/2009/03/01/pyglet-asentaminen/</link>
		<comments>http://www.suomipelit.com/2009/03/01/pyglet-asentaminen/#comments</comments>
		<pubDate>Sun, 01 Mar 2009 10:00:25 +0000</pubDate>
		<dc:creator>Suomipelit.com</dc:creator>
				<category><![CDATA[Artikkelit]]></category>
		<category><![CDATA[Käytännön oppaat]]></category>
		<category><![CDATA[opengl]]></category>
		<category><![CDATA[pyglet]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.suomipelit.com/?p=1438</guid>
		<description><![CDATA[Tämä artikkeli kertoo kuinka pyglet asennetaan. Kyseisen kirjaston hyödyllisyyden toteaminen jää käyttäjän vastuulle.]]></description>
			<content:encoded><![CDATA[<p>Pyglet (<a href="http://pyglet.org" target="_blank">http://pyglet.org</a>/) on multimediakirjasto pythonille. Tämä artikkeli kertoo kuinka pyglet asennetaan. Kyseisen kirjaston hyödyllisyyden toteaminen jää käyttäjän vastuulle.</p>
<h2>Asentaminen (Ubuntu Intrepid Ibex)</h2>
<p>Asentaminen tapahtuu helpoiten ubuntussa, avaa terminaali ja kirjoita seuraavat komennot:</p>
<pre>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">sudo aptitude install python<br />
wget <span style="color: #483d8b;">&quot;http://peak.telecommunity.com/dist/ez_setup.py&quot;</span><br />
sudo python ez_setup.<span style="color: black;">py</span><br />
sudo easy_install pyglet</div></td></tr></tbody></table></div>
</pre>
<p>Jos aikoo kirjoittaa omia kirjastoja jatkossa, kannattaa tämän lisäksi tehdä <a href="http://peak.telecommunity.com/DevCenter/EasyInstall#administrator-installation">http://peak.telecommunity.com/DevCenter/EasyInstall#administrator-installation</a>, joka sallii kirjastojen asentamisen käyttäjäkohtaisesti ilman root-oikeuksia.</p>
<p>Python2.6:ssa on valmiiksi säädettynä käyttäjäkohtainen hakemisto johon voi asentaa moduleita. Tällöin tarvitsee vain luoda kyseinen hakemisto ja kirjoittaa distutils/distutils.cfg pythonin asennushakemistoon (todennäköisesti /usr/lib/python2.6)</p>
<p>Esimerkki distutils.cfg:stä:</p>
<pre>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: black;">&#91;</span>install<span style="color: black;">&#93;</span><br />
install_lib = ~/.<span style="color: black;">local</span>/lib/python2.6/site-packages<br />
<span style="color: #808080; font-style: italic;"># seuraavan rivin voi jättää pois:</span><br />
install_scripts = ~/.<span style="color: black;">local</span>/bin</div></td></tr></tbody></table></div>
</pre>
<p>Jonka jälkeen voi ladata ez_setup.py -skriptin ja suorittaa sen käyttäjäkohtaisesti.</p>
<h2>Asentaminen (Windows)</h2>
<p>Ensiksi pitää asentaa python. Kaiken pitäisi toimia hyvin pythonin 2.6 -versiolla. Jollet halua AMD64-asennusta niin normaalin binäärin asentaminen pitäisi riittää: <a href="http://www.python.org/ftp/python/2.6.1/python-2.6.1.msi">http://www.python.org/ftp/python/2.6.1/p&#8230;</a></p>
<p>Lataa skripti <a href="http://peak.telecommunity.com/dist/ez_setup.py">http://peak.telecommunity.com/dist/ez_se&#8230;</a> (klikkaa oikealla ja paina &#8216;tallenna nimellä&#8217;) hakemistoon mihin asensit pythonin. Käynnistä cmd ja kirjoita:</p>
<pre>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #dc143c;">cd</span> <span style="color: #483d8b;">&quot;C:<span style="color: #000099; font-weight: bold;">\P</span>rogram Files<span style="color: #000099; font-weight: bold;">\P</span>ython26<span style="color: #000099; font-weight: bold;">\&quot;</span><br />
python.exe ez_setup.py</span></div></td></tr></tbody></table></div>
</pre>
<p>Korvaa &#8220;C:\Program Files\Python26\&#8221; omalla hakemistopolullasi. Tässä välin setuptools asentuu. Asennuksen jälkeen kirjoita:</p>
<pre>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #dc143c;">cd</span> Scripts<br />
easy_install.<span style="color: black;">exe</span> pyglet</div></td></tr></tbody></table></div>
</pre>
<p>Jos haluat asiat helpoksi, aseta pythonin asennuspolku ja &#8216;Scripts&#8217; -hakemisto ympäristömuuttujien PATH -arvoon. Tämä artikkeli ei kuitenkaan opeta käyttöjärjestelmän käyttöä joten muuttujien asettaminen jää lukijan selvitettäväksi.</p>
<h2>Ensimmäinen ikkuna</h2>
<p>Tässä on ensimmäinen ohjelma. Voit joko kirjoittaa sen suoraan pythoniin tai kirjoittaa tekstitiedostoon ja antaa tiedoston tulkille. Rautalangasta kirjoitettuna: &#8216;python eka.py&#8217;</p>
<pre>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> pyglet<br />
window = pyglet.<span style="color: black;">window</span>.<span style="color: black;">Window</span><span style="color: black;">&#40;</span>width=<span style="color: #ff4500;">200</span>, height=<span style="color: #ff4500;">100</span>, caption=u<span style="color: #483d8b;">&quot;Ensimmäinen&quot;</span><span style="color: black;">&#41;</span><br />
pyglet.<span style="color: black;">app</span>.<span style="color: black;">run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
</pre>
<pre><a href="http://www.suomipelit.com/tiedostot/2010/03/ensimmainen.png" rel="lightbox[1438]"><img class="aligncenter size-full wp-image-1439" title="ensimmainen" src="http://www.suomipelit.com/tiedostot/2010/03/ensimmainen.png" alt="" width="209" height="129" /></a></pre>
<p><a rel="lightbox[artikkelikuva_194]" href="http://www.suomipelit.com/kaikki/images/artikkelit/194/ensimmainen.png"></a></p>
<hr />Easy_install:in avulla on mahdollista asentaa myös muita kirjastoja, valinnan mukaan, siispä nämä ohjeet helpottavat muidenkin kirjastojen asentamista jatkossa.</p>
<p><em>Artikkelin kirjoitti alun perin Cheery.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.suomipelit.com/2009/03/01/pyglet-asentaminen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenGL:n perusteet &#8211; Osa 4: Valot ja varjot</title>
		<link>http://www.suomipelit.com/2004/07/27/opengln-perusteet-osa-4-valot-ja-varjot/</link>
		<comments>http://www.suomipelit.com/2004/07/27/opengln-perusteet-osa-4-valot-ja-varjot/#comments</comments>
		<pubDate>Tue, 27 Jul 2004 10:00:04 +0000</pubDate>
		<dc:creator>Suomipelit.com</dc:creator>
				<category><![CDATA[Artikkelit]]></category>
		<category><![CDATA[Käytännön oppaat]]></category>
		<category><![CDATA[2d]]></category>
		<category><![CDATA[3d]]></category>
		<category><![CDATA[gl]]></category>
		<category><![CDATA[grafiikka]]></category>
		<category><![CDATA[opengl]]></category>
		<category><![CDATA[perusteet]]></category>
		<category><![CDATA[valot]]></category>
		<category><![CDATA[varjot]]></category>

		<guid isPermaLink="false">http://www.suomipelit.com/?p=1185</guid>
		<description><![CDATA[OpenGL on käyttöjärjestelmäriippumaton kirjasto 2D- ja 3D-grafiikan piirtoon. Tämä artikkelisarja opettaa sinulle 3D-grafiikan perusteet OpenGL:ää käyttäen. Esimerkeissä käytetään C\C++ kieltä. Tämä on artikkelisarjan viimeinen osa.]]></description>
			<content:encoded><![CDATA[<p>OpenGL on käyttöjärjestelmäriippumaton kirjasto 2D- ja 3D-grafiikan piirtoon. Tämä artikkelisarja opettaa sinulle 3D-grafiikan perusteet OpenGL:ää käyttäen. Esimerkeissä käytetään C\C++ kieltä. Tämä on artikkelisarjan viimeinen osa.</p>
<h2>1. Valaistuksen matematiikkaa</h2>
<p style="text-align: center;"><a href="http://www.suomipelit.com/tiedostot/2010/03/valot.jpg" rel="lightbox[1185]"><img class="aligncenter size-full wp-image-1194" title="Vasemmalla ilman valoja. Keskellä valojen kanssa ja oikealla myös varjot mukana. Huomaa lisääntynyt realismi." src="http://www.suomipelit.com/tiedostot/2010/03/valot.jpg" alt="" width="484" height="120" /></a></p>
<p><a title="Vasemmalla ilman valoja. Keskellä valojen kanssa ja oikealla myös varjot mukana. Huomaa lisääntynyt realismi." rel="lightbox[artikkelikuva_60]" href="http://www.suomipelit.com/kaikki/images/artikkelit/60/valot.jpg"></a>Vasemmalla ilman valoja. Keskellä valojen kanssa ja oikealla myös varjot mukana. Huomaa lisääntynyt realismi. Oikeassa elämässä näkemämme kuva syntyy, kun jostakin valonlähteestä lähtevä valo heijastuu jostakin pinnasta silmämme verkkokalvolle. Voisimme siis teoriassa laskea virtuaalimaailmassa olevan kappaleen valaistuksen sinkoamalla virtuaalisesta valonlähteestä miljardeittain valonsäteitä ja laskemalla mitkä niistä osuvat renderöimäämme pintaan.  Miljardien valonsäteiden radan laskeminen ei kuitenkaan sovi reaaliaikasovellukselle. Ajatus voidaan tietenkin kääntää päälaelleen. Jäljitetään pinnan jokaisesta pikselistä valonsäteen rataa nurinkurisesti ja katsotaan johtaako se valonlähteeseen. Tätä menetelmää kutsutaan termillä &#8220;ray tracing&#8221;. Tekniikka on huomattavasti kevyempi ja sitä käyttäviä demoja on muutamia, mutta myös tämä tekniikka on vielä liian raskas varsinkin peleille.  Koska emme voi laskea valon vaikutusta täydellisen tarkasti, täytyy meidän löytää jokin keino arvioida sitä. Arviointitekniikoita on useita, joista tässä artikkelissa esittelen kaksi samankaltaista nimeltään: Blinn ja Phong.  Näissä tekniikoissa pinnasta verkkokalvolle saapuva valo jaetaan karkeasti neljään eri tyyppiin: ympäristövaloon (ambient light), hajavaloon (diffuse light), peiliheijastukseen (specular light) ja itsesäteiltyyn valoon (emissive light).</p>
<h3>1.1 Hajavalo</h3>
<p>Hajavalo on valoa, joka tulee suoraan jostakin valonlähteestä pintaan. Pinta absorboi osan tästä valosta ja heijastaa loput eteenpäin silmän verkkokalvolle. Merkitsemme hajavaloa tässä artikkelissa symbolilla D (niin kuin diffuse). Hajavalon määrä on riippuvainen siitä kulmasta, jossa valonsäde saapuu pintaan. Jos L (niin kuin light) on vektori kohti valonlähdettä ja N (niin kuin normal) pinnan normaalivektori ja kummankin näiden vektorien pituus on yksi, niin hajavalon määrä saadaan näiden pistetulona eli N · L. Pinta ei kuitenkaan heijasta valon kaikkia aallonpituuksia tasapuolisesti, vaan se absorboi osaa paremmin ja osaa huonommin. Tästa muodostuu pinnan väri. Esim. jos pinta absorboi kaiken muun paitsi punaisen valon näyttää pinta punaiselta. Kaiken lisäksi pintaan saapuva valo ei välttämättä ole valkoista eli sisällä kaikkia mahdollisia aallonpituuksia. Meidän tarvitsee siis kertoa hajavalo vielä pinnan värillä, jota merkitsemme symbolilla Cd (niin kuin color ja decal) ja valon värillä, jota merkitsemme symbolilla Cl (niin kuin color ja light). Niinpä saamme hajavalon lopulliseksi yhtälöksi: Cd * Cl * ( N · L ) . Tässä * ei siis tarkoita pistetuloa vaan värien kertomista komponenteittain.</p>
<h3>1.2 Ympäristövalo</h3>
<p>Ympäristövalo on valoa, jonka ei voida sanoa tulevan mistään tietystä suunnasta ja se vaikuttaa kaikkiin pintoihin samalla tavalla, olkoot ne sitten missä asennossa tahansa suhteessa valonlähteeseen. Tämä johtuu siitä, että valonsäteet kimpoilevat pinnasta toiseen sekoittuen lopulta yhteinäiseksi tasaiseksi valoksi. Merkitsemme tässä artikkelissa ympäristövaloa symbolilla A (niin kuin ambient). Ympäristävalon määrä on koko ajan vakio ja sitä ei oikein voi laskea mitenkään, vaan se sen määrä on arvioitava. Jos minimi on 0 ja maksimi 1, niin realistinen kuva saadaan yleensä hyvin pienillä arvoilla esim 0.1. Koska pinta heijastaa myös ympäristövalosta vain tietyt aallonpituudet, täytyy se kertoa pinnan värillä, joilloin saamme tälle komponentille yhtälön: Cl * A.</p>
<h3>1.3	Peiliheijastus</h3>
<p>Kun valo osuu pintaan tietyssä kulmassa, ei pinta absorboikkaan yhtään valoa vaan heijastaa sen sellaisenaan eteenpäin. Kutsumme tällaista valoa peiliheijastuneeksi ja merkitsemme sitä symbolilla S (niin kuin specular). Peiliheijastuksen kulma riippuu pinnan materiaalista, kutsumme tätä ominaisuutta pinnan kiiltävyydeksi ja merkitsemme sitä symbolilla G (niin kuin gloss). Lisäksi tähän vaikuttaa pinnan tasaisuus, jota merkitsemme symbolilla M, realistinen M:n arvo on yleensä välillä 8 &#8211; 16. Peiliheijastus riippuu valonlähteen sijainnin lisäksi myös siitä mistä kulmasta pintaa katsellaan. Meidän tarvitsee tietää siis vielä vektori, joka osoittaa kohti kameraa. Merkitsemme tätä vektoria symbolilla E (niin kuin eye). Peiliheijastuksen laskemiseeen on kaksi tapaa: ns phong- ja blinn-valaistusmallit.  Phong-mallissa meidän tarvitsee tietää vektori R (niin kuin reflection), joka saadaan kun vektori E peilataan vektorin N suhteen. Tämä tehdään kaavalla: R = 2 * (N · L) * N &#8211; L. Kun R on tiedossa saadaan peiliheijastus kaavasta Cl * G * (L · R)^M. Eli valon väri kertaa G kertaa L:n ja R:n pistetulo potenssiin M. Pinnan väri ei siis vaikuta peiliheijastukseen.  <a href="http://www.suomipelit.com/tiedostot/2010/03/phong.jpg" rel="lightbox[1185]"><img class="aligncenter size-full wp-image-1190" title="phong" src="http://www.suomipelit.com/tiedostot/2010/03/phong.jpg" alt="" width="300" height="226" /></a> <a rel="lightbox[artikkelikuva_60]" href="http://www.suomipelit.com/kaikki/images/artikkelit/60/phong.jpg"></a> Vektorin R laskeminen on kuitenkin hieman turhan monimutkainen. Tämän takia on olemassa yksinkertaisempi malli Blinn. Blinn-mallissa vektoria R ei tarvita, vaan lasketaan vektori H, joka puolittaa vektoreiden L ja E välisen kulman. Tähän jälkeen peiliheijastus lasketaan yhtälöstä: Cl * G * (N · H)^M.  <a href="http://www.suomipelit.com/tiedostot/2010/03/blinn.jpg" rel="lightbox[1185]"><img class="aligncenter size-full wp-image-1186" title="blinn" src="http://www.suomipelit.com/tiedostot/2010/03/blinn.jpg" alt="" width="300" height="226" /></a> <a rel="lightbox[artikkelikuva_60]" href="http://www.suomipelit.com/kaikki/images/artikkelit/60/blinn.jpg"></a> Potenssilasku ^M kuitenkin muodostaa pienen ongelman. Potenssiin korotus nimittäin on kaikesta nykyajan laskentatehosta huolimatta varsin hidas operaatio varsinkin kun se joudutaan laskemaan, jopa tuhansia kertoja per frame. Tämän takia saattaa joskus olla järkevää lukita M arvoon 16 ja aproksimoida funktiota x^16, jollakin toisella yksinkertaisemmalla funktiolla. Tällaisia ovat mm: max( 0, 4*(x-0.75) ) ja max( 0, 4*(x*x-0.75) ).</p>
<h3>1.4 Itsesäteilty valo</h3>
<p>Viimeinen muoto on itsesäteilty valo. Tämä on valoa, jota pinta itse tuottaa. Tyypillinen itsevalaiseva pinta on fosfori. Merkitsemme tätä valoa symbolilla E (niin kuin emissive). Tätäkään valoa ei voida mitenkään laskea vaan se on arvioitava. Tavallisilla pinnoilla tämä se on yleensä 0. Jos oletamme, että pinta säteilee itsensä väristä valoa saamme tämän komponentin kaavaksi: Cd * E.</p>
<h3>1.5 Lopullinen valoyhtälö</h3>
<p>Nyt voimme muodostaa yhtälön, joka antaa meille hyvin realistisen valaistuksen. Laskemme vain eri muodot yhteen eli kokonaisvalo, jota merkitsemme symbolilla I (niin kuin illumination) on A+D+S+E. Jos vielä puramme yhtälön auki blinn-mallin mukaisesti saamme I = Cd * A + Cd * Cl * ( N · L ) + Cl * G * ( N · H ) ^ M + Cd * E . Tämä ei ota vielä huomioon sitä tosiasiaa, että valon kirkkaus vaimenee mitä kauempana valonlähteestä ollaan. Yhtälö pitää siis kertoa vaimennustermillä, joka saadaan jakamalla 1 jollakin sopivalla vakiolla k kerrottuna etäisyyden (käytämme symbolia d) neliöllä eli 1/(1+k*d^2). Tämä olisi siis fysikaalisesti oikein, mutta ei välttämättä hyvän näköinen. Niinpä usein käytetään jotain muuta vaimennustermiä esim: max( 0, 1 &#8211; ( d / r )^2 ). Tällöin valon kirkkaus on maksimissaan keskellä valonlähdettä ja hiipuu nollaan saavutettaessä etäisyys r ja on nolla kaikkialla tätä kauempana.  Lopullinen (blinn-mallin mukainen) yhtälö on siis: I = 1/(1+k*d^2) * ( Cd * A + Cd * Cl * ( N · L ) + Cl * G * ( N · H ) ^ M + Cd * E ).  <a href="http://www.suomipelit.com/tiedostot/2010/03/illumination.jpg" rel="lightbox[1185]"><img class="aligncenter size-full wp-image-1187" title="illumination" src="http://www.suomipelit.com/tiedostot/2010/03/illumination.jpg" alt="" width="491" height="326" /></a> <a rel="lightbox[artikkelikuva_60]" href="http://www.suomipelit.com/kaikki/images/artikkelit/60/illumination.jpg"></a> Jos valonlähteitä on useampia pitää valaistus laskea kaikille valoille erikseen ja sitten summata tulokset.</p>
<h2>2. Käytännön toteutus</h2>
<p>Nyt siis tiedämme valaistukseen tarvittavan yhtälön. Mutta kuinka kappale sitten oikein valaistaan sillä? Helposti, lasketaan yhtälö kappaleen jokaiselle verteksille ja annetaan tulos värinä OpenGL:lle <strong>glColor3f()</strong>-funktiolla.  Tehdään seuraavaksi funktio, joka laskee tämän valoyhtälön syötteenään saamalle verteksille. Se saa syötteenään verteksin sijainnin (Pv), valon sijainnin (Pl), pinnan värin (Cd), valon värin (Cl) ja pinnan normaalin (N). Funktio laskee verteksille valon ja antaa sen OpenGL:lle värinä. Yksinkertaisuuden vuoksi se jättää vaimenemisen huomiotta ja olettaa itsesäteillyn valon olevan nolla.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">void</span> valo<span style="color: #009900;">&#40;</span><span style="color: #993333;">float</span> Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #993333;">float</span> Pl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #993333;">float</span> Cd<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #993333;">float</span> Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #993333;">float</span> N<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #993333;">const</span> <span style="color: #993333;">float</span> A<span style="color: #339933;">=</span><span style="color:#800080;">0.1</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">const</span> <span style="color: #993333;">float</span> G<span style="color: #339933;">=</span><span style="color:#800080;">0.9</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">const</span> <span style="color: #993333;">float</span> M<span style="color: #339933;">=</span><span style="color: #0000dd;">16</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #993333;">float</span> L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">float</span> temp<span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Laske vektori L, joka osoittaa kohti valoa.</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>Pl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>Pl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>Pl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; temp<span style="color: #339933;">=</span>sqrt<span style="color: #009900;">&#40;</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Laske vektori E, joka osoittaa kohti kameraa.</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; temp<span style="color: #339933;">=</span>sqrt<span style="color: #009900;">&#40;</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Laske vektori H, joka puolittaa vektorien E ja L välisen kulman.</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; temp<span style="color: #339933;">=</span>sqrt<span style="color: #009900;">&#40;</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Laske ympäristövalo + hajavalo + peiliheijastus</span><br />
&nbsp; I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span> A<span style="color: #339933;">*</span>Cd<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+</span> Cd<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> L<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> G<span style="color: #339933;">*</span>Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pow<span style="color: #009900;">&#40;</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> H<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> M<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span> A<span style="color: #339933;">*</span>Cd<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+</span> Cd<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> L<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> G<span style="color: #339933;">*</span>Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pow<span style="color: #009900;">&#40;</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> H<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> M<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span> A<span style="color: #339933;">*</span>Cd<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+</span> Cd<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> L<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> G<span style="color: #339933;">*</span>Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pow<span style="color: #009900;">&#40;</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> H<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> M<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Anna tulos OpenGL:lle.</span><br />
&nbsp; glColor3f<span style="color: #009900;">&#40;</span>I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Tämä johtaa kuitenkin ongelmaan teksturoinnin yhteydessä. Pinnan värihän saadaan tällöin tekstuurista, joten se voi olla eri jokaisella pikselillä. Miten siis tekstuuri suhtautuu valaistukseen? Jos luit sarjan edellisen osan muistat varmaan, että värin ja tekstuurin yhdistämisestä huolehtii texture environment, joka oletuksena kertoo värin ja tekstuurin keskenään (<em>GL_MODULATE</em>). Jos jätemme valoyhtälöstä pois komponentin Cd saamme yhtälön: I = 1/(1+k*d^2) * ( A + Cl * ( N · L ) + Cl * G * ( N · H ) ^ M + E ). Jos nyt laskemme valaistuksen tämän yhtälön mukaisesti ja annamme texture environmentin kertoa värin tektuurilla saamme lopulliseksi väriksi: I = Cd * ( 1/(1+k*d^2) * ( A + Cl * ( N · L ) + Cl * G * ( N · H ) ^ M + E ) ), joka on muuten sama kuin alkuperäinen yhtälömmekin paitsi, että myös peiliheijastus tulee kerrottua pinnan värillä. Tämä ei ole suuri katastrofi, jos peiliheijastuksen arvo on mitättömän pieni ( G on noin 0 ), mutta pilaa koko vaikutelman, jos peiliheijastuksen osuus on merkittävä. Tämän ongelman voi korjata toissijaisella värillä, josta puhumme seuraavaksi.</p>
<h3>2.1	Toissijainen vär</h3>
<p><strong>glColor3f()</strong>-funktiolla annettua väriä kutsutaan ensisijaiseksi väriksi. On kuitenkin olemassa laajennus <em>GL_EXT_secondary_color</em>, joka sallii toissijaisen värin määrittämisen. Tämä laajennus tuo mukanaan mm. funktion glSecondaryColor3fEXT(Glfloat red, Glfloat green, Glfloat blue), jolla toissijainen väri annetaan. Toissijainen väri ei osallistu texture environmenttiin, vaan se lisätään (siis lasketaan yhteen) pikselin väriin vasta sen jälkeen kun teksture environment on tehnyt tehtävänsä. Tämä kuitenkin tapahtuu vain, jos <em>GL_COLOR_SUM_EXT </em>on päällä. Se saadaan päälle kutsulla <strong>glEnable</strong>(<em>GL_COLOR_SUM_EXT</em>).  Korjataan nyt edellisen kappaleen funktiota niin, että se olettaa pinnan värin tulevan tekstuurista ja erottaa peiliheijastuksen toissijaiseen väriin. Funktio olettaa, että <em>GL_EXT_secondary_color</em>-laajennos on tuettu ja että <em>GL_COLOR_SUM_EXT </em>ja <em>GL_TEXTURE_2D </em>ovat päällä ja texture environment on <em>GL_MODULATE</em>-moodissa.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">void</span> valo2<span style="color: #009900;">&#40;</span><span style="color: #993333;">float</span> Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #993333;">float</span> Pl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #993333;">float</span> Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #993333;">float</span> N<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #993333;">const</span> <span style="color: #993333;">float</span> A<span style="color: #339933;">=</span><span style="color:#800080;">0.1</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">const</span> <span style="color: #993333;">float</span> G<span style="color: #339933;">=</span><span style="color:#800080;">0.9</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">const</span> <span style="color: #993333;">float</span> M<span style="color: #339933;">=</span><span style="color: #0000dd;">16</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #993333;">float</span> L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> S<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">float</span> temp<span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Laske vektori L, joka osoittaa kohti valoa.</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>Pl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>Pl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>Pl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; temp<span style="color: #339933;">=</span>sqrt<span style="color: #009900;">&#40;</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Laske vektori E, joka osoittaa kohti kameraa.</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=-</span>Pv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; temp<span style="color: #339933;">=</span>sqrt<span style="color: #009900;">&#40;</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
<br />
&nbsp;<span style="color: #666666; font-style: italic;">// Laske vektori H, joka puolittaa vektorien E ja L välisen kulman.</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>E<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; temp<span style="color: #339933;">=</span>sqrt<span style="color: #009900;">&#40;</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
&nbsp; H<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/=</span>temp<span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Laske ympäristövalo + hajavalo</span><br />
&nbsp; I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span> A &nbsp; &nbsp; <span style="color: #339933;">+</span> &nbsp; &nbsp; Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> L<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span> A &nbsp; &nbsp; <span style="color: #339933;">+</span> &nbsp; &nbsp; Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> L<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span> A &nbsp; &nbsp; <span style="color: #339933;">+</span> &nbsp; &nbsp; Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> L<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// &nbsp;Laske &nbsp;peiliheijastus</span><br />
&nbsp; S<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span> G<span style="color: #339933;">*</span>Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pow<span style="color: #009900;">&#40;</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> H<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> M<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; S<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span> G<span style="color: #339933;">*</span>Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pow<span style="color: #009900;">&#40;</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> H<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> M<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; S<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span> G<span style="color: #339933;">*</span>Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>pow<span style="color: #009900;">&#40;</span>pisteTulo<span style="color: #009900;">&#40;</span>N<span style="color: #339933;">,</span> H<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> M<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Anna tulos OpenGL:lle.</span><br />
&nbsp; glColor3f<span style="color: #009900;">&#40;</span>I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> I<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; glSecondaryColor3fEXT<span style="color: #009900;">&#40;</span>S<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> S<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> S<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<h2>3. OpenGL:n oma valojärjestelmä</h2>
<p>Ei kuitenkaan ole pakko kirjoittaa omaa funktiota, joka laskee valaistuksen, sillä OpenGL sisältää myös oman valaistusjärjestelmän. Valaistus saadaan päälle kutsulla <strong>glEnable</strong>(<em>GL_LIGHTING</em>);. Kun valaistus on päällä laskee OpenGL valot automaattisesti ja korvaa värit saamillaan tuloksilla.<strong> glColor3f()</strong>-funktiolla ei siis ole mitään vaikutusta silloin kun valaistus on päällä! Valonlähteitä on maksimissaan kahdeksan ja niitä voidaan laittaa päälle ja pois yksitellen <strong>glEnable()</strong> ja <strong>glDisable()</strong>-funktioilla, joille annetaan parametrina <em>GL_LIGHT</em>x, jos x on valon numero väliltä 0-7.  Valon attribuutteja (sijaintia, väriä jne&#8230;) voidaan muuttaa <strong>glLightfv()</strong>-funktiolla, jonka prototyyppi näyttää tältä:  void glLightfv(GLenum light, GLenum pname, const GLfloat *params);  Ensimmäinen parametri kertoo valon, jonka attribuutteja muutetaan (siis <em>GL_LIGHT</em>x). Toinen on muuttava attribuutti.</p>
<p>Tärkeimmät ovat <em>GL_AMBIENT </em>(ympäristovalon eli A:n arvo), <em>GL_DIFFUSE </em>ja <em>GL_SPECULAR </em>(valon väri eli Cl, OpenGL siis sallii eri valon värit hajavalolle ja peiliheijastukselle), <em>GL_QUADRATIC_ATTENUATION </em>(vaimenemisen vakio k) ja <em>GL_POSITION </em>(valon sijainti). Viimeinen parametri on osoitin 4-komponenttiseen taulukkoon, joka sisältää attribuutin uuden arvon. 3 ensimmäistä kenttää ovat attribuutin uusi arvo ja viimeisen kentän on oltava 1. Paitsi <em>GL_QUADRATIC_ATTENUATION </em>tapauksessa, jossa taulukko sisältää vain yhden arvon.  Valaistavan pinnan ominaisuuksia voidaan asettaa <strong>glMaterialfv()</strong>-funktiolla.</p>
<p>Prototyyppi näyttää tältä:  void glMaterialfv(GLenum face, GLenum pname, const GLfloat *params);  Ensimmäisen parametrin on oltava <em>GL_FRONT_AND_BACK</em>. Toisen parametrin mahdolliset arvot ovat: <em>GL_AMBIENT_AND_DIFFUSE </em>(pinnan väri), <em>GL_SPECULAR </em>(pinnan kiiltävyys eli G:n arvo), <em>GL_EMISSION </em>(itsesäteillyn valon määrä eli E:n arvo) ja <em>GL_SHININESS </em>(vakion M arvo). Viimeinen parametri on jälleen kerran osoitin 4 komponenttiseen taulukkoon, joka sisältää uuden arvon. Paitsi <em>GL_SHININESS </em>tapauksessa, jossa taulukko sisältää vain yhden arvon.  Koska pinnan normaalia tarvitaan valaistuksen laskemiseen täytyy se antaa OpenGL:lle. Tämä tehdään funktiolla glNormal3f(), jonka prototyyppi näyttää tältä:  void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz);</p>
<p>Se siis ottaa normaalivektorin x, y ja z komponentit parametrinaan. Huomaa, että tämän vektorin pituuden tulee olla 1. Tätä funktiota kutsutaan <strong>glBegin()</strong> ja<strong> glEnd()</strong>-funktioiden välissä ja jokaiselle verteksille erikseen.  On olemassa <em>GL_EXT_separate_specular_color</em>-laajennus, joka saa OpenGL erottamaan laskemansa valon peiliheijastuskomponentin toissijaiseksi väriksi. Tämä tehdään kutsulla <strong>glLightModel</strong>(<em>GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_ SEPARATE_SPECULAR_COLOR_EXT</em>); <a title="Oikealla ilman peiliheijastusta ja muissa sen kanssa, mutta keskellä GL_SEPARATE_SPECULAR_COLOR_EXT ei ole päällä kun taas vasemmalla se on." rel="lightbox[artikkelikuva_60]" href="http://www.suomipelit.com/kaikki/images/artikkelit/60/separatespecular.jpg"></a></p>
<p style="text-align: center;"><a href="http://www.suomipelit.com/tiedostot/2010/03/separatespecular.jpg" rel="lightbox[1185]"><img class="aligncenter size-full wp-image-1191" title="Oikealla ilman peiliheijastusta ja muissa sen kanssa, mutta keskellä GL_SEPARATE_SPECULAR_COLOR_EXT ei ole päällä kun taas vasemmalla se on." src="http://www.suomipelit.com/tiedostot/2010/03/separatespecular.jpg" alt="" width="480" height="121" /></a></p>
<h2>4. Pikselin tarkka valaistus</h2>
<p>Huomattavaa on, että OpenGL:n sisäinen valojärjestelmä laskee valot vain vertekseille. Ei siis jokaiselle pikselille erikseen. Tämän jälkeen jokaiselle verteksille lasketut valoarvot (värit), interpoloidaan pikseleille. Kaikki näyttää ihan hyvältä niin kauan kuin polygonien koko on tarpeeksi pieni ja valon lähde kaukana niistä. Jos näin ei ole alkavat virheet näkyä. Parempi olisikin, jos voisimme laskea valoarvot jokaiselle pikselille erikseen jolloin tuloksena olisi huomattavasti realistisempi kuva. <a href="http://www.suomipelit.com/tiedostot/2010/03/perpixel.jpg" rel="lightbox[1185]"><img class="aligncenter size-full wp-image-1189" title="Vasemmalla kuvatun 8 kolmiosta koostuvan pinnan valaistus laskettu vertekseille (keskellä) ja pikseleille (oikealla)." src="http://www.suomipelit.com/tiedostot/2010/03/perpixel.jpg" alt="" width="550" height="122" /></a> <strong>glColor3f()</strong>-funktiolla ei kuitenkaan voi antaa väriä erikseen jokaiselle pikselille. Ainoastaan vertekseille. Seuraavassa kappaleessa esittelen pikselivarjostimiksi kutsutun tekniikan, jolla tämä ongelma saadaan pois päiväjärjestyksestä, mutta sitä ennen esittelen muutaman kiertotien.  Jos sekä valo että piirrettävä polygoni ovat staattisia eli ne eivät liiku voidaan valon vaikutus piirtää etukäteen tekstuuriin esim. jollakin kuvankäsittelyohjelmalla.</p>
<p>Tällöin säästetään myös tehoa, kun mitään valaistukseen liittyvää ei tarvitse laskea ajon aikana. Tätä tekniikkaa kutsutaan termillä &#8220;lightmapping&#8221; ja sitä käyttävät mm. pelit Quake 2 ja 3 sekä half-life.  Ajatus voidaan viedä vieläkin pidemmälle. Miksei valoefektejä lasketa tekstuureihin ajon aikana ja muuttuneita tekstuureja sitten ladata uudestaan näytönohjaimen muistiin <strong>glTexImage2D()</strong>-funktiolla. Jos tekstuurit ovat tarpeeksi matalaresoluutioisia, tämä on ihan toimiva vaihtoehto. Jos tekstuurit kuitenkin ovat kovin korkearesoluutioisia kuluu tekstuurien päivittämiseen liikaa aikaa ja menetelmä ei toimi.</p>
<p>Tämän tekniikan nimi on ”dynamic lightmapping”. Mm. pelit Alien vs Predator 1 ja 2 käyttävät tätä tekniikkaa.  Texture environment osaa laskea erilaisia funktioita jokaiselle pikselille, yhdistäen eri tekstuureja. On itse asiassa mahdollista laskea texture environment:in avulla valoyhtälöt jokaiselle pikselille. Tähän tarvitaan laajennukset <em>GL_ARB_texture_env_combine</em>, <em>GL_ARB_texture_env_crossbar </em>(tai <em>GL_NV_texture_env_combine4</em>) ja <em>GL_ARB_texture_env_dot3</em> ja vähintään 4 teksturointiyksikköä. Lisäksi peiliheijastuksessa tarvittava potenssiinkorotus ei ole mahdollinen, joten sitä on arvioitava jollakin yksinkertaisemmalla funktiolla.</p>
<h2>5. Verteksi- ja pikselivarjostinohjelmat</h2>
<p>Verteksi- tai pikselivarjostin on ohjelma tai pidemminkin funktio, jonka OpenGL suorittaa jokaista verteksiä/pikseliä kohden. Parasta tässä on, että voit kirjoittaa tämän funktion itse. Näitä funktioita kutsutaan varjostimiksi, koska niitä käytetään usein nimenomaan valaistuksen laskentaan. Varjostinohjelmat saavat syötteenään verteksin/pikselin kaikki arvot, kuten värin ja sijainnin ja tuottavat tuloksenaan uudet arvot.</p>
<p>Huomaa, että koska pikselivarjostinohjelmat suoritetaan kerran jokaista pikseliä kohden, ja kuvassa voi helposti olla miljoonia pikseleitä kasvaa tarvittavan tehon määrä valtavaksi. Tämän takia pikselivarjostimet toimivat vain kaikkein uusimmissa näytönohjaimissa, kuten GeForceFX ja Ati Radeon 9500. Nämä varjostimet ovat saatavilla laajennusten <em>GL_ARB_vertex_program</em>, <em>GL_ARB_fragment_program</em>, <em>GL_ARB_vertex_shader </em>ja <em>GL_ARB_fragment_shader </em>muodossa.  Verteksivarjostimet eivät tuo varsinaisesti mitään uutta. Ne saavat syötteenään verteksin sijainnin, värin jne. Suorittavat näillä jotain laskentaa ja korvaavat arvot uusilla.</p>
<p>Olisit voinut tietenkin laskea nämä uudet arvot omassa ohjelmassasi ja antaa ne OpenGL:lle alkuarvoina, joilloin koko verteksivarjostinta ei olisi tarvittu. Etu on siinä, että verteksivarjostimen koodi suoritetaan näytönohjaimen prosessorilla, joka on nimenomaan erikoistunut grafiikan piirtämiseen ja suorittaa verteksivarjostinohjelman yleensä (joskaan ei aina) nopeammin kuin tietokoneen keskusyksikkö. Näin ollen verteksivarjostimet nostavat ohjelman suorituskykyä, ei sen graafista laatua.</p>
<p>Pikselivarjostimet ovat sen sijaan toinen juttu. Ei nimittäin ole muuta keinoa tehdä pikselikohtaisia laskutoimituksia (texture environment:illa kikkailua lukuunottamatta). Niiden avulla on mahdollista laskea blinnin tai phongin valoyhtälöt jokaiselle pikselille erikseen. Mm. Doom 3:n hieno grafiikka perustuu tähän. Valitettavasti pikselivarjostimilla on katastrofaalinen vaikutus suorituskykyyn. Esim. 800&#215;600 resoluutioisessa ikkunassa on 480000 pikseliä (olettaen että yhtään pikseliä ei piirretä kahdesti). Jos pikselivarjostin, jossa on vain 10 rivia koodia, suoritetaan jokaiselle pikselille tekee se lähes 5 miljoonaa suoritettavaa koodiriviä.</p>
<p>On siinä näytönohjaimella laskemista.  Varjostinohjelmat voidaan kirjoittaa, joko konekielellä (laajennukset <em>GL_ARB_vertex_program </em>ja <em>GL_ARB_fragment_program</em>) tai korkeamman tason glSlang-kielellä (laajennukset <em>GL_ARB_vertex_shader </em>ja <em>GL_ARB_fragment_shader</em>) (myös Direct3D:llä on vastaavanlainen korkeamman tason kieli nimeltä HLSL). Lisäksi on olemassa NVidian kehittämä Cg. Se on siitä vekkuli, että se toimii sekä OpenGL:ssä, että Direct3D:ssä. Jotta voisit käyttää varjostinohjelmia sinun täytyy opetella jokin näistä kielistä. En kuitenkaan aijo esitellä niitä sen enempää, sillä niistä saisi vaikka oman artikkelinsa. Varjostinohjelmat ovat kuitenkin tulevaisuutta, joten niitä kannattaa joskus edes vilkaista.</p>
<h2>6. Sapluunapuskuri</h2>
<p>Ennen kuin voimme mennä eteenpäin pitää minun esitellä sinulle yksi kätevä työkalu nimeltä sapluunapuskuri (englanniksi stencil buffer). Sapluunapuskuri toimii nimensä mukaan sapluunana. Ensin sapluunapuskuriin piirretään jotain, jonka jälkeen sapluunatestaus asetetaan päälle. Tämän jälkeen pikselit piirtyvät vain niihin kohtiin, joissa sapluunapuskuriin on piirretty jotain (tai halutessa toisin päin).</p>
<p>Ennen kuin sapluunapuskuria voidaan käyttää pitää se laittaa päälle. Tämä tehdään kutsulla <strong>glEnable</strong>(<em>GL_STENCIL_TEST</em>).  Sapluunapuskuriin ei kuitenkaan voida tallentaa syvyysarvoja (kuten syvyyspuskuriin) tai väriarvoja kuten väripuskuriin, vaan lukuja väliltä 0 – 255 (olettaen, että sapluunapuskurille varattujen bittien määrä per pikseli on 8). Se mitä sapluunapuskurissa olevalle luvulle tapahtuu sinne piirrettäessä valitaan <strong>glStencilOp()</strong>-funktiolla.</p>
<p>Prototyyppi näyttää tältä:  void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass);  Kolme eri tapausta. Eli mitä tehdään kun pikseli ei läpäise sapluunatestiä (fail), mitä tehdään, kun pikseli läpäisi sapluunatestin, mutta ei syvyystestiä (zfail) ja mitä tehdään, kun pikseli läpäisi molemmat (zpass). Kaikkien parametrien mahdolliset arvot ovat: <em>GL_KEEP </em>(ei muutosta), <em>GL_ZERO </em>(korvataan nollalla), <em>GL_REPLACE </em>(korvataan jollakin vakioarvolla, joka annetaan myöhemmin esiteltävällä <strong>glStencilFunc()</strong> -funktion ref-parametrina), <em>GL_INCR </em>(kasvattaa lukua yhdellä), <em>GL_DECR </em>(vähentää lukua yhdellä) ja <em>GL_INVERT </em>(kääntää bitit).</p>
<p>Käytettävä sapluunatesti voidaan valita funktiolla <strong>glStencilFunc()</strong>. Sen prototyyppi on tämän näköinen:  void glStencilFunc(GLenum func, GLint ref, GLuint mask);  Parametri func kertoo käytettävän funktion. Mahdollisia vaihtoehtoja ovat <em>GL_NEVER </em>(pikseliä ei koskaan piirretä), <em>GL_ALWAYS </em>(pikseli läpäisee testin aina, eli sapluunatesti on pois päältä), <em>GL_EQUAL </em>(pikseli piirretään vain jos sen kohdalla oleva arvo sapluunapuskurissa on sama kuin ref-parametrin arvo), <em>GL_LESS </em>ja <em>GL_GREATER</em>. Viimeinen parametri on maski. Sen arvo on yleensä ~0 eli binääriluku 11111111.</p>
<p>Ennen käyttöä sapluunapuskuri on tietenkin tyhjennettävä. Se tapahtuu kutsulla <strong>glClear</strong>(<em>GL_STENCIL_BUFFER_BIT</em>). Lisäksi on huomattava, että kun kirjoitamme sapluunapuskuriin emme varmaan halua samalla piirtää mitään väripuskuriin. Tämä voidaan estää kutsulla glColorMask(0,0,0,0); ja äskeisen vaikutus saadaan kumottua kutsulla glColorMask(1,1,1,1);.</p>
<h2>7. Varjot</h2>
<p>OpenGL ei sisällä valmista glEnable(GL_SHADOWS)-mekanismia, jolla varjot voisi loihtia helposti. Tämä sen takia, että piirtäessään yhtä polygonia OpenGL ei tiedä mitä kaikkea se tulee vielä piirtämään ennen kuin kuva on valmis. On kuitenkin paljon algoritmeja, joilla varjoja voi tehdä. Helpointa olisi tietenkin käyttää ns. feikkivarjoja eli piirtää kuvaan jotain mikä näyttää hieman varjolta esim. musta ympyrä kappaleen alle. Kun halutaan fysikaalisesti realistisia varjoja tarvitaan hieman enemmän työtä. Kaksi kuuluisinta varjoalgoritmia ovat &#8220;shadow map&#8221;-algoritmi ja ”stencil shadow volumes”-algoritmi.</p>
<p>Kumpikaan algoritmi ei perustu siihen, että ne piirtäisivät varjon, vaan pidemminkin piirtävät kaiken muun paitsi varjon, jolloin varjon kohdat jäävät mustiksi. Itse pidän enemmän &#8220;stencil shadow volumes&#8221;-algoritmista, jota käytämme myös esimerkkiohjelmassamme, mutta esittelen ensin hieman hankalamman &#8220;shadow map&#8221;-algoritmin perusidean ja jätän yksityiskohdat lukijan oman tutkisen varaan.</p>
<h3>7.1	&#8220;Shadow map&#8221;-algoritmi</h3>
<p>&#8220;Shadow map&#8221;-algoritmin idea on seuraavanlainen. Renderoidaan kuva ensin valonlähteen näkökulmasta. Valonlähteen on siis oltava suunnattu, eikä &#8220;shadow map&#8221;-algoritmi toimi pistemäisille valonlähteille (yksi syy miksi en pidä siitä). Kopioidaan tämän kuvan syvyyspuskuri tekstuuriin. Kutsukaamme tätä tekstuuria nimellä shadow map.</p>
<p style="text-align: center;"><a href="http://www.suomipelit.com/tiedostot/2010/03/shadowmap1.jpg" rel="lightbox[1185]"><img class="aligncenter size-full wp-image-1192" title="Vasemmalla näkymä valonlähteen perspektiivistä katsottuna. Oikealla tämän kuvan syvyyspuskuri esitettynä niin, että vaaleat kohteet ovat lähellä ja tummat kaukana. Huomaa kuinka valo ei näe omia varjojaan." src="http://www.suomipelit.com/tiedostot/2010/03/shadowmap1.jpg" alt="" width="480" height="180" /></a></p>
<p>Teksturoidaan tällä tekstuurilla kaikki kappaleet valiten tekstuurikoordinaatit niin, että tekstuuri tulee projisoitua kappaleiden päälle valonlähteestä katsottuna. Tämän jälkeen renderoidaan kuva normaalisti samalla testaten jokaiselle pikselille, onko sen etäisyys valonlähteestä suurempi kuin sen kohdalla shadow map:issa oleva arvo. Jos on, pikseli on varjossa ja se voidaan jättää piirtämättä, muuten ei.</p>
<p style="text-align: center;"><a href="http://www.suomipelit.com/tiedostot/2010/03/shadowmap2.jpg" rel="lightbox[1185]"><img class="aligncenter size-full wp-image-1193" title="Vasemmalla näkymä ilman varjoja. Keskellä näkymä teksturoituna &quot;shadow map&quot;-tekstuurilla, joka on projisoitu näkymän päälle. Oikealla näkymä, jossa sellaiset pikselit joiden etäisyys valosta on suurempi kuin arvo sen &quot;shadow map&quot;-tekstuurissa on jätetty piirtämättä (mustiksi)." src="http://www.suomipelit.com/tiedostot/2010/03/shadowmap2.jpg" alt="" width="480" height="120" /></a></p>
<p>Itse kuvan renderointi valonlähteestä nähtynä ei ole hankalaa. Syvyyspuskurin kopiointi tekstuuriin taas voidaan tehdä <strong>glCopyTexSubImage2D()</strong>-funktiolla. Sen prototyyppi näyttää tältä.  void glCopyTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height );  Ensimmäisen parametrin on oltava <em>GL_TEX_IMAGE_2D </em>ja toisen 0. Offset-parametrit kertovat kohdan tekstuurista, johon kuva kopioidaan (yleensä 0,0) ja x, y kohdan ruudulta, josta data kopioidaan (yleensä 0,0). Width ja height ovat kopioitavan alueen koko.</p>
<p>Huomaa, että tektuurin, johon data tällä funktiolla kopioidaan pitää olla jo valmiiksi olemassa eli se on täytetty jollakin datalla käyttäen <strong>glTexImage2D()</strong>-funktioita. Lisäksi tämän tekstuurin tulee olla ns. &#8220;depth texture&#8221;, tai muuten <strong>glCopyTexSubImage2D()</strong> kopioi väridatan eikä syvyysdataa.. Tämä uusi tekstuurimuoto tulee <em>GL_ARB_depth_texture</em>-laajennoksen mukana ja tekstuuri on tätä muotoa, kun <strong>glTexImage2D()</strong>-funktion components-parametri asetetaan symboliin <em>GL_DEPTH_TEXTURE_ARB</em>.  Tekstuurikoordinaattien laskeminen eli tekstuurin projisointi kappaleiden päälle on aika matemaattinen juttu, jonka jätän käsittelemättä. Mainittakoon kuitenkin, että OpenGL sisältää automaattisen tekstuurikoordinaattien generoinnin, jolla tämä voidaan hoitaa.</p>
<p>Kun shadow map on luotu ja kappaleet teksturoitu sillä jää enää jäljelle kysymys: Kuinka oikein testaamme onko pikseli kauempana valosta kuin sen shadow map arvo? Voisimme tietenkin suorittaa tämän testin pikselivarjostimessa, mutta OpenGL sisältää ihan valmiin laajennoksen tätä varten. Tämän laajennoksen nimi on GL_ARB_shadow. Jätän tähän laajennokseen tutustumisen lukijan oman mielenkiinnon varaan ja siirryn &#8220;stencil shadow volumes&#8221;-algoritmiin.</p>
<h3>7.2	”Stencil shadow volumes”-algoritmi</h3>
<p>Shadow volume eli &#8220;katvetila&#8221; (jos tiedät paremman suomennoksen niin kerro toki minullekkin) on monitahokas, joka sulkee sisäänsä kaikki ne pisteet, jotka jäävät varjoon ja vastaavasti mikään katvetilan ulkopuolella oleva piste ei ole varjossa. Algoritmin idea on muodostaa monitahokkaalle valonlähteestä päin katsottu silhuetti. Venyttää tätä silhuettia valonlähteestä poispäin joilloin muodostuu monitahokkaan katvetila valonlähteen suhteen.</p>
<p>Monitahokkaan silhuetin löytäminen saattaa aluksi tuntua hankalalta tehtävältä, mutta se on itse asiassa aika helppoa. Seuraavassa yksi algoritmi. Parempiakin varmasti löytyy, mutta uskon tämän olevan aika helppo ymmärtää.</p>
<pre>for (jokaiselle monitahokaan taholle)
{
  if (tämä taho osoittaa kohti valoa)
  {
    for (jokaiselle tämän tahon vierustaholle)
    {
      if (tämä vierustaho EI osoita kohti valoa)
      {
        Tahojen välinen särmä kuuluu silhuettiin.
      }
    }
  }
}</pre>
<p>Silhuetin löytymisen jälkeen se täytyy venyttää katvetilaksi. Tämä on yksinkertaista. Projisoidaan jokaisesta särmästä kopio poispäin valonlähteestä ja yhdistetään tämä särmä alkuperäisen kanssa nelikulmioksi, joka muodostaa yhden katvetilan tahoista. Näin saadaan päistä avoin katvetila. Tämä katvetila voidaan vielä tarvittaessa sulkea käyttämällä alkuperäisen monitahokkaan omia polygoneja.</p>
<p>Kun katvetila on muodostettu herää enää kysymys: Kuinka testataan mitkä pikselit ovat sen sisässä ja mitkä sen ulkopuolella? Kikka on seuraavanlainen. Ensin kuva renderöidään normaalisti, mutta tummemmalla värillä (esim. käyttäen pelkkää ympäristövaloa) täyttäen samalla syvyyspuskuri. Tämän jälkeen syvyyspuskurin päivitys laitetaan pois päältä ( <strong>glDepthMask</strong>(<em>GL_FALSE</em>) ), mutta säilyttäen syvyystestaus päällä. Tämän jälkeen katvetila piirretään sapluunapuskuriin ja saplaanaoperaatio asetetaan sellaiseksi, että sapluunapuskurin bitit, käännetään aina, kun sinne piirretään jotain ( <strong>glStencilOp</strong>(<em>GL_KEEP, GL_KEEP, GL_INVERT</em>) ).</p>
<p>Näin katvetilan sisään jäävät pikselit saadaan arvoon 1 ja sen ulkopuoliset arvoon 0. Tämä sen takia, että syvyystestauksesta johtuen katvetilan ulkopuoliset bitit käännetään parillinen määrä kertoja, kun taas sisällä olevat pariton määrä kertoja. Tämän jälkeen kuva piirretään uudestaan oikealla värillä, mutta tällä kertaa saplaanatestaus päällä niin, että piirto tapahtuu vain niihin kohtiin missä saplaanapuskurin arvo on 0 ( <strong>glStencilFunc</strong>(<em>GL_EQUAL</em>, 0, ~0) ). Näin ollen varjostetulle alueelle ei piirry mitään ja niihin jää tumma varjon väri.  <a href="http://www.suomipelit.com/tiedostot/2010/03/keilat.jpg" rel="lightbox[1185]"><img class="aligncenter size-full wp-image-1188" title="keilat" src="http://www.suomipelit.com/tiedostot/2010/03/keilat.jpg" alt="" width="453" height="198" /></a> <a rel="lightbox[artikkelikuva_60]" href="http://www.suomipelit.com/kaikki/images/artikkelit/60/keilat.jpg"></a> Valitettavasti koverien monitahokkaiden tapauksessa antamani algoritmi tuottaa silhuetteja, jotka leikkaavat itsensä. Tällöin bittien kääntäminen sapluunapuskurissa ei anna oikeaa tulosta (kuten käy myös silloin kun kamera on katvetilan sisässä). Bittien kääntämisen sijaan voidaan käyttää jotain muuta algoritmia kuten &#8220;z-pass&#8221; tai ”Carmack’s reverse”. Näiden idea on piirtää katvetila kaksi kertaa.</p>
<p>Ensimmäisellä kerralla sen etupuoli sapluunapuskurin arvoa kasvattaen ja toisella sen takapuoli sapluunapuskurin arvoa vähentäen, jolloin saadaan taas katvetilan ulkopuolella olevat bitit arvoon 0 ja muut johonkin nollasta poikkeavaan arvoon. Jätän kuitenkin näihin algoritmeihin tutustumisen lukijan omalle vastuulle.</p>
<h2>8. Esimerkkiohjelma</h2>
<p>Esimerkkiohjelma piirtää tason ja sen päälle kuution ja yhden valonlähteen. Sekä taso, että kuutio valaistaan OpenGL:n omilla valoilla ja varjot tehdään käyttäen ”stencil shadow volumes”-algoritmia. Tämä on tähän astisista esimerkkiohjelmista monimutkaisin, mutta ei mahdoton ymmärtää. Voit imuroida oheisen lähdekoodin ja valmiiksi käännetyn version tästä: <a href="http://www.suomipelit.com/tiedostot/2004/07/testi4.zip">testi4.zip</a>.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;height:600px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br />92<br />93<br />94<br />95<br />96<br />97<br />98<br />99<br />100<br />101<br />102<br />103<br />104<br />105<br />106<br />107<br />108<br />109<br />110<br />111<br />112<br />113<br />114<br />115<br />116<br />117<br />118<br />119<br />120<br />121<br />122<br />123<br />124<br />125<br />126<br />127<br />128<br />129<br />130<br />131<br />132<br />133<br />134<br />135<br />136<br />137<br />138<br />139<br />140<br />141<br />142<br />143<br />144<br />145<br />146<br />147<br />148<br />149<br />150<br />151<br />152<br />153<br />154<br />155<br />156<br />157<br />158<br />159<br />160<br />161<br />162<br />163<br />164<br />165<br />166<br />167<br />168<br />169<br />170<br />171<br />172<br />173<br />174<br />175<br />176<br />177<br />178<br />179<br />180<br />181<br />182<br />183<br />184<br />185<br />186<br />187<br />188<br />189<br />190<br />191<br />192<br />193<br />194<br />195<br />196<br />197<br />198<br />199<br />200<br />201<br />202<br />203<br />204<br />205<br />206<br />207<br />208<br />209<br />210<br />211<br />212<br />213<br />214<br />215<br />216<br />217<br />218<br />219<br />220<br />221<br />222<br />223<br />224<br />225<br />226<br />227<br />228<br />229<br />230<br />231<br />232<br />233<br />234<br />235<br />236<br />237<br />238<br />239<br />240<br />241<br />242<br />243<br />244<br />245<br />246<br />247<br />248<br />249<br />250<br />251<br />252<br />253<br />254<br />255<br />256<br />257<br />258<br />259<br />260<br />261<br />262<br />263<br />264<br />265<br />266<br />267<br />268<br />269<br />270<br />271<br />272<br />273<br />274<br />275<br />276<br />277<br />278<br />279<br />280<br />281<br />282<br />283<br />284<br />285<br />286<br />287<br />288<br />289<br />290<br />291<br />292<br />293<br />294<br />295<br />296<br />297<br />298<br />299<br />300<br />301<br />302<br />303<br />304<br />305<br />306<br />307<br />308<br />309<br />310<br />311<br />312<br />313<br />314<br />315<br />316<br />317<br />318<br />319<br />320<br />321<br />322<br />323<br />324<br />325<br />326<br />327<br />328<br />329<br />330<br />331<br />332<br />333<br />334<br />335<br />336<br />337<br />338<br />339<br />340<br />341<br />342<br />343<br />344<br />345<br />346<br />347<br />348<br />349<br />350<br />351<br />352<br />353<br />354<br />355<br />356<br />357<br />358<br />359<br />360<br />361<br />362<br />363<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#include &lt;windows.h&gt;</span><br />
<span style="color: #339933;">#include &lt;gl\gl.h&gt;</span><br />
<span style="color: #339933;">#include &lt;gl\glu.h&gt;</span><br />
<span style="color: #339933;">#include &lt;math.h&gt;</span><br />
<span style="color: #339933;">#include &lt;stdio.h&gt;</span><br />
<span style="color: #666666; font-style: italic;">//#include &lt;gl\glext.h&gt; &nbsp;// Ei tarvita tässä ohjelmassa</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Määrittele laitekonteksti globaaliksi sitä nimittäin tarvitaan myös pääfunktiossa.</span><br />
HDC hdc<span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Valon sijainti</span><br />
<span style="color: #993333;">float</span> lightPos<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">5</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Viestinkäsittelijä</span><br />
LRESULT CALLBACK WindowProc<span style="color: #009900;">&#40;</span>HWND hwnd<span style="color: #339933;">,</span> UINT uMsg<span style="color: #339933;">,</span> WPARAM wParam<span style="color: #339933;">,</span> LPARAM lParam<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #b1b100;">switch</span> <span style="color: #009900;">&#40;</span>uMsg<span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Koska piirrämme ikkunan sisällön pääsilmukassa jatkuvasti uudelleen</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// reakoimme WM_PAINT-viestiin vain tyhjentämällä ikkunan mustaksi.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_PAINT<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; PAINTSTRUCT p<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; BeginPaint<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glClear<span style="color: #009900;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; SwapBuffers<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; EndPaint<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Ikkuna yritetään sulkea kutsu PostQuitMessage()-funktiota.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_CLOSE<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; PostQuitMessage<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Käsittele myös WM_SIZE se lähetetään ikkunalle aina kun sen kokoa muutetaan.</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Tämä on oiva tilaisuus muuttaa viewport</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// oikean kokoiseksi peittämään koko ikkuna.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_SIZE<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Ikkunan uusi koko saadaan lParam parametrista LOWORD ja HIWORD makroilla.</span><br />
&nbsp; &nbsp; &nbsp; glViewport<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> LOWORD<span style="color: #009900;">&#40;</span>lParam<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> HIWORD<span style="color: #009900;">&#40;</span>lParam<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Viestiä ei käsitelty kutsu DefWindowProc()-funktiota.</span><br />
&nbsp; <span style="color: #b1b100;">return</span> DefWindowProc<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> uMsg<span style="color: #339933;">,</span> wParam<span style="color: #339933;">,</span> lParam<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #993333;">int</span> luoIkkuna<span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> leveys<span style="color: #339933;">,</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> korkeus<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>otsikko<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Rekisteröi ikkunaluokka</span><br />
&nbsp; WNDCLASS wc<span style="color: #339933;">;</span><br />
&nbsp; memset<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>wc<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>WNDCLASS<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">style</span> <span style="color: #339933;">=</span> CS_HREDRAW <span style="color: #339933;">|</span> CS_VREDRAW <span style="color: #339933;">|</span> CS_OWNDC<span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">hCursor</span><span style="color: #339933;">=</span> LoadCursor<span style="color: #009900;">&#40;</span>NULL<span style="color: #339933;">,</span> IDC_ARROW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">lpfnWndProc</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>WNDPROC<span style="color: #009900;">&#41;</span> WindowProc<span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">hInstance</span> <span style="color: #339933;">=</span> GetModuleHandle<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">lpszClassName</span> <span style="color: #339933;">=</span> <span style="color: #ff0000;">&quot;OpenGLtutoriaali&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>RegisterClass<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>wc<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp;<span style="color: #666666; font-style: italic;">// Luo ikkuna</span><br />
&nbsp; RECT r<span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">left</span><span style="color: #339933;">=</span>GetSystemMetrics<span style="color: #009900;">&#40;</span>SM_CXSCREEN<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">-</span>leveys<span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">top</span><span style="color: #339933;">=</span>GetSystemMetrics<span style="color: #009900;">&#40;</span>SM_CYSCREEN<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">-</span>korkeus<span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">right</span><span style="color: #339933;">=</span>r.<span style="color: #202020;">left</span><span style="color: #339933;">+</span>leveys<span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">bottom</span><span style="color: #339933;">=</span>r.<span style="color: #202020;">top</span><span style="color: #339933;">+</span>korkeus<span style="color: #339933;">;</span><br />
&nbsp; AdjustWindowRectEx<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>r<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; WS_CLIPSIBLINGS <span style="color: #339933;">|</span> WS_CLIPCHILDREN <span style="color: #339933;">|</span> WS_OVERLAPPEDWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; FALSE<span style="color: #339933;">,</span> &nbsp;WS_EX_APPWINDOW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; HWND hwnd<span style="color: #339933;">;</span><br />
&nbsp; hwnd<span style="color: #339933;">=</span>CreateWindowEx<span style="color: #009900;">&#40;</span>WS_EX_APPWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #ff0000;">&quot;OpenGLtutoriaali&quot;</span><span style="color: #339933;">,</span> otsikko<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; WS_CLIPSIBLINGS <span style="color: #339933;">|</span> WS_CLIPCHILDREN <span style="color: #339933;">|</span> WS_OVERLAPPEDWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; r.<span style="color: #202020;">left</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">top</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">right</span><span style="color: #339933;">-</span>r.<span style="color: #202020;">left</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">bottom</span><span style="color: #339933;">-</span>r.<span style="color: #202020;">top</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; NULL<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> GetModuleHandle<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo laitekonteksti</span><br />
&nbsp; hdc<span style="color: #339933;">=</span>GetDC<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>hdc<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Valitse pikseliformaatti</span><br />
&nbsp; PIXELFORMATDESCRIPTOR pfd<span style="color: #339933;">;</span><br />
&nbsp; memset<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>pfd<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>PIXELFORMATDESCRIPTOR<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">nSize</span><span style="color: #339933;">=</span><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>PIXELFORMATDESCRIPTOR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">nVersion</span><span style="color: #339933;">=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">dwFlags</span><span style="color: #339933;">=</span>PFD_DRAW_TO_WINDOW<span style="color: #339933;">|</span>PFD_SUPPORT_OPENGL<span style="color: #339933;">|</span>PFD_DOUBLEBUFFER<span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">iPixelType</span><span style="color: #339933;">=</span>PFD_TYPE_RGBA<span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cRedBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cGreenBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cBlueBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cAlphaBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cStencilBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cDepthBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">16</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">iLayerType</span><span style="color: #339933;">=</span>PFD_MAIN_PLANE<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">int</span> pixelFormat<span style="color: #339933;">;</span><br />
&nbsp; pixelFormat<span style="color: #339933;">=</span>ChoosePixelFormat<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pfd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>pixelFormat<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>SetPixelFormat<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> pixelFormat<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pfd<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo renderöintikonteksti</span><br />
&nbsp; HGLRC hrc<span style="color: #339933;">;</span><br />
&nbsp; hrc<span style="color: #339933;">=</span>wglCreateContext<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>hrc<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>wglMakeCurrent<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> hrc<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Tuo ikkuna näkyviin</span><br />
&nbsp; ShowWindow<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> SW_SHOW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; SetForegroundWindow<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; SetFocus<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Palauta onnistuminen</span><br />
&nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Laskee kahden vektorin pistetulon</span><br />
<span style="color: #993333;">float</span> pistetulo<span style="color: #009900;">&#40;</span><span style="color: #993333;">float</span> v1<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #993333;">float</span> v2<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #b1b100;">return</span> v1<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>v2<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>v1<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>v2<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span>v1<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">*</span>v2<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Taso piirretään käyttäen useita pieniä nelikulmioita</span><br />
<span style="color: #666666; font-style: italic;">// paremman valaistuksen saavuttamiseksi</span><br />
<span style="color: #993333;">void</span> piirraTaso<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #993333;">int</span> x<span style="color: #339933;">,</span> z<span style="color: #339933;">;</span><br />
<br />
&nbsp; glBegin<span style="color: #009900;">&#40;</span>GL_QUADS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; glNormal3f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>z<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> z<span style="color: #339933;">&lt;</span><span style="color: #0000dd;">22</span><span style="color: #339933;">;</span> z<span style="color: #339933;">+=</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>x<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> x<span style="color: #339933;">&lt;</span><span style="color: #0000dd;">22</span><span style="color: #339933;">;</span> x<span style="color: #339933;">+=</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #339933;">+</span>x<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #339933;">+</span>z<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #339933;">+</span>x<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #339933;">+</span>z<span style="color: #339933;">+</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #339933;">+</span>x<span style="color: #339933;">+</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #339933;">+</span>z<span style="color: #339933;">+</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #339933;">+</span>x<span style="color: #339933;">+</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #339933;">+</span>z<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Piirtää kuution tai sen katvetilan, jos katvetila-parametri on TRUE</span><br />
<span style="color: #993333;">void</span> piirraKuutio<span style="color: #009900;">&#40;</span>BOOL katvetila<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Data piirrettävää kuutiota varten</span><br />
&nbsp; <span style="color: #993333;">static</span> <span style="color: #993333;">float</span> vertex<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">8</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">static</span> <span style="color: #993333;">int</span> index<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">6</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span><span style="color: #0000dd;">7</span><span style="color: #339933;">,</span><span style="color: #0000dd;">6</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">7</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #009900;">&#123;</span><span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">6</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">7</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">6</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Tahojen normaalit</span><br />
&nbsp; <span style="color: #993333;">static</span> <span style="color: #993333;">float</span> normal<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">6</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Katvetilan muodostusta varten jokaisen tahon on tiedettävä naapurinsa.</span><br />
&nbsp; <span style="color: #993333;">static</span> <span style="color: #993333;">int</span> naapuri<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">6</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Jokaiselle verteksille valoa kohti osoittava vektori.</span><br />
&nbsp; <span style="color: #993333;">static</span> <span style="color: #993333;">float</span> L<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">8</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>katvetila<span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Piirrä kuutio</span><br />
&nbsp; &nbsp; glBegin<span style="color: #009900;">&#40;</span>GL_QUADS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">int</span> i<span style="color: #339933;">,</span> j<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span><span style="color: #0000dd;">6</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; glNormal3f<span style="color: #009900;">&#40;</span>normal<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> normal<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> normal<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>j<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> j<span style="color: #339933;">&lt;</span><span style="color: #0000dd;">4</span><span style="color: #339933;">;</span> j<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span>vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">int</span> i<span style="color: #339933;">,</span>j<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Laske valoa kohti osoittavat vektorit.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; L<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>lightPos<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span>vertex<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; L<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>lightPos<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span>vertex<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; L<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span>lightPos<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span>vertex<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Piirrä katvetila.</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Tässä tulee sairaan paljon indeksointia, joka olisi voitu välttää</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// jonkinlaisen verteksi-structuren ja osoittimien käytöllä.</span><br />
&nbsp; &nbsp; glBegin<span style="color: #009900;">&#40;</span>GL_QUADS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Jokaiselle taholle</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span><span style="color: #0000dd;">6</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Jos tämä taho osoittaa kohti valoa</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>pistetulo<span style="color: #009900;">&#40;</span> normal<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> L<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">&gt;=</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Jokaiselle vierustaholle</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>j<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> j<span style="color: #339933;">&lt;</span><span style="color: #0000dd;">4</span><span style="color: #339933;">;</span> j<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Jos tämä vierustaho EI osoita kohti valoa</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>pistetulo<span style="color: #009900;">&#40;</span>normal<span style="color: #009900;">&#91;</span> naapuri<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> L<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span> naapuri<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&lt;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Tahojen välinen särmä kuuluu silhuettiin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// venytä se nelikulmioksi poispäin valosta.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span>vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span>vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#40;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">%</span><span style="color:#800080;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#40;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">%</span><span style="color:#800080;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#40;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">%</span><span style="color:#800080;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span>vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#40;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">%</span><span style="color:#800080;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">100</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#40;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">%</span><span style="color:#800080;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#40;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">%</span><span style="color:#800080;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">100</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#40;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">%</span><span style="color:#800080;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#40;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">%</span><span style="color:#800080;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">100</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#40;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">%</span><span style="color:#800080;">4</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span>vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">100</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">100</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;vertex<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">100</span><span style="color: #339933;">*</span>L<span style="color: #009900;">&#91;</span> index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Pääfunktio</span><br />
<span style="color: #993333;">int</span> WINAPI WinMain<span style="color: #009900;">&#40;</span>HINSTANCE hInstance<span style="color: #339933;">,</span> HINSTANCE hPrevInstance<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LPSTR lpCmdLine<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> nCmdShow<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #993333;">float</span> angle<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> aika<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> piirtoaika<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> alkuaika<span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo ikkuna</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>luoIkkuna<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">800</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">600</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;OpenGL:n perusteet - Osa 4: Valot ja varjot&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Määrittele viewport koko ikkunan kokoiseksi</span><br />
&nbsp; glViewport<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">800</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">600</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Koska koordinaatisto on itseasiassa matriisi täytyy meidän ottaa</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// projektiomatriisi käsiteltäväksi ennen gluPerspective-kutsua.</span><br />
&nbsp; glMatrixMode<span style="color: #009900;">&#40;</span>GL_PROJECTION<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; gluPerspective<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">60</span><span style="color: #339933;">,</span> <span style="color:#800080;">800.0</span><span style="color: #339933;">/</span><span style="color:#800080;">600.0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">100</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Kaikki matriisia muuttavat käskyt vaikuttavat tämän jälkeen modelview-matriisiin</span><br />
&nbsp; glMatrixMode<span style="color: #009900;">&#40;</span>GL_MODELVIEW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Laita näkymättömien pintojen poisto ja sysyyspuskurialgoritmi päälle.</span><br />
&nbsp; glEnable<span style="color: #009900;">&#40;</span>GL_CULL_FACE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp;<span style="color: #666666; font-style: italic;">// Valitse syvyystestausfunktio &quot;&lt;=&quot; oletuksena olevan &quot;&lt;&quot; tilalle.</span><br />
&nbsp; glDepthFunc<span style="color: #009900;">&#40;</span>GL_LEQUAL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; glEnable<span style="color: #009900;">&#40;</span>GL_DEPTH_TEST<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Aseta valo nro. 0 päälle</span><br />
&nbsp; <span style="color: #993333;">float</span> Cl<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color:#800080;">0.8</span><span style="color: #339933;">,</span><span style="color:#800080;">0.8</span><span style="color: #339933;">,</span><span style="color:#800080;">0.8</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">float</span> A<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color:#800080;">0.2</span><span style="color: #339933;">,</span><span style="color:#800080;">0.2</span><span style="color: #339933;">,</span><span style="color:#800080;">0.2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">float</span> Cd<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
&nbsp; glLightfv<span style="color: #009900;">&#40;</span>GL_LIGHT0<span style="color: #339933;">,</span> GL_DIFFUSE<span style="color: #339933;">,</span> Cl<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp;<span style="color: #666666; font-style: italic;">// Väri</span><br />
&nbsp; glLightfv<span style="color: #009900;">&#40;</span>GL_LIGHT0<span style="color: #339933;">,</span> GL_AMBIENT<span style="color: #339933;">,</span> A<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #666666; font-style: italic;">// Ympätisrövalon määrä</span><br />
&nbsp; glMaterialfv<span style="color: #009900;">&#40;</span>GL_FRONT_AND_BACK<span style="color: #339933;">,</span> GL_AMBIENT_AND_DIFFUSE<span style="color: #339933;">,</span> Cd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Pinnan väri</span><br />
&nbsp; glEnable<span style="color: #009900;">&#40;</span>GL_LIGHT0<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// OpenGL lisää valaistukseen vielä yhden valonlähteistä</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// riippumattoman ympäristövalon, josta haluamme päästä eroon.</span><br />
&nbsp; <span style="color: #993333;">float</span> nolla<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
&nbsp; glLightModelfv<span style="color: #009900;">&#40;</span>GL_LIGHT_MODEL_AMBIENT<span style="color: #339933;">,</span> nolla<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Viestinkäsittelysilmukka</span><br />
&nbsp; alkuaika<span style="color: #339933;">=</span>GetTickCount<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; MSG msg<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>PeekMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> PM_REMOVE<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>msg.<span style="color: #202020;">message</span><span style="color: #339933;">==</span>WM_QUIT<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; TranslateMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; DispatchMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Käytämme GetTickCount()-funktiota, joka palauttaa ajan millisekunneissa,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// laskemaan kuvan piirtämiseen kuluneen ajan.</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Näin voimme ajastaa valon liikkumaan samalla nopeudella kaikilla kokeilla.</span><br />
&nbsp; &nbsp; &nbsp; aika<span style="color: #339933;">=</span>GetTickCount<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; piirtoaika<span style="color: #339933;">=</span>aika<span style="color: #339933;">-</span>alkuaika<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>piirtoaika<span style="color: #339933;">&gt;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; alkuaika<span style="color: #339933;">=</span>aika<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Kasvata pyörityskulmaa hieman seuraavaa framea varten.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; angle<span style="color: #339933;">+=</span><span style="color:#800080;">0.03</span><span style="color: #339933;">*</span>piirtoaika<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Tyhjennä väripuskuri, syvyyspuskuri ja sapluunapuskuri</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glClear<span style="color: #009900;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: #339933;">|</span>GL_DEPTH_BUFFER_BIT<span style="color: #339933;">|</span>GL_STENCIL_BUFFER_BIT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Aseta modelview-matriisi</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glLoadIdentity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666; font-style: italic;">// &quot;Resetoi&quot; matriisi yksikkömatriisiksi</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTranslatef<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Siirrä hieman kauemmaksi kamerasta</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glRotatef<span style="color: #009900;">&#40;</span>angle<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Pyöritä hieman Y-akselin ympäri</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Siirrä valoa</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; lightPos<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #0000dd;">5</span><span style="color: #339933;">*</span>sin<span style="color: #009900;">&#40;</span>angle<span style="color: #339933;">*-</span><span style="color:#800080;">0.04</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; lightPos<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #0000dd;">5</span><span style="color: #339933;">+</span>sin<span style="color: #009900;">&#40;</span>angle<span style="color: #339933;">*</span><span style="color:#800080;">0.1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; lightPos<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #0000dd;">5</span><span style="color: #339933;">*</span>cos<span style="color: #009900;">&#40;</span>angle<span style="color: #339933;">*-</span><span style="color:#800080;">0.04</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glLightfv<span style="color: #009900;">&#40;</span>GL_LIGHT0<span style="color: #339933;">,</span> GL_POSITION<span style="color: #339933;">,</span> lightPos<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Ensimmäinen vaihe.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// täytetään syvyyspuskuri ja piirretään kuva käyttäen pelkkää ympäristövaloa</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glDisable<span style="color: #009900;">&#40;</span>GL_LIGHTING<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glDisable<span style="color: #009900;">&#40;</span>GL_STENCIL_TEST<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glColor3f<span style="color: #009900;">&#40;</span>A<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> A<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> A<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; piirraTaso<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; piirraKuutio<span style="color: #009900;">&#40;</span>FALSE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Toinen vaihe</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Piirrä katvetila sapluunapuskuriin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Jos haluat päästä eroon varjoista kommentoi tämä toinen vaihe pois</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glDisable<span style="color: #009900;">&#40;</span>GL_CULL_FACE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Katvetilasta pitää piirtää kaikki osat</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glEnable<span style="color: #009900;">&#40;</span>GL_STENCIL_TEST<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Sapluunapuskuri päälle</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glColorMask<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #666666; font-style: italic;">// Emme halua päivittää väripuskuria</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glDepthMask<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666; font-style: italic;">// Emmekä syvyyspuskuria</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glStencilFunc<span style="color: #009900;">&#40;</span>GL_ALWAYS<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glStencilOp<span style="color: #009900;">&#40;</span>GL_KEEP<span style="color: #339933;">,</span> GL_KEEP<span style="color: #339933;">,</span> GL_INVERT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Käännä bitit piirtäessä</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; piirraKuutio<span style="color: #009900;">&#40;</span>TRUE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glEnable<span style="color: #009900;">&#40;</span>GL_CULL_FACE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glColorMask<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glDepthMask<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Viimeinen vaihe</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Piirrä lopullinen kuva kohtiin, jossa sapluunapuskurin arvo on 0</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glEnable<span style="color: #009900;">&#40;</span>GL_LIGHTING<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glStencilFunc<span style="color: #009900;">&#40;</span>GL_EQUAL<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> ~<span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glStencilOp<span style="color: #009900;">&#40;</span>GL_KEEP<span style="color: #339933;">,</span> GL_KEEP<span style="color: #339933;">,</span> GL_KEEP<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; piirraTaso<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; piirraKuutio<span style="color: #009900;">&#40;</span>FALSE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Piirrä vielä valonlähde</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glDisable<span style="color: #009900;">&#40;</span>GL_LIGHTING<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glDisable<span style="color: #009900;">&#40;</span>GL_STENCIL_TEST<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glPointSize<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glBegin<span style="color: #009900;">&#40;</span>GL_POINTS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glColor3f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span>lightPos<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> lightPos<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> lightPos<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Vaihda puskuri näytölle.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; SwapBuffers<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<h2>9. Loppusanat</h2>
<p>Tässä artikkelissa opit valoista ja varjoista. Tässä artikkelisarjassa olemme nyt käyneet läpi pintapuolisesti kaikki 3d grafiiikan perusasiat. Lopuksi listaan vielä joitakin linkkejä, joista löydät rutkasti lisää luottevaa OpenGL:stä ja 3D grafiikasta yleensäkkin.</p>
<p><a href="http://www.opengl.org/">http://www.opengl.org</a> – OpenGL:n virallinen kotisivu. Uutisia, viralliset speksit ja keskustelufoorumit löytyvät täältä.</p>
<p><a href="http://nehe.gamedev.net/">http://nehe.gamedev.net</a> – NeHe Productions. Netin ylivoimaisesti suosituimmat openGL tutoriaalit.</p>
<p><a href="http://www.gamedev.net/download/redbook.pdf">http://www.gamedev.net/download/redbook&#8230;.</a> &#8211; The Red Book. Virallinen OpenGL:n opaskirja. Tämä netistä löytyvä ilmaisversio on aika hemmetin vanha, mutta ajaa asiansa. Uusin versio on saatavilla vain kirjakaupoista, mutta siitä on netissä yksi näyteluku:</p>
<p><a href="http://www.opengl.org/documentation/red_book_1.0/OpenGL_PG_ch09.pdf">http://www.opengl.org/documentation/red_&#8230;</a> .  <a href="http://oss.sgi.com/projects/ogl-sample/registry/">http://oss.sgi.com/projects/ogl-sample/r&#8230;</a> &#8211; SGI:n ylläpitämä OpenGL:n laajennusrekisteri. Sama löytyy myös kaikkien näytönohjainvalmistajien kotisivuilta.</p>
<p><a href="http://www.delphi3d.net/hardware/index.php">http://www.delphi3d.net/hardware/index.p&#8230;</a> &#8211; OpenGL Hardware Registry. Rekisteri, jossa on lueteltu valtavasti näytönohjaimia ja kerrottu mitä laajennuksia ne tukevat.  <a href="http://www.mesa3d.org/">http://www.mesa3d.org/</a> &#8211; Mesa 3D Graphics Library. Software OpenGL &#8220;ajurit&#8221;. Voit kokeilla näiden &#8220;ajurien&#8221; avulla laajennuksia, joita oma näytönohjaimesi ei tue.  <a href="http://www.opengl.org/resources/faq/technical/index.html">http://www.opengl.org/resources/faq/tech&#8230;</a> &#8211; OpenGL faq. Usein kysytyt kysymykset OpenGL:stä.</p>
<p><a href="http://www.gametutorials.com/gtstore/c-1-test-cat.aspx">http://www.gametutorials.com/gtstore/c-1&#8230;</a> &#8211; Game tutorials. 50 aloittelijoille tarkoitettua OpenGL-tutoriaalia.</p>
<p><a href="http://www.ultimategameprogramming.com/">http://www.ultimategameprogramming.com</a> &#8211; Ultimate game programming. Lähes 100 hieman edistyneimmille tarkoitettua OpenGL-tutoriaalia.  <a href="http://www.codesampler.com/oglsrc.htm">http://www.codesampler.com/oglsrc.htm</a> &#8211; CodeSampler. Paljon OpenGL tutoriaaleja aina aloittelijoille tarkoitetuista edistyneimpiin.  Raportoithan kaikki tästä artikkelista löytämäsi virheet (niin kirjoitus-, kuin asiavirheetkin) osoitteeseen markus.ilmola@pp.inet.fi , niin korjaan ne mahdollisimman nopeasti. Myös kaikki kommentit ja kysymykset ovat tervetulleita</p>
<hr /><em>Artikkelin kirjoitti alun perin markus.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.suomipelit.com/2004/07/27/opengln-perusteet-osa-4-valot-ja-varjot/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenGL:n perusteet &#8211; Osa 3: Teksturointi</title>
		<link>http://www.suomipelit.com/2004/07/07/opengln-perusteet-osa-3-teksturointi/</link>
		<comments>http://www.suomipelit.com/2004/07/07/opengln-perusteet-osa-3-teksturointi/#comments</comments>
		<pubDate>Wed, 07 Jul 2004 10:00:58 +0000</pubDate>
		<dc:creator>Suomipelit.com</dc:creator>
				<category><![CDATA[Artikkelit]]></category>
		<category><![CDATA[Käytännön oppaat]]></category>
		<category><![CDATA[2d]]></category>
		<category><![CDATA[3d]]></category>
		<category><![CDATA[c/cpp]]></category>
		<category><![CDATA[grafiikka]]></category>
		<category><![CDATA[opengl]]></category>
		<category><![CDATA[perusteet]]></category>
		<category><![CDATA[teksturointi]]></category>

		<guid isPermaLink="false">http://www.suomipelit.com/?p=1173</guid>
		<description><![CDATA[OpenGL on laajassa käytössä oleva käyttöjärjestelmäriippumaton rajapinta 2D- ja 3D-grafiikan piirtoon. Tämä artikkelisarja opettaa sinulle 3D-grafiikan perusteet OpenGL:ää käyttäen. Esimerkeissä käytetään C\C++ kieltä. Tämä on artikkelisarjan kolmas osa.]]></description>
			<content:encoded><![CDATA[<p>OpenGL on laajassa käytössä oleva käyttöjärjestelmäriippumaton rajapinta 2D- ja 3D-grafiikan piirtoon. Tämä artikkelisarja opettaa sinulle 3D-grafiikan perusteet OpenGL:ää käyttäen. Esimerkeissä käytetään C\C++ kieltä. Tämä on artikkelisarjan kolmas osa.</p>
<h2>1. Johdatus tekstuureihin</h2>
<p>Monitahokkaalla voidaan siis helposti jäljitellä kappaleen muotoa, mutta entäpä sen pintakuviota? Tietysti voimme värittää monitahokkaan glColor3f()-funktion kutsuilla, mutta harvan kappaleen pinnan väritys on kauniin tasainen. Voisimme tietenkin jakaa monitahokkaan tahot yhä pienempiin ja pienempiin polygoneihin, jolloin saisimme aikaiseksi millaisen värikuvion tahansa, mutta vähänkään shakkilautaa monimutkaisemmissa kuvioissa polygonien määrä nousisi valtavan suureksi. Olisikin hyvä, jos voisimme päällystää monitahokkaan valmiilla kuvalla, joka sisältäisi tarvittavan pintakuvion. Juuri tätä varten ovat olemassa tekstuurit. Tekstuuri voidaan piirtää erikseen jollakin kuvankäsittelyohjelmalla tai se voidaan generoida ajon aikana. Esim. shakkilautakuvion tuottaminen algoritmillisesti ei ole kovin hankalaa.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/asteroidi.jpg" rel="lightbox[1173]"><img class="aligncenter size-full wp-image-1175" title="asteroidi" src="http://www.suomipelit.com/tiedostot/2010/03/asteroidi.jpg" alt="" width="476" height="150" /></a></p>
<p><a title="Asteroidin malli ilman tekstuuria ja sen kanssa. Oikealla käytetty tekstuuri." rel="lightbox[artikkelikuva_59]" href="http://www.suomipelit.com/kaikki/images/artikkelit/59/asteroidi.jpg"></a>Asteroidin malli ilman tekstuuria ja sen kanssa. Oikealla käytetty tekstuuri.</p>
<p>Kuinka sitten määritellään miten tekstuuri asettuu monitahokkaan pinnalle? Tämä tehdään tekstuurikoordinaattien avulla. Jokaiselle verteksille määritellään sen sijainnin lisäksi myös missä kohtaa tekstuuria se sijaitsee. Tekstuurin origo sijaitsee sen vasemmassa alakulmassa. X-akseli kasvaa oikealle ja Y-akseli ylöspäin. Siis tavallisen koordinaatiston tapaan. Huomattavaa kuitenkin on, että riippumatta tektuurin koosta tai sen leveyden ja korkeuden suhteesta oikean ylänurkan koordinaatit ovat aina ( 1, 1 ).</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/texcoord.jpg" rel="lightbox[1173]"><img class="aligncenter size-full wp-image-1182" title="texcoord" src="http://www.suomipelit.com/tiedostot/2010/03/texcoord.jpg" alt="" width="219" height="200" /></a></p>
<p><a rel="lightbox[artikkelikuva_59]" href="http://www.suomipelit.com/kaikki/images/artikkelit/59/texcoord.jpg"></a></p>
<p>Tekstuurikoordinaatit annetaan OpenGL:lle glTexCoord2f()-funktiolla. Funktiota kutsutaan jokaiselle verteksille erikseen. Sen prototyyppi näyttää tältä:</p>
<pre>void glTexCoord2f(GLfloat s, GLfloat t);</pre>
<p>s ja t ovat siis tekstuurikoordinaatin x ja y komponentit. Huomattavaa lisäksi on, että teksturointi täytyy myös laittaa päälle glEnable()-funktiolla, jolle annetaan parametrina <em>GL_TEXTURE_2D</em>. Käytimme tässä siis 2D-tekstuureja. On myös muita tekstuurityyppejä kuten 1D-tekstuurit. Silloin koordinaatti annettaisiin funktiolla <strong>glTexCoord1f()</strong> ja teksturointi laitettaisiin päälle antamalla <strong>glEnable(</strong>)-funktiolle parametriksi <em>GL_TEXTURE_1D</em>.</p>
<p>Kuten glVertex-sarjan funktiolla annetut koordinaatit kerrottiin modelview-matriisilla, niin glTexCoord-sarjan funktioilla annetut koordinaatit kerrotaan tekstuurimatriisilla. Tätä matriisia voi muokata samoin kuin modelview-matriisiakin. Tekstuurimatriisi valitaan <strong>glMatrixMode()</strong>-funktiolla, jolle annetaan parametrina <em>GL_TEXTURE </em>ja sitä voi muokata samoilla funktioilla kuin kaikkia muitakin matriiseja eli esim. <strong>glTranslatef()</strong> ja <strong>glRotatef()</strong>.</p>
<h2>2. Tekstuuriobjektit</h2>
<p>OpenGL:ssä tekstuurit ovat näytönohjaimen muistissa sijaitsevia objekteja (olioita), jotka täytyy luoda ennen käyttöä. Tekstuurin luominen tehdään funktiolla glGenTextures(). Sen prototyyppi näyttää tältä:</p>
<pre>void glGenTextures(GLsizei n, GLuint *textures);</pre>
<p>Parametri n kertoo kuinka monta tekstuuriobjektia luodaan ja parametri textures on osoitin taulukkoon, johon luotujen tekstuurien tunnukset laitetaan.</p>
<p>Teksturoinnin hoitaa näytönohjaimen teksturointiyksikkö. Jotta teksturointi olisi mahdollista, pitää tekstuuri ensin sitoa tähän teksturointiyksikköön glBindTexture()-funktiolla. Sen prototyyppi näyttää tältä.</p>
<pre>void glBindTexture(GLenum target, GLuint texture);</pre>
<p>Texture on sidottavan tekstuurin tunnus eli se, joka saatiin <strong>glGenTextures()</strong>-funktiolta. Vain yksi tekstuuri voi olla sidottuna kerrallaan (tästä on tosin poikkeus, josta puhumme kappaleessa multiteksturointi)!</p>
<p>Target on sidottavan tekstuurin tyyppi. OpenGL:ssä on useita eri tekstuurityyppejä, mutta hyödyllisin niistä on <em>GL_TEXTURE_2D </em>eli 2D-tekstuuri, joka vastaa tavallista kuvaa. Luodessa tekstuuri on tyypitön ja tekstuuri omaa sen tyypin, jona se ensimmäisen kerran sidotaan teksturointiyksikköön.</p>
<p>Kun polygoni piirretään, teksturoidaan se sillä tekstuurilla, joka on sillä hetkellä sidottuna teksturointiyksikköön. Myös kaikki tekstuureihin vaikuttavat funktiot, joista tässä artikkelissa puhumme vaikuttavat siihen tekstuuriin, joka on sillä hetkellä sidottuna.</p>
<p>Luotu tekstuuri on kuitenkin tyhjä, eikä sisällä mitään dataa. Jos kokeilisit teksturoida tyhjällä tekstuurilla saisit tulokseksi pelkkää valkoista väriä. Niinpä tekstuuriin täytyy ladata dataa. 2D-tekstuuriin data ladataan funktiolla <strong>glTexImage2D()</strong>. Prototyyppi on tämän näköinen:</p>
<pre>void glTexImage2D(
GLenum target,
GLint level,
GLint components,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
const GLvoid *pixels);</pre>
<p>Parametrin target arvon pitää olla aina <em>GL_TEXTURE_2D</em>.</p>
<p>Parametrien level ja border arvojen pitää olla nolla.</p>
<p>Parametri Components kertoo formaatin, jossa OpenGL tallentaa tekstuurin sisäisesti näytönohjaimen muistiin. Tämä voi olla joko tarkka formaatti tai haluttavienvärikomponenttien määrä, jolloin OpenGL valitsee automaattisesti sopivan formaatin. Pitääksemme asiat yksinkertaisena käytämme värikomponenttien määrää. Tämä on yleensä 3 (red, green ja blue). Joskus myös 4 (red, green, blue ja alpha), jos alphakanava on mukana, mutta alphakanavasta enemmän kappaleessa läpinäkyvyys.</p>
<p>Width ja height kertovat tekstuurin leveyden ja korkeuden. Näiden lukujen täytyy olla kakkosen potensseja eli 32, 64, 128, 256 jne. Näillä arvoilla on myös jokin yläraja, jonka saat selville funktiolla glGetIntegerv(), parametrilla <em>GL_MAX_TEXTURE_SIZE</em>. Hyvin vanhoissa näytönohjaimissa raja on 256, kun taas uusissa 4096 tai jopa enemmän.</p>
<p>Format kertoo tekstuuriin syötettävän datan muodon. Tämä on yleensä joko <em>GL_RGB </em>tai <em>GL_RGBA </em>jos alphakin on mukana. Ladattavan datan pitää siis sisältää tekstuurin kaikkien pikselien värit tyyliin RGBRGBRGB&#8230; jne. Eli ensimmäisen pikselin värin Red, Green ja Blue komponentit, sitten seuraavan jne. Jos tekstuurissa on alphakanava mukana (<em>GL_RGBA</em>), pitää datan taas olla muodossa RGBARGBARGBA&#8230; jne.</p>
<p>Type-parametri kertoo ladattavan datan tyypin. Vaihtoehdot ovat: <em>GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, ja GL_FLOAT</em>. Yleisin käytetty muoto on <em>GL_UNSIGNED_BYTE</em>.</p>
<p>Viimeinen parametri on osoitin varsinaiseen ladattavaan dataan, joka on esim. piirretty kuvankäsittelyohjelmalla tai generoitu jollakin algoritmilla. Jos datan tyyppi on <em>GL_FLOAT</em> pitää näiden arvojen olla välillä 0-1. Muuten suurin käytetyllä tyypillä esitettävissä oleva luku tulkitaan luvuksi 1 ja pienin luvuksi 0. Huomaa, että data ladataan siihen tekstuuriin, joka on sillä hetkellä sidottuna teksturointiyksikköön. Jos tekstuuri sisältää jo dataa, korvautuu se uudella.</p>
<p>Kun tekstuuri käy turhaksi, se voidaan poistaa funktiolla:</p>
<pre>glDeleteTextures(GLsizei n,	 const GLuint * textures);</pre>
<p>Parametrien merkitykset ovat samat kuin glGenTextures()-funktiossakin, eli poistettavien tekstuurien määrä ja osoitin taulukkoon, joka sisältää poistettavien tekstuurien tunnukset.</p>
<h2>3. Tekstuurin reunat ja suodatus</h2>
<p>Mitä mahtaakaan tapahtua, jos annetut tekstuurikoordinaatit menevät tekstuurin reunojen ulkopuolelle? Sen voit valita itse. Vaihtoehdot ovat joko korvata ulkopuoliset pikselit jollain vakio värillä (mustalla), korvata ne lähimmällä reunapikselillä tai alkaa toistaa pikseleitä tekstuurin toisesta reunasta. Reunakäyttäytyminen asetetaan funktiolla glTexParameteri(). Prototyyppi näyttää tältä:</p>
<pre>void glTexParameteri(GLenum target, GLenum pname, GLint param);</pre>
<p>Ensimmäinen parametri on tekstuurin tyyppi (tässä tapauksessa GL_TEXTURE_2D). Toisen parametrin on oltava <em>GL_TEXTURE_WRAP_S</em> tai <em>GL_TEXTURE_WRAP_T</em>. Se ilmaisee asetetaanko käyttäytyminen vaaka vai pystyakselille. Voit siis laittaa kummallekkin akselille erilaisen. Viimeinen parametri on <em>GL_CLAMP, GL_CLAMP_TO_EDGE, tai GL_REPEAT</em>. Vaihtoehdot on kuvattu alla olevassa kuvassa.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/reunat.jpg" rel="lightbox[1173]"><img class="aligncenter size-full wp-image-1180" title="reunat" src="http://www.suomipelit.com/tiedostot/2010/03/reunat.jpg" alt="" width="462" height="100" /></a></p>
<p><a rel="lightbox[artikkelikuva_59]" href="http://www.suomipelit.com/kaikki/images/artikkelit/59/reunat.jpg"></a></p>
<p>Itseasiassa <em>GL_CLAMP:n </em>käyttäytyminen on hieman erilainen kuin tässä annetaan ymmmärtää ja kappaleessa 6 kerrotusta syystä <em>GL_CLAMP_TO_EDGE </em>on määritelty tiedostosssa glext.h eikä gl.h kuten muut, mutta asiat selviävät tarkemmin virallisista spekseistä jos kiinnostaa.</p>
<p>3D-korttien alkuaikoina oli Voodoo-korttien ajureissa bugi, jonka takia <em>GL_CLAMP </em>käyttäytyi samoin kuin <em>GL_CLAMP_TO_EDGE</em>. Monet sovelluksen tekijät luottivat sokeasti tähän käyttäytymiseen tarkistamatta asiaa dokumentaatiosta ja näin ollen kun ohjelmia käytettiin korteilla, joissa tätä bugia ei ollut, oli grafiikka joskus virheellistä. Tämän ja sen takia, että <em>GL_CLAMP:n </em>oikeaoppinen käyttäytyminen on käytännössä hyödytön, monet näytönohjainvalmistajat jättivät mahdollisuuden laittaa tämä bugi päälle omissa näytönohjaimissaan.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/clampbugi.jpg" rel="lightbox[1173]"><img class="aligncenter size-full wp-image-1176" title="clampbugi" src="http://www.suomipelit.com/tiedostot/2010/03/clampbugi.jpg" alt="" width="380" height="175" /></a></p>
<p><a rel="lightbox[artikkelikuva_59]" href="http://www.suomipelit.com/kaikki/images/artikkelit/59/clampbugi.jpg"></a></p>
<p>Kun teksturoitua kappaletta katsotaan niin läheltä, että yksi tekstuurin kuvapiste eli tekseli näyttää suuremmalta kuin pikseli, kuva ns. puuroutuu eli muuttuu (lego)palikkamaiseksi. Asia voidaan korjata suodatuksella, joka saadaan päälle tutulla <strong>glTexParameteri()</strong>-funktiolla, joka saa toisena parametrinaan <em>GL_TEXTURE_MAG_FILTER </em>ja viimeisenä parametrinaan joko <em>GL_NEAREST</em>, jos suodatus halutaan pois päältä, tai <em>GL_LINEAR </em>jos suodatus halutaan päälle. Oletuksena suodatus on jo valmiina päällä.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/suodatus.jpg" rel="lightbox[1173]"><img class="aligncenter size-full wp-image-1181" title="suodatus" src="http://www.suomipelit.com/tiedostot/2010/03/suodatus.jpg" alt="" width="499" height="175" /></a></p>
<p><a rel="lightbox[artikkelikuva_59]" href="http://www.suomipelit.com/kaikki/images/artikkelit/59/suodatus.jpg"></a></p>
<p>Vastaavasti kun kappale on niin kaukana, että yhden pikselin alalle mahtuu monta tekseliä alkaa kuva ”vilkkua”. Tähänkin ongelmaan on ratkaisu. Sitä kutsutaan termillä ”mipmapping”. Ideana on tallentaa tekstuurista monta erikokoista versiota ja valita niistä sitten se, joka lähinnä vastaa oikeaa kokoa. Mipmapping asetetaan päälle glTexParameteri()-funktiolla. Tällä kertaa keskimmäisenä parametrina on GL_TEXTURE_MIN_FILTER ja viimeisenä GL_LINEAR_MIPMAP_LINEAR. Kun mipmapping halutaan pois päältä, käytetään GL_LINEAR_MIPMAP_LINEAR parametrin sijasta parametria GL_LINEAR tai GL_NEAREST, riippuen siitä, halutaanko myös kaukana olevat tekselit suodattaa. Oletuksena mipmapping on päällä.</p>
<p>Lisäksi meidän on generoitava mipmap:it. OpenGL osaa tehdä tämän automaattisesti useammallakin eri tavalla, mutta helpoimmalla pääset kun lataat datan glTexImage2D()-funktion sijasta gluBuild2Dmipmaps()-funktiolla. Sen prototyyppi on seuraavanlainen.</p>
<pre>int gluBuild2DMipmaps(
    GLenum target,
    GLint components,
    GLint width,
    GLint height,
    GLenum format,
    GLenum type,
    const void * data
   );</pre>
<p>Parametrien merkitykset ovat samat kuin glTexImage2D()-funktiollakin.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/mipmap.jpg" rel="lightbox[1173]"><img class="aligncenter size-full wp-image-1178" title="mipmap" src="http://www.suomipelit.com/tiedostot/2010/03/mipmap.jpg" alt="" width="550" height="185" /></a></p>
<p><a rel="lightbox[artikkelikuva_59]" href="http://www.suomipelit.com/kaikki/images/artikkelit/59/mipmap.jpg"></a></p>
<p>Koska mipmapping on oletuksena päällä, törmää usein tilanteeseen, jossa unohtaa generoida mippappien tarvitseman datan (käyttää siis pelkästään funktiota <strong>glTexImage2D</strong>). Tämän takia mipmaping tulee muistaa kääntää pois päältä aina, kun sitä ei tarvitse.</p>
<h2>4. Läpinäkyvyys</h2>
<p>Yksi kysymys, joka usein nousee esille on, kuinka jokin tietty tekstuurin väri saadaan läpinäkyväksi. Mitään väriä ei voida suoraan asettaa läpinäkyväksi, vaan värille täytyy määrittää tavallisten red, green ja blue komponenttien lisäksi vielä neljäs läpinäkyvyyskomponentti eli ns. alphakomponentti. Useimmat kuvankäsittelyohjelmat kuten Paint Shop Pro ja Photo Shop tukevat alphakanavaa. Kuvaformaateista esim. TGA ja PNG tukevat alphakanavaa.</p>
<p>Voit myös generoida alphakanavan ajon aikana. Kun lataat tekstuurin, testaa onko pikselin väri se, jonka haluat läpinäkyväksi. Jos on aseta sen alpha nollaksi, muuten ykköseksi (tai jos et käytä <em>GL_FLOAT</em>-tyyppiä, niin käyttämäsi tyypin maksimi arvoon).</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/alien.jpg" rel="lightbox[1173]"><img class="aligncenter size-full wp-image-1174" title="alien" src="http://www.suomipelit.com/tiedostot/2010/03/alien.jpg" alt="" width="483" height="128" /></a></p>
<p><a title="Kuvassa vasemmalla tekstuuri, joka sisältää kuvan avaruushirviöstä. Keskellä tämän tekstuurin alphakanava. Oikealla tekstuuri piirretty taustan päälle, niin että pikselit joiden alphan arvo on pienempi kuin 0.5 (musta) on jätetty piirtämättä." rel="lightbox[artikkelikuva_59]" href="http://www.suomipelit.com/kaikki/images/artikkelit/59/alien.jpg"></a>Kuvassa vasemmalla tekstuuri, joka sisältää kuvan avaruushirviöstä. Keskellä tämän tekstuurin alphakanava. Oikealla tekstuuri piirretty taustan päälle, niin että pikselit joiden alphan arvo on pienempi kuin 0.5 (musta) on jätetty piirtämättä.</p>
<p>On kaksi tapaa saada aikaan läpinäkyvyys alphan avulla. Ne ovat <em>GL_ALPHA_TEST </em>ja <em>GL_BLEND</em>. Ne voidaan laittaa päälle glEnable()-funktiolla antamalla kyseinen symboli parametrina.</p>
<p><em>GL_ALPHA_TEST:n </em>ideana on asettaa funktio, joka joko hyväksyy tai hylkää pikselin sen alphan arvon perusteella. Tämä funktio asetetaan glAlphaFunc()-funktiolla. Sen prototyyppi näyttää tältä:</p>
<pre>void glAlphaFunc(GLenum func, GLclampf ref);</pre>
<p>Ensimmäinen parametri kertoo funktion. Sen mahdolliset arvot ovat <em>GL_NEVER, GL_LESS, GL_EQUAL, GL_GREATER</em> ja <em>GL_ALWAYS</em>. Nimestä pystyy helposti näkemään mitä ne tekevät. Viimeinen kertoo tämän funktion käyttämän vertailuarvon. Esim. jos haluaisimme, että pikseli piirretään vain kun sen alphan arvo on yli 0.5 käyttäisimme kutsua <strong>glAlphaFunc</strong>(<em>GL_GREATER</em>, 0.5);.</p>
<p><em>GL_BLEND</em>:n idea on hieman erilainen. Siinä pikselin lopullinen väri lasketaan sen alkuperäisestä väristä ja ikkunassa pikselin paikalla olevan aikaisemman pikselin väristä. Lopullinen väri lasketaan kaavalla S*uusiPikseli+D*vanhaPikseli. Parametrit S ja D asetetaan funktiolla <strong>glBlendFunc()</strong>. Prototyyppi on seuraavan näköinen:</p>
<pre>glBlendFunc(GLenum sfactor, GLenum dfactor);</pre>
<p>sFactor asettaa S parametrin ja sFactor D parametrin. Kummatkin arvot on valittava seuraavista: <em>GL_ZERO, GL_ONE, GL_DST_COLOR, GL_SRC_COLOR, GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA ja GL_ONE_MINUS_DST_ALPHA</em>. Nimistä on helppo päätellä mitä ne ovat, kun panet merkille, että SCR tarkoittaa uutta pikseliä ja DST vanhaa pikseliä. Esim. jos haluaisimme tekstuurin alphakanavan määräävän pikselin läpinäkyvyyden käyttäisimme kutsua: <strong>glBlendFunc</strong>(<em>GL_SCR_ALPHA, GL_ONE_MINUS_SCR_ALPHA</em>). <em>GL_BLEND </em>siis mahdollistaa osittaisen läpinäkyvyyden toisin kuin <em>GL_ALPHA_TEST</em>.</p>
<p><em>GL_ALPHA_TEST</em>:llä ja <em>GL_BLEND</em>:llä on vielä yksi merkittävä ero. <em>GL_ALPHA_TEST </em>nimittäin jättää läpinäkyvät pikselit piirtämättä syvyyspuskuriin, kun taas GL_BLEND piirtää kaikki pikselit syvyyspuskuriin. Myös täysin läpinäkyvät. Olettaen tietenkin, että <em>GL_DEPTH_TEST </em>on päällä.</p>
<p>Kaksiulotteista teksturoitua suorakaiteen muotoista osittain läpinäkyvää polygonia kutsutaan joskus kuvahahmoksi (englanniksi sprite). Ne ovat varsin käytännöllisia 2D-grafiikassa. Kaksiulotteisten kuvien piirtoon löytyy OpenGL.stä ihan oma funktionsa: <strong>glBitmap()</strong>, mutta se on hitaampi ja vähemmän käytännöllinen kuin teksturoidun nelikulmion piirto, joten en suosittele sen käyttöä.</p>
<h2>5. Texture environment</h2>
<p>Polygoneillehan voitiin määrätä väri <strong>glColor3f()</strong>-funktiolla, mutta kuinka tämä väri sitten yhdistyy tekstuurin väriin? Tästä asiasta huolehtii ”texture environment”. Texture environment on itse asiassa funktio, joka saa syötteenään varsinaisen värin ja tekstuurin värin ja laskee näistä pikselin lopullisen värin. Tämä funktio pitää valita muutamasta valmiista vaihtoehdosta. Texture environment:in funktio valitaan funktiolla <strong>glTexEnvi()</strong>, jonka prototyyppi näyttää tältä:</p>
<pre>void glTexEnvi(GLenum target, GLenum pname, GLint param);</pre>
<p>Ensimmäisen parametrin arvon on aina oltava <em>GL_TEXTURE_ENV </em>ja toisen <em>GL_TEXTURE_ENV_MODE</em>. Kolmas on asetettava funktio. Sen mahdolliset arvot ovat: <em>GL_MODULATE</em>, <em>GL_DECAL </em>ja <em>GL_ADD</em>. <em>GL_MODULATE </em>kertoo värit keskenään ja <em>GL_ADD </em>taas laskee ne yhteen. <em>GL_DECAL </em>sen sijaan interpoloi näiden arvojen välillä käyttäen viitteenä tekstuurin alphakanavaa. Alphan arvolla yksi väri on tekstuurin väri ja arvolla nolla varsinainen väri. Muilla arvoilla jossakin tässä välissä. Jos tekstuurissa ei ole alphakanavaa, katsotaan alphan arvon olevan yksi.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/multitexture.jpg" rel="lightbox[1173]"><img class="aligncenter size-full wp-image-1179" title="multitexture" src="http://www.suomipelit.com/tiedostot/2010/03/multitexture.jpg" alt="" width="451" height="368" /></a></p>
<p><a rel="lightbox[artikkelikuva_59]" href="http://www.suomipelit.com/kaikki/images/artikkelit/59/multitexture.jpg"></a></p>
<h2>6. OpenGL:n laajennukset</h2>
<p>Ennen kuin voimme jatkaa, pitää meidän puhua jokunen sana OpenGL:n laajennuksista (englanniksi extensions).</p>
<p>Näytönohjaimet kehittyvät koko ajan ja niihin ilmestyy uusia ominaisuuksia. Tämän takia myös niitä käyttävien rajapintojen on kehityttävä mukana. Direct3D:n tapauksessa tämä on ratkaistu julkaisemalla siitä uusi versio vuoden parin välein. Tällä uudella versiolla ei ole välttämättä mitään yhteistä vanhan kanssa ja koko rajapinta on pahimmillaan opeteltava uudestaan. OpenGL:ssä sen sijaan rakennetaan vanhan päälle. Aina, kun jokin uusi ominaisuus ilmestyy näytönohjaimiin, julkaistaan siitä laajennus OpenGL:ään. Laajennus tuo mukanaan nipun uusia funktioita ja/tai uusia parametrejä vanhoihin funktioihin. Joskus ei kumpaakaan. Laajennuksista pitää kirjaa SGI:n laajennusrekisteri osoitteessa: <a href="http://oss.sgi.com/projects/ogl-sample/registry/">http://oss.sgi.com/projects/ogl-sample/r&#8230;</a> Lisäksi kaikkien näytönohjainvalmistajien kotisivuilta on löytyy sama rekisteri.</p>
<p>Voidaksesi käyttää laajennuksia tarvitset uuden otsikkotiedoston glext.h. Saat sen osoitteesta: <a href="http://oss.sgi.com/projects/ogl-sample/ABI/glext.h.">http://oss.sgi.com/projects/ogl-sample/A&#8230;</a> Se mitä laajennuksia käytössä on riippuu koneen näytönohjaimesta. Uudet näytönohjaimet tukevat lähes kaikkia laajennuksia, kun taas hyvin vanhat vain muutamaa. Saat selville tuetut laajennukset funktiolla glGetString(), jolle annetaan parametrinä <em>GL_EXTENSIONS</em>. Se palauttaa osoittimen merkkijonoon, joka sisältää kaikkien tuettujen laajennusten nimet välilyönnillä eroteltuna.</p>
<p>Laajennus ei siis tuo välttämättä mitään uusia funktioita tai parametrejä. Se vain sallii jotain sellaista, joka oli aikaisemmin kiellettyä. Hyvä esimerkki tästä on <em>ARB_texture_non_power_of_two</em>-laajennus, joka sallii käytettävän tekstuureja, joiden koko ei ole kakkosen potenssi. Eli jos <strong>glGetString</strong>(<em>GL_EXTENSIONS</em>) palauttamassa merkkijonossa esiintyy nimi <em>GL_ARB_texture_non_power_of_two </em>voit käyttää minkä kokoisia tekstuureja tahansa.</p>
<p>Jos taas laajennus tuo uusia parametrejä ei laajennuksen käyttö ole hankalaa silloinkaan. Kaikki uudet symbolit on nimittäin määritelty tiedostossa glext.h. Hyvä esimerkki tällaisesta laajennuksesta on <em>GL_ARB_texture_env_combine</em>-laajennos, joka tuo texture environment:iin rutkasti lisää vaihtoehtoja perinteisten <em>GL_MODULATE</em>:n ja<em> GL_ADD</em>:n lisäksi.</p>
<p>Vasta, kun laajennus tuo mukanaan uusia funktioita, on laajennuksen käyttö hieman hankalampaa. Funktioihin pitää nimittäin käydä noutamassa osoittimet. wglGetProcAddress() funktiolla. Sen prototyyppi näyttää tältä:</p>
<pre>PROC wglGetProcAddress(
    LPCSTR  lpszProc 	//Name of the extension function
   );</pre>
<p>Eli sille annetaan parametrinä uuden funktion nimi ja se palauttaa osoittimen siihen.</p>
<p>Laajennuksia on tällä hetkellä useampi sata, joten niiden hallinnointi käsin alkaa olla sulaa hulluutta. Tämän takia netti on pullollaan erilaisia kirjastoja laajennusten hallintaan. Niiden periaate on, että ne tarjoavat jonkin helppokäyttöisen funktion, joka lataa yhdellä kutsulla osoittimet kaikkiin näytönohjaimen tukemiin laajennuksiin. Yksi hyvä kirjasto tähän on GLEW: <a href="http://glew.sourceforge.net/">http://glew.sourceforge.net/</a> .</p>
<p><strong>Suosittelen lämpimästi, että heti, kun alat tarvita laajennuksia, lataa GLEW ja käytä sitä. ÄLÄ ala pelleilemään niiden kanssa ”käsin”. GLEW:n avulla sinun tarvitsee tehdä yksi ainut funktio kutsu ja kaikki laajennukset ovat suoraan käytössäsi.</strong></p>
<p>Huomaa vielä, että jokaisella laajennuksen nimellä on jokin etuliite. Esim. ARB, EXT, NV tai ATI. ARB ja EXT ovat laajennuksia, joita kaikkien näytönohjainvalmistajien kortit tukevat. Kun taas muut ovat valmistajakohtaisia laajennuksia. Vältä niiden käyttöä, sillä ne ovat tuettuja yleensä vain yhden valmistajan kortilla. Pyri käyttämään ensisijaisesti ARB-laajennuksia ja toissijaisesti EXT-laajennuksia.</p>
<h2>7. Eksoottisemmat tekstuurimuodot</h2>
<p>1D- ja 2D-tekstuurien lisäksi OpenGL:ssä kaksi muutakin tekstuurimuotoa: 3D-tekstuurit (<em>GL_TEXTURE_3D_EXT</em>) ja cubemap-tekstuurit (<em>GL_TEXTURE_CUBE_MAP_ARB</em>). Kummatkin nämä tekstuurimuodot ovat laajennuksia eli sinun pitää tarkistaa ennen niiden käyttöä, että käytössä oleva näytönohjain tukee niitä.</p>
<h3>7.1 3D-tekstuurit</h3>
<p>3D-tekstuurit ovat looginen jatko 1D- ja 2D-tekstuureille. 3D tekstuurit ovat laajennus OpenGL:ään ja tämän laajennuksen nimi on <em>GL_EXT_texture3D</em>. Eli niitä voidaan käyttää vain, jos <strong>glGetString</strong>(<em>GL_EXTENSIONS</em>)-kutsun palauttama merkkijono sisältää kyseisen nimen. Tämä laajennus tuo mukanaan yhden uuden funktion<em> glTexImage3DEXT()</em>, jonka prototyyppi näyttää tältä:</p>
<pre>void glTexImage3DEXT(GLenum target,
		       GLint level,
		       GLenum internalformat,
		       GLsizei width,
		       GLsizei height,
		       GLsizei depth,
		       GLint border,
		       GLenum format,
		       GLenum type,
		       const GLvoid* pixels);</pre>
<p>Meidän tarvitsee siis hakea osoitin tähän funktioon ennen sen käyttöä. Se tehdään seuraavasti:</p>
<pre>void (*glTexImage3DEXT)(GLenum, GLint, GLenum, GLsizei, GLsizei,
                        GLsizei, GLint, GLenum, GLenum, const GLvoid*) =
  wglGetProcAddress("glTexImage3DEXT ");</pre>
<p>Jätin tyyppimuunnoksen selkeyden vuoksi tekemättä. Tai helpommin:</p>
<pre>PFNGLTEXIMAGE3DEXTPROC glTexImage3DEXT=
  (PFNGLTEXIMAGE3DEXTPROC )wglGetProcAddress("glTexImage3DEXT ");</pre>
<p><em>PFNGLTEXIMAGE3DEXTPROC</em>-typedef on määritelty tiedostosssa glext.h. Kun osoitin on haettu voidaan funktiota käyttää normaalisti. glTexImage3DEXT()-funktio toimii aivan samoin kuin <strong>glTexImage1D()</strong> ja <strong>glTexImage2D()</strong>:kin. Siinä vain on tekstuurin leveyden ja korkeuden lisäksi mukana syvyys. Lisäksi tekstuurikoordinaatit pitää antaa <strong>glTexCoord3f()</strong>-funktiolla ja teksturointi laittaa päälle kutsulla <strong>glEnable</strong>(<em>GL_TEXTURE_3D_EXT</em>);</p>
<h3>7.2 Cube map-tekstuurit</h3>
<p>&#8220;Cube map&#8221;-tekstuuri on nimensä mukaisesti kuution muotoinen tekstuuri. Se muodostuu kuudesta eri 2D-tekstuurista, joista jokainen muodostaa kuution yhden sivun. Myös cube map on laajennus. Sen nimi on ARB_texture_cube_map. Cube map ei tuo uusia funktioita ainoastaan uusia parametrejä.</p>
<p>Data cube map:iin ladataan <strong>glTexImage2D()</strong>-funktiolla. Ainoa ero on, että ensimmäiseksi parametriksi tulee <em>GL_TEXTURE_2D</em>:n sijaan <em>TEXTURE_CUBE_MAP_POSITIVE_X_ARB, TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, TEXTURE_CUBE_MAP_POSITIVE_Z_ARB</em> tai <em>TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB</em>, riippuen siitä mikä kuution kuudesta eri sivusta halutaan asettaa. Vastaavasti cube map teksturointi laitetaan päälle glEnable()-functiolla, jolle annetaan parametrina <em>TEXTURE_CUBE_MAP_ARB</em>.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/cubemap.jpg" rel="lightbox[1173]"><img class="aligncenter size-full wp-image-1177" title="cubemap" src="http://www.suomipelit.com/tiedostot/2010/03/cubemap.jpg" alt="" width="400" height="300" /></a></p>
<p><a rel="lightbox[artikkelikuva_59]" href="http://www.suomipelit.com/kaikki/images/artikkelit/59/cubemap.jpg"></a></p>
<p>Tekstuurikoordinaatit toimivat cube map:issa hieman oudosti. Tekstuurikoordinaatti annetaan <strong>glTexCoord3f()</strong>-funktiolla, mutta koordinaattia vastaa kuutiolla piste, joka saadaan kuution keskipisteestä lähtevän <strong>glTexCoord3f()</strong>-funktiolla annetun vektorin suuntaisen suoran ja kuution leikkauspisteestä.</p>
<h2>8. Multiteksturointi</h2>
<p>Multiteksturointi tarkoittaa mahdollisuutta päällystää polygoni usealla tekstuurilla yhtä aikaa. Näytönohjaimissa on ns. teksturointiyksikköjä joista jokaiseen voi sitoa oman tekstuurin. Kun pikseli sitten piirretään vaikuttaa sen väriin jokainen teksturointiyksikkö.</p>
<p>Nykyisissä näytönohjaimissa voi olla jopa 8-16 teksturointiyksikköä, kun taas vanhoissa yleensä vain 2-4. Saat selville näytönohjaimen teksturointiyksiköiden määrän <strong>glGetIntegerv()</strong>-funktiolla, jolle annetaan parametrina <em>GL_MAX_TEXTURE_UNITS_ARB</em>. Kuten muutkin nykyiset hienoudet on myös multiteksturointi laajennus. Multiteksturointi tuo OpenGL:ään useitakin uusia funktioita kuten:</p>
<pre>void glMultiTexCoord1fARB(GLenum texture, GLfloat s);
void glMultiTexCoord2fARB(GLenum texture, GLfloat s, GLfloat t);
void glActiveTextureARB(GLenum texture);.</pre>
<p>Jokaiseen teksturointiyksikköön voi olla sidottuna kerrallaan yksi tekstuuri. glBindTexture() sitoo tekstuurin kulloinkin aktiivisena olevaan teksturointi yksikköön. Yksi teksturointiyksiköistä voi olla aktiivisena kerrallaan ja aktiivinen yksikkö valitaan <strong>glActiveTextureARB()</strong>-funktiolla joka saa syötteenään <em>GL_TEXTURE0_ARB, GL_TEXTURE1_ARB, GL_TEXTURE2_ARB</em> jne. eli aktivoitavan teksturointi yksikön. Huomaa myös, että kutsu <strong>glEnable</strong>(<em>GL_TEXTURE_2D</em>) laittaa teksturoinnin päälle siihen teksturointiyksikköön, joka on sillä hetkellä aktiivisena, eli funktiota on kutsuttava jokaiselle teksturointiyksikölle erikseen.</p>
<p>Tekstuurikoordinaatit vuorostaan annetaan <strong>glMultiTexCoord2fARB()</strong>-funktiolla. Sen ensimmäinen parametri kertoo teksturointiyksikön samoin kuin<strong> glActiveTextureARB()</strong>-funktiollakin ja loput tekstuurikoordinaatit. <strong>glTexCoord2f()</strong>-funktion kutsu vastaa <strong>glMultiTexCoord2fARB()</strong>-funktion kutsua, jonka ensimmäinen parametri on GL_TEXTURE0_ARB.</p>
<p>Vielä viimeinen ongelma on, mikä sitten määrää kuinka nämä tekstuurit yhdistyvät? Vastaus on tietenkin teksture environment. <strong>glTextureEnvi()</strong>-funktio asettaa texture environment funktion aktivoituna olevaan teksturointiyksikköön. Jokaisella teksturointiyksiköllä on siis oma texture environment funktio. Kun pikseli piirretään saa se aluksi <strong>glColor3f()</strong>-funktiolla annetun värin. Sen jälkeen pikselin väriin vaikuttaa vuoronperään jokainen teksturointiyksikkö, jolle teksturointi on laitettu päälle, omalla texture environment funktiollaan.</p>
<h2>9. Esimerkkiohjelma</h2>
<p>Vaikka tässä artikkelissa puhuimmekin OpenGL:än laajennuksista ja monista edistyneimmistä teksturointitekniikoista on esimerkkiohjelma varsin yksinkertainen.</p>
<p>Se lataa levyltä kaksi tekstuuria tiedostoista ”alien.kuva” ja ”tausta.kuva”. Ohjelma piirtää kaksi nelikulmaista polygonia, joista toisen se teksturoi alien-tekstuurilla ja toisen taustatekstuurillla.</p>
<p>Data näissä tiedostoissa on ns. raakamuodossa eli se voidaan antaa sellaisenaan glTexImage2D()-funktiolle. Raakadatakuvia voi tallentaa yleisimmillä kuvankäsittelyohjelmilla. Tällaisten raakatiedostojen käyttö ei kuitenkaan ole suositeltavaa sillä ne eivät sisällä esimerkiksi tietoa kuvan koosta, joten se on tiedettävä erikseen.</p>
<p>Yleensä kannattaakin käyttää jotain hyvää standardia tiedostomuotoa kuten JPG tai PNG. Näiden formaattien lataamisesta voisi kuitenkin kirjoittaa vaikka oman artikkelinsa, joten käytän tässä helpompaa raakadataformaattia. On olemassa valmiita kirjastoja, jotka osaavat lukea lukuisia kuvaformaatteja. Yksi hyvä tällainen on DEVIL. DEVIL kirjaston käytöstä on tässä artikkelissa liite seuraavalla sivulla.</p>
<p>Saadaksesi esimerkkiohjelman toimimaan sinun tarvitsee imuroida kuvatiedostot (<a href="http://www.suomipelit.com/tiedostot/2004/07/testi3.zip">testi3.zip</a>). Paketti sisältää myös oheisen lähdekoodin ja valmiiksi käännetyn version.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;height:600px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br />92<br />93<br />94<br />95<br />96<br />97<br />98<br />99<br />100<br />101<br />102<br />103<br />104<br />105<br />106<br />107<br />108<br />109<br />110<br />111<br />112<br />113<br />114<br />115<br />116<br />117<br />118<br />119<br />120<br />121<br />122<br />123<br />124<br />125<br />126<br />127<br />128<br />129<br />130<br />131<br />132<br />133<br />134<br />135<br />136<br />137<br />138<br />139<br />140<br />141<br />142<br />143<br />144<br />145<br />146<br />147<br />148<br />149<br />150<br />151<br />152<br />153<br />154<br />155<br />156<br />157<br />158<br />159<br />160<br />161<br />162<br />163<br />164<br />165<br />166<br />167<br />168<br />169<br />170<br />171<br />172<br />173<br />174<br />175<br />176<br />177<br />178<br />179<br />180<br />181<br />182<br />183<br />184<br />185<br />186<br />187<br />188<br />189<br />190<br />191<br />192<br />193<br />194<br />195<br />196<br />197<br />198<br />199<br />200<br />201<br />202<br />203<br />204<br />205<br />206<br />207<br />208<br />209<br />210<br />211<br />212<br />213<br />214<br />215<br />216<br />217<br />218<br />219<br />220<br />221<br />222<br />223<br />224<br />225<br />226<br />227<br />228<br />229<br />230<br />231<br />232<br />233<br />234<br />235<br />236<br />237<br />238<br />239<br />240<br />241<br />242<br />243<br />244<br />245<br />246<br />247<br />248<br />249<br />250<br />251<br />252<br />253<br />254<br />255<br />256<br />257<br />258<br />259<br />260<br />261<br />262<br />263<br />264<br />265<br />266<br />267<br />268<br />269<br />270<br />271<br />272<br />273<br />274<br />275<br />276<br />277<br />278<br />279<br />280<br />281<br />282<br />283<br />284<br />285<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#include &lt;windows.h&gt;</span><br />
<span style="color: #339933;">#include &lt;stdio.h&gt;</span><br />
<span style="color: #339933;">#include &lt;math.h&gt;</span><br />
<span style="color: #339933;">#include &lt;gl\gl.h&gt;</span><br />
<span style="color: #339933;">#include &lt;gl\glu.h&gt;</span><br />
<span style="color: #666666; font-style: italic;">//#include &lt;gl\glext&gt; &nbsp;// Ei tarvita tässä ohjelmassa</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Määrittele laitekonteksti globaaliksi sitä nimittäin tarvitaan myös pääfunktiossa.</span><br />
HDC hdc<span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Viestinkäsittelijä</span><br />
LRESULT CALLBACK WindowProc<span style="color: #009900;">&#40;</span>HWND hwnd<span style="color: #339933;">,</span> UINT uMsg<span style="color: #339933;">,</span> WPARAM wParam<span style="color: #339933;">,</span> LPARAM lParam<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #b1b100;">switch</span> <span style="color: #009900;">&#40;</span>uMsg<span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Koska piirrämme ikkunan sisällön pääsilmukassa jatkuvasti uudelleen</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// reakoimme WM_PAINT-viestiin vain tyhjentämällä ikkunan mustaksi.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_PAINT<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; PAINTSTRUCT p<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; BeginPaint<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glClear<span style="color: #009900;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; SwapBuffers<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; EndPaint<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Ikkuna yritetään sulkea kutsu PostQuitMessage()-funktiota.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_CLOSE<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; PostQuitMessage<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Käsittele myös WM_SIZE se lähetetään ikkunalle aina kun sen kokoa muutetaan.</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Tämä on oiva tilaisuus muuttaa viewport</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// oikean kokoiseksi peittämään koko ikkuna.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_SIZE<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Ikkunan uusi koko saadaan lParam parametrista LOWORD ja HIWORD makroilla.</span><br />
&nbsp; &nbsp; &nbsp; glViewport<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> LOWORD<span style="color: #009900;">&#40;</span>lParam<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> HIWORD<span style="color: #009900;">&#40;</span>lParam<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Viestiä ei käsitelty kutsu DefWindowProc()-funktiota.</span><br />
&nbsp; <span style="color: #b1b100;">return</span> DefWindowProc<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> uMsg<span style="color: #339933;">,</span> wParam<span style="color: #339933;">,</span> lParam<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #993333;">int</span> luoIkkuna<span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> leveys<span style="color: #339933;">,</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> korkeus<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>otsikko<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Rekisteröi ikkunaluokka</span><br />
&nbsp; WNDCLASS wc<span style="color: #339933;">;</span><br />
&nbsp; memset<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>wc<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>WNDCLASS<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">style</span> <span style="color: #339933;">=</span> CS_HREDRAW <span style="color: #339933;">|</span> CS_VREDRAW <span style="color: #339933;">|</span> CS_OWNDC<span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">hCursor</span><span style="color: #339933;">=</span> LoadCursor<span style="color: #009900;">&#40;</span>NULL<span style="color: #339933;">,</span> IDC_ARROW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">lpfnWndProc</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>WNDPROC<span style="color: #009900;">&#41;</span> WindowProc<span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">hInstance</span> <span style="color: #339933;">=</span> GetModuleHandle<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">lpszClassName</span> <span style="color: #339933;">=</span> <span style="color: #ff0000;">&quot;OpenGLtutoriaali&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>RegisterClass<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>wc<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo ikkuna</span><br />
&nbsp; RECT r<span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">left</span><span style="color: #339933;">=</span>GetSystemMetrics<span style="color: #009900;">&#40;</span>SM_CXSCREEN<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">-</span>leveys<span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">top</span><span style="color: #339933;">=</span>GetSystemMetrics<span style="color: #009900;">&#40;</span>SM_CYSCREEN<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">-</span>korkeus<span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">right</span><span style="color: #339933;">=</span>r.<span style="color: #202020;">left</span><span style="color: #339933;">+</span>leveys<span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">bottom</span><span style="color: #339933;">=</span>r.<span style="color: #202020;">top</span><span style="color: #339933;">+</span>korkeus<span style="color: #339933;">;</span><br />
&nbsp; AdjustWindowRectEx<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>r<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; WS_CLIPSIBLINGS <span style="color: #339933;">|</span> WS_CLIPCHILDREN <span style="color: #339933;">|</span> WS_OVERLAPPEDWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; FALSE<span style="color: #339933;">,</span> &nbsp;WS_EX_APPWINDOW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; HWND hwnd<span style="color: #339933;">;</span><br />
&nbsp; hwnd<span style="color: #339933;">=</span>CreateWindowEx<span style="color: #009900;">&#40;</span>WS_EX_APPWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #ff0000;">&quot;OpenGLtutoriaali&quot;</span><span style="color: #339933;">,</span> otsikko<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; WS_CLIPSIBLINGS <span style="color: #339933;">|</span> WS_CLIPCHILDREN <span style="color: #339933;">|</span> WS_OVERLAPPEDWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; r.<span style="color: #202020;">left</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">top</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">right</span><span style="color: #339933;">-</span>r.<span style="color: #202020;">left</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">bottom</span><span style="color: #339933;">-</span>r.<span style="color: #202020;">top</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; NULL<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> GetModuleHandle<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo laitekonteksti</span><br />
&nbsp; hdc<span style="color: #339933;">=</span>GetDC<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>hdc<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Valitse pikseliformaatti</span><br />
&nbsp; PIXELFORMATDESCRIPTOR pfd<span style="color: #339933;">;</span><br />
&nbsp; memset<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>pfd<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>PIXELFORMATDESCRIPTOR<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">nSize</span><span style="color: #339933;">=</span><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>PIXELFORMATDESCRIPTOR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">nVersion</span><span style="color: #339933;">=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">dwFlags</span><span style="color: #339933;">=</span>PFD_DRAW_TO_WINDOW<span style="color: #339933;">|</span>PFD_SUPPORT_OPENGL<span style="color: #339933;">|</span>PFD_DOUBLEBUFFER<span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">iPixelType</span><span style="color: #339933;">=</span>PFD_TYPE_RGBA<span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cRedBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cGreenBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cBlueBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cAlphaBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cStencilBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cDepthBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">16</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">iLayerType</span><span style="color: #339933;">=</span>PFD_MAIN_PLANE<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">int</span> pixelFormat<span style="color: #339933;">;</span><br />
&nbsp; pixelFormat<span style="color: #339933;">=</span>ChoosePixelFormat<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pfd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>pixelFormat<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>SetPixelFormat<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> pixelFormat<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pfd<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo renderöintikonteksti</span><br />
&nbsp; HGLRC hrc<span style="color: #339933;">;</span><br />
&nbsp; hrc<span style="color: #339933;">=</span>wglCreateContext<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>hrc<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>wglMakeCurrent<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> hrc<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp;<span style="color: #666666; font-style: italic;">// Tuo ikkuna näkyviin</span><br />
&nbsp; ShowWindow<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> SW_SHOW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; SetForegroundWindow<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; SetFocus<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Palauta onnistuminen</span><br />
&nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Pääfunktio</span><br />
<span style="color: #993333;">int</span> WINAPI WinMain<span style="color: #009900;">&#40;</span>HINSTANCE hInstance<span style="color: #339933;">,</span> HINSTANCE hPrevInstance<span style="color: #339933;">,</span><br />
LPSTR lpCmdLine<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> nCmdShow<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>data<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">float</span> angle<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; GLuint taustaTekstuuri<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; GLuint alienTekstuuri<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; FILE <span style="color: #339933;">*</span>tiedosto<span style="color: #339933;">=</span>NULL<span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> aika<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> piirtoaika<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> alkuaika<span style="color: #339933;">;</span><br />
<br />
&nbsp;<span style="color: #666666; font-style: italic;">// Luo ikkuna</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>luoIkkuna<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">800</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">600</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;OpenGL:n perusteet - Osa 3: Teksturointi&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Varaa muistia väliaikaiselle datalle</span><br />
&nbsp; data<span style="color: #339933;">=</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>malloc<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">256</span><span style="color: #339933;">*</span><span style="color: #0000dd;">256</span><span style="color: #339933;">*</span><span style="color: #0000dd;">4</span><span style="color: #339933;">*</span><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>data<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// luo yksi tekstuuriobjekti</span><br />
&nbsp; glGenTextures<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>taustaTekstuuri<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Sido äsken luotu tekstuuri teksturointiyksikköön</span><br />
&nbsp; glBindTexture<span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> taustaTekstuuri<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Lataa kuvadata tiedostosta.</span><br />
&nbsp; tiedosto<span style="color: #339933;">=</span>fopen<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;tausta.kuva&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;rb&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>tiedosto<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; fread<span style="color: #009900;">&#40;</span>data<span style="color: #339933;">,</span> <span style="color: #0000dd;">3</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">128</span><span style="color: #339933;">*</span><span style="color: #0000dd;">128</span><span style="color: #339933;">,</span> tiedosto<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; fclose<span style="color: #009900;">&#40;</span>tiedosto<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Lataa data tekstuuriin</span><br />
&nbsp; glTexImage2D<span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">3</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">128</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">128</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> GL_RGB<span style="color: #339933;">,</span> GL_UNSIGNED_BYTE<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Suodatus päälle</span><br />
&nbsp; glTexParameteri <span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> GL_TEXTURE_MAG_FILTER<span style="color: #339933;">,</span> GL_LINEAR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; glTexParameteri <span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> GL_TEXTURE_MIN_FILTER<span style="color: #339933;">,</span> GL_LINEAR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// luo yksi tekstuuriobjekti</span><br />
&nbsp; glGenTextures<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>alienTekstuuri<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Sido äsken luotu tekstuuri teksturointiyksikköön</span><br />
&nbsp; glBindTexture<span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> alienTekstuuri<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Lataa kuvadata tiedostosta</span><br />
&nbsp; tiedosto<span style="color: #339933;">=</span>fopen<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;alien.kuva&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;rb&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>tiedosto<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; fread<span style="color: #009900;">&#40;</span>data<span style="color: #339933;">,</span> <span style="color: #0000dd;">4</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">256</span><span style="color: #339933;">*</span><span style="color: #0000dd;">256</span><span style="color: #339933;">,</span> tiedosto<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; fclose<span style="color: #009900;">&#40;</span>tiedosto<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Lataa data tekstuuriin. Huomaa, että tässä on nyt alpha mukana!</span><br />
&nbsp; glTexImage2D<span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">4</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">256</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">256</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> GL_RGBA<span style="color: #339933;">,</span> GL_UNSIGNED_BYTE<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Suodatus päälle</span><br />
&nbsp; glTexParameteri <span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> GL_TEXTURE_MAG_FILTER<span style="color: #339933;">,</span> GL_LINEAR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; glTexParameteri <span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> GL_TEXTURE_MIN_FILTER<span style="color: #339933;">,</span> GL_LINEAR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Vapauta väliaikainen data</span><br />
&nbsp; free<span style="color: #009900;">&#40;</span>data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Teksturointi päälle</span><br />
&nbsp; glEnable<span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Viestinkäsittelysilmukka</span><br />
&nbsp; alkuaika<span style="color: #339933;">=</span>GetTickCount<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; MSG msg<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>PeekMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> PM_REMOVE<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>msg.<span style="color: #202020;">message</span><span style="color: #339933;">==</span>WM_QUIT<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; TranslateMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; DispatchMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Käytämme GetTickCount()-funktiota, joka palauttaa ajan millisekunneissa,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// laskemaan kuvan piirtämiseen kuluneen ajan.</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Näin voimme ajastaa alienin pyörimään samalla nopeudella kaikilla kokeilla.</span><br />
&nbsp; &nbsp; &nbsp; aika<span style="color: #339933;">=</span>GetTickCount<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; piirtoaika<span style="color: #339933;">=</span>aika<span style="color: #339933;">-</span>alkuaika<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>piirtoaika<span style="color: #339933;">&gt;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; alkuaika<span style="color: #339933;">=</span>aika<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Kasvata pyörityskulmaa hieman seuraavaa framea varten.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Alien pyörii nyt 0.06 astetta millisekunnissa</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// eli 1 kierroksen 6 sekunnissa</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; angle<span style="color: #339933;">+=</span><span style="color:#800080;">0.06</span><span style="color: #339933;">*</span>piirtoaika<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Tyhjennä puskuri</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;glClear<span style="color: #009900;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Piirretään ensin tausta</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Luo 2D koordinaatisto</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glMatrixMode<span style="color: #009900;">&#40;</span>GL_PROJECTION<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glLoadIdentity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; gluOrtho2D<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">800</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">600</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Aseta modelview-matriisi</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glMatrixMode<span style="color: #009900;">&#40;</span>GL_MODELVIEW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glLoadIdentity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Aseta tekstuurimatriisi niin, että taustaan saadaan hieman liikettä.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glMatrixMode<span style="color: #009900;">&#40;</span>GL_TEXTURE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glLoadIdentity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTranslatef<span style="color: #009900;">&#40;</span>sin<span style="color: #009900;">&#40;</span><span style="color:#800080;">0.01</span><span style="color: #339933;">*</span>angle<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> cos<span style="color: #009900;">&#40;</span><span style="color:#800080;">0.01</span><span style="color: #339933;">*</span>angle<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Ota alpha test pois päältä sitä ei tarvita taustassa</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glDisable<span style="color: #009900;">&#40;</span>GL_ALPHA_TEST<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Sido taustatekstuuri</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glBindTexture<span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> taustaTekstuuri<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Piirrä koko ikkunan peittävä nelikulmio</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glBegin<span style="color: #009900;">&#40;</span>GL_QUADS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTexCoord2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTexCoord2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">6</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">800</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTexCoord2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">6</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">4</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">800</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">600</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTexCoord2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">4</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">600</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// piirretään sitten alieni</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Aseta 3D-koordinaatisto</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glMatrixMode<span style="color: #009900;">&#40;</span>GL_PROJECTION<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glLoadIdentity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; gluPerspective<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">60</span><span style="color: #339933;">,</span> <span style="color:#800080;">800.0</span><span style="color: #339933;">/</span><span style="color:#800080;">600.0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Aseta modelview-matriisi</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glMatrixMode<span style="color: #009900;">&#40;</span>GL_MODELVIEW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glLoadIdentity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTranslatef<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Siirrä alienia hieman kauemmaksi kamerasta</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glRotatef<span style="color: #009900;">&#40;</span>angle<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp;<span style="color: #666666; font-style: italic;">// Pyöritä alienia y-akselin ympäri</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Aseta tekstuurimatriisi</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glMatrixMode<span style="color: #009900;">&#40;</span>GL_TEXTURE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glLoadIdentity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// laita alpha test päälle</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glEnable<span style="color: #009900;">&#40;</span>GL_ALPHA_TEST<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// aseta alpha test niin että vain pikselit,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// joiden alpha arvo on yli 0.5 piirretään</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glAlphaFunc<span style="color: #009900;">&#40;</span>GL_GREATER<span style="color: #339933;">,</span> <span style="color:#800080;">0.5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Sido alien tekstuuri</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glBindTexture<span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> alienTekstuuri<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Piirrä alien</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glBegin<span style="color: #009900;">&#40;</span>GL_QUADS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTexCoord2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTexCoord2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTexCoord2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTexCoord2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Vaihda puskuri näytölle.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; SwapBuffers<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<h2>10. Loppusanat</h2>
<p>Tässä artikkelissa opit teksturoimaan. Seuraavassa ja viimeisessä osassa puhumme valoista ja varjoista. Raportoithan kaikki tästä artikkelista löytämäsi virheet (niin kirjoitus-, kuin asiavirheetkin) osoitteeseen markus.ilmola@pp.inet.fi , niin korjaan ne mahdollisimman nopeasti. Myös kaikki kommentit ja kysymykset ovat tervetulleita.</p>
<h2>Liite 1: DEVIL – kuvatiedostojen pikkupaholainen</h2>
<p>Esimerkkiohjelmassa käyttämäni kuvat olivat ns. raakadatakuvia, koska data on niissä sellaisessa muodossa, että se kelpaa suoraan OpenGL:lle, eikä niiden lataus siis vaadi mitään ylimääräisiä toimenpiteitä. Raakadatakuvien käyttö ei kuitenkaan ole suositeltavaa, koska ne eivät sisällä mitään tietoa kuvan tyypistä, koosta jne. Lisäksi raakadatakuvien tallentaminen kuvankäsittelyohjelmilla on ongelmallista. Onkin suositeltavaa käyttää jotain oikeaa kuvaformaattia kuten jpg tai png.</p>
<p>Oikeissa kuvaformaateissa on kuitenkin se vika, että niissä oleva data EI kelpaa sellaisenaan OpenGL:lle. Kuvadata voi olla esim. pakattu tilan säästämiseksi, sen seassa voi olla jotain ylimääräistä metatietoa tai se on vain yksinkertaisesti ”väärässä” järjestyksessä. Jotta kuva voidaan ladata, pitäisi olla tarkka tieto sen rakenteesta. Ensin mahdollinen pakkaus pitäisi purkaa, ylimääräiset tiedot poistaa ja järjestää data sopivaan järjestykseen. Vasta tämän jälkeen datan voi antaa OpenGL:lle.</p>
<p>Kuvatiedostojen speksit ovat yleensä julkisia ja ne löytyvät netistä, mutta koska kuvaformaatteja on tuhottoman paljon, ja eri formaatit sopivat eri tilanteisiin, olisi liian iso urakka kirjoittaa latausfunktiota niille kaikille. On kuitenkin olemassa ilmaisia apukirjastoja, jotka osaavat ladata valtavan määrän erilaisia kuvaformaatteja. Yksi niistä on nimeltään DEVIL. Se on siinä mielessä hyvä aisapari OpenGL:lle, että sen käyttöliittymä on apinoitu suoraan OpenGL:stä.</p>
<p>DEVIL-kirjaston voi ladata osoitteesta: <a href="http://openil.sourceforge.net/">http://openil.sourceforge.net/.</a> Imuroi uusin versio ja kopioi ”.lib”-tiedostot kääntäjäsi ”lib”-hakemistoon ja ”.h”-tiedostot kääntäjäsi ”include/il”-hakemistoon. ”.dll”-tiedostot tulevat samaan hakemistoon projektisi kanssa. Paketti sisältää itseasiassa 3 eri dll-tiedostoa, mutta tavallisesti tarvitset vain tiedoston ”devil.dll”. Jotta voisit käyttää DEVIL:iä, sinun pitää sisällyttää projektiisi otsikkotiedosto il.h. Tämä tehdään seuraavasti:</p>
<pre>#include &lt;il\il.h&gt;</pre>
<p>Lisäksi ohjelma pitää linkittää tiedoston devil.lib kanssa.</p>
<p>Ensimmäinen toimenpide DEVIL:iä käytettäessä on alustus. Tämä tehdään yhdellä funktiokutsulla.</p>
<pre>ilInit();</pre>
<p>Siinä kaikki. Alustus pitää tehdä ennen kuin yhtään DEVIL:in funktiota saa kutsua.</p>
<p>Nyt pääsemmekin itse asiaan. Kuten tulet huomaamaan DEVIL:in käyttö on lähes identtistä OpenGL:n tekstuurin latauksen kanssa.</p>
<p>Ensiksi pitää luoda kuvaobjekti. Se tehdään funktiolla:</p>
<pre>ILvoid ilGenImages( ILsizei Num,  ILuint *Images );</pre>
<p>”Num” kertoo kuinka monta kuvaa luodaan ja ”Images” on osoitin taulukoon, jonne kuvien tunnukset tallennetaan. Kun kuva on luotu, se pitää sitoa nykyiseksi kuvaksi. Kaikki kuvaan vaikuttavat funktiot operoivat sille kuvalle, joka on sillä hetkellä sidottuna nykyisenä kuvana. Kuvan sitominen tehdään funktiolla:</p>
<pre>ILvoid ilBindImage(ILuint Image);</pre>
<p>”Image” on siis sidottavan kuvan tunnus. Nykyiseen kuvaan voidaan ladata dataa kuvatiedostosta funktiolla:</p>
<pre>ILboolean ilLoadImage(char *FileName);</pre>
<p>Vain yksi parametri, eli ladattavan tiedoston nimi. DEVIL tunnistaa tiedoston tyypin automaattisesti ja osaa ladata seuraavan tyyppisiä kuvia: bmp, cut, dcx, dds, ico, gif, jpg, lbm. Lif, mdl, pcd, pcx, pic, png, pnm, psd, psp, raw, sgi, tga, tif, wal, act, pal ja hdr.<br />
Funktio palauttaa nollan, jos lataus epäonnistui, ja eri suuren kuin nolla, jos onnistui.</p>
<p>Kuvan latauksen jälkeen kuva on muistissa ja enää tarvitsee saada data ulos siitä OpenGL:n ymmärtämässä muodossa. Sitä ennen tarvitsee kuitenkin udella kuvan tiedot kuten koko jne. Tämä tehdään funktiolla:</p>
<pre>ILint ilGetInteger( ILenum Mode );</pre>
<p>”Mode” kertoo mikä tieto halutaan ja funktio palauttaa kyseisen tiedon. ”Mode”:lle on iso kasa mahdollisia arvoja, mutta tässä tärkeimmät.</p>
<p>IL_IMAGE_WIDTH – kuvan leveys pikseleinä.</p>
<p>IL_IMAGE_HEIGHT – kuvan korkeus pikseleinä.</p>
<p>IL_IMAGE_FORMAT – Kertoo missä muodossa kuvan data ladatussa tiedostossa oli. Mahdolliset arvot ovat: IL_COLOUR_INDEX, IL_RGB, IL_RGBA, IL_BGR, IL_BGRA ja IL_LUMINANCE. Tätä tarvitaan tutkimaan oliko ladatussa kuvassa alphakanava. Jos formaatti on IL_RGBA tai IL_BGRA kuvassa oli alphakanava, muuten ei.</p>
<p>Varsinainen data saadaan ulos funktiolla:</p>
<pre>ILvoid ilCopyPixels(
  ILuint XOff,
  ILuint YOff,
  ILuint ZOff,
  ILuint Width,
  ILuint Height,
  ILuint Depth,
  ILenum Format,
  ILenum Type,
  ILvoid *Data
);</pre>
<p>”Off” parametrit kertovat mistä kohdasta lähtien data kopioidaan. Koska yleensä halutaan koko kuva, ovat nämä nollia.</p>
<p>Width, Height ja Depth kertovat kopioitavan palan koon, jotka jälleen kopioitaessa koko kuva, ovat itse kuvan koko (joka saatiin ilGetInteger funktiolla). Depth parametrin pitää olla 1.</p>
<p>”Format” kertoo formaatin, jossa data halutaan ulos. Ei ole mitään merkitystä missä muodossa data ladatussa kuvassa oli, sillä sen saa ulos missä formaatissa haluaa. Jotta data kelpaa OpenGL:lle on sen oltava formaatissa IL_RGB tai IL_RGBA, jos alpha kanavakin halutaan mukaan.</p>
<p>”Data” on osoitin taulukkoon, johon kuvan data kopioidaan. ”Type” on tämän taulukon alkion tyyppi esim.: IL_UNSIGNED_BYTE tai IL_FLOAT .</p>
<p>Lopuksi, kun data on kopioitu talteen, pitää kuva tuhota pois turhia resursseja tuhlaamasta. Tämä tehdään funktiolla:</p>
<pre>ILvoid ilDeleteImages( ILsizei Num, const ILuint *Images);</pre>
<p>Seuraavassa esimerkissä teemme funktion, joka lataa kuvan ja tekee siitä tekstuurin. DEVIL pitää toki alustaa kutsulla ”ilInit()” ennen kuin tätä funktiota saa kutsua.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;height:600px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">GLuint lataaTekstuuri<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>fileName<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>data<span style="color: #339933;">=</span>NULL<span style="color: #339933;">;</span><br />
&nbsp; GLuint tekstuuri<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; ILuint kuva<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> korkeus<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> leveys<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> komponentteja<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; ILuint ilFormat<span style="color: #339933;">;</span><br />
&nbsp; GLuint glFormat<span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Lataa kuva</span><br />
&nbsp; ilGenImages<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>kuva<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; ilBindImage<span style="color: #009900;">&#40;</span>kuva<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>ilLoadImage<span style="color: #009900;">&#40;</span>fileName<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Kysy kuvan tiedot</span><br />
&nbsp; leveys<span style="color: #339933;">=</span>ilGetInteger<span style="color: #009900;">&#40;</span>IL_IMAGE_WIDTH<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; korkeus<span style="color: #339933;">=</span>ilGetInteger<span style="color: #009900;">&#40;</span>IL_IMAGE_HEIGHT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Onko alpha mukana?</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>ilGetInteger<span style="color: #009900;">&#40;</span>IL_IMAGE_FORMAT<span style="color: #009900;">&#41;</span><span style="color: #339933;">==</span>IL_RGBA <span style="color: #339933;">||</span><br />
&nbsp; &nbsp; &nbsp; ilGetInteger<span style="color: #009900;">&#40;</span>IL_IMAGE_FORMAT<span style="color: #009900;">&#41;</span><span style="color: #339933;">==</span>IL_BGRA<span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; komponentteja<span style="color: #339933;">=</span><span style="color: #0000dd;">4</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; ilFormat<span style="color: #339933;">=</span>IL_RGBA<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; glFormat<span style="color: #339933;">=</span>GL_RGBA<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; komponentteja<span style="color: #339933;">=</span><span style="color: #0000dd;">3</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; ilFormat<span style="color: #339933;">=</span>IL_RGB<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; glFormat<span style="color: #339933;">=</span>GL_RGB<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Varaa muistia väliaikaiselle datalle</span><br />
&nbsp; data<span style="color: #339933;">=</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>malloc<span style="color: #009900;">&#40;</span>leveys<span style="color: #339933;">*</span>korkeus<span style="color: #339933;">*</span>komponentteja<span style="color: #339933;">*</span><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>data<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Kopio data</span><br />
&nbsp; ilCopyPixels<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> leveys<span style="color: #339933;">,</span>korkeus<span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> ilFormat<span style="color: #339933;">,</span> IL_UNSIGNED_BYTE<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Tuhoa kuva</span><br />
&nbsp; ilDeleteImages<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>kuva<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// luo yksi tekstuuriobjekti</span><br />
&nbsp; glGenTextures<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>tekstuuri<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Sido äsken luotu tekstuuri teksturointiyksikköön</span><br />
&nbsp; glBindTexture<span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> tekstuuri<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Lataa data tekstuuriin</span><br />
&nbsp; glTexImage2D<span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> komponentteja<span style="color: #339933;">,</span> leveys<span style="color: #339933;">,</span> korkeus<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;glFormat<span style="color: #339933;">,</span> GL_UNSIGNED_BYTE<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Suodatus päälle</span><br />
&nbsp; glTexParameteri <span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> GL_TEXTURE_MAG_FILTER<span style="color: #339933;">,</span> GL_LINEAR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; glTexParameteri <span style="color: #009900;">&#40;</span>GL_TEXTURE_2D<span style="color: #339933;">,</span> GL_TEXTURE_MIN_FILTER<span style="color: #339933;">,</span> GL_LINEAR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Vapauta väliaikainen data</span><br />
&nbsp; free<span style="color: #009900;">&#40;</span>data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Palauta luotu tekstuuri</span><br />
&nbsp; <span style="color: #b1b100;">return</span> tekstuuri<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<hr /><em>Artikkelin kirjoitti alun perin markus.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.suomipelit.com/2004/07/07/opengln-perusteet-osa-3-teksturointi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenGL:n perusteet &#8211; Osa 2: 3D-grafiikka</title>
		<link>http://www.suomipelit.com/2004/06/09/opengln-perusteet-osa-2-3d-grafiikka/</link>
		<comments>http://www.suomipelit.com/2004/06/09/opengln-perusteet-osa-2-3d-grafiikka/#comments</comments>
		<pubDate>Wed, 09 Jun 2004 10:00:52 +0000</pubDate>
		<dc:creator>Suomipelit.com</dc:creator>
				<category><![CDATA[Artikkelit]]></category>
		<category><![CDATA[Käytännön oppaat]]></category>
		<category><![CDATA[2d]]></category>
		<category><![CDATA[3d]]></category>
		<category><![CDATA[c/cpp]]></category>
		<category><![CDATA[grafiikka]]></category>
		<category><![CDATA[opengl]]></category>
		<category><![CDATA[perusteet]]></category>

		<guid isPermaLink="false">http://www.suomipelit.com/?p=1161</guid>
		<description><![CDATA[OpenGL on laajassa käytössä oleva käyttöjärjestelmäriippumaton rajapinta 2D- ja 3D-grafiikan piirtoon. Tämä artikkelisarja opettaa sinulle 3D-grafiikan perusteet OpenGL:ää käyttäen. Esimerkeissä käytetään C\C++ kieltä. Tämä on artikkelisarjan toinen osa.]]></description>
			<content:encoded><![CDATA[<h1><span style="font-weight: normal; font-size: 13px;">OpenGL on laajassa käytössä oleva käyttöjärjestelmäriippumaton rajapinta 2D- ja 3D-grafiikan piirtoon. Tämä artikkelisarja opettaa sinulle 3D-grafiikan perusteet OpenGL:ää käyttäen. Esimerkeissä käytetään C\C++ kieltä. Tämä on artikkelisarjan toinen osa.</span></h1>
<h2>1. 3-ulotteisen kappaleen esittäminen tietokoneella</h2>
<p>Tapoja kuvata 3-ulotteinen kappale tietokoneella on monta, mutta se tapa, jota lähes kaikki pelit käyttävät, on aproksimoida eli arvioida kappaletta monitahokkaalla (englanniksi polyhedron). Monitahokas on 3-ulotteinen kappale, jota rajoittaa monikulmioista eli polygoneista koostuva suljettu pinta. Nämä polygonit ovat monitahokkaan tahoja. Tahkojen leikkausviivoja kutsutaan särmiksi ja särmien leikkauspisteitä kärjiksi eli vertekseiksi. Alla oleva kuva esittää monitahokasta, jossa verteksit on merkitty sinisellä, särmät punaisella ja polygonit harmaalla.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/monitahokas.jpg" rel="lightbox[1161]"><img class="aligncenter size-full wp-image-1166" title="monitahokas" src="http://www.suomipelit.com/tiedostot/2010/03/monitahokas.jpg" alt="" width="237" height="202" /></a><br />
<a rel="lightbox[artikkelikuva_58]" href="http://www.suomipelit.com/kaikki/images/artikkelit/58/monitahokas.jpg"></a><br />
Monitahokkaat voidaan jakaa kahteen ryhmään: kuperiin ja koveriin. Monitahokas on kupera, jos mitkä tahansa kaksi sen vertekseistä voidaan yhdistää viivalla niin, että tämä viiva ei käy monitahokkaan ulkopuolella. Muussa tapauksessa monitahokas on kovera.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/kuko.jpg" rel="lightbox[1161]"><img class="aligncenter size-full wp-image-1165" title="kuko" src="http://www.suomipelit.com/tiedostot/2010/03/kuko.jpg" alt="" width="500" height="240" /></a><br />
<a rel="lightbox[artikkelikuva_58]" href="http://www.suomipelit.com/kaikki/images/artikkelit/58/kuko.jpg"></a><br />
Monitahokkaan särmät ja verteksit muodostavat verkon, josta käytetään yleensä englanninkielistä termiä mesh. Jos monitahokkaasta piirretään pelkät särmät kutsutaan kuvaa rautalankamalliksi (englanniksi wire-frame).</p>
<p>Kun monitahokkaalla halutaan aproksimoida jotain kappaletta rakennetaan monitahokas, jonka pinta mukailee mahdollisimman tarkasti alkuperäisen kappaleen pintaa. Mitä enemmän polygoneja monitahokkaassa on, sitä tarkemmin se jäljittelee alkuperäistä kappaletta. Se ei voi kuitenkaan koskaan mallintaa kappaletta täydellisen tarkasti (ellei sitten alkuperäinen kappale ollut monitahokas itsekkin). Kuitenkin hyvin suurilla polygonimäärillä ihmissilmä ei enää huomaa eroa.</p>
<p style="text-align: center;"><a href="http://www.suomipelit.com/tiedostot/2010/03/apro.jpg" rel="lightbox[1161]"><img class="aligncenter size-full wp-image-1162" title="apro" src="http://www.suomipelit.com/tiedostot/2010/03/apro.jpg" alt="" width="461" height="230" /></a><br />
<a rel="lightbox[artikkelikuva_58]" href="http://www.suomipelit.com/kaikki/images/artikkelit/58/apro.jpg"></a><br />
Monitahokkaan tallentaminen tietokoneen muistiin on helppoa. Meidän pitää vain tallentaa jokaisen verteksin koordinaatit, sekä tieto siitä mitkä verteksit aina muodostavat tahon. Tämä voidaan toteuttaa vaikka indeksoimalla verteksejä. Vaikka monitahokkaan tahot voivat olla mitä tahansa monikulmioita, voidaan mikä tahansa monikulmio muodostaa kolmioista. Tämän takia riittää, että voimme tallentaa ainoastaan kolmioita.</p>
<p>Esim. Kuutio, jonka keskipiste sijaitsee origossa ja ”säde” on yksi, voitaisiin tallentaa seuraavasti:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">float</span> vertex<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">8</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
<span style="color: #993333;">int</span> index<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">6</span><span style="color: #339933;">*</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span><span style="color: #0000dd;">7</span><span style="color: #339933;">,</span><span style="color: #0000dd;">6</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #0000dd;">5</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">7</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">6</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #0000dd;">7</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">6</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">5</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Eli tallennetaan kuution jokaisen 8 verteksin sijainti, sekä indeksit, jotka ilmoittavat mitkä 4 verteksiä aina muodostavat tahon.</p>
<h2>2. 3D-koordinaatisto</h2>
<p>Tämän artikkelisarjan ensimmäisessä osassa loimme 2D-koordinaatiston gluOrtho2D()-funktiolla. 3D-grafiikan tapauksessa tarvitsemme 3D-koordinaatiston. Tälläinen koordinaatisto luodaan OpenGL:ssä funktiolla gluPerspeksive(), jonka prototyyppi näyttää tältä:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">void</span> gluPerspective<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; GLdouble fovy<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; GLdouble aspect<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; GLdouble zNear<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; GLdouble zFar<br />
&nbsp; &nbsp;<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Koordinaatisto on helpoin käsittää jos ajattelet, että jossain päin kyberavaruutta kelluu kamera. Origo sijaitsee tämän kameran linssin keskellä. X-akseli kulkee vaakatasossa ja sen arvot kasvavat oikealle mentäessä. Y-akseli kulkee pystysuuntaan ja sen arvot kasvavat ylöspäin mentäessä. &lt;b&gt;Kamera katsoo kohti negatiivista Z-akselia.&lt;/b&gt; Kameralle on myös määritelty näkökentän leveys (englanniksi field of view eli FOV), joka määrää kuinka monen asteen levyisen kaistaleen kamera näkee. Näin ollen kameran kerralla näkemä alue muodostaa kartion. Koska kappaleita, jotka ovat hyvin kaukana kamerasta tai hyvin lähellä sitä, ei ole järkevää piirtää, rajoitetaan kameran katselukartiota vielä kahdella tasolla ns. lähi- ja kaukoleikkaustasolla. Kaikki kaukotason takana olevat kappaleet jätetään piirtämättä samoin kaikki lähitason edessä olevat. Näin ollen näkyväksi alueeksi jää enää katkaistu kartio eli frustum.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/koordinaatisto.jpg" rel="lightbox[1161]"><img class="aligncenter size-full wp-image-1164" title="koordinaatisto" src="http://www.suomipelit.com/tiedostot/2010/03/koordinaatisto.jpg" alt="" width="419" height="215" /></a></p>
<p><a rel="lightbox[artikkelikuva_58]" href="http://www.suomipelit.com/kaikki/images/artikkelit/58/koordinaatisto.jpg"></a><br />
gluPerspective()-funktion fovy-parametri kertoo kameran näkökentän leveyden. Tämän arvon on oltava suurempi kuin 0 ja pienempi kuin 180. Suurilla arvoilla saadaan laajakulmanäkymä ja pienillä arvoilla putkinäkömäinen efekti. Vaikka ihmissilmän näkökentän leveys on lähes 180 astetta astetta (tarkan näön alue noin 30 astetta) peittää monitori vain pienen osan näkökentästä, joten realistinen arvo on noin 45-60 astetta. Near ja far-parametrit kertovat lähi- ja kaukotason etäisyydet kamerasta. Huomaa, että lähitäson etäisyys pitää olla suurempi kuin 0 ja kaukotason on aina oltava kauempana kuin lähitason. Lähitaso kannattaa pitää mahdollisimman kaukana kamerasta ja kaukotaso mahdollisimman lähellä kameraa, jotta näkyvä alue pysyy optimaalisen pienenä. Aspect-parametri kertoo kuvasuhteen. Sen on oltava viewportin_leveys/viewportin_korkeus tai muuten kuva vääristyy.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/fov.jpg" rel="lightbox[1161]"><img class="aligncenter size-full wp-image-1163" title="fov" src="http://www.suomipelit.com/tiedostot/2010/03/fov.jpg" alt="" width="402" height="199" /></a><br />
<a rel="lightbox[artikkelikuva_58]" href="http://www.suomipelit.com/kaikki/images/artikkelit/58/fov.jpg"></a><br />
gluOrtho2D() ja gluPerspektive()-funktioista on olemassa hieman monipuolisemmat versiot glOrtho() ja glFrustum(), mutta en käsittele niitä tässä artikkelissa.</p>
<h2>3. Renderöinti</h2>
<p>OpenGL:ssä monitahokas piirretään yksinkertaisesti polygoni kerrallaan. Piirtäminen aloitetaan glBegin()-funktiolla, jolle annetaan parametriksi GL_TRIANGLES, jos halutaan piirtää kolmioita tai GL_QUADS, jos halutaan piirtää nelikulmioita. Tämän jälkeen annetaan verteksien sijainnit glVertex3f()-funktiolla. Jos glBegin()-funktion parametri oli GL_TRIANGLES, piirretään jokaisen kolmen annetun verteksin välille aina kolmio. Tai jos se oli GL_QUADS piirretään jokaisen neljän verteksin välille aina nelikulmio. Lopuksi kutsutaan glEnd()-funktioita. Jokaiselle verteksille voidaan myös määrätä väri kutsumalla glColor3f()-funktiota ennen jokaista glVertex3f()-funktion kutsua. Esim. kappaleessa 1 määritelty kuutio voitaisiin piirtää esimerkiksi seuraavalla tavalla:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glBegin<span style="color: #009900;">&#40;</span>GL_QUADS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #993333;">int</span> i<span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span><span style="color: #0000dd;">6</span><span style="color: #339933;">*</span><span style="color: #0000dd;">4</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; glVertex3f<span style="color: #009900;">&#40;</span>vertex<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> vertex<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> vertex<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Eli kutsutaan glVertex3f()-funktiota neljä kertaa jokaista kuution kuutta tahoa kohti.</p>
<p>Kun polygonien määrä kasvaa suureksi käy glBegin()-,lEnd()-parin käyttäminen tehottomaksi, sillä jokaista kolmiota kohden tarvitaan aina kolme glVertex3f()-funktion kutsua. Esim. jos meillä olisi 10000 kolmekulmaista polygonia tarvittaisiin 30000 glVertex3f()-funktion kutsua. Ei hyvä! Tämän takia OpenGL:ssä on kolme muutakin tapaa piirtää polygoneja. Ne ovat ”display list”, ”vertex array” ja ”vertex buffer object”.</p>
<h3>3.1 Display listit</h3>
<p>Display list:in ideana on ”nauhoittaa” funktion kutsuja, jonka jälkeen kaikki nauhoitetut kutsut voidaan ”toistaa” yhdellä funktion kutsulla. Ensin display list pitää luoda glGenLists()-funktiolla. Funktio palauttaa luodun display list:n tunnuksen. Nauhoitus aloitetaan glNewList()-funktiolla, jolle annetaan parametrina glGenLists()-funktiolta saatu tunnus ja symboli GL_COMPILE. Tämän jälkeen voidaan kutsua vapaasti lähes mitä tahansa OpenGL:n funktioita ja ne nauhoittuvat. Kun display list on valmis kutsutaan glEndList()-funktioita. Myöhemmin nauhoitus voidaan toistaa kuinka monta kertaa tahansa glCallList()-funktiolla, jolle annetaan parametrina display list:in tunnus. Huomaa, että display list:in sisältöä ei voi muuttaa. Display list voidaan tuhota glDeleteList()-funktiolla. Esim. äsken piirretty kuutio voitaisiin nauhoittaa display list:iin seuraavasti:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> tunnus<span style="color: #339933;">;</span><br />
tunnus<span style="color: #339933;">=</span>glGenLists<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glNewList<span style="color: #009900;">&#40;</span>tunnus<span style="color: #339933;">,</span> GL_COMPILE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glBegin<span style="color: #009900;">&#40;</span>GL_QUADS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #993333;">int</span> i<span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span><span style="color: #0000dd;">6</span><span style="color: #339933;">*</span><span style="color: #0000dd;">4</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; glVertex3f<span style="color: #009900;">&#40;</span>vertex<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> vertex<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> vertex<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glEndList<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Vastaavasti se voitaisiin tämän jälkeen piirtää koska tahansa kutsulla glCallList(tunnus);.</p>
<h3>3.2 Vertex array</h3>
<p>Vertex array:n ideana on antaa OpenGL:lle osoitin verteksidataan, jonka jälkeen kaikki polygonit voidaan piirtää yhdellä funktion kutsulla. Ennen kuin vertex array:ta voidaan käyttää pitää se laittaa päälle glEnableClientState()-funktiolla, jolle annetaan parametrina GL_VERTEX_ARRAY. Tämän jälkeen annetaan osoitin verteksidataan glVertexPointer()-funktiolla, jonka prototyyppi näyttää tältä:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">void</span> glVertexPointer<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; GLint size<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; GLenum type<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; GLsizei stride<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #993333;">const</span> GLvoid <span style="color: #339933;">*</span>pointer<br />
&nbsp; &nbsp;<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Ensimmäinen parametri kertoo komponenttien määrän per verteksi (yleensä 3). Seuraava datan tyypin (yleensä GL_FLOAT). Kolmas verteksien etäisyyden toisistaan muistissa (yleensä sizeof(verteksi)). Ja viimeinen on osoitin verteksidataan. Kun osoitin on annettu voidaan varsinainen renderöinti tehdä yhdellä glDrawElements()-funktion kutsulla. Sen prototyyppi näyttää tältä:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">void</span> glDrawElements<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; GLenum mode<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; GLsizei count<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; GLenum type<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #993333;">const</span> GLvoid <span style="color: #339933;">*</span>indices<br />
&nbsp; &nbsp;<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Ensimmäisellä parametrilla on sama merkitys kuin glBegin()-funktionkin parametrilla. Viimeinen on osoitin taulukkoon, joka indeksoi glVertexPointer()-funktiolla annettuja verteksejä. Toinen parametri kertoo alkioiden määrän tässä taulukossa. Toiseksi viimeinen kertoo tämän taulukon alkioden tyypin (yleensä GL_UNSIGNED_INT). Seuraava esimerkki piirtää kappaleessa yksi määritellyn kuution käyttäen vertex array:ta.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glEnableClientState<span style="color: #009900;">&#40;</span>GL_VERTEX_ARRAY<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glVertexPointer<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span> GL_FLOAT<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">float</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> vertex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glDrawElements<span style="color: #009900;">&#40;</span>GL_QUADS<span style="color: #339933;">,</span> <span style="color: #0000dd;">6</span><span style="color: #339933;">*</span><span style="color: #0000dd;">4</span><span style="color: #339933;">,</span> GL_UNSIGNED_INT<span style="color: #339933;">,</span> index<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<h3>3.3 Vertex buffer object</h3>
<p>Se viimeinen tapa on sitten vertex buffer object eli VBO. Se on muuten sama kuin vertex array, mutta siinä verteksidata siirretään keskusmuistista nopeampaan näytönohjaimen muistiin. Koska VBO:n edut tulevat esiin vasta valtavan suurilla polygonimäärillä ja tämä on vain OpenGL:n perusteet-artikkeli, en käsittele sitä.</p>
<h2>4. Näkymättömien pintojen poisto</h2>
<p>Koska monitahokkaat ovat määritelmän mukaan suljettuja, emme voi koskaan nähdä tahojen takapuolia, ainoastaan niiden etupuolet. Tämän takia olisi tehokkuuden kannalta järkevää, jos polygoni jätettäisiin piirtämättä silloin kun sen takapuoli on kameraan päin. Nyt ilmestyykin ongelma. Mistä oikein tietää kumpi polygonin puolista on sen takapuoli ja kumpi etupuoli? Eivätkös ne ole ihan samanlaisia kummatkin? OpenGL:ssä polygonin etupuoli määritellään niin, että jos numeroimme sen verteksit järjestyksessä, on etupuoli se, jolta katsottuna verteksien numerot kasvavat vastapäivään.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/puolet.jpg" rel="lightbox[1161]"><img class="aligncenter size-full wp-image-1168" title="puolet" src="http://www.suomipelit.com/tiedostot/2010/03/puolet.jpg" alt="" width="256" height="120" /></a><br />
<a rel="lightbox[artikkelikuva_58]" href="http://www.suomipelit.com/kaikki/images/artikkelit/58/puolet.jpg"></a><br />
Näkymättömien pintojen poisto kytketään päälle glEnable()-functiolla, jolle annetaan parametrina GL_CULL_FACE. Vastaavasti sen saa pois päältä glDisable()-funktiolla samalla parametrilla. Voit myös halutessasi päättää jätetäänkö piirtämättä taka-, vai etupuolet. Tämä tehdään glCullFace()-funktiolla, jolle annetaan parametrina, joko GL_FRONT tai GL_BACK. Oletusarvo on GL_BACK. Sinun ei tietenkään tarvitse itse numeroida verteksejä, vaan OpenGL numeroi ne siinä järjestyksessä, kun se saa ne esim. glVertex3f()-funktiolta.</p>
<h2>5. Päällekkäisyysongelma</h2>
<p>Aina kun piirrät OpenGL:ssä jotain, se peittää alleen kaiken ennen sitä piirretyn. Tästä seuraa se, että jos monitahokkaan takenpana olevat polygonit piirretään etummaisten jälkeen, peittävät ne etummaiset alleen ja saatu kuva on näin ollen virheellinen. Jos näkymättömien pintojen poisto laitetaan päälle, ei tätä ongelmaa esiinny, jos monitahokas on kupera, sillä siinä mitkään kaksi kameraan päin olevaa polygonia ei peitä toisiaan. Sen sijaan koveran monitahokkaan tapauksessa ei pelkkä näkymättömien pintojen poisto auta, vaan tarvitaan avuksi jotain toista algoritmia. Kaksi kuuluisinta ovat: maalarin algoritmi ja syvyyspuskurialgoritmi.</p>
<p><strong>5.1 Maalarin algoritmi.</strong></p>
<p>Maalarin algoritmin idea on yksinkertainen. Polygonit lajitellaan ja piirretään tämän jälkeen järjestyksessä takimmaisesta etummaiseen, samoin kuin maalari tekee maalatessaan taulua. On kuitenkin muutama tapaus, joissa maalarin algoritmi ei toimi, eli kuva on aina virheellinen riippumatta siitä missä järjestyksessä polygonit piirretään. Alla pari esimerkkiä.</p>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/paallekkein.jpg" rel="lightbox[1161]"><img class="aligncenter size-full wp-image-1167" title="paallekkein" src="http://www.suomipelit.com/tiedostot/2010/03/paallekkein.jpg" alt="" width="392" height="137" /></a><br />
<a rel="lightbox[artikkelikuva_58]" href="http://www.suomipelit.com/kaikki/images/artikkelit/58/paallekkein.jpg"></a><br />
Tämän takia maalarin algoritmia ei kannatakkaan käyttää kuin joissakin erikoistapauksissa.</p>
<p><strong>5.2 Syvyyspuskurialgoritmi</strong></p>
<p>Syvyyspuskurialgoritmin ideana on tallentaa pikselin värin lisäksi myös sen etäisyys kamerasta. Tämä syvyysarvo tallennetaan ns. syvyyspuskuriin eli Z-puskuriin. Aina ennen pikselin piirtoa lasketaan sen syvyysarvo. Tarkistetaan puskurista, onko kyseisellä paikalla olevan pikselin syvyysarvo jo pienempi kuin uuden pikselin syvyys. Jos on, niin pikseli jätetään piirtämättä. Jos taas ei, niin pikseli piirretään ja syvyyspuskuriin päivitetään uusi arvo.</p>
<p>OpenGL:ssä on syvyyspuskuri sisäänrakennettuna. Se tarvitsee vain kytkeä päälle glEnable()-funktiolla, jolle annetaan parametrina GL_DEPTH_TEST. Syvyyspuskuri on tietenkin tyhjennettävä ennen piirtämistä. Tämä tehdään glClear()-funktiolla, jolle annetaan parametrina GL_DEPTH_BUFFER_BIT.</p>
<h2>6. Matriisit</h2>
<p>Voidaksesi käyttää OpenGL:ää sinun ei tarvitse ymmärtää matriisien syvintä olemusta. Riittää, että tiedät niiden perusperiaatteen. Matriisi on taulukko (OpenGL:n tapauksessa 4&#215;4 taulukko), jonka jokaisessa solussa on jokin mielivaltainen luku. Matriisilla voidaan kertoa vektori, jolloin vektori muuntuu toiseksi vektoriksi. Millaiseksi, se riippuu siitä, mitä lukuja matriisi sisälsi. Valitsemalla matriisin alkiot sopivasti saadaan vektori vaikka pyörimään jonkin akselin ympäri jonkin kulman verran.</p>
<p>Jos matriisin alkiot valitaan niin, että vinorivillä on ykkösiä ja kaikkialla muualla nollia, saadaan ns. yksikkömatriisi (englanniksi identity matrix), jolla kertomalla vektori ei muutu miksikään.</p>
<p>Myös matriiseja voidaan kertoa keskenään, jolloin matriisien ominaisuudet yhdistyvät. Esim. jos meillä on matriisi, joka pyörittää 30 astetta Z-akselin ympäri ja matriisi, joka pyörittää 50 astetta Z-akselin ympäri saadaan niiden tulona matriisi, joka pyörittää 80 astetta Z-akselin ympäri. Jos haluat tarkempia tietoja matriiseista lue artikkeli: <a href="http://www.suomipelit.com/2004/04/23/matriisimatematiikkaa-peliohjelmoijille/">Matriisimatematiikkaa peliohjelmoijille</a>.</p>
<p>OpenGL:ssä on sisäänrakennettuna useitakin matriiseja. Tässä artikkelissa olemme kiinnostuneita modelview-matriisista ja projektiomatriisista. Aina kun annat OpenGL:lle verteksin glVertex-sarjan funktiolla kerrotaan kyseinen verteksi ensin modelview-matriisilla ja sitten projektiomatriisilla. Kummatkin nämä matriisit ovat oletuksena yksikkömatriiseja eli verteksi ei muutu miksikään.</p>
<p>OpenGL sisältää kasan funktioita, joilla sen sisäisiä matriiseja voidaan muokata. Ennen kuin voimme käyttää niitä meidän on kuitenkin päätettävä mitä matriisia haluamme muokata. Tämä tehdään glMatrixMode()-funktiolla, joka saa parametrikseen, joko GL_MODELVIEW tai GL_PROJECTION riippuen siitä kumpaa matriiseista haluamme muokata. Myös muita vaihtoehtoja on, mutta emme käsittele niitä tässä artikkelissa.</p>
<p>Seuraavassa tärkeimmät matriiseja muokkaavista funktioista:</p>
<p>glLoadIdentity() &#8211; korvaa nykyisen matriisin yksikkömatriisilla.</p>
<p>glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) &#8211; kertoo nykyisen matriisin matriisilla, joka pyörittää vektoria angle astetta akselin x, y, z ympäri.</p>
<p>glTranslatef(GLfloat x, GLfloat y, GLfloat z ) &#8211; siirtää vektoria parametrien x, y ja z verran.</p>
<p>Seuraava esimerkki siirtää ensin -5 yksikköä z-akselin suuntaan ja pyörittää sitten 60 astetta x-akselin ympäri.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glLoadIdentity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glTranslatef<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glRotatef<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">60</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Eli jos nyt annat OpenGL:lle yhdenkin verteksin, siirretetään sitä ensin 5 yksikköä negatiivisen z-akselin suuntaan ja pyöritetään sitten 60 astetta x-akselin ympäri ennen piirtämistä.</p>
<p>Myös koordinaatistot tallennetaan matriisiin. Niille on varattu varta vasten projektiomatriisi. gluOrtho2D() ja gluPerspektive() ovatkin itse asiassa matriiseja muokkaavia funktioita, jotka kertovat nykyisen matriisin luomallaan koordinaatistomatriisilla. Tämän takia projektiomatriisi on ensin valittava glMatrixMode()-funktiolla ennen kummankaan kutsua.</p>
<p>Nykyinen matriisi voidaan halutessa tallentaa varastoon pinoon kutsulla glPushMatrix();. Pinon päällimmäinen matriisi taas voidaan ladata takaisin kutsulla glPopMatrix();. Pinoon mahtuu maksimissaan 32 modelview-matriisia ja 2-projektiomatriisia (kummallakin on oma pino).</p>
<h2>7 Esimerkkiohjelma</h2>
<p>Seuraava ohjelma avaa ikkunan ja piirtää siihen pyörivän värikkään kuution. Koska se kuinka monta kertaa sekunnissa tietokone piirtää kuvan riippuu sen tehosta, pyörisi kuutio eri nopeudella eri kokeilla. Tämän takia käytämme GetTickCount()-funktiota, joka palauttaa ajan millisekunteina, mittaamaan kuvan piirtämiseen kuluvan ajan. Näin voimme ajastaa pyörimisnopeuden samaksi kaikilla koneilla. Voit imuroida oheisen lähdekoodin ja valmiiksi käännetyn version tästä: <a href="http://www.suomipelit.com/tiedostot/2004/06/testi2.zip">testi2.zip</a> .</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;height:600px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br />92<br />93<br />94<br />95<br />96<br />97<br />98<br />99<br />100<br />101<br />102<br />103<br />104<br />105<br />106<br />107<br />108<br />109<br />110<br />111<br />112<br />113<br />114<br />115<br />116<br />117<br />118<br />119<br />120<br />121<br />122<br />123<br />124<br />125<br />126<br />127<br />128<br />129<br />130<br />131<br />132<br />133<br />134<br />135<br />136<br />137<br />138<br />139<br />140<br />141<br />142<br />143<br />144<br />145<br />146<br />147<br />148<br />149<br />150<br />151<br />152<br />153<br />154<br />155<br />156<br />157<br />158<br />159<br />160<br />161<br />162<br />163<br />164<br />165<br />166<br />167<br />168<br />169<br />170<br />171<br />172<br />173<br />174<br />175<br />176<br />177<br />178<br />179<br />180<br />181<br />182<br />183<br />184<br />185<br />186<br />187<br />188<br />189<br />190<br />191<br />192<br />193<br />194<br />195<br />196<br />197<br />198<br />199<br />200<br />201<br />202<br />203<br />204<br />205<br />206<br />207<br />208<br />209<br />210<br />211<br />212<br />213<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#include &lt;windows.h&gt;</span><br />
<span style="color: #339933;">#include &lt;gl\gl.h&gt;</span><br />
<span style="color: #339933;">#include &lt;gl\glu.h&gt;</span><br />
<span style="color: #666666; font-style: italic;">//#include &lt;gl\glext.h&gt; &nbsp;// Ei tarvita tässä ohjelmassa</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Määrittele laitekonteksti globaaliksi sitä nimittäin tarvitaan myös pääfunktiossa.</span><br />
HDC hdc<span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Viestinkäsittelijä</span><br />
LRESULT CALLBACK WindowProc<span style="color: #009900;">&#40;</span>HWND hwnd<span style="color: #339933;">,</span> UINT uMsg<span style="color: #339933;">,</span> WPARAM wParam<span style="color: #339933;">,</span> LPARAM lParam<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #b1b100;">switch</span> <span style="color: #009900;">&#40;</span>uMsg<span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Koska piirrämme ikkunan sisällön pääsilmukassa jatkuvasti uudelleen</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// reagoimme WM_PAINT-viestiin vain tyhjentämällä ikkunan mustaksi.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_PAINT<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; PAINTSTRUCT p<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; BeginPaint<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glClear<span style="color: #009900;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; SwapBuffers<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; EndPaint<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Ikkuna yritetään sulkea kutsu PostQuitMessage()-funktiota.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_CLOSE<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; PostQuitMessage<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Käsittele myös WM_SIZE se lähetetään ikkunalle aina kun sen kokoa muutetaan.</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Tämä on oiva tilaisuus muuttaa viewport</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// oikean kokoiseksi peittämään koko ikkuna.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_SIZE<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Ikkunan uusi koko saadaan lParam parametrista LOWORD ja HIWORD makroilla.</span><br />
&nbsp; &nbsp; &nbsp; glViewport<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> LOWORD<span style="color: #009900;">&#40;</span>lParam<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> HIWORD<span style="color: #009900;">&#40;</span>lParam<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Viestiä ei käsitelty kutsu DefWindowProc()-funktiota.</span><br />
&nbsp; <span style="color: #b1b100;">return</span> DefWindowProc<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> uMsg<span style="color: #339933;">,</span> wParam<span style="color: #339933;">,</span> lParam<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #993333;">int</span> luoIkkuna<span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> leveys<span style="color: #339933;">,</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> korkeus<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>otsikko<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Rekisteröi ikkunaluokka</span><br />
&nbsp; WNDCLASS wc<span style="color: #339933;">;</span><br />
&nbsp; memset<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>wc<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>WNDCLASS<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">style</span> <span style="color: #339933;">=</span> CS_HREDRAW <span style="color: #339933;">|</span> CS_VREDRAW <span style="color: #339933;">|</span> CS_OWNDC<span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">hCursor</span><span style="color: #339933;">=</span> LoadCursor<span style="color: #009900;">&#40;</span>NULL<span style="color: #339933;">,</span> IDC_ARROW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">lpfnWndProc</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>WNDPROC<span style="color: #009900;">&#41;</span> WindowProc<span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">hInstance</span> <span style="color: #339933;">=</span> GetModuleHandle<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">lpszClassName</span> <span style="color: #339933;">=</span> <span style="color: #ff0000;">&quot;OpenGLtutoriaali&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>RegisterClass<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>wc<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo ikkuna</span><br />
&nbsp; RECT r<span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">left</span><span style="color: #339933;">=</span>GetSystemMetrics<span style="color: #009900;">&#40;</span>SM_CXSCREEN<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">-</span>leveys<span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">top</span><span style="color: #339933;">=</span>GetSystemMetrics<span style="color: #009900;">&#40;</span>SM_CYSCREEN<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">-</span>korkeus<span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">right</span><span style="color: #339933;">=</span>r.<span style="color: #202020;">left</span><span style="color: #339933;">+</span>leveys<span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">bottom</span><span style="color: #339933;">=</span>r.<span style="color: #202020;">top</span><span style="color: #339933;">+</span>korkeus<span style="color: #339933;">;</span><br />
&nbsp; AdjustWindowRectEx<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>r<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; WS_CLIPSIBLINGS <span style="color: #339933;">|</span> WS_CLIPCHILDREN <span style="color: #339933;">|</span> WS_OVERLAPPEDWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; FALSE<span style="color: #339933;">,</span> &nbsp;WS_EX_APPWINDOW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; HWND hwnd<span style="color: #339933;">;</span><br />
&nbsp; hwnd<span style="color: #339933;">=</span>CreateWindowEx<span style="color: #009900;">&#40;</span>WS_EX_APPWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #ff0000;">&quot;OpenGLtutoriaali&quot;</span><span style="color: #339933;">,</span> otsikko<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; WS_CLIPSIBLINGS <span style="color: #339933;">|</span> WS_CLIPCHILDREN <span style="color: #339933;">|</span> WS_OVERLAPPEDWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; r.<span style="color: #202020;">left</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">top</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">right</span><span style="color: #339933;">-</span>r.<span style="color: #202020;">left</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">bottom</span><span style="color: #339933;">-</span>r.<span style="color: #202020;">top</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; NULL<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> GetModuleHandle<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo laitekonteksti</span><br />
&nbsp; hdc<span style="color: #339933;">=</span>GetDC<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>hdc<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Valitse pikseliformaatti</span><br />
&nbsp; PIXELFORMATDESCRIPTOR pfd<span style="color: #339933;">;</span><br />
&nbsp; memset<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>pfd<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>PIXELFORMATDESCRIPTOR<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">nSize</span><span style="color: #339933;">=</span><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>PIXELFORMATDESCRIPTOR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">nVersion</span><span style="color: #339933;">=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">dwFlags</span><span style="color: #339933;">=</span>PFD_DRAW_TO_WINDOW<span style="color: #339933;">|</span>PFD_SUPPORT_OPENGL<span style="color: #339933;">|</span>PFD_DOUBLEBUFFER<span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">iPixelType</span><span style="color: #339933;">=</span>PFD_TYPE_RGBA<span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cRedBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cGreenBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cBlueBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cAlphaBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cStencilBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cDepthBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">16</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">iLayerType</span><span style="color: #339933;">=</span>PFD_MAIN_PLANE<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">int</span> pixelFormat<span style="color: #339933;">;</span><br />
&nbsp; pixelFormat<span style="color: #339933;">=</span>ChoosePixelFormat<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pfd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>pixelFormat<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>SetPixelFormat<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> pixelFormat<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pfd<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo renderöintikonteksti</span><br />
&nbsp; HGLRC hrc<span style="color: #339933;">;</span><br />
&nbsp; hrc<span style="color: #339933;">=</span>wglCreateContext<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>hrc<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>wglMakeCurrent<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> hrc<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Tuo ikkuna näkyviin</span><br />
&nbsp; ShowWindow<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> SW_SHOW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; SetForegroundWindow<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; SetFocus<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Palauta onnistuminen</span><br />
&nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Pääfunktio</span><br />
<span style="color: #993333;">int</span> WINAPI WinMain<span style="color: #009900;">&#40;</span>HINSTANCE hInstance<span style="color: #339933;">,</span> HINSTANCE hPrevInstance<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LPSTR lpCmdLine<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> nCmdShow<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Data piirrettävää kuutiota varten</span><br />
&nbsp; <span style="color: #993333;">float</span> vertex<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">8</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">float</span> color<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">8</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">int</span> index<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">6</span><span style="color: #339933;">*</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span><span style="color: #0000dd;">7</span><span style="color: #339933;">,</span><span style="color: #0000dd;">6</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #0000dd;">5</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">7</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">6</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #0000dd;">7</span><span style="color: #339933;">,</span><span style="color: #0000dd;">3</span><span style="color: #339933;">,</span><span style="color: #0000dd;">2</span><span style="color: #339933;">,</span><span style="color: #0000dd;">6</span><span style="color: #339933;">,</span> &nbsp;<span style="color: #0000dd;">4</span><span style="color: #339933;">,</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span><span style="color: #0000dd;">5</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">float</span> angle<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> aika<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> piirtoaika<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> alkuaika<span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo ikkuna</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>luoIkkuna<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">800</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">600</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;OpenGL:n perusteet - Osa 2: 3D grafiikka&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Määrittele viewport koko ikkunan kokoiseksi</span><br />
&nbsp; glViewport<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">800</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">600</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Koska koordinaatisto on itseasiassa matriisi täytyy meidän ottaa</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// projektiomatriisi käsiteltäväksi ennen gluPerspective-kutsua.</span><br />
&nbsp; glMatrixMode<span style="color: #009900;">&#40;</span>GL_PROJECTION<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; gluPerspective<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">60</span><span style="color: #339933;">,</span> <span style="color:#800080;">800.0</span><span style="color: #339933;">/</span><span style="color:#800080;">600.0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">100</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Kaikki matriisia muuttavat käskyt vaikuttavat tämän jälkeen modelview-matriisiin</span><br />
&nbsp; glMatrixMode<span style="color: #009900;">&#40;</span>GL_MODELVIEW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Laita näkymättömien pintojen poisto ja sysyyspuskurialgoritmi päälle.</span><br />
&nbsp; glEnable<span style="color: #009900;">&#40;</span>GL_CULL_FACE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; glEnable<span style="color: #009900;">&#40;</span>GL_DEPTH_TEST<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Viestinkäsittelysilmukka</span><br />
&nbsp; alkuaika<span style="color: #339933;">=</span>GetTickCount<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; MSG msg<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>PeekMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> PM_REMOVE<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>msg.<span style="color: #202020;">message</span><span style="color: #339933;">==</span>WM_QUIT<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; TranslateMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; DispatchMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Käytämme GetTickCount()-funktiota, joka palauttaa ajan millisekunneissa,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// laskemaan kuvan piirtämiseen kuluneen ajan.</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Näin voimme ajastaa kuution pyörimään samalla nopeudella kaikilla kokeilla.</span><br />
&nbsp; &nbsp; &nbsp; aika<span style="color: #339933;">=</span>GetTickCount<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; piirtoaika<span style="color: #339933;">=</span>aika<span style="color: #339933;">-</span>alkuaika<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>piirtoaika<span style="color: #339933;">&gt;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; alkuaika<span style="color: #339933;">=</span>aika<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Kasvata pyörityskulmaa hieman</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Kuutio pyörii nyt 0.06 astetta millisekunnissa</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// eli 1 kierroksen 6 sekunnissa</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; angle<span style="color: #339933;">+=</span><span style="color:#800080;">0.06</span><span style="color: #339933;">*</span>piirtoaika<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Tyhjennä väripuskuri ja syvyyspuskuri</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glClear<span style="color: #009900;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: #339933;">|</span>GL_DEPTH_BUFFER_BIT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Aseta modelview-matriisi</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glLoadIdentity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// &quot;Resetoi&quot; matriisi yksikkömatriisiksi</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glTranslatef<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Siirrä kuutiota hieman kauemmaksi kamerasta</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glRotatef<span style="color: #009900;">&#40;</span>angle<span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp;<span style="color: #666666; font-style: italic;">// Pyöritä kuutiota hieman joka akselin ympäri</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glRotatef<span style="color: #009900;">&#40;</span>angle<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glRotatef<span style="color: #009900;">&#40;</span>angle<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Piirrä kuutio</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glBegin<span style="color: #009900;">&#40;</span>GL_QUADS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333;">int</span> i<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span><span style="color: #0000dd;">6</span><span style="color: #339933;">*</span><span style="color: #0000dd;">4</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; glColor3f<span style="color: #009900;">&#40;</span>color<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> color<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> color<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; glVertex3f<span style="color: #009900;">&#40;</span>vertex<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> vertex<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> vertex<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Toinen tapa piirtää kuutio vertex array:lla.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/*<br />
&nbsp; &nbsp; &nbsp; &nbsp; glEnableClientState(GL_VERTEX_ARRAY);<br />
&nbsp; &nbsp; &nbsp; &nbsp; glEnableClientState(GL_COLOR_ARRAY);<br />
&nbsp; &nbsp; &nbsp; &nbsp; glVertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex);<br />
&nbsp; &nbsp; &nbsp; &nbsp; glColorPointer(3, GL_FLOAT, sizeof(float[3]), color);<br />
&nbsp; &nbsp; &nbsp; &nbsp; glDrawElements(GL_QUADS, 4*6, GL_UNSIGNED_INT, index);<br />
&nbsp; &nbsp; &nbsp; &nbsp; */</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Vaihda puskuri näytölle.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; SwapBuffers<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<h2>8 Loppusanat</h2>
<p>Tässä artikkelissa opit piirtämään kolmeulotteisia kappaleita OpenGL:llä. Seuraavassa osassa puhumme tekstuureista. Raportoithan kaikki tästä artikkelista löytämäsi virheet (niin kirjoitus-, kuin asiavirheetkin) osoitteeseen markus.ilmola@pp.inet.fi , niin korjaan ne mahdollisimman nopeasti. Myös kaikki kommentit ja kysymykset ovat tervetulleita.</p>
<hr /><em>Artikkelin kirjoitti alun perin markus.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.suomipelit.com/2004/06/09/opengln-perusteet-osa-2-3d-grafiikka/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>OpenGL:n perusteet &#8211; Osa 1: Ikkunan luominen</title>
		<link>http://www.suomipelit.com/2004/05/28/opengln-perusteet-osa-1-ikkunan-luominen/</link>
		<comments>http://www.suomipelit.com/2004/05/28/opengln-perusteet-osa-1-ikkunan-luominen/#comments</comments>
		<pubDate>Fri, 28 May 2004 10:00:03 +0000</pubDate>
		<dc:creator>Suomipelit.com</dc:creator>
				<category><![CDATA[Artikkelit]]></category>
		<category><![CDATA[Käytännön oppaat]]></category>
		<category><![CDATA[2d]]></category>
		<category><![CDATA[3d]]></category>
		<category><![CDATA[c/cpp]]></category>
		<category><![CDATA[gl]]></category>
		<category><![CDATA[grafiikka]]></category>
		<category><![CDATA[ikkuna]]></category>
		<category><![CDATA[ikkunan luominen]]></category>
		<category><![CDATA[opengl]]></category>
		<category><![CDATA[perusteet]]></category>

		<guid isPermaLink="false">http://www.suomipelit.com/?p=1155</guid>
		<description><![CDATA[Ennen vanhaan grafiikkaa piirrettiin kirjoittamalla se suoraan näytönohjaimen muistiin. Kun tiettyyn osoitteeseen näytönohjaimen muistissa kirjoitettiin tavu, syttyi vastaavaan kohtaan näyttöä vastaavan värinen pikseli. Ja kun yksi pikseli kerran osattiin piirtää, niin monesta pikselistähän sai aikaan mitä tahansa kuvia. Kaikki kuitenkin muuttui 3D-kiihdytinten myötä. Enää grafiikkaa ei piirrettykään tietokoneen prosessorin avulla, vaan näytönohjaimen prosessorin avulla, joka on varta vasten suunniteltu grafiikan piirtämiseen ja suoriutuu tehtävästä näin ollen jopa 300 kertaa nopeammin vastaavan kellotaajuiseen keskussuorittimeen verrattuna. ]]></description>
			<content:encoded><![CDATA[<p>OpenGL on laajassa käytössä oleva käyttöjärjestelmäriippumaton rajapinta 2D- ja 3D-grafiikan piirtoon. Tämä artikkelisarja opettaa sinulle 3D-grafiikan perusteet OpenGL:ää käyttäen. Esimerkeissä käytetään C\C++ kieltä. Tämä on artikkelisarjan ensimmäinen osa.</p>
<h2>1. Johdanto</h2>
<p><a href="http://www.suomipelit.com/tiedostot/2010/03/opengllogo.jpg" rel="lightbox[1155]"><img class="alignleft size-full wp-image-1156" title="opengllogo" src="http://www.suomipelit.com/tiedostot/2010/03/opengllogo.jpg" alt="" width="240" height="180" /></a>Ennen vanhaan grafiikkaa piirrettiin kirjoittamalla se suoraan näytönohjaimen muistiin. Kun tiettyyn osoitteeseen näytönohjaimen muistissa kirjoitettiin tavu, syttyi vastaavaan kohtaan näyttöä vastaavan värinen pikseli. Ja kun yksi pikseli kerran osattiin piirtää, niin monesta pikselistähän sai aikaan mitä tahansa kuvia. Kaikki kuitenkin muuttui 3D-kiihdytinten myötä. Enää grafiikkaa ei piirrettykään tietokoneen prosessorin avulla, vaan näytönohjaimen prosessorin avulla, joka on varta vasten suunniteltu grafiikan piirtämiseen ja suoriutuu tehtävästä näin ollen jopa 300 kertaa nopeammin vastaavan kellotaajuiseen keskussuorittimeen verrattuna.</p>
<p>Ongelmaksi muodostuu kuitenkin se, että jokainen näytönohjain on erilainen ja eri grafiikkakoodin kirjoittaminen kaikille mahdollisille näytönohjaimille olisi mahdotonta. Tämän takia asia hoidetaan niin sanottujen rajapintojen kautta. Eli näytönohjaimesi ajurit tarjoavat sinulle standardoituja funktioita, jotka toimivat samoin kaikilla näytönohjaimilla. Toinen ilmiselvä hyöty on, että ohjelmoijan ei itse tarvitse kasata kuviota yksittäisistä pikseleistä vaan yksinkertaisten primitiivien (kuten viivojen ja kolmioiden) piirtoon on valmiit funktiot.</p>
<p>3D-korttien alkuaikoina tällaisia rajapintoja oli kolme: Glide, Direct3D ja OpenGL. Glide:ä ylläpitäneen 3Dfx:n hävittyä myös Glide kuoli pois. Niinpä nykyään on olemassa kaksi rajapintaa: Microsoftin DirectX-paketin osana oleva Direct3D ja SGI:n alun perin kehittämä, nykyään ARB:n (suurimpien näytönohjainvalmistajien yhteenliittymä) ylläpitämä OpenGL. Molemmat ovat yhtä nopeita ja molemmilla voi tehdä samat asiat. Ainut ero on, että siinä missä Direct3D toimii vain Windows-käyttöjärjestelmässä (ja sen 8-version muunnos Xbox-pelikonsolissa), OpenGL toimii käytännössä kaikissa käyttöjärjestelmissä ja jopa kämmenmikroissa ja matkapuhelimissa (OpenGL ES). Tämä artikkeli käsittelee OpenGL-rajapintaa, jonka aloituskynnys on Direct3D:tä hieman pienempikin. Käytämme tässä artikkelisarjassa Windows-käyttöjärjestelmää, mutta ikkunan luontia lukuunottamatta OpenGL:n käyttö on kaikilla käyttöjärjestelmillä samanlaista.</p>
<p>OpenGL:n virallisen speksin voit imuroida täältä: <a href="http://www.opengl.org/documentation/specs/version2.0/glspec20.pdf">http://www.opengl.org/documentation/spec&#8230;</a><br />
OpenGL:n opetteleminen spesifikaatiota tutkimalla on kuitenkin vaivalloista, joten aloittakaamme tutoriaali.</p>
<h2>2. Tarvittavat kirjastot</h2>
<p>OpenGL:n otsikkotiedostot tulevat kaikkien yleisimpien kääntäjien mukana. Ne ovat nimeltään opengl.h ja glu.h . Lisäksi, koska tässä artikkelissa teemme Windows-ohjelmia, pitää mukaan liittää windows.h. <strong>Ohjelma pitää myös linkittää kirjastojen opengl32.lib ja glu32.lib kanssa.</strong> Katso kääntäjäsi ohjeista kuinka tämä tehdään. Esim. Dev-Cpp:lla tämä tehdään kirjoittamalla projektin asetuksista löytyvään linker-kenttään &#8220;-lopengl32 -lglu32&#8243;. Myöhemmin tulet tarvitsemaan vielä tiedostoa glext.h . Kyseinen tiedosto päivittyy vähän väliä, joten imuroi itsellesi uusin versio osoitteesta: <a href="http://oss.sgi.com/projects/ogl-sample/ABI/glext.h.">http://oss.sgi.com/projects/ogl-sample/A&#8230;</a></p>
<p>OpenGL:ää käyttävän C/C++-kielisen tiedoston alku näyttäisi siis tyypillisesti tältä:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#include &lt;windows.h&gt;</span><br />
<span style="color: #339933;">#include &lt;GL/gl.h&gt;</span><br />
<span style="color: #339933;">#include &lt;GL/glu.h&gt;</span><br />
<span style="color: #339933;">#include &lt;GL/glext.h&gt;</span></div></td></tr></tbody></table></div>
</pre>
<h2>3. Ikkunan luominen</h2>
<p>Ennen kuin voit piirtää yhtään mitään on sinun luotava ikkuna. Ikkunalla ei varsinaisesti ole mitään tekemistä OpenGL:n kanssa. Se on vain välttämätön paha, joka on tehtävä ennen kuin pääsemme asiaan. Vaikka OpenGL onkin käyttöjärjestelmäriippumaton on ikkunan luominen jokaisella käyttöjärjestelmällä aina erilainen prosessi. Tämä artikkeli käsittelee Windows-ohjelmointia, joten näytän kuinka ikkuna luodaan Windowssissa. Ikkunan luonnissa on periaatteessa 3 eri vaihetta:</p>
<p>1. Rekisteröi ikkunaluokka<br />
2. Luo ikkuna<br />
3. Luo ikkunaan renderöintikonteksti</p>
<p>Ensimmäinen vaihe on helppo. Täytetään WNDCLASS-tyyppinen rakenne ja rekisteröidään se RegisterClass()-funktiolla. Kummatkin on määritelty windows.h:ssa. Sinun ei siis itse tarvitse toteuttaa kumpaakaan!</p>
<p>WNDCLASS-rakenteen määrittely näyttää tältä:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">typedef</span> <span style="color: #993333;">struct</span> _WNDCLASS<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; UINT style<span style="color: #339933;">;</span><br />
&nbsp; WNDPROC lpfnWndProc<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">int</span> cbClsExtra<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">int</span> cbWndExtra<span style="color: #339933;">;</span><br />
&nbsp; HANDLE hInstance<span style="color: #339933;">;</span><br />
&nbsp; HICON hIcon<span style="color: #339933;">;</span><br />
&nbsp; HCURSOR hCursor<span style="color: #339933;">;</span><br />
&nbsp; HBRUSH hbrBackground<span style="color: #339933;">;</span><br />
&nbsp; LPCTSTR lpszMenuName<span style="color: #339933;">;</span><br />
&nbsp; LPCTSTR lpszClassName<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span> WNDCLASS<span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>ja RegisterClass()-funktion prototyyppi tältä:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">ATOM RegisterClass<span style="color: #009900;">&#40;</span><br />
CONST WNDCLASS <span style="color: #339933;">*</span>lpWndClass <span style="color: #666666; font-style: italic;">// address of structure with class data</span><br />
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Luodaan nyt yksi WNDCLASS-rakenne, täytetään se asianmukaisesti ja rekisteröidään se.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">WNDCLASS wc<span style="color: #339933;">;</span><br />
memset<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>wc<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>WNDCLASS<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
wc.<span style="color: #202020;">style</span> <span style="color: #339933;">=</span> CS_HREDRAW <span style="color: #339933;">|</span> CS_VREDRAW <span style="color: #339933;">|</span> CS_OWNDC<span style="color: #339933;">;</span><br />
wc.<span style="color: #202020;">hCursor</span><span style="color: #339933;">=</span> LoadCursor<span style="color: #009900;">&#40;</span>NULL<span style="color: #339933;">,</span> IDC_ARROW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
wc.<span style="color: #202020;">lpfnWndProc</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>WNDPROC<span style="color: #009900;">&#41;</span> WindowProc<span style="color: #339933;">;</span><br />
wc.<span style="color: #202020;">hInstance</span> <span style="color: #339933;">=</span> GetModuleHandle<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
wc.<span style="color: #202020;">lpszClassName</span> <span style="color: #339933;">=</span> <span style="color: #ff0000;">&quot;OpenGLtutoriaali&quot;</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>RegisterClass<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>wc<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Huomattavaa tässä olivat kentät <em>lpfnWndProc </em>ja <em>lpszClassName</em>. <em>lpszClassName</em>:en pitää keksiä jokin uniikki nimi tälle ikkunaluokalle. Tätä nimeä tarvitaan myöhemmin. Jokainen ikkuna tarvitsee toimiakseen viestinkäsittelijäfunktion. <em>lpfnWndProc </em>sisältää tämän funktion. Palaamme viestinkäsittelijöihin myöhemmin. Loput kentät sisältävät erilaisia asetuksia kuten käytettävän hiiren kursorin jne. Anna niiden olla sellaisena kuin ne ovat yllä, sillä niiden muuttaminen saattaa tehdä ikkunasta OpenGL-yhteensopimattoman.</p>
<p>Seuraava vaihe on vähintään yhtä helppo. Luodaan ikkuna<strong> CreateWindowEx()</strong>-funktiolla. Sen prototyyppi näyttää tältä:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">HWND CreateWindowEx<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;DWORD dwExStyle<span style="color: #339933;">,</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666; font-style: italic;">// extended window style</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LPCTSTR lpClassName<span style="color: #339933;">,</span> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// pointer to registered class name</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LPCTSTR lpWindowName<span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// pointer to window name</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;DWORD dwStyle<span style="color: #339933;">,</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666; font-style: italic;">// window style</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333;">int</span> x<span style="color: #339933;">,</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// horizontal position of window</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333;">int</span> y<span style="color: #339933;">,</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// vertical position of window</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333;">int</span> nWidth<span style="color: #339933;">,</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// window width</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333;">int</span> nHeight<span style="color: #339933;">,</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666; font-style: italic;">// window height</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;HWND hWndParent<span style="color: #339933;">,</span> &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// handle to parent or owner window</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;HMENU hMenu<span style="color: #339933;">,</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// handle to menu, or child-window identifier</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;HINSTANCE hInstance<span style="color: #339933;">,</span> &nbsp;<span style="color: #666666; font-style: italic;">// handle to application instance</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LPVOID lpParam &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// pointer to window-creation data</span><br />
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Luodaan nyt ikkuna käyttäen kyseistä funktiota.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">HWND hwnd<span style="color: #339933;">;</span><br />
hwnd<span style="color: #339933;">=</span>CreateWindowEx<span style="color: #009900;">&#40;</span>WS_EX_APPWINDOW<span style="color: #339933;">,</span><br />
<span style="color: #ff0000;">&quot;OpenGLtutoriaali&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot; OpenGL:n perusteet - Osa 1: Ikkunan luominen&quot;</span><span style="color: #339933;">,</span><br />
WS_CLIPSIBLINGS <span style="color: #339933;">|</span>WS_CLIPCHILDREN<span style="color: #339933;">|</span> WS_OVERLAPPEDWINDOW<span style="color: #339933;">,</span><br />
<span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">800</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">600</span><span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> GetModuleHandle<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Jälleen ainoat huomionarvoiset parametrit ovat lpClassName, johon siis pitää antaa äsken rekisteröimämme ikkunaluokan nimi, <em>lpWindowName</em>, joka sisältää ikkunan otsikkorivillä näkyvän tekstin ja <em>nWidth </em>ja <em>nHeight</em>, jotka sisältävät ikkunan koon. <em>x </em>ja <em>y </em>ovat ikkunan sijainti suhteessa näytön vasempaan ylänurkkaan. Funktio palauttaa kahvan luotuun ikkunaan. Ota se talteen, sillä sitä tarvitaan myöhemmin. Loput parametrit ovat jälleen erilaisia asetuksia, jotka vaikuttavat ikkunan ulkonäköön ja käyttäytymiseen. Jos esim. haluat, että ikkunan kokoa ei voi muuttaa, lisää <em>dwStyle</em>-parametrin perään vielä liput &#8220;&amp; ~<em>WS_MAXIMIZEBOX</em> &amp; ~<em>WS_SIZEBOX</em>&#8221; ja jos haluat, että ikkunalla ei ole reunoja eikä otsikkoriviä vaihda <em>dwStyle</em>-parametrin <em>WS_OVERLAPPEDWINDOW</em>-lippu <em>WS_POPUP</em>-lippuun. Erilaisia asetuksia on siis tuhottomasti.</p>
<p>Width ja Height parametrien ilmaisema ikkunan koko on siis koko ikkunan koko. Osa ikkunasta kuitenkin jää otsikkopalkin ja reunojen alle, joten haluamme ehkä mieluummin määrittää sen alueen koon, jolle voi piirtää, eli ns. asiakasalueen koon. Tähän voimme käyttää apuna <strong>AdjustWindowRectEx()</strong>-funktiota, joka laskee koko ikkunan koon asiakasalueen koosta. Se käyttää apunaan RECT-rakennetta. Prototyypit ovat tämän näköiset:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">BOOL AdjustWindowRectEx<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; LPRECT lpRect<span style="color: #339933;">,</span>&nbsp; <span style="color: #666666; font-style: italic;">// pointer to client-rectangle structure</span><br />
&nbsp; &nbsp; DWORD dwStyle<span style="color: #339933;">,</span>&nbsp; <span style="color: #666666; font-style: italic;">// window styles</span><br />
&nbsp; &nbsp; BOOL bMenu<span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// menu-present flag</span><br />
&nbsp; &nbsp; DWORD dwExStyle &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// extended style</span><br />
&nbsp;<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #993333;">typedef</span> <span style="color: #993333;">struct</span> _RECT <span style="color: #009900;">&#123;</span> &nbsp; &nbsp;<span style="color: #666666; font-style: italic;">// rc</span><br />
&nbsp; &nbsp; LONG left<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; LONG top<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; LONG right<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; LONG bottom<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span> RECT<span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>RECT-rakenne sisältää ikkunan vasemman ylänurkan kooridinaatit (left ja top) ja oikean alanurkan koordinaatit (right ja bottom). Se pitää esitäyttää asiakasalueen koolla. Tämän jälkeen kutsumme <strong>AdjustWindowRectEx()</strong>-funktiota, joka muuttaa RECT-rakenteen vastaamaan koko ikkunan kokoa. Seuraavassa paranneltu ikkunan luonti, joka vielä keskittää ikkunan utelemalla näytön resoluution <strong>GetSystemMetrics()</strong>-funktiolla. (Luvut 800 ja 600 ovat esimerkki tyypillisestä ikkunan koosta)</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RECT r<span style="color: #339933;">;</span><br />
r.<span style="color: #202020;">left</span><span style="color: #339933;">=</span>GetSystemMetrics<span style="color: #009900;">&#40;</span>SM_CXSCREEN<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">-</span><span style="color: #0000dd;">800</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
r.<span style="color: #202020;">top</span><span style="color: #339933;">=</span>GetSystemMetrics<span style="color: #009900;">&#40;</span>SM_CYSCREEN<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">-</span><span style="color: #0000dd;">600</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
r.<span style="color: #202020;">right</span><span style="color: #339933;">=</span>r.<span style="color: #202020;">left</span><span style="color: #339933;">+</span><span style="color: #0000dd;">800</span><span style="color: #339933;">;</span><br />
r.<span style="color: #202020;">bottom</span><span style="color: #339933;">=</span>r.<span style="color: #202020;">top</span><span style="color: #339933;">+</span><span style="color: #0000dd;">600</span><span style="color: #339933;">;</span><br />
AdjustWindowRectEx<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>r<span style="color: #339933;">,</span><br />
&nbsp; WS_CLIPSIBLINGS <span style="color: #339933;">|</span> WS_CLIPCHILDREN <span style="color: #339933;">|</span> WS_OVERLAPPEDWINDOW<span style="color: #339933;">,</span><br />
&nbsp; FALSE<span style="color: #339933;">,</span> &nbsp;WS_EX_APPWINDOW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
HWND hwnd<span style="color: #339933;">;</span><br />
&nbsp; hwnd<span style="color: #339933;">=</span>CreateWindowEx<span style="color: #009900;">&#40;</span>WS_EX_APPWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #ff0000;">&quot;OpenGLtutoriaali&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot; OpenGL:n perusteet - Osa 1: Ikkunan luominen&quot;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; WS_CLIPSIBLINGS <span style="color: #339933;">|</span> WS_CLIPCHILDREN <span style="color: #339933;">|</span> WS_OVERLAPPEDWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; r.<span style="color: #202020;">left</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">top</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">right</span><span style="color: #339933;">-</span>r.<span style="color: #202020;">left</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">bottom</span><span style="color: #339933;">-</span>r.<span style="color: #202020;">top</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; NULL<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> GetModuleHandle<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Viimeinen vaihe on hankalin. Meidän pitää luoda ikkunaan renderöintikonteksti. Tässäkin on kolme vaihetta: ensin tehdään laitekonteksti, sitten valitaan pikseliformaatti ja lopuksi vasta luodaan renderöintikonteksti.</p>
<p>Laitekonteksti luodaan GetDC()-funktiolla, jolle annetaan parametrinä ikkunan kahva.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">HDC hdc<span style="color: #339933;">;</span><br />
hdc<span style="color: #339933;">=</span>GetDC<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>hdc<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Luodaksemme pikseliformaatin meidän täytyy täyttää <em>PIXELFORMATDESCRIPTOR</em>-rakenne. Sen määrittely näyttää tältä:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">typedef</span> <span style="color: #993333;">struct</span> tagPIXELFORMATDESCRIPTOR <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">// pfd</span><br />
&nbsp; WORD nSize<span style="color: #339933;">;</span><br />
&nbsp; WORD nVersion<span style="color: #339933;">;</span><br />
&nbsp; DWORD dwFlags<span style="color: #339933;">;</span><br />
&nbsp; BYTE iPixelType<span style="color: #339933;">;</span><br />
&nbsp; BYTE cColorBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cRedBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cRedShift<span style="color: #339933;">;</span><br />
&nbsp; BYTE cGreenBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cGreenShift<span style="color: #339933;">;</span><br />
&nbsp; BYTE cBlueBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cBlueShift<span style="color: #339933;">;</span><br />
&nbsp; BYTE cAlphaBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cAlphaShift<span style="color: #339933;">;</span><br />
&nbsp; BYTE cAccumBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cAccumRedBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cAccumGreenBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cAccumBlueBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cAccumAlphaBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cDepthBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cStencilBits<span style="color: #339933;">;</span><br />
&nbsp; BYTE cAuxBuffers<span style="color: #339933;">;</span><br />
&nbsp; BYTE iLayerType<span style="color: #339933;">;</span><br />
&nbsp; BYTE bReserved<span style="color: #339933;">;</span><br />
&nbsp; DWORD dwLayerMask<span style="color: #339933;">;</span><br />
&nbsp; DWORD dwVisibleMask<span style="color: #339933;">;</span><br />
&nbsp; DWORD dwDamageMask<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span> PIXELFORMATDESCRIPTOR<span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Täytetään nyt kyseinen rakenne asianmukaisesti, jonka jälkeen valitsemme ja asetamme pikseliformaatin funktioilla <strong>ChoosePixelFormat()</strong> ja <strong>SetPixelFormat()</strong>. Ideana on, että täytämme <em>PIXELFORMATDESCRIPTOR</em>-rakenteeseen tiedot siitä millaisen pikseliformaatin haluamme. Valitsemme sitten lähimmän vastaavan ChoosePixelFormat()-funktiolla ja asetamme sen palauttaman pikseliformaatin varsinaiseksi pikseliformaatiksi.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">PIXELFORMATDESCRIPTOR pfd<span style="color: #339933;">;</span><br />
memset<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>pfd<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>PIXELFORMATDESCRIPTOR<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
pfd.<span style="color: #202020;">nSize</span><span style="color: #339933;">=</span><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>PIXELFORMATDESCRIPTOR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
pfd.<span style="color: #202020;">nVersion</span><span style="color: #339933;">=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
pfd.<span style="color: #202020;">dwFlags</span><span style="color: #339933;">=</span>PFD_DRAW_TO_WINDOW<span style="color: #339933;">|</span>PFD_SUPPORT_OPENGL<span style="color: #339933;">|</span>PFD_DOUBLEBUFFER<span style="color: #339933;">;</span><br />
pfd.<span style="color: #202020;">iPixelType</span><span style="color: #339933;">=</span>PFD_TYPE_RGBA<span style="color: #339933;">;</span><br />
pfd.<span style="color: #202020;">cRedBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
pfd.<span style="color: #202020;">cGreenBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
pfd.<span style="color: #202020;">cBlueBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
pfd.<span style="color: #202020;">cAlphaBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
pfd.<span style="color: #202020;">cStencilBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
pfd.<span style="color: #202020;">cDepthBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">16</span><span style="color: #339933;">;</span><br />
pfd.<span style="color: #202020;">iLayerType</span><span style="color: #339933;">=</span>PFD_MAIN_PLANE<span style="color: #339933;">;</span><br />
<span style="color: #993333;">int</span> pixelFormat<span style="color: #339933;">;</span><br />
pixelFormat<span style="color: #339933;">=</span>ChoosePixelFormat<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pfd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>pixelFormat<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>SetPixelFormat<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> pixelFormat<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pfd<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Lopuksi luomme renderöintikontekstin. Tämä tehdään ns. wigle-funktioilla wglCreateContext() ja wglMakeCurrent().</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">HGLRC hrc<span style="color: #339933;">;</span><br />
hrc<span style="color: #339933;">=</span>wglCreateContext<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>hrc<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>wglMakeCurrent<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> hrc<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Lopuksi ikkuna tehdään vielä näkyväksi ShowWindow()-funktiolla ja tuodaan etualalle funktioilla SetForegroundWindow() ja SetFocus().</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">ShowWindow<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> SW_SHOW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
SetForegroundWindow<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
SetFocus<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<h2>4. Viestinkäsittelijä</h2>
<p>Koska Windowsissa pyörii useampi ohjelma yhtä aikaa täytyy niillä olla jokin tapa kommunikoida toistensa ja Windowssin kanssa. Tämä tapa on ns. viestinkäsittelijäfunktio, jollainen jokaisella ikkunalla täytyy olla. Aina kun Windowssilla on jokin viesti jollekkin ohjelmalle se kutsuu kyseisen ohjelman viestinkäsittelijää. Sinun on siis itse toteutettava ohjelmallesi viestinkäsittelyfunktio ja sen prototyypin on aina näytettävä seuraavalta:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">LRESULT CALLBACK WindowProc<span style="color: #009900;">&#40;</span><br />
HWND hwnd<span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// handle of window</span><br />
UINT uMsg<span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// message identifier</span><br />
WPARAM wParam<span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// first message parameter</span><br />
LPARAM lParam <span style="color: #666666; font-style: italic;">// second message parameter</span><br />
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Funktiolla on siis neljä parametria, joista meitä kiinnostaa erityisesti uMsg. Se sisältää itse viestin. Sillä on tuhottomasti erilaisia mahdollisia arvoja esim: <em>WM_ACTIVE</em>, <em>WM_CLOSE</em> ja <em>WM_PAINT</em>. Sinun ei kuitenkaan tarvitse reagoida niihin kaikkiin vaan ainoastaan niihin joihin haluat. Ainut &#8220;pakollinen&#8221; käsiteltävä on <em>WM_CLOSE</em>, johon reagoidaan kutsumalla <strong>PostQuitMessage()</strong>-funktiota parametrillä 0. Ikkuna nimittäin saa kyseisen viestin, kun käyttäjä yrittää sulkea sen esim. painamalla sulkemispainiketta. Muita tärkeitä viestejä ovat WM_SIZE, jonka ohjelma saa aina kun sen ikkunan kokoa muutetaan ja <em>WM_PAINT</em>, jonka ohjelma saa aina kun ikkuna täytyy piirtää uudestaan. Näin voi käydä esim. kun ikkunan edessä ollut toinen ikkuna on siirretty syrjään. <em>WM_PAINT</em>-viestin käsittely alkaa aina <strong>BeginPaint()</strong>-funktiolla ja loppuu <strong>EndPaint()</strong>-funktioon. Jos käsittelet jonkin viestin palauta 0 ja jos taas et, lähetä se <strong>DefWindowProc()</strong>-funktiolle ja palauta sen palauttama arvo. Viestin käsittely lienee helpointa toteuttaa switch-rakenteella. Seuraavassa yksinkertainen esimerkkitoteutus:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">LRESULT CALLBACK WindowProc<span style="color: #009900;">&#40;</span>HWND hwnd<span style="color: #339933;">,</span> UINT uMsg<span style="color: #339933;">,</span> WPARAM wParam<span style="color: #339933;">,</span> LPARAM lParam<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #b1b100;">switch</span> <span style="color: #009900;">&#40;</span>uMsg<span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Ikkuna yritetään sulkea kutsu PostQuitMessage()-funktiota.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_CLOSE<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; PostQuitMessage<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Viestiä ei käsitelty kutsu DefWindowProc()-funktiota.</span><br />
&nbsp; <span style="color: #b1b100;">return</span> DefWindowProc<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> uMsg<span style="color: #339933;">,</span> wParam<span style="color: #339933;">,</span> lParam<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<h2>5. Pääfunktio</h2>
<p>DOS:issa ja Linuxsissa pääfunktio on yleensä muotoa:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span><span style="color: #339933;">*</span> argv<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Windowsissa asia on hieman monimutkaisempi. Pääfunktio on muotoa:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> WINAPI WinMain<span style="color: #009900;">&#40;</span>HINSTANCE hInstance<span style="color: #339933;">,</span> HINSTANCE hPrevInstance<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LPSTR lpCmdLine<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> nCmdShow<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Paljon mutkikkaita parametrejä, mutta eipä hätää, niistä ei tarvitse välittää. Lisäksi pääfunktiosta täytyy löytyä standardi viestinkäsittelysilmukka:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">MSG msg<span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>PeekMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> PM_REMOVE<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>msg.<span style="color: #202020;">message</span><span style="color: #339933;">==</span>WM_QUIT<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; TranslateMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; DispatchMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Lisää oma suoritettava ohjelmakoodisi tähän</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Tyypillisesti tässä välissä suoritetaan</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// pelilogiikkaa ja renderöidään yksi &quot;frame&quot;.</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Eli kyseessä on loputon silmukka, joka purkaa jonosta Windowssin ohjelmalle lähettämiä viestejä ja käsittelee ne. Ainoastaan silloin, kun ei ole yhtään viestiä käsiteltävänä voidaan suorittaa ohjelman omaa koodia. Silmukasta saa poistua vasta kun ohjelma saa sulkemisviestin WM_QUIT. Jonka jälkeen ohjelman tulee sammua.</p>
<h2>6. Grafiikan piirtäminen</h2>
<p>Kun ikkuna on luotu päästään itse asiaan eli grafiikan piirtoon. Itseasiassa varsinainen OpenGL osio alkaa vasta tästä.</p>
<p>Ensin on määriteltävä viewport eli se alue ikkunasta, jolle piirretään. Tämä tapahtuu<strong> glViewport()</strong>-funktiolla. Sen prototyyppi näyttää tältä:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">void</span> glViewport<span style="color: #009900;">&#40;</span>GLint x<span style="color: #339933;">,</span> GLint y<span style="color: #339933;">,</span> GLsizei width<span style="color: #339933;">,</span> GLsizei height<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>x ja y ovat viewportin vasemman alareunan koordinaatit suhteessa ikkunan vasemman alareunan koordinaatteihin ja width ja height viewportin leveys ja korkeus (siis pikseleissä ilmaistuna). Esim. jos meillä on 800&#215;600 ikkuna ja haluamme koko sen alan piirtämistä varten käyttäisimme kutsua glViewport(0, 0, 800, 600);. Viewport voi myös periaatteessa mennä ikkunan reunojen yli, jolloin ikkunan ulkopuolisia alueita ei yksinkertaisesti piirretä, mutta bugisimmilla näytönohjaimenajureilla tämä saattaa aiheuttaa ongelmia.</p>
<p>Kun viewport on määritelty täytyy vielä määritellä koordinaatisto (tai pidemminkin projektiomatriisi, mutta siitä enemmän joskus toiste). OpenGL:ssä on kaksi erilaista koordinaatistoa: 2D-koordinaatisto 2D-grafiikkaa varten ja 3D-koordinaatisto 3D-grafiikkaa varten. Käytämme tässä esimerkissä hieman helpompaa 2D-koordinaatistoa. Se luodaan funktiolla <strong>gluOrtho2D()</strong>, jonka prototyyppi näyttää tältä:</p>
<pre>void gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);</pre>
<p>OpenGL:ssä X-akseli kulkee vaakasuorassa ja Y-akseli pystysuorassa. left-parametri kertoo X-akselin arvon viewportin vasemmassa reunassa ja right X-akselin arvon viewportin oikeassa reunassa. Vastaavasti bottom ja top Y-akselille. Esim. jos haluaisimme määritellä koordinaatiston niin, että origo olisi viewportin keskellä ja sekä Y- että X-akseli ulottuisivat 10 yksikköä joka suuntaan käyttäisimme kutsua <strong>gluOrtho2D</strong>(-10, 10, -10, 10);. Jos taas meillä olisi kokoa 800&#215;600 oleva viewport ja haluaisimme koordinaatiston, jossa origo on vasemmassa alanurkassa ja yksi pikseli vastaa aina yhtä yksikköä käyttäisimme kutsua gluOrtho2D(0, 800, 0, 600);.</p>
<p>Vihdoin ja viimein pääsemme piirtämään itse grafiikkaa. OpenGL:ssä on monta tapaa piirtää, mutta helpoin niistä on varmasti <strong>glBegin()</strong> <strong>glEnd()</strong> parin, eli ns. välitysmoodin käyttäminen. Ensin kutsutaan<strong> glBegin()</strong>-funktiota, jonka prototyyppi näyttää tältä:</p>
<pre>void glBegin(GLenum mode);</pre>
<p>Sillä on siis vain yksi parametri mode, joka kertoo mitä piirretään. Sen mahdolliset arvot ovat: <em>GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP ja GL_POLYGON</em>. Näistä tärkeimmät ovat <em>GL_POINTS</em>, joka piirtää pisteitä, <em>GL_LINES</em>, joka piirtää viivoja ja <em>GL_TRIANGLES</em>, joka piirtää kolmioita.</p>
<p><strong>glBegin()</strong>-kutsun jälkeen kutsumme<strong> glVertex2f()</strong>-funktiota toistuvasti. Sille annetaan piirrettävän primitiivin kontrollipisteen koordinaatit. Sen prototyyppi näyttää tältä.</p>
<pre>void glVertex2f(GLfloat x, GLfloat y);</pre>
<p>Eli X ja Y koordinaatit annetaan parametrina. Se missä kohtaa ikkunaa nämä pisteet sijaitsevat määräyttyy luodun koordinaatiston ja viewportin mukaan.</p>
<p><em>GL_POINTS </em>tapauksessa jokaiseen <strong>glVertex2f()</strong>-funktion määräämiin koordinaatteihin piirretään piste. <em>GL_LINES</em> tapauksessa aina kahden <strong>glVertex2f()</strong>-kutsun määräämien koordinaattien välille piirretään viiva ja <em>GL_TRIANGLES</em> tapauksessa aina kolmen kutsun välille kolmio. Käytimme tässä siis <strong>glVertex2f()</strong>-funktiota koska meillä on 2D koordinaatisto. Myöhemmin 3D-koordinaatistossa käytämme <strong>glVertex3f()</strong>-funktiota.</p>
<p>Lopuksi kun kaikki tarvittavat <strong>glVertex2f()</strong> kutsut on tehty kutsutaan <strong>glEnd()</strong>-funktiota. Se ei ota yhtään parametriä.</p>
<p>Seuraava esimerkki piirtää viivan pisteestä (0, 0) pisteeseen (200, 100).</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glBegin<span style="color: #009900;">&#40;</span>GL_LINES<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">200</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">100</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Piirrettävälle primitiiville voidaan myös asettaa väri <strong>glColor3f()</strong>-funktiolla. Prototyyppi näyttää tältä:</p>
<pre>void glColor3f(GLfloat red,  GLfloat green, GLfloat blue);.</pre>
<p>Se ottaa parametrinaan värin red, green ja blue arvot. Nämä arvot ovat väliltä 0-1 ja niitä sekoittamalla voidaan muodostaa kaikki mahdolliset värit. Väri voidaan asettaa halutessa jokaiselle primitiivin kontrollipisteelle erikseen. Jos primitiivin kontrollipisteet ovat eri väriset niiden väliin jäävien pikselien värit interpoloidaan. Eli jos viivan toinen pää on musta ja toinen valkea, on viiva keskeltä harmaa. Seuraava esimerkki piirtää kolmion, jonka yksi nurkka on punainen, yksi sininen ja yksi vihreä.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glBegin<span style="color: #009900;">&#40;</span>GL_TRIANGLES<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glColor3f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glColor3f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glColor3f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Vielä pari juttua ennen kuin kaikki on täydellistä. Nimittäin ennen piirtoa ikkuna on tyhjennettävä kaikesta mahdollisesta muusta grafiikasta, tämä tapahtuu <strong>glClear()</strong>-funktiolla, jolle annetaan parametriksi <em>GL_COLOR_BUFFER_BIT</em>.</p>
<p>Se toinen juttu on sitten niin sanottu kaksoispuskurointi. OpenGL:ssä on kaksi piirtopintaa (tosin vain silloin kun pikseliformaaatti luotiin <em>PFD_DOUBLEBUFFER </em>parametrillä), joista toinen on aina näyttövuorossa ja toinen aina piirtovuorossa. Niinpä aina kun piirrät jotain se ei ilmesty näytölle vaan sille toiselle piilossa olevalle pinnalle. Jotta grafiikka saataisiin näkyväksi täytyy nämä pinnat piirtämisen jälkeen vaihtaa keskenään <strong>SwapBuffers()</strong>-funktiolla, jonka prototyyppi näyttää tältä:</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">BOOL SwapBuffers<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; HDC &nbsp;hdc&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Device context whose buffers get swapped</span><br />
&nbsp;<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Eli se ottaa parametrinään ikkunan luonnin yhteydessä saadun laitekontekstin. Kahta piirtopintaa käytetään, jotta käyttäjä ei näe kuvan valmistumista piste kerrallaan (joskin hyvin nopeasti), vaan näkee sen vasta kun koko kuva on valmis.</p>
<h2>7. Esimerkkiohjelma</h2>
<p>Lopuksi täydellinen esimerkkiohjelma, joka luo ikkunan ja piirtää sen keskelle kolmion. Huomaa kuinka itse ikkunan luominen vie suurimman osan koodista, kun taas varsinainen grafiikan piirto vie vain muutaman rivin. Tämän takia Internet on pullollaan erilaisia &#8220;kehys&#8221;-kirjastoja, joilla voit luoda ikkunan nopeasti parilla funktion kutsulla. Näistä kuuluisimpia ovat (nyt jo hieman vanhentunut) GLUT ( <a href="http://www.xmission.com/~nate/glut.html">http://www.xmission.com/~nate/glut.html</a> ) ja GLFW ( <a href="http://glfw.sourceforge.net/">http://glfw.sourceforge.net/</a> ). Myös erittäin suoritulla SDL-kirjastolla (<a href="http://www.libsdl.org/">http://www.libsdl.org</a> ) voi luoda OpenGL-yhteensopivan ikkunan.</p>
<p>Vielä mainittakoon, että jos haluat saada käyttäjältä syötettä, niin näppäimen tila voidaan lukea Windowsissa GetAsyncKeyState()-funktiolla ja hiiren tila GetCursorPos()-funktiolla. Lisää tietoa näiden käytöstä löytyy msdn:stä ( <a href="http://msdn.microsoft.com/">http://msdn.microsoft.com/</a> ). Jos käytät GLUT:a, GLFW:tä tai SDL:ää, niin näistä kyllä löytyy taas omat funktionsa näppäinten lukuun.</p>
<p>Voit imuroida oheisen lähdekoodin ja valmiiksi käännetyn version tästä: <a href="http://www.suomipelit.com/tiedostot/2004/05/testi1.zip">testi1.zip</a>.</p>
<pre>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;height:600px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br />92<br />93<br />94<br />95<br />96<br />97<br />98<br />99<br />100<br />101<br />102<br />103<br />104<br />105<br />106<br />107<br />108<br />109<br />110<br />111<br />112<br />113<br />114<br />115<br />116<br />117<br />118<br />119<br />120<br />121<br />122<br />123<br />124<br />125<br />126<br />127<br />128<br />129<br />130<br />131<br />132<br />133<br />134<br />135<br />136<br />137<br />138<br />139<br />140<br />141<br />142<br />143<br />144<br />145<br />146<br />147<br />148<br />149<br />150<br />151<br />152<br />153<br />154<br />155<br />156<br />157<br />158<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#include &lt;windows.h&gt;</span><br />
<span style="color: #339933;">#include &lt;gl\gl.h&gt;</span><br />
<span style="color: #339933;">#include &lt;gl\glu.h&gt;</span><br />
<span style="color: #339933;">#include &lt;math.h&gt;</span><br />
<span style="color: #666666; font-style: italic;">//#include &lt;gl\glext.h&gt; &nbsp;// Ei tarvita tässä ohjelmassa</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Määrittele laitekonteksti globaaliksi sitä nimittäin tarvitaan myös pääfunktiossa.</span><br />
HDC hdc<span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Viestinkäsittelijä</span><br />
LRESULT CALLBACK WindowProc<span style="color: #009900;">&#40;</span>HWND hwnd<span style="color: #339933;">,</span> UINT uMsg<span style="color: #339933;">,</span> WPARAM wParam<span style="color: #339933;">,</span> LPARAM lParam<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #b1b100;">switch</span> <span style="color: #009900;">&#40;</span>uMsg<span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp;<span style="color: #666666; font-style: italic;">// Koska piirrämme ikkunan sisällön pääsilmukassa jatkuvasti uudelleen</span><br />
&nbsp; &nbsp;<span style="color: #666666; font-style: italic;">// reakoimme WM_PAINT-viestiin vain tyhjentämällä ikkunan mustaksi.</span><br />
&nbsp; &nbsp;<span style="color: #b1b100;">case</span> WM_PAINT<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; PAINTSTRUCT p<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; BeginPaint<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glClear<span style="color: #009900;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; SwapBuffers<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; EndPaint<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Ikkuna yritetään sulkea kutsu PostQuitMessage()-funktiota.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_CLOSE<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; PostQuitMessage<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Käsittele myös WM_SIZE se lähetetään ikkunalle aina kun sen kokoa muutetaan.</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Tämä on oiva tilaisuus muuttaa viewport</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// oikean kokoiseksi peittämään koko ikkuna.</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">case</span> WM_SIZE<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Ikkunan uusi koko saadaan lParam parametrista LOWORD ja HIWORD makroilla.</span><br />
&nbsp; &nbsp; &nbsp; glViewport<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> LOWORD<span style="color: #009900;">&#40;</span>lParam<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> HIWORD<span style="color: #009900;">&#40;</span>lParam<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Viestiä ei käsitelty kutsu DefWindowProc()-funktiota.</span><br />
&nbsp; <span style="color: #b1b100;">return</span> DefWindowProc<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> uMsg<span style="color: #339933;">,</span> wParam<span style="color: #339933;">,</span> lParam<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #993333;">int</span> luoIkkuna<span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> leveys<span style="color: #339933;">,</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> korkeus<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>otsikko<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #339933;">&lt;/</span>pre<span style="color: #339933;">&gt;</span><br />
<span style="color: #339933;">&lt;</span>pre<span style="color: #339933;">&gt;</span><span style="color: #666666; font-style: italic;">// Rekisteröi ikkunaluokka</span><br />
&nbsp; WNDCLASS wc<span style="color: #339933;">;</span><br />
&nbsp; memset<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>wc<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>WNDCLASS<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">style</span> <span style="color: #339933;">=</span> CS_HREDRAW <span style="color: #339933;">|</span> CS_VREDRAW <span style="color: #339933;">|</span> CS_OWNDC<span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">hCursor</span><span style="color: #339933;">=</span> LoadCursor<span style="color: #009900;">&#40;</span>NULL<span style="color: #339933;">,</span> IDC_ARROW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">lpfnWndProc</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>WNDPROC<span style="color: #009900;">&#41;</span> WindowProc<span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">hInstance</span> <span style="color: #339933;">=</span> GetModuleHandle<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; wc.<span style="color: #202020;">lpszClassName</span> <span style="color: #339933;">=</span> <span style="color: #ff0000;">&quot;OpenGLtutoriaali&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>RegisterClass<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>wc<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo ikkuna</span><br />
&nbsp; RECT r<span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">left</span><span style="color: #339933;">=</span>GetSystemMetrics<span style="color: #009900;">&#40;</span>SM_CXSCREEN<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">-</span>leveys<span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">top</span><span style="color: #339933;">=</span>GetSystemMetrics<span style="color: #009900;">&#40;</span>SM_CYSCREEN<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">-</span>korkeus<span style="color: #339933;">/</span><span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">right</span><span style="color: #339933;">=</span>r.<span style="color: #202020;">left</span><span style="color: #339933;">+</span>leveys<span style="color: #339933;">;</span><br />
&nbsp; r.<span style="color: #202020;">bottom</span><span style="color: #339933;">=</span>r.<span style="color: #202020;">top</span><span style="color: #339933;">+</span>korkeus<span style="color: #339933;">;</span><br />
&nbsp; AdjustWindowRectEx<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>r<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; WS_CLIPSIBLINGS <span style="color: #339933;">|</span> WS_CLIPCHILDREN <span style="color: #339933;">|</span> WS_OVERLAPPEDWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; FALSE<span style="color: #339933;">,</span> &nbsp;WS_EX_APPWINDOW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; HWND hwnd<span style="color: #339933;">;</span><br />
&nbsp; hwnd<span style="color: #339933;">=</span>CreateWindowEx<span style="color: #009900;">&#40;</span>WS_EX_APPWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #ff0000;">&quot;OpenGLtutoriaali&quot;</span><span style="color: #339933;">,</span> otsikko<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; WS_CLIPSIBLINGS <span style="color: #339933;">|</span> WS_CLIPCHILDREN <span style="color: #339933;">|</span> WS_OVERLAPPEDWINDOW<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; r.<span style="color: #202020;">left</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">top</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">right</span><span style="color: #339933;">-</span>r.<span style="color: #202020;">left</span><span style="color: #339933;">,</span> r.<span style="color: #202020;">bottom</span><span style="color: #339933;">-</span>r.<span style="color: #202020;">top</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; NULL<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> GetModuleHandle<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo laitekonteksti</span><br />
&nbsp; hdc<span style="color: #339933;">=</span>GetDC<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>hdc<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Valitse pikseliformaatti</span><br />
&nbsp; PIXELFORMATDESCRIPTOR pfd<span style="color: #339933;">;</span><br />
&nbsp; memset<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>pfd<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>PIXELFORMATDESCRIPTOR<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">nSize</span><span style="color: #339933;">=</span><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>PIXELFORMATDESCRIPTOR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">nVersion</span><span style="color: #339933;">=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">dwFlags</span><span style="color: #339933;">=</span>PFD_DRAW_TO_WINDOW<span style="color: #339933;">|</span>PFD_SUPPORT_OPENGL<span style="color: #339933;">|</span>PFD_DOUBLEBUFFER<span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">iPixelType</span><span style="color: #339933;">=</span>PFD_TYPE_RGBA<span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cRedBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cGreenBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cBlueBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cAlphaBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cStencilBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">8</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">cDepthBits</span><span style="color: #339933;">=</span><span style="color: #0000dd;">16</span><span style="color: #339933;">;</span><br />
&nbsp; pfd.<span style="color: #202020;">iLayerType</span><span style="color: #339933;">=</span>PFD_MAIN_PLANE<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">int</span> pixelFormat<span style="color: #339933;">;</span><br />
&nbsp; pixelFormat<span style="color: #339933;">=</span>ChoosePixelFormat<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pfd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>pixelFormat<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>SetPixelFormat<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> pixelFormat<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>pfd<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo renderöintikonteksti</span><br />
&nbsp; HGLRC hrc<span style="color: #339933;">;</span><br />
&nbsp; hrc<span style="color: #339933;">=</span>wglCreateContext<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>hrc<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>wglMakeCurrent<span style="color: #009900;">&#40;</span>hdc<span style="color: #339933;">,</span> hrc<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Tuo ikkuna näkyviin</span><br />
&nbsp; ShowWindow<span style="color: #009900;">&#40;</span>hwnd<span style="color: #339933;">,</span> SW_SHOW<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; SetForegroundWindow<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; SetFocus<span style="color: #009900;">&#40;</span>hwnd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp;<span style="color: #666666; font-style: italic;">// Palauta onnistuminen</span><br />
&nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Pääfunktio</span><br />
<span style="color: #993333;">int</span> WINAPI WinMain<span style="color: #009900;">&#40;</span>HINSTANCE hInstance<span style="color: #339933;">,</span> HINSTANCE hPrevInstance<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LPSTR lpCmdLine<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> nCmdShow<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// Luo ikkuna</span><br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>luoIkkuna<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">800</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">600</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;OpenGL:n perusteet - osa 1: Ikkunan luominen&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Määrittele viewport ja koordinaatisto koko ikkunan kokoiseksi</span><br />
&nbsp; glViewport<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">800</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">600</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; glMatrixMode<span style="color: #009900;">&#40;</span>GL_PROJECTION<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; gluOrtho2D<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">13</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">13</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// Viestinkäsittelysilmukka</span><br />
&nbsp; MSG msg<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>PeekMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> PM_REMOVE<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>msg.<span style="color: #202020;">message</span><span style="color: #339933;">==</span>WM_QUIT<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; TranslateMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; DispatchMessage<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Tyhjennä puskuri</span><br />
&nbsp; &nbsp; &nbsp; glClear<span style="color: #009900;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Piirrä kolmio</span><br />
&nbsp; &nbsp; &nbsp; glBegin<span style="color: #009900;">&#40;</span>GL_TRIANGLES<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glColor3f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glColor3f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glColor3f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glVertex2f<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">5</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; glEnd<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Vaihda puskuri näytölle.</span><br />
&nbsp; &nbsp; &nbsp; SwapBuffers<span style="color: #009900;">&#40;</span>hdc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<h2>8. Loppusanat</h2>
<p>Tässä artikkelissa opit luomaan OpenGL-yhteensopivan ikkunan Windows-käyttöjärjestelmässä. Huomaa, että jos asiat olisi tehty aivan oikeaoppisesti, niin luotu ikkuna olisi pitänyt vielä tuhota ohjelman sammuessa, mutta luotin tässä sokeasti siihen, että käyttöjärjestelmä vapauttaa automaattisesti tarpeettomat resurssit.</p>
<p>Seuraavassa tutoriaalissa siirrymme varsinaisen 3D-grafiikan piirtoon. Raportoithan kaikki tästä artikkelista löytämäsi virheet (niin kirjoitus-, kuin asiavirheetkin) osoitteeseen markus.ilmola@pp.inet.fi , niin korjaan ne mahdollisimman nopeasti. Myös kaikki kommentit ja kysymykset ovat tervetulleita.</p>
<hr /><em>Artikkelin kirjoitti alun perin markus.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.suomipelit.com/2004/05/28/opengln-perusteet-osa-1-ikkunan-luominen/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
