|   | 1 | = Računalniška grafika = | 
                  
                          |   | 2 |  | 
                  
                          |   | 3 | Leon Kos | 
                  
                          |   | 4 |  | 
                  
                          |   | 5 |  | 
                  
                          |   | 6 |   Predstavljeni so bistveni prijemi pri programiranju | 
                  
                          |   | 7 |   računalniške grafike z grafično knjižnico OpenGL. Ta | 
                  
                          |   | 8 |   dokument naj bi bil osnova za vaje pri predmetih RPK, OPK, PK in | 
                  
                          |   | 9 |   izdelavo seminarjev s tega področja. Ker študenti FS | 
                  
                          |   | 10 |   pridobijo znanje programiranja v jeziku Fortran, so primeri podani za | 
                  
                          |   | 11 |   ta jezik. To pa ne pomeni, da je teorija omejena le na ta jezik, saj | 
                  
                          |   | 12 |   brez bistvenih popravkov kode lahko pišemo tudi v jeziku C in C++. | 
                  
                          |   | 13 |  | 
                  
                          |   | 14 |  | 
                  
                          |   | 15 | = Uvod = | 
                  
                          |   | 16 |  | 
                  
                          |   | 17 | Za modeliranje posebnih modelov običajno ni možno uporabiti | 
                  
                          |   | 18 | splošno namenskih grafičnih orodij. To se pokaže predvsem | 
                  
                          |   | 19 | pri vizualizaciji inženirskih preračunov. Rezultati modeliranja | 
                  
                          |   | 20 | običajno niso le funkcije ampak kompleksni objekti kot so grafi, | 
                  
                          |   | 21 | vodi, hierarhične strukture, animacije gibanja, mehanizmi, | 
                  
                          |   | 22 | kontrola poti, volumski modeli posebnih oblik, ... | 
                  
                          |   | 23 |  | 
                  
                          |   | 24 | Skozi razvoj računalnikov so se uvajali različni standardi za | 
                  
                          |   | 25 | grafiko. Od začetnikov kot je GKS in njegovega naslednika PHIGS je | 
                  
                          |   | 26 | ostal le še spomin. To pa predvsem zaradi zahtevnosti | 
                  
                          |   | 27 | implementacije in zaprtosti kode. Kot edini odprti standard obstaja | 
                  
                          |   | 28 | le OpenGL, ki ga je najprej uvedel SGI na svojih grafično podprtih | 
                  
                          |   | 29 | delovnih postajah. Poleg OpenGL obstaja tudi Microsoftov Direct3D, ki | 
                  
                          |   | 30 | pa je omejen na PC računalnike z Windows in ni tako enostaven za | 
                  
                          |   | 31 | uporabo kot OpenGL, ki se je zaradi svoje odprtosti in zmogljivosti | 
                  
                          |   | 32 | uveljavil na vseh operacijskih sistemih in strojnih platformah. | 
                  
                          |   | 33 |  | 
                  
                          |   | 34 | Jezik OpenGL je konstruiran kot strojno-neodvisen vmesnik med | 
                  
                          |   | 35 | programsko kodo in grafičnim pospeševalnikom. Strojna | 
                  
                          |   | 36 | neodvisnost jezika OpenGL poneni tudi to, da v specifikaciji jezika ni | 
                  
                          |   | 37 | podpore za nadzor okenskega sistema in dogodkov (\emph{events}) pri | 
                  
                          |   | 38 | interaktivnem programiranju. Za tak nadzor so za vsak operacijski | 
                  
                          |   | 39 | sistem izdelani vmesniki, ki povezujejo OpenGL stroj z okenskim | 
                  
                          |   | 40 | sistemom.  | 
                  
                          |   | 41 |  | 
                  
                          |   | 42 | Zaradi specifičnosti različnih okenskih sistemov (Windows, | 
                  
                          |   | 43 | Xwindow, MacOS, BeOS) je potrebno za vsak sistem uporabiti posebne | 
                  
                          |   | 44 | prijeme pri klicanje OpenGL ukazov. Da bi vseeno lahko posali | 
                  
                          |   | 45 | programe, s sicer omejeno funkcionalnostjo uporabniškega vmesnika, | 
                  
                          |   | 46 | se je izdelala knjižnica GLUT (GL UTility), ki vse razlike | 
                  
                          |   | 47 | med operacijskimi sistemi kompenzira in vpeljuje skupen način | 
                  
                          |   | 48 | manipuliranja z dogodki (\emph{events}). S knjižnico GLUT je tako | 
                  
                          |   | 49 | mogoče pisati prenosljive programe, ki so enostavni za | 
                  
                          |   | 50 | programiranje in dovolj zmogljivi za nezahtevne uporabniške | 
                  
                          |   | 51 | vmesnike. | 
                  
                          |   | 52 |  | 
                  
                          |   | 53 |  | 
                  
                          |   | 54 | = Enostavni OpenGL program = | 
                  
                          |   | 55 |  | 
                  
                          |   | 56 | Osnovni jezik OpenGL je podan v knjižnici GL. Bolj zahtevni | 
                  
                          |   | 57 | primitivi se gradijo z knjižnico GLU (GL Utility) v kateri so | 
                  
                          |   | 58 | podprogrami, ki uporabljajo rutine GL. Rutine GLU vsebujejo več | 
                  
                          |   | 59 | GL ukazov, ki pa so splošno uporabni in so bili zato | 
                  
                          |   | 60 | standardizirani.  | 
                  
                          |   | 61 |  | 
                  
                          |   | 62 | \subsection{Dogodki} | 
                  
                          |   | 63 | Vsi okenski vmesniki delujejo na principu dogodkov (\emph{events}). To | 
                  
                          |   | 64 | so signali okenskega sistema, ki se pošiljajo programu. Naš | 
                  
                          |   | 65 | program je tako v celoti odgovoren za vsebino okna. Okenski sistem mu | 
                  
                          |   | 66 | le dodeli področje (okno) katero vsebino mora popolnoma | 
                  
                          |   | 67 | nadzorovati. Poleg dodeljenega področja pa okenski sistem | 
                  
                          |   | 68 | pošilja še sporočila našemu programu. Najbolj pogosta | 
                  
                          |   | 69 | sporočila so:  | 
                  
                          |   | 70 | \begin{description} | 
                  
                          |   | 71 | \item[display] Prosim obnovi (nariši) vsebino okna. Več | 
                  
                          |   | 72 |   možnih primerov je, da se to zgodi. Lahko je drugo okno odkrilo | 
                  
                          |   | 73 |   del našega okna, okno se je premaknilo na omizju ali pa se je | 
                  
                          |   | 74 |   ponovno prikazalo po tem ko je bilo ikonizirano. Prestrezanje tega | 
                  
                          |   | 75 |   dogodek je obvezno saj mora prav vsak program poskrbeti, da se | 
                  
                          |   | 76 |   vsebina okna obnovi. | 
                  
                          |   | 77 | \item[reshape] Velikost/oblika okna se je spremenila. Poračunaj | 
                  
                          |   | 78 |   vsebino okna za novo velikost. Ta dogodek se zgodi, kadar | 
                  
                          |   | 79 |   uporabnik z miško spremeni velikost okna. | 
                  
                          |   | 80 | \item[keyboard] Pritisnjena je bila tipka na tipkovnici.  | 
                  
                          |   | 81 | \item[mouse] Stanje gumbov na miški se je spremenilo. Uporabnik je | 
                  
                          |   | 82 |   pritisnil ali sprostil enega od gumbov. | 
                  
                          |   | 83 | \item[motion] Uporabnik premika miško ob pritisnjenem gumbu. | 
                  
                          |   | 84 | \item[timer] Program zahteva sporočilo po preteku po določenega | 
                  
                          |   | 85 |   časa, da bo popravil vsebino okna. Primerno je za časovne | 
                  
                          |   | 86 |   simulacije. | 
                  
                          |   | 87 | \end{description} | 
                  
                          |   | 88 | Seveda poleg naštetih dogodkov obstajajo še drugi dogodki, za | 
                  
                          |   | 89 | katere lahko skrbi naš program. Ni pa potrebno da naš program | 
                  
                          |   | 90 | skrbi za vse naštete dogodke. Običajno mora program povedati | 
                  
                          |   | 91 | okenskem sistemu, za katere dogodke bo skrbel in za te dogodke mu bo | 
                  
                          |   | 92 | sistem tudi pošiljal sporočila.  | 
                  
                          |   | 93 |  | 
                  
                          |   | 94 | \subsection{GLUT} | 
                  
                          |   | 95 | Za abstrakcijo dogodkov | 
                  
                          |   | 96 | okenskega sistema v našem primeru skrbi knjižnica GLUT. Primer | 
                  
                          |   | 97 | minimalnega programa, ki nariše črto, je naslednji: | 
                  
                          |   | 98 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 99 | subroutine display | 
                  
                          |   | 100 | include 'GL/fgl.h' | 
                  
                          |   | 101 | implicit none | 
                  
                          |   | 102 | call fglClear(GL_COLOR_BUFFER_BIT) | 
                  
                          |   | 103 | call fglColor3f(1.0, 0.4, 1.0) | 
                  
                          |   | 104 | call fglBegin(GL_LINES) | 
                  
                          |   | 105 | call fglVertex2f(0.1,0.1) | 
                  
                          |   | 106 | call fglVertex3f(0.8,0.8,1.0) | 
                  
                          |   | 107 | call fglEnd | 
                  
                          |   | 108 | call fglFlush | 
                  
                          |   | 109 | end | 
                  
                          |   | 110 |  | 
                  
                          |   | 111 | program crta | 
                  
                          |   | 112 | external display | 
                  
                          |   | 113 | include 'GL/fglut.h' | 
                  
                          |   | 114 | call fglutInit | 
                  
                          |   | 115 | call fglutInitDisplayMode(GLUT_SINGLE + GLUT_RGB) | 
                  
                          |   | 116 | call fglutCreateWindow('Fortran GLUT program') | 
                  
                          |   | 117 | call fglutDisplayFunc(display) | 
                  
                          |   | 118 | call fglutMainLoop | 
                  
                          |   | 119 | end | 
                  
                          |   | 120 | \end{verbatim} | 
                  
                          |   | 121 | } | 
                  
                          |   | 122 |      | 
                  
                          |   | 123 | Fortranski program je sestavljen iz dveh delov: glavnega programa | 
                  
                          |   | 124 | \texttt{crta} in podprograma display. Z ukazom \texttt{fglutInit} | 
                  
                          |   | 125 | inicializiramo GLUT knjižnico podprogramov. Sledi zahteva po vrsti | 
                  
                          |   | 126 | okna. S konstantama GLUT\_SINGLE in GLUT\_RGB povemo, da želimo | 
                  
                          |   | 127 | okno z eno ravnino tribarvnega RGB prostora.  spremenljivka | 
                  
                          |   | 128 | \texttt{window} hrani številko okna, ki jo naredi | 
                  
                          |   | 129 | \texttt{fglutCreateWindow} in hkrati pove OS, kakšen naj bo napis | 
                  
                          |   | 130 | na oknu. Okenskemu sistemu moramo še dopovedati, katere dogodke bo | 
                  
                          |   | 131 | program prestrezal. Za podani primer je to le prikaz vsebine okna. S | 
                  
                          |   | 132 | klicem podprograma \texttt{fglutDisplayFunc} prijavimo OS, da naj | 
                  
                          |   | 133 | pošilja sporočila za izris, knjižnici GLUT pa s tem  | 
                  
                          |   | 134 | dopovemo, da ob zahtevi za ponovni izris pokliče podprogram | 
                  
                          |   | 135 | \texttt{display}.  | 
                  
                          |   | 136 |  | 
                  
                          |   | 137 | Zadnji klic v glavnem programu je vedno \texttt{fglutMainLoop}. Ta | 
                  
                          |   | 138 | podprogram se konča le takrat se konča celoten program. Kot že | 
                  
                          |   | 139 | ime podprograma govori, je to glavna zanka programa, v kateri GLUT | 
                  
                          |   | 140 | sistematično sprejema sporočila in kliče naše | 
                  
                          |   | 141 | podprograme za dogodke. V podanem primeru je to le en tip dogodkov, ki | 
                  
                          |   | 142 | je tudi najbolj uporaben - \texttt{display}. Ostale tipe dogodkov pa | 
                  
                          |   | 143 | \texttt{fglutMainLoop} obdeluje na privzeti način, ki je lahko | 
                  
                          |   | 144 | preprosto ignoriranje sporočila ali pa klicanje vgrajenega | 
                  
                          |   | 145 | podprograma, ki obdela sporočilo. Izgled glavnega programa je tako | 
                  
                          |   | 146 | običajno zelo podoben za vse tipe GLUT programov v katerem si | 
                  
                          |   | 147 | sledijo ukazi v naslednjem zaporedju: | 
                  
                          |   | 148 | \begin{enumerate} | 
                  
                          |   | 149 | \item Vključi definicije konstant \texttt{GLUT} z ukazom | 
                  
                          |   | 150 |   \texttt{include 'GL/glut.h'} | 
                  
                          |   | 151 | \item Dopovej Fortranu, da so imena, kot je npr. \texttt{display}, | 
                  
                          |   | 152 |   podprogrami in ne spremenljivke. To se naredi z ukazom \texttt{external} | 
                  
                          |   | 153 | \item Inicializiraj GLUT | 
                  
                          |   | 154 | \item Nastavi parametre okna (položaj, velikost, tip, bitne | 
                  
                          |   | 155 |   ravnine, pomnilnik) | 
                  
                          |   | 156 | \item Naredi okno in ga poimenuj | 
                  
                          |   | 157 | \item Prijavi podprograme, ki jih bo program izvajal ob | 
                  
                          |   | 158 |   dogodkih. Obvezno prestrezanje je le za \emph{display}. Ostali so poljubni. | 
                  
                          |   | 159 | \item Nastavi lastnosti OpenGL stroja. To so običajno ukazi | 
                  
                          |   | 160 |   \texttt{fglEnable} ali pa kakšna nastavitev luči, materialov | 
                  
                          |   | 161 |   in obnašanja GL stroja. V tem področju se običajno | 
                  
                          |   | 162 |   nastavi tudi ostale spremenljivke, ki niso neposredno vezane na | 
                  
                          |   | 163 |   OpenGL, ampak na samo delovanje programa, ki poleg prikaza dela | 
                  
                          |   | 164 |   še kaj drugega. | 
                  
                          |   | 165 | \item Zadnji je klic \texttt{fglutMainLoop}, iz katerega se program | 
                  
                          |   | 166 |   vrne, ko zapremo okno. Ob tem glavni program konča. | 
                  
                          |   | 167 | \end{enumerate} | 
                  
                          |   | 168 |  | 
                  
                          |   | 169 |  | 
                  
                          |   | 170 | \subsection{Izris v jeziku OpenGL} | 
                  
                          |   | 171 | V podprogramu \texttt{display} se morajo torej nahajati ukazi, ki | 
                  
                          |   | 172 | nekaj narišejo v okno. To so ukazi v jeziku OpenGL ali krajše | 
                  
                          |   | 173 | v jeziku GL. Vsi podprogrami ali funkcije v GL imajo predpono pri | 
                  
                          |   | 174 | imenu \emph{gl} oziroma za Fortran \emph{fgl}. Te predpone so potrebne | 
                  
                          |   | 175 | zaradi možnega prekrivanja z imeni v drugih knjižnicah in | 
                  
                          |   | 176 | jezikih. Za razumevanje jezika se lahko funkcije razlaga brez teh | 
                  
                          |   | 177 | predpon, saj je OpenGL koncipiran tako, da so tipi argumentov za vse | 
                  
                          |   | 178 | jezike podobni. Za posamezen jezik se predpostavi prefiks (za Fortran | 
                  
                          |   | 179 | je to \texttt{fgl}, za C pa \texttt{gl}) | 
                  
                          |   | 180 |  | 
                  
                          |   | 181 | Podprogram \texttt{display} torej skrbi za izris vsebine okna. Z | 
                  
                          |   | 182 | ukazom \emph{Clear} se briše celotno področje okna.  Kaj | 
                  
                          |   | 183 | konkretno se briše povemo z argumentom. V našem primeru je to | 
                  
                          |   | 184 | \texttt{GL\_COLOR\_BUFFER\_BIT}, kar pomeni brisanje vseh točk v | 
                  
                          |   | 185 | barvnem pomnilniku.  | 
                  
                          |   | 186 |  | 
                  
                          |   | 187 | Z ukazom \emph{Color} se nastavi trenutna barva grafičnih | 
                  
                          |   | 188 | gradnikov, ki se bodo izrisovali v nadaljnih ukazih. Kot argument se | 
                  
                          |   | 189 | podaja barva v RGB komponentah. Običajno imajo GL ukazi na koncu | 
                  
                          |   | 190 | imena tudi oznako tipa argumentov, ki jih je potrebno podati pri klicu | 
                  
                          |   | 191 | podprograma. To je običaj za skoraj vse jezike. Tako imamo za | 
                  
                          |   | 192 | Fortran in za C pri podprogramih, kot končnico imena še oznako o | 
                  
                          |   | 193 | številu argumentov in tip argumentov. Podprogram \emph{fglColor3f} | 
                  
                          |   | 194 | torej pomeni, da zahteva podprogram tri argumente tipa \texttt{float}, | 
                  
                          |   | 195 | kar je ekvivalentno v fortranu tipu \emph{real} ali \texttt{real*4}. | 
                  
                          |   | 196 | Najbolj uporabljane GL ukaze lahko torej podamo z različnimi tipi | 
                  
                          |   | 197 | argumentov za isti ukaz. Izbor tipa argumentov je odvisen od | 
                  
                          |   | 198 | programerja in njegovih zahtev. Tako so argumenti za isto funkcijo | 
                  
                          |   | 199 | izbrani glede na priročnost. Za podani primer imamo ukaz | 
                  
                          |   | 200 | \emph{Vertex} v dveh oblikah in isti tip argumentov. \texttt{Vertex2f} | 
                  
                          |   | 201 | pomeni, da podajamo kordinate vozlišča z dvema argumentoma. | 
                  
                          |   | 202 | Tipi argumentov (končnic) so naslednji: | 
                  
                          |   | 203 | \begin{description} | 
                  
                          |   | 204 | \item[f] V jeziku C float in real ali real*4 za Fortran | 
                  
                          |   | 205 | \item[d] double za C in real*8 za Fortran | 
                  
                          |   | 206 | \item[i] integer | 
                  
                          |   | 207 | \item[s] short integer v C-ju ali integer*2 za F | 
                  
                          |   | 208 | \end{description} | 
                  
                          |   | 209 | Namesto fiksiranega števila argumentov obstajajo tudi funkcije, ki | 
                  
                          |   | 210 | imajo podan argument v obliki vektorja. Za to se uporabi končnica | 
                  
                          |   | 211 | \texttt{v}. Nekaj primerov končnic: | 
                  
                          |   | 212 | \begin{description} | 
                  
                          |   | 213 | \item[3f] Sledijo trije argumenti realnih števil | 
                  
                          |   | 214 | \item[3i] Sledijo trije argumenti celih števil | 
                  
                          |   | 215 | \item[3fv] Sledi vektor treh realnih števil | 
                  
                          |   | 216 | \end{description} | 
                  
                          |   | 217 |  | 
                  
                          |   | 218 | Ker je GL v osnovi 3D pomeni, da so argumenti če sta podani le dve  | 
                  
                          |   | 219 | koordinati $x$ in $y$ v ravnini $z=0$. Torej je to ekvivalentno klicu | 
                  
                          |   | 220 | podprograma \emph{Vertex(x, y, 0)}. V našem primeru imamo | 
                  
                          |   | 221 | tudi nastavitev vozlišča z ukazom | 
                  
                          |   | 222 | \texttt{Vertex3f(0.8,0.8,1.0)}, ki podaja vse tri koordinate v | 
                  
                          |   | 223 | prostoru. Koordinata $z=1$ je torej podana, vendar je zaradi | 
                  
                          |   | 224 | privzetega začetnega ortografskega pogleda v prostor ravnine (x,y) | 
                  
                          |   | 225 | koordinata $z$ po globini neopazna. če pa bi bila projekcija | 
                  
                          |   | 226 | perspekvivna in ne ortogonalna, bi opazili tudi vpliv | 
                  
                          |   | 227 | koordinate $z$. Raznolikost tipov argumentov se pokaže ravno pri | 
                  
                          |   | 228 | podajanju vozlišč, saj obstajajo naslednjji podprogrami: | 
                  
                          |   | 229 | \emph{glVertex2d, glVertex2f, glVertex2i, glVertex2s, glVertex3d, | 
                  
                          |   | 230 |   glVertex3f, glVertex3i, glVertex3s, glVertex4d, glVertex4f, | 
                  
                          |   | 231 |   glVertex4i, glVertex4s, glVertex2dv, glVertex2fv, glVertex2iv, | 
                  
                          |   | 232 |   glVertex2sv, glVertex3dv, glVertex3fv, glVertex3iv, glVertex3sv, | 
                  
                          |   | 233 |   glVertex4dv, glVertex4fv, glVertex4iv, glVertex4sv}. In vse to za | 
                  
                          |   | 234 | en sam ukaz. | 
                  
                          |   | 235 |  | 
                  
                          |   | 236 | Namen velikega števila istih podprogramov za isto funkcijo je | 
                  
                          |   | 237 | opustitev pretvarjanja tipov in s tem pisanje bolj razumljive | 
                  
                          |   | 238 | in hitrejše kode. V jeziku C++ ali Java, ki pa sam dodaja ustrezne | 
                  
                          |   | 239 | argumente k imenom funkcij, pa bi lahko obstajal le en podprogram (npr. | 
                  
                          |   | 240 | \emph{glVertex}), jezik pa bi sam dodal ustrezne končnice in s tem | 
                  
                          |   | 241 | klical ustrezno funkcijo. | 
                  
                          |   | 242 |  | 
                  
                          |   | 243 | Izris grafičnih elementov risbe se v GL podaja med ukazoma | 
                  
                          |   | 244 | \emph{glBegin} in \emph{glEnd}.  Predmet risanja podamo kot argument v | 
                  
                          |   | 245 | ukazu \texttt{Begin}. Na splošno velja, da funkcije brez končnic | 
                  
                          |   | 246 | zahtevajo en sam argument s konstanto, ki je podana v \emph{header} | 
                  
                          |   | 247 | datoteki s končnico \texttt{.h} in se vključuje za začetek | 
                  
                          |   | 248 | programske enote s stavkom \texttt{include 'GL/fgl.h'}. Za fortran je | 
                  
                          |   | 249 | programska enota vsak podprogram, zato moramo pri vsakem | 
                  
                          |   | 250 | podprogramu, ki uporablja te konstante, na začetku dopisati | 
                  
                          |   | 251 | še vključevanje teh konstant. Za C je modul \emph{.c} | 
                  
                          |   | 252 | datoteka, in ni potrebno vključevanje definicij konstant za vsak | 
                  
                          |   | 253 | podprogram, kot je to nujno za Fortran.  | 
                  
                          |   | 254 |  | 
                  
                          |   | 255 | Vse te GL konstante, ki so napisane v \emph{fgl.h} in \emph{fglu.h} | 
                  
                          |   | 256 | imajo standardno predpono \texttt{GL\_} in je za vse jezike | 
                  
                          |   | 257 | enoznačen. Ker pa Fortran ne zahteva deklaracje spremenljivk in | 
                  
                          |   | 258 | ima implicitno definirane tipe je prav možno, da se zatipkamo pri | 
                  
                          |   | 259 | imenu konstante, kar za Fortran pomeni realno številko z | 
                  
                          |   | 260 | vrednostjo 0.0. Da se izognemo takim težavam, se priporoča | 
                  
                          |   | 261 | ukaz \emph{implicit none}, s katerim izključimo predpostavljene | 
                  
                          |   | 262 | tipe in moramo za vsako spremenljivko povedati, kakšnega tipa je. | 
                  
                          |   | 263 | žal pa F77 ne omogoča prototipov tako, da je še vedno | 
                  
                          |   | 264 | potrebna pazljivost, kakšne tipe podajamo kot argumente | 
                  
                          |   | 265 | podprogramom. Posebno to velja za podprograme \emph{GLU}, ki | 
                  
                          |   | 266 | običajno nimajo tako razvejanih možnosti argumentov, kot | 
                  
                          |   | 267 | knjižnica \emph{GL}. | 
                  
                          |   | 268 |  | 
                  
                          |   | 269 | Zadnji ukaz \texttt{glFlush} dopove GL stroju naj vse te ukaze, ki jih | 
                  
                          |   | 270 | je sprejel do sedaj, spravi iz svojih internih pomnilnikov v okno | 
                  
                          |   | 271 | okenskega sistema. Ker imamo v našem primeru le enostaven izris, | 
                  
                          |   | 272 | smo se odločili le za en slikovni pomnilnik | 
                  
                          |   | 273 | (\texttt{GLUT\_SINGLE}), ki je primeren le za statične slike. Za | 
                  
                          |   | 274 | aplikacije pri katerih se vsebina zaslona pogosto spreminja, je | 
                  
                          |   | 275 | primerneje uporabiti okno z dvema grafičnima pomnilnikoma | 
                  
                          |   | 276 | \texttt{GLUT\_DOUBLE}. Prednost slednjega je v tem, da v en pomnilnik | 
                  
                          |   | 277 | rišemo, drugega pa prikazujemo. Rišemo v ravnino, ki je v ozadju. | 
                  
                          |   | 278 | Ob koncu risanja pa le zamenjamo ravnini. Ker pa je to odvisno od | 
                  
                          |   | 279 | sistema se ukaz za zamenjavo risalnih ravnin imenuje | 
                  
                          |   | 280 | \texttt{glutSwapBuffers}. Prednost takega načina se pokaže pri | 
                  
                          |   | 281 | animacijah.  | 
                  
                          |   | 282 |  | 
                  
                          |   | 283 | = Geometrijski primitivi = | 
                  
                          |   | 284 | Uporabiti je mogoče le enostavne primitive.  To pa predvsem zaradi | 
                  
                          |   | 285 | zahtevane hitrosti in enostavosti izdelave strojnega pospeševanja. | 
                  
                          |   | 286 | Ločimo tri vrste teh enostavnih primitivov: | 
                  
                          |   | 287 | \begin{itemize} | 
                  
                          |   | 288 | \item točke ali pike | 
                  
                          |   | 289 | \item črte  | 
                  
                          |   | 290 | \item ploskvice konveksnega tipa | 
                  
                          |   | 291 | \end{itemize} | 
                  
                          |   | 292 | Bolj zahtevne predstavitve izvedemo z kombiniranjem teh primitivov. Tako | 
                  
                          |   | 293 | krivulje različnih tipov aproksimiramo z lomljenkami, površine | 
                  
                          |   | 294 | pa s ploskvicami. Za najbolj razširjene kompleksne tipe se že | 
                  
                          |   | 295 | nahajajo podprogrami v knjižnici \emph{GLU}. Obstajajo tudi | 
                  
                          |   | 296 | možnosti sestavljenih enostavnih gradnikov za črte in | 
                  
                          |   | 297 | ploskvice. Za črte poznamo tako naslednje možnosti: | 
                  
                          |   | 298 | \begin{description} | 
                  
                          |   | 299 | \item[GL\_LINES] Pari vozlišč podajajo posamezne segmente | 
                  
                          |   | 300 | \item[GL\_LINE\_STRIP] Zaporedje povezanih vozlišč podaja | 
                  
                          |   | 301 |   lomljenko | 
                  
                          |   | 302 | \item[GL\_LINE\_LOOP] Lomljenka se zaključi tako, da poveže | 
                  
                          |   | 303 |   prvo in zadnje vozlišče. | 
                  
                          |   | 304 | \end{description} | 
                  
                          |   | 305 | Konstante so podane kot argument za podprogram \emph{Begin}. Za | 
                  
                          |   | 306 | ploskve se podaja več točk. Najenostavnejše ploskve so | 
                  
                          |   | 307 | trikotniki. Možni so še ravninski štirikotniki in konveksni | 
                  
                          |   | 308 | ravninski mnogokotniki. Enostavne elemente lahko podajamo tudi v | 
                  
                          |   | 309 | pasovih in trikotnike v pahljačah: | 
                  
                          |   | 310 | \begin{description} | 
                  
                          |   | 311 | \item[GL\_TRIANGLES] Tri vozlišča za en trikotnik | 
                  
                          |   | 312 | \item[GL\_TRIANGLE\_STRIP] Pas trikotnikov. Tri vozlišča za | 
                  
                          |   | 313 |   prvi in nato vsako nadaljnje vozlišče k prejšnjemo | 
                  
                          |   | 314 |   trikotniku doda nov trikotnik.  | 
                  
                          |   | 315 | \item[GL\_TRIANGLE\_FAN] Pahljača: vsako dodatno vozlišče | 
                  
                          |   | 316 |   naredi dodaten trikotnik v smislu dežnika. | 
                  
                          |   | 317 | \item[GL\_QUADS] Ravninski štirikotnik se podaja s štirimi | 
                  
                          |   | 318 |   vozlišči. | 
                  
                          |   | 319 | \item[GL\_QUAD\_STRIP] Dodatni štirikotniki gradijo pas z | 
                  
                          |   | 320 |   dodajanjem parov vozlišč. | 
                  
                          |   | 321 | \item[GL\_POLYGON] En sam konveksni mogokotnik poljubnega števila | 
                  
                          |   | 322 |   vozlišč.  | 
                  
                          |   | 323 | \end{description} | 
                  
                          |   | 324 | Za nesestavljeni tipe gradnikov lahko med \emph{Begin} in \emph{End} | 
                  
                          |   | 325 | podamo tudi več vozlišč. Tip gradnika se pri pri tem | 
                  
                          |   | 326 | avtomatsko ponovi. Med \emph{Begin} in \emph{End} se lahko uporabljajo | 
                  
                          |   | 327 | še ukazi za barvo \emph{glColor} in normale \emph{glNormal}. Ti | 
                  
                          |   | 328 | ukazi nastavljajo trenutno stanje, ki velja za vsa naslednja | 
                  
                          |   | 329 | vozlišča. Primer podprograma za prikaz enega trikotnika v | 
                  
                          |   | 330 | ravnini je naslednji: | 
                  
                          |   | 331 | {\scriptsize | 
                  
                          |   | 332 | \begin{verbatim} | 
                  
                          |   | 333 | subroutine display | 
                  
                          |   | 334 | implicit none | 
                  
                          |   | 335 | include 'GL/fgl.h' | 
                  
                          |   | 336 | call fglClear(GL_COLOR_BUFFER_BIT) | 
                  
                          |   | 337 | call fglBegin(GL_TRIANGLES) | 
                  
                          |   | 338 | call fglColor3f(1.0, 0.0, 0.0) | 
                  
                          |   | 339 | call fglVertex2f(-1.0, -1.0) | 
                  
                          |   | 340 | call fglColor3f(0.0, 1.0, 0.0) | 
                  
                          |   | 341 | call fglVertex2f(0.0, 1.0) | 
                  
                          |   | 342 | call fglColor3f(0.0, 0.0, 1.0) | 
                  
                          |   | 343 | call fglVertex2f(1.0, 0.0) | 
                  
                          |   | 344 | call fglEnd | 
                  
                          |   | 345 | call fglFlush | 
                  
                          |   | 346 | end | 
                  
                          |   | 347 | \end{verbatim} | 
                  
                          |   | 348 | } | 
                  
                          |   | 349 | Pred vsako točko je podana še trenutna barva. Izrisani | 
                  
                          |   | 350 | trikotnik tako ni enotne barve ampak se njegova notranjost preliva iz | 
                  
                          |   | 351 | ene skrajne barve v drugo. Rezultat prikazuje slika \ref{fig:color-triangle}. | 
                  
                          |   | 352 | \begin{figure}[htbp] | 
                  
                          |   | 353 |   \centering | 
                  
                          |   | 354 |   \includegraphics[height=1.5in]{color-triangle} | 
                  
                          |   | 355 |   \caption{Trikotnik s podanimi barvami v vozliščih} | 
                  
                          |   | 356 |   \label{fig:color-triangle} | 
                  
                          |   | 357 | \end{figure} | 
                  
                          |   | 358 | Uporaba različnih barv v vozliščih  mogoče ni posebno | 
                  
                          |   | 359 | uporabna. Za podajanje normal pa je običajno potrebno, da so | 
                  
                          |   | 360 | normale v vozliščih različne. Različne normale v | 
                  
                          |   | 361 | vozliščih nastajajo povsod tam kjer imajo ploskvice skupen rob, | 
                  
                          |   | 362 | za katerega želimo, da ima gladek prehod. To pa je povsod tam, kjer | 
                  
                          |   | 363 | aproksimiramo ,,gladko`` površino z osnovnimi gradniki.  Slika | 
                  
                          |   | 364 | \ref{fig:normala} kaže splošno postavitev treh točk v | 
                  
                          |   | 365 | prostoru.  | 
                  
                          |   | 366 | \begin{figure}[htbp] | 
                  
                          |   | 367 |   \centering | 
                  
                          |   | 368 |   \includegraphics{normal0} | 
                  
                          |   | 369 |   \caption{Normala} | 
                  
                          |   | 370 |   \label{fig:normala} | 
                  
                          |   | 371 | \end{figure} | 
                  
                          |   | 372 | Normalo za trikotnik | 
                  
                          |   | 373 | z vozlišči $\vec{r}_0, \vec{r}_1, \vec{r}_2$ izračunamo z | 
                  
                          |   | 374 | vektorskim produktom | 
                  
                          |   | 375 | $$ \vec{n} = \frac{  (\vec{r}_1-\vec{r}_0)\times (\vec{r}_2-\vec{r}_0) } | 
                  
                          |   | 376 |     {|(\vec{r}_1-\vec{r}_0)\times (\vec{r}_2-\vec{r}_0)|}  | 
                  
                          |   | 377 | $$ | 
                  
                          |   | 378 |      | 
                  
                          |   | 379 | Imenovalec zgornje enačbe je dolžina vektorja $\vec{n}$. | 
                  
                          |   | 380 | Normala je pravokotna na razliko vektorjev, ki podajajo | 
                  
                          |   | 381 | vozlišče gradnika. | 
                  
                          |   | 382 |  | 
                  
                          |   | 383 |  | 
                  
                          |   | 384 | = Geometrijske transformacije = | 
                  
                          |   | 385 | Osnova vseh grafičnih knjižnic so tudi osnovne geometrijske | 
                  
                          |   | 386 | transformacije, kot so:   | 
                  
                          |   | 387 | \begin{description} | 
                  
                          |   | 388 | \item[Translate(x, y, z)] Premik v smeri vektorja | 
                  
                          |   | 389 | \item[Rotate(fi, x, y, z)]  Rotacija za \emph{fi} stopinj okoli osi | 
                  
                          |   | 390 |   podane z  (x, y, z) | 
                  
                          |   | 391 | \item[Scale(x, y, z)] Skaliranje po posameznih oseh  | 
                  
                          |   | 392 | \end{description} | 
                  
                          |   | 393 | Ukazi za transformacije se ne smejo pojavljati med \emph{Begin/End}, | 
                  
                          |   | 394 | saj bi to pomenilo, da se transformacija spreminja med izrisom. | 
                  
                          |   | 395 | Geometrijske transformacije nam pomagajo pri modeliranju, saj lahko | 
                  
                          |   | 396 | podajamo vozlišča gradnikov v nekem poljubnem koordinatnem | 
                  
                          |   | 397 | sistemu. To je lahko svetovni koordinatni sistem ali lokalni | 
                  
                          |   | 398 | koordinatni sistem. Za primer izberimo izris krivulje $y(x)=\sin(x)$ v | 
                  
                          |   | 399 | jeziku GL. Kot smo že opazili, je prednastavljeno okno v GLUT | 
                  
                          |   | 400 | obliki kvadrata, velikosti (-1,-1) do (1,1). Vsega skupaj torej dve | 
                  
                          |   | 401 | enoti. V zaslonskih koordinatah je prednastavljena velikost okna | 
                  
                          |   | 402 | $300\times 300$ pikslov. Za nas je pomembno, da sinus narišemo v | 
                  
                          |   | 403 | mejah od -1 do 1. Vzemimo primer, ko predvidimo število točk. | 
                  
                          |   | 404 | Podprogram za izris je naslednji: | 
                  
                          |   | 405 |  | 
                  
                          |   | 406 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 407 | subroutine display | 
                  
                          |   | 408 | include 'GL/fgl.h' | 
                  
                          |   | 409 | call fglClear(GL_COLOR_BUFFER_BIT) | 
                  
                          |   | 410 | call fglBegin(GL_LINE_STRIP) | 
                  
                          |   | 411 | do i=0,10 | 
                  
                          |   | 412 |   y = sin((i-5)/5.0*3.14) | 
                  
                          |   | 413 |   call fglVertex2f((i-5)/5.0, y/3.14) | 
                  
                          |   | 414 | end do | 
                  
                          |   | 415 | call fglEnd | 
                  
                          |   | 416 | call fglFlush | 
                  
                          |   | 417 | end | 
                  
                          |   | 418 | \end{verbatim}} | 
                  
                          |   | 419 | Da smo spravili naših 11 točk lomljenke v okvir -1, 1 je bilo | 
                  
                          |   | 420 | potrebno premakniti koordinatni sistem osi $x$ za 5, ga nato še | 
                  
                          |   | 421 | skalirati tako, da smo iz območja [0,10] dobili območje [-3.14, | 
                  
                          |   | 422 | 3.14]. čeprav smo za izračun koordinate y potrebovali na osi x | 
                  
                          |   | 423 | območje [-3.14, 3.14] pa je potrebna os $x$ za izris v območju | 
                  
                          |   | 424 | [-1,1]. Zato pri izrisu podajamo os $x$ tako, da ponovno | 
                  
                          |   | 425 | poračunavamo območje [0,10] v območje [-1,1], tako da \texttt{i}-ju | 
                  
                          |   | 426 | odštejemo 5 in delimo z 5. Lahko bi tudi delili s 5 in odšteli | 
                  
                          |   | 427 | 1. Nekoliko bi poenostavili stvari, če bi imeli vsaj en kordinatni | 
                  
                          |   | 428 | sistem že takoj uporaben. Recimo os $x$. Zanka se nekoliko | 
                  
                          |   | 429 | poenostavi, še vedno pa je potrebno vse koordinate pomanjšati | 
                  
                          |   | 430 | za 3.14 oziroma poskalirati. | 
                  
                          |   | 431 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 432 | do x=-3.14, 3.14, 0.6 | 
                  
                          |   | 433 | y = sin(x) | 
                  
                          |   | 434 | call fglVertex2f(x/3.14, y/3.14) | 
                  
                          |   | 435 | end do | 
                  
                          |   | 436 | \end{verbatim}} | 
                  
                          |   | 437 | Bolj razumljivo bi bilo risati kar v lokalnem koordinatnem sistemu in | 
                  
                          |   | 438 | prednastaviti pomanjšavo modela. Za pomanjšavo uporabimo | 
                  
                          |   | 439 | ukaz za skaliranje, ki posamezne koordinate množi s konstanto 1/3.14, | 
                  
                          |   | 440 | preden se izriše. Podprogram za izris je naslednji: | 
                  
                          |   | 441 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 442 | subroutine display | 
                  
                          |   | 443 | include 'GL/fgl.h' | 
                  
                          |   | 444 | call fglClear(GL_COLOR_BUFFER_BIT) | 
                  
                          |   | 445 | call fglScalef(1/3.14, 1/3.14, 1.0) | 
                  
                          |   | 446 | call fglBegin(GL_LINE_STRIP) | 
                  
                          |   | 447 | do x=-3.14, 3.14, 0.6 | 
                  
                          |   | 448 | y = sin(x) | 
                  
                          |   | 449 | call fglVertex2f(x, y) | 
                  
                          |   | 450 | end do | 
                  
                          |   | 451 | call fglEnd | 
                  
                          |   | 452 | call fglFlush | 
                  
                          |   | 453 | end | 
                  
                          |   | 454 | \end{verbatim}} | 
                  
                          |   | 455 | Prednost takega načina razmišljanja se pokaže, že ko | 
                  
                          |   | 456 | želimo pod sinusom narisati še krivuljo kosinusa. Seveda ni | 
                  
                          |   | 457 | možno obeh krivulj risati z \emph{GL\_LINE\_STRIP} v isti | 
                  
                          |   | 458 | zanki. Zato se odločimo za ponovno risanje v lokalnem | 
                  
                          |   | 459 | koordinatnem sistemu in prednastavimo pomik navzdol za 1.5 enote. | 
                  
                          |   | 460 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 461 | subroutine display | 
                  
                          |   | 462 | include 'GL/fgl.h' | 
                  
                          |   | 463 | call fglClear(GL_COLOR_BUFFER_BIT) | 
                  
                          |   | 464 | call fglScalef(1/3.14, 1/3.14, 1.0) | 
                  
                          |   | 465 | call fglBegin(GL_LINE_STRIP) | 
                  
                          |   | 466 | do x=-3.14, 3.14, 0.6 | 
                  
                          |   | 467 | y = sin(x) | 
                  
                          |   | 468 | call fglVertex2f(x, y) | 
                  
                          |   | 469 | end do | 
                  
                          |   | 470 | call fglEnd | 
                  
                          |   | 471 | call fglTranslatef(0.0, -1.5, 0.0) | 
                  
                          |   | 472 | call fglBegin(GL_LINE_STRIP) | 
                  
                          |   | 473 | do x=-3.14, 3.14, 0.6 | 
                  
                          |   | 474 | y = cos(x) | 
                  
                          |   | 475 | call fglVertex2f(x, y) | 
                  
                          |   | 476 | end do | 
                  
                          |   | 477 | call fglEnd | 
                  
                          |   | 478 | call fglFlush | 
                  
                          |   | 479 | end | 
                  
                          |   | 480 | \end{verbatim}} | 
                  
                          |   | 481 | Podani program za kosinus ne nastavlja ponovno skaliranja, saj je ukaz | 
                  
                          |   | 482 | že pred tem nastavil pomanjšavo. Translacija za -1.5 se izvede | 
                  
                          |   | 483 | v koordinatnem sistemu kosinusa. Splošen napotek za razumevanje | 
                  
                          |   | 484 | transformacije vsakega vozlišča je, da se za podano koordinato | 
                  
                          |   | 485 | upoštevajo transformacije, kot so napisane od spodaj na | 
                  
                          |   | 486 | vzgor. Transformacija, ki se izvede zadnja je torej napisana na prvem | 
                  
                          |   | 487 | mestu v programu. Tak način transformiranja točk nam | 
                  
                          |   | 488 | omogoča enostavnejše modeliranje. Koordinata $y$ kosinusa se | 
                  
                          |   | 489 | izračuna tako, da se pred izrisom najprej vsaki točki $y$ | 
                  
                          |   | 490 | prišteje translacija -1.5 in potem se še izvede skaliranje | 
                  
                          |   | 491 | tako, da se ta vmesna točka pomnoži še z 1/3.14.  | 
                  
                          |   | 492 |  | 
                  
                          |   | 493 |  | 
                  
                          |   | 494 | \subsection{Nadzor transformacijske matrike} | 
                  
                          |   | 495 | OpenGL pa za izračun koordinat ne hrani vse zgodovine posameznih | 
                  
                          |   | 496 | transformacij za nazaj, saj bi bilo to računsko potratno. Vse te | 
                  
                          |   | 497 | transformacije, ki jih v poljubnem zaporedju navajamo v programu, | 
                  
                          |   | 498 | popravljajo transformacijsko matriko. OpenGL ima le dve aktivni | 
                  
                          |   | 499 | transformacijski matriki, ki jih uporablja za poračun koordinat. | 
                  
                          |   | 500 | Prva matrika je modelna, druga pa je projekcijska. Mi bomo | 
                  
                          |   | 501 | uporabljali le modelno transformacijo in upoštevali, da | 
                  
                          |   | 502 | projekcijska matrika omogoča prikaz ravnine $(x,y)$ v področju | 
                  
                          |   | 503 | [-1,1]. Modelna matrika je tudi stalno aktivna, če se ne | 
                  
                          |   | 504 | izbere projekcijsko. | 
                  
                          |   | 505 |  | 
                  
                          |   | 506 | Modelna matrika se ob vsakem klicu transformacijskega podprograma | 
                  
                          |   | 507 | popravi. Začetna oblika modelne matrike je enotska. Vsak klic | 
                  
                          |   | 508 | podprograma \emph{Translate}, \emph{Scale} in \emph{Rotate} pa matriko | 
                  
                          |   | 509 | popravi tako, da so upoštevane vse prejšnje transformacije in | 
                  
                          |   | 510 | nad njimi še novo podana transformacija. Matrika je torej stalna, | 
                  
                          |   | 511 | kar se kaže tudi v napaki prejšnjega programa za izris sinusa | 
                  
                          |   | 512 | in kosinusa, ki je pri vsakem ponovnem izrisu trikrat manjši. To | 
                  
                          |   | 513 | lahko preverimo tako, da okno prekrijemo s kakim drugim oknom in ga | 
                  
                          |   | 514 | potem ponovno odkrijemo. Kot že omenjeno, je na začetku | 
                  
                          |   | 515 | programa matrika enotska. S podprogramom \emph{fglLoadIdentity} na | 
                  
                          |   | 516 | začetku bi lahko to tudi zagotovili ob vsakem izrisu. | 
                  
                          |   | 517 |  | 
                  
                          |   | 518 | Za bolj zahtevne transformacije je potrebno matriko začasno | 
                  
                          |   | 519 | shraniti in obnoviti. OpenGL ima v ta namen poseben pomnilnik v obliki | 
                  
                          |   | 520 | sklada, v katerega lahko shranjujemo trenutno | 
                  
                          |   | 521 | transformacijsko matriko. V pomnilniku oblike LIFO (\emph{Last In, | 
                  
                          |   | 522 |   First Out}) je prostora je za najmanj 32 matrik. Pomnilnik si lahko | 
                  
                          |   | 523 | predstavljamo kot hladilnik, v katerega shranjujemo matrike. Matriko, ki | 
                  
                          |   | 524 | jo želimo shraniti, potisnemo na začetek in to tako, da | 
                  
                          |   | 525 | vse ostale matrike potisnemo malo naprej na polici. Ko nekaj želimo | 
                  
                          |   | 526 | iz hladilnika, je to lahko le zadnja matrika. če | 
                  
                          |   | 527 | želimo predzadnjo, moramo poprej vzeti zadnjo. Za shranitev | 
                  
                          |   | 528 | trenutne matrike se uporabi \textbf{glPushMatrix}, za ponastavitev iz | 
                  
                          |   | 529 | sklada pa uporabimo \textbf{glPopMatrix}. Izkaže se, da je za | 
                  
                          |   | 530 | modeliranje taka oblika pomnilnika povsem primerna.  | 
                  
                          |   | 531 |  | 
                  
                          |   | 532 | Za primer vzemimo primer kocke sestavljene iz šestih ploskev. Za | 
                  
                          |   | 533 | izris kvadrata obstaja že krajša funkcija \texttt{glRectf(x1, | 
                  
                          |   | 534 |   y1, x2, y2)} za ravnino $z=0$. če želimo imeti kvadrat v | 
                  
                          |   | 535 | poljubni ravnini, pa uporabimo transformacije.  | 
                  
                          |   | 536 | {\scriptsize | 
                  
                          |   | 537 | \begin{verbatim} | 
                  
                          |   | 538 | subroutine kvadrat(i) | 
                  
                          |   | 539 | real r(6), g(6), b(6) | 
                  
                          |   | 540 | data r /1,0,0,1,1,1/, g /0,1,0,1,0,0/ | 
                  
                          |   | 541 | data b /0,0,1,0,1,1/ | 
                  
                          |   | 542 | call fglPushMatrix | 
                  
                          |   | 543 | call fglColor3f(r(i), g(i), b(i)) | 
                  
                          |   | 544 | call fglTranslatef(0.0, 0.0, 1.0) | 
                  
                          |   | 545 | call fglRectf(-1.0, -1.0, 1.0, 1.0) | 
                  
                          |   | 546 | call fglPopMatrix | 
                  
                          |   | 547 | end | 
                  
                          |   | 548 |  | 
                  
                          |   | 549 | subroutine display | 
                  
                          |   | 550 | implicit none | 
                  
                          |   | 551 | include 'GL/fgl.h' | 
                  
                          |   | 552 | call fglClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT) | 
                  
                          |   | 553 | call fglPushMatrix | 
                  
                          |   | 554 | call fglRotatef(30.0, 1.0, 0.0, 0.0) | 
                  
                          |   | 555 | call fglRotatef(30.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 556 | call fglScalef(0.5, 0.5, 0.5) | 
                  
                          |   | 557 | call kvadrat(1) | 
                  
                          |   | 558 | call fglRotatef(90.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 559 | call kvadrat(2) | 
                  
                          |   | 560 | call fglRotatef(90.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 561 | call kvadrat(3) | 
                  
                          |   | 562 | call fglRotatef(90.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 563 | call kvadrat(4) | 
                  
                          |   | 564 | call fglRotatef(90.0, 1.0, 0.0, 0.0) | 
                  
                          |   | 565 | call kvadrat(5) | 
                  
                          |   | 566 | call fglRotatef(180.0, 1.0, 0.0, 0.0) | 
                  
                          |   | 567 | call kvadrat(6) | 
                  
                          |   | 568 | call fglPopMatrix | 
                  
                          |   | 569 | call fglFlush | 
                  
                          |   | 570 | end | 
                  
                          |   | 571 |  | 
                  
                          |   | 572 | program kocka | 
                  
                          |   | 573 | external display | 
                  
                          |   | 574 | include 'GL/fglut.h' | 
                  
                          |   | 575 | include 'GL/fgl.h' | 
                  
                          |   | 576 | call fglutinit | 
                  
                          |   | 577 | call fglutInitDisplayMode(GLUT_SINGLE+GLUT_DEPTH) | 
                  
                          |   | 578 | call fglutCreateWindow('Fortran GLUT program') | 
                  
                          |   | 579 | call fglutDisplayFunc(display) | 
                  
                          |   | 580 | call fglEnable(GL_DEPTH_TEST) | 
                  
                          |   | 581 | call fglutmainloop | 
                  
                          |   | 582 | end | 
                  
                          |   | 583 | \end{verbatim} | 
                  
                          |   | 584 | } Podprogram \emph{kvadrat} je narejen tako, da riše transliran | 
                  
                          |   | 585 | kvadrat v ravnini $z=1$. To lahko razumemo kot nov primitiv, saj par | 
                  
                          |   | 586 | ukazov Push/Pop ne popravlja transformacije ob klicu podprograma. | 
                  
                          |   | 587 | šest stranic se riše z rotacijo osnovne stranice okoli osi y | 
                  
                          |   | 588 | in x. Modelna matrika se shani z začetnim ukazom \emph{Push} in | 
                  
                          |   | 589 | potem ponovno obnovi z ukazom \emph{Pop}. | 
                  
                          |   | 590 |  | 
                  
                          |   | 591 |  | 
                  
                          |   | 592 | \subsection{Globinski pomilnik} | 
                  
                          |   | 593 | Da se ploskve v prostoru pravilno izrisujejo tudi takrat, ko | 
                  
                          |   | 594 | rišemo ploskvice za drugimi, je potrebno uporabiti globinski | 
                  
                          |   | 595 | pomnilnik ali \emph{z-buffer}. To pa mora omogočati že sam | 
                  
                          |   | 596 | okenski sistem, zato je potrebno tak način prikaza zahtevati že | 
                  
                          |   | 597 | pri \texttt{fglutInitDisplayMode} in kasneje še dopovedati GL | 
                  
                          |   | 598 | stroju, da poleg barve točk na zaslonu shranjuje še koordinato | 
                  
                          |   | 599 | $z$ v svoj pomnilnik. S tem pomnilnikom GL ob rasterizaciji lika za | 
                  
                          |   | 600 | vsako točko ugotovi, če je že kakšna točka po | 
                  
                          |   | 601 |  globini pred njim in jo zato ne riše. Z ukazom | 
                  
                          |   | 602 | \texttt{fglEnable(GL\_DEPTH\_TEST)} se zahteva izračunavanje | 
                  
                          |   | 603 | globine, ki jo je potrebno tako kot barvo pred vsakim začetkom | 
                  
                          |   | 604 | risanja pobrisati z ukazom \texttt{fglClear}. | 
                  
                          |   | 605 |  | 
                  
                          |   | 606 | \begin{figure}[htbp] | 
                  
                          |   | 607 |   \centering | 
                  
                          |   | 608 |   \includegraphics{half-cube} | 
                  
                          |   | 609 |   \caption{Kocka brez spodnjega in zgornjega pokrova (kvadrat(5) in kvadrat(6)} | 
                  
                          |   | 610 |   \label{fig:half-cube} | 
                  
                          |   | 611 | \end{figure} | 
                  
                          |   | 612 |  | 
                  
                          |   | 613 | če rišemo zaprte modele, potem notranjosti ni možno | 
                  
                          |   | 614 | videti. Primer odprtega modela kaže slika \ref{fig:half-cube}. V | 
                  
                          |   | 615 | takih primerih se ob uporabi prostorskega pomnilnika običajno kar | 
                  
                          |   | 616 | polovica ploskvic modela prekrije v celoti in kasneje na zaslonu ni | 
                  
                          |   | 617 | vidna. Skupna značilnost vseh teh ploskvic, ki se prekrijejo je, | 
                  
                          |   | 618 | da imajo normalo površine negativno ($n_z < 0$). Da se izogemo | 
                  
                          |   | 619 | nepotrebni rasterizaciji teh ploskvic, vključimo | 
                  
                          |   | 620 | \texttt{GL\_CULL\_FACE}. Da pa bo izločanje delovalo, mora imeti | 
                  
                          |   | 621 | GL podatek za normalo površine, ki jo je potrebno podati pred | 
                  
                          |   | 622 | podatki v vozliščih. Za pravilno delovanje globinskega | 
                  
                          |   | 623 | pomnilnika je potrebna tudi nastavitev projekcijske matrike kot je to | 
                  
                          |   | 624 | opisano v \S\ref{sec:viewing}. | 
                  
                          |   | 625 |  | 
                  
                          |   | 626 | \subsection{Animacija} | 
                  
                          |   | 627 | \label{sec:animate} | 
                  
                          |   | 628 | Imejmo primer animacije vozil na avtocesti. Predstavljeno bo | 
                  
                          |   | 629 | cestišče v eno smer z dvema pasovoma, voznim in prehitevalnim. | 
                  
                          |   | 630 | Vozila imajo začetni položaj in hitrost. Opazujemo | 
                  
                          |   | 631 | vozišče dolžine 500 metrov. Hitrost vozila med vožnjo se ne | 
                  
                          |   | 632 | spreminja. Spreminja se le položaj vozil (x, y) na | 
                  
                          |   | 633 | cestišču, ki jih izriše  podprogram \texttt{vozilo}. | 
                  
                          |   | 634 |  | 
                  
                          |   | 635 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 636 | subroutine display | 
                  
                          |   | 637 | implicit none | 
                  
                          |   | 638 | include 'GL/fgl.h' | 
                  
                          |   | 639 | common /vozila/ y(5), v(5) | 
                  
                          |   | 640 | real y, v, pas | 
                  
                          |   | 641 | integer i | 
                  
                          |   | 642 | data y /0,50,120,170,200/ | 
                  
                          |   | 643 | data v /50,30,45,31,33/ | 
                  
                          |   | 644 | call fglClear(GL_COLOR_BUFFER_BIT) | 
                  
                          |   | 645 | call fglPushMatrix | 
                  
                          |   | 646 | call fglRotatef(-45.0, 0.0, 0.0, 1.0) | 
                  
                          |   | 647 | call fglTranslatef(0.0, -1.0, 0.0) | 
                  
                          |   | 648 | call fglScalef(0.004, 0.004, 0.004) | 
                  
                          |   | 649 | call fglColor3f(0.0, 0.0, 0.0) | 
                  
                          |   | 650 | call fglRectf(-4.0, 0.0, 4.0, 500.0) | 
                  
                          |   | 651 | call fglTranslatef(0.0, -50.0, 0.0) | 
                  
                          |   | 652 | do i=1,5 | 
                  
                          |   | 653 |    if (i.ne.5 .and. y(i+1)-y(i).lt.10.0) then | 
                  
                          |   | 654 |      pas=-2.0 | 
                  
                          |   | 655 |    else | 
                  
                          |   | 656 |       pas = 2.0 | 
                  
                          |   | 657 |    end if | 
                  
                          |   | 658 |    call vozilo(y(i), pas) | 
                  
                          |   | 659 | end do | 
                  
                          |   | 660 | call fglPopMatrix | 
                  
                          |   | 661 | call fglutSwapBuffers | 
                  
                          |   | 662 | end | 
                  
                          |   | 663 |  | 
                  
                          |   | 664 | subroutine vozilo(y, pas) | 
                  
                          |   | 665 | call fglPushMatrix | 
                  
                          |   | 666 | call fglColor3f(1.0, 1.0, 1.0) | 
                  
                          |   | 667 | call fglTranslatef(pas, y, 0.5) | 
                  
                          |   | 668 | call fglRectf(-2.0, 0.0, 2.0, 6.0) | 
                  
                          |   | 669 | call fglPopMatrix | 
                  
                          |   | 670 | end | 
                  
                          |   | 671 |  | 
                  
                          |   | 672 | subroutine ura(n) | 
                  
                          |   | 673 | common /vozila/ y(5), v(5) | 
                  
                          |   | 674 | real y, v, dt | 
                  
                          |   | 675 | dt = 0.1 | 
                  
                          |   | 676 | do i=1,5 | 
                  
                          |   | 677 |   y(i)=y(i)+v(i)*dt | 
                  
                          |   | 678 | end do | 
                  
                          |   | 679 | call fglutPostRedisplay | 
                  
                          |   | 680 | call fglutTimerfunc(100, ura, 0) | 
                  
                          |   | 681 | end | 
                  
                          |   | 682 |  | 
                  
                          |   | 683 | program Mad Max | 
                  
                          |   | 684 | external display | 
                  
                          |   | 685 | external ura | 
                  
                          |   | 686 | include 'GL/fglut.h' | 
                  
                          |   | 687 | integer window | 
                  
                          |   | 688 | call fglutInit | 
                  
                          |   | 689 | call fglutInitDisplayMode(GLUT_RGB+GLUT_DOUBLE) | 
                  
                          |   | 690 | call fglutCreateWindow('Avtocesta') | 
                  
                          |   | 691 | call fglClearColor(0.0, 0.5, 0.0, 0.0) | 
                  
                          |   | 692 | call fglutDisplayFunc(display) | 
                  
                          |   | 693 | call fglutTimerFunc(100, ura, 0) | 
                  
                          |   | 694 | call fglutMainLoop | 
                  
                          |   | 695 | end | 
                  
                          |   | 696 | \end{verbatim} | 
                  
                          |   | 697 | } | 
                  
                          |   | 698 |  | 
                  
                          |   | 699 | Pas predstavlja odmik v smeri $x$ od sredine cestišča. Vse | 
                  
                          |   | 700 | enote so v metrih. Vozilo je zaradi sorazmerja narisano | 
                  
                          |   | 701 | nekoliko večje. Za animacije je primernejša uporaba dvojnega | 
                  
                          |   | 702 | pomnilnika \texttt{GLUT\_DOUBLE}. S tem se izognemo težavam izrisa, | 
                  
                          |   | 703 | saj v trenutku, ko se zgornja plast izrisuje, nemoteno rišemo v | 
                  
                          |   | 704 | spodnjo plast. Ko je spodnja plast izdelana z ukazom | 
                  
                          |   | 705 | \emph{fglutSwapBuffers}, zamenjamo trenutni prikaz. | 
                  
                          |   | 706 |  | 
                  
                          |   | 707 | Za animacijo, pri kateri je zahtevano točno časovno zaporedje je | 
                  
                          |   | 708 | primerno uporabiti uro (\emph{timer}), ki program opozori, da je | 
                  
                          |   | 709 | pretekel predpisani čas in da je potrebno izračunati nov | 
                  
                          |   | 710 | položaj vozil. V našem primeru je podana spremeba vsakih 100~ms | 
                  
                          |   | 711 | in zato nov položaj v smeri $y$ linearno narašča za $v(i) | 
                  
                          |   | 712 | dt$, kjer je hitrost podana v metrih na sekundo. Izbor 0.1s za premik | 
                  
                          |   | 713 | pomeni 1/0.1=10 posnetkov na sekundo, kar je spodnja meja pri | 
                  
                          |   | 714 | animacijah. Po poračunu novih položajev pošljemo | 
                  
                          |   | 715 | sporočilo \emph{fglutPostRedisplay}, da se na novo izriše | 
                  
                          |   | 716 | scena. Lahko bi tudi neposredno klicali \texttt{display}, vendar bi | 
                  
                          |   | 717 | bilo potem potrebno zagotoviti še kompenzacijo hitrosti, saj | 
                  
                          |   | 718 | že v podprogramu ura izgubimo nekaj časa pri izrečunu | 
                  
                          |   | 719 | novih položajev. Prostorski pomnilnik v tem primeru ni potreben, | 
                  
                          |   | 720 | saj je zagotovljeno, da se izrisi prekrijejo v pravilnem vrstnem redu. | 
                  
                          |   | 721 |  | 
                  
                          |   | 722 | \subsection{Transformacije pogleda} | 
                  
                          |   | 723 | \label{sec:viewing} | 
                  
                          |   | 724 | Za zahtevnejše načine gledanja na model je potrebno nastaviti | 
                  
                          |   | 725 | projekcijo modela iz svetovnih koordinat v normalizirane oz. zaslonske | 
                  
                          |   | 726 | koordinate. V praksi obstajata dva načina projekcije: ortografska in | 
                  
                          |   | 727 | perspektivna. V tehniški predstavitvah se uporablja predvsem | 
                  
                          |   | 728 | paralelna oz. ortografska projekcija. Le v primeru animacije, kjer | 
                  
                          |   | 729 | želimo poudariti bližino in oddaljenost določenih | 
                  
                          |   | 730 | objektov, se uporablja tudi perspektivna projekcija. | 
                  
                          |   | 731 | \begin{figure}[htbp] | 
                  
                          |   | 732 |   \centering | 
                  
                          |   | 733 |   \includegraphics[width=3in]{viewing} | 
                  
                          |   | 734 |   \caption{Zaporedje pretvorbe koordinat vozlišč} | 
                  
                          |   | 735 |   \label{fig:viewing} | 
                  
                          |   | 736 | \end{figure} | 
                  
                          |   | 737 |  | 
                  
                          |   | 738 | OpenGL ločuje projekcijsko matriko in modelno matriko zato, | 
                  
                          |   | 739 | da ni potrebno nastavljati projekcije pri vsakem izrisu.  Slika | 
                  
                          |   | 740 | \ref{fig:viewing} kaže zaporedje transformacij iz svetovnih | 
                  
                          |   | 741 | koordinat v zaslonske. Pri risanju modela običajno začnemo z | 
                  
                          |   | 742 | enotsko \emph{ModelView} matriko.  | 
                  
                          |   | 743 |  | 
                  
                          |   | 744 | Najpreprostejši način prikaza, kot je bil prikazan tudi v | 
                  
                          |   | 745 | dosedanjih primerih je, da stlačimo naš model s | 
                  
                          |   | 746 | transformacijami v privzete normalizirane koordinate [-1, 1]. Pri tem | 
                  
                          |   | 747 | načinu sta tako modelna kot projekcijska matrika enotski. Modelna | 
                  
                          |   | 748 | matrika je enotska le na začetku vsakega risanja, projekcijska pa | 
                  
                          |   | 749 | je konstantna ves čas. Pri takem načinu ni potrebno | 
                  
                          |   | 750 | preklapljati med trenutno aktivnima projekcijama. In če se | 
                  
                          |   | 751 | zadovoljimo s takim načinom, potem zadostuje tudi | 
                  
                          |   | 752 | privzeta zaslonska transformacija pri spremembi velikosti okna, ki je | 
                  
                          |   | 753 | pri sistemu GLUT le enovrstičen ukaz: | 
                  
                          |   | 754 |  | 
                  
                          |   | 755 | {\scriptsize\texttt{call fglViewport (0, 0, width, height)}} | 
                  
                          |   | 756 |  | 
                  
                          |   | 757 | Nekoliko zahtevnejša je sorazmerna sprememba, | 
                  
                          |   | 758 | ki ne bo anamorfično popravljala velikosti okna: | 
                  
                          |   | 759 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 760 | subroutine  reshape (w, h) | 
                  
                          |   | 761 | integer w, h | 
                  
                          |   | 762 | implicit none | 
                  
                          |   | 763 | include 'GL/fgl.h' | 
                  
                          |   | 764 | common /viewport/ width, height | 
                  
                          |   | 765 | integer width, height | 
                  
                          |   | 766 | real*8 left, right, bottom, top, znear, zfar | 
                  
                          |   | 767 | width = w | 
                  
                          |   | 768 | height = h | 
                  
                          |   | 769 | if (w .ge. h) then | 
                  
                          |   | 770 |         left = -width/(1.0*height) | 
                  
                          |   | 771 |         right = width/(1.0*height) | 
                  
                          |   | 772 |         bottom = -1.0 | 
                  
                          |   | 773 |         top = 1.0 | 
                  
                          |   | 774 | else | 
                  
                          |   | 775 |         left = -1.0 | 
                  
                          |   | 776 |         right = 1.0 | 
                  
                          |   | 777 |         bottom = -height/(1.0*width) | 
                  
                          |   | 778 |         top = height/(1.0*width) | 
                  
                          |   | 779 | end if | 
                  
                          |   | 780 | znear = -1.0 | 
                  
                          |   | 781 | zfar = 1.0 | 
                  
                          |   | 782 | call fglViewport (0, 0, width, height) | 
                  
                          |   | 783 | call fglMatrixMode (GL_PROJECTION) | 
                  
                          |   | 784 | call fglLoadIdentity | 
                  
                          |   | 785 | call fglOrtho(left, right, bottom, top, znear, zfar) | 
                  
                          |   | 786 | call fglMatrixMode(GL_MODELVIEW) | 
                  
                          |   | 787 | end | 
                  
                          |   | 788 | \end{verbatim} | 
                  
                          |   | 789 | } | 
                  
                          |   | 790 |      | 
                  
                          |   | 791 | Predstavljeni podprogram se priporoča v uporabo za vse programe, | 
                  
                          |   | 792 | ki pripravljajo model v velikosti [-1,~1] za \emph{ModelView}. če | 
                  
                          |   | 793 | bi želeli dodati modelno transformacijo v \emph{reshape}, potem za | 
                  
                          |   | 794 | zadnjo vrstico dopišemo še modelno transformacijo in nato v | 
                  
                          |   | 795 | programu za izris pred začetkom le obnovimo stanje modelne | 
                  
                          |   | 796 | matrike. Primer animacije \ref{sec:animate} bi tako imel namesto | 
                  
                          |   | 797 | nastavitve modelne transformacije slednje v podprogramu \emph{reshape}. | 
                  
                          |   | 798 | Začetna nastavitev modelne matrike pred začetkom izrisa v | 
                  
                          |   | 799 | podprogramu \emph{display} pa bi bila: | 
                  
                          |   | 800 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 801 | call fglClear(GL_COLOR_BUFFER_BIT) | 
                  
                          |   | 802 | call fglPushMatrix | 
                  
                          |   | 803 | ... izris | 
                  
                          |   | 804 | call fglPopMatrix | 
                  
                          |   | 805 | \end{verbatim} | 
                  
                          |   | 806 | } | 
                  
                          |   | 807 | Takoj za brisanjem zaslona z ukazom \emph{Push} shranimo modelno | 
                  
                          |   | 808 | matriko in jo ob koncu ponovno nastavimo na začetno vrednost. | 
                  
                          |   | 809 | V podprogramu \emph{reshape}, pa modelno matriko popravljamo: | 
                  
                          |   | 810 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 811 | call fglMatrixMode(GL_MODELVIEW) | 
                  
                          |   | 812 | call fglLoadIdentity | 
                  
                          |   | 813 | call fglRotatef(-45.0, 0.0, 0.0, 1.0) | 
                  
                          |   | 814 | call fglTranslatef(0.0, -1.0, 0.0) | 
                  
                          |   | 815 | call fglScalef(0.004, 0.004, 0.004) | 
                  
                          |   | 816 | \end{verbatim} | 
                  
                          |   | 817 | } | 
                  
                          |   | 818 | Tak pristop nekoliko jasneje predstavi program, saj so vse enote, s | 
                  
                          |   | 819 | katerimi manipuliramo, v programu za izris v svetovnih oz. modelnih | 
                  
                          |   | 820 | koordinatah. V spošnem se priporoča nastavitev projekcije za | 
                  
                          |   | 821 | vse modele, ki uporabljajo izris ploskev. To pa zaradi tega, ker je | 
                  
                          |   | 822 | privzeta projekcijska matrika enotska. Poglejmo to na primeru | 
                  
                          |   | 823 | paralelne projekcije \emph{glOrtho(l,r,b,,n,f)}: | 
                  
                          |   | 824 | $$ | 
                  
                          |   | 825 |    PM = \left[  | 
                  
                          |   | 826 |      \begin{array}{cccc} | 
                  
                          |   | 827 |        \frac{2}{r-l} &      0        &       0        & \frac{r+l}{l-r} \cr  | 
                  
                          |   | 828 |                0     & \frac{2}{t-b} &       0        & \frac{t+b}{t-b} \cr  | 
                  
                          |   | 829 |                0     &      0        & \frac{2}{f-n}  & \frac{f+n}{f-n} \cr  | 
                  
                          |   | 830 |                0     &      0        &       0        &      1          \cr | 
                  
                          |   | 831 |      \end{array} | 
                  
                          |   | 832 |      \right]\quad . | 
                  
                          |   | 833 | $$ | 
                  
                          |   | 834 | Za primer normalizacijskega prostora v obsegu [-1,1] je tako matrika paralelne | 
                  
                          |   | 835 | projekcije | 
                  
                          |   | 836 | $$ | 
                  
                          |   | 837 |    PM(-1, 1, -1, 1, -1, 1) = \left[  | 
                  
                          |   | 838 |      \begin{array}{cccc} | 
                  
                          |   | 839 |        1 &   0   &   0   & 0 \cr  | 
                  
                          |   | 840 |        0 &   1   &   0   & 0 \cr  | 
                  
                          |   | 841 |        0 &   0   &  -1   & 0 \cr  | 
                  
                          |   | 842 |        0 &   0   &   0   & 1 \cr  | 
                  
                          |   | 843 |      \end{array} | 
                  
                          |   | 844 |      \right]\quad , | 
                  
                          |   | 845 | $$ | 
                  
                          |   | 846 | kar se razlikuje od enotske prav v koordinati $z$. če bi | 
                  
                          |   | 847 | projekcijsko matriko ohranili enotsko, potem bi to pomenilo, da objekt | 
                  
                          |   | 848 | gledamo kot zrcalno sliko zadnje strani. Nastavitev projekcijske matrike | 
                  
                          |   | 849 | je torej obvezna za vse izrise ploskvic po globini, kot tudi za modele | 
                  
                          |   | 850 | z osenčenjem. Zaradi tega je tudi program za izris kocke | 
                  
                          |   | 851 | nelogično postavil v ospredje modro stranico in ne rdečo. | 
                  
                          |   | 852 |  | 
                  
                          |   | 853 | = Osvetlitev = | 
                  
                          |   | 854 | Do sedaj predstavljeni primeri so uporabljali le sintetične barve. | 
                  
                          |   | 855 | To pomeni, da se barva vsake ploskvice ne spreminja v odvisnosti od | 
                  
                          |   | 856 | položaja v prostoru. Tak način prikaza je uporaben le za | 
                  
                          |   | 857 | omejen nabor prostorskih modelov. Neprimeren je že za vse modele, | 
                  
                          |   | 858 | ki imajo površine sestavljene iz primitivov in te površine | 
                  
                          |   | 859 | niso ravninske. Za primer kocke (slika \ref{fig:half-cube}) je bilo | 
                  
                          |   | 860 | potrebno za vsako stranico nastaviti svojo barvo, da smo lahko dobili | 
                  
                          |   | 861 | vtis prostora. če bi kocko risali le z eno barvo, potem bi dobili | 
                  
                          |   | 862 | na zaslon le obris.  | 
                  
                          |   | 863 |  | 
                  
                          |   | 864 | Za bolj realističen izris je potrebno vključiti računanje | 
                  
                          |   | 865 | osvetlitve.  žal osvetlitev zajema veliko parametrov, ki jih je | 
                  
                          |   | 866 | potrebno nastaviti preden lahko karkoli dobimo na zaslonu. Tako je | 
                  
                          |   | 867 | potrebno nastavljati položaj in lastnosti luči, osvetlitveni | 
                  
                          |   | 868 | model in lastnosti površin modelov. Za vsako luč se lahko tako | 
                  
                          |   | 869 | nastavi 10 lastnosti in vsaka površina ima 5 lastnosti materiala. | 
                  
                          |   | 870 |  | 
                  
                          |   | 871 | Kot predpogoj za pravilno osvetljen model pa je podana normala v | 
                  
                          |   | 872 | vsakem vozlišču vsake ploskvice. Najpreprostejši način | 
                  
                          |   | 873 | pri uporabi osvetlitve je, da parametre luči ne nastavljamo in da | 
                  
                          |   | 874 | uporabimo nastavljanje lastnosti materiala površine le z ukazom za | 
                  
                          |   | 875 | barvo. S tem vpeljemo veliko  predpostavk, ki pa so za šolsko rabo | 
                  
                          |   | 876 | povsem uporabne. Predpostavljena je le ena luč bele svetlobe s | 
                  
                          |   | 877 | položajem $(0, 0, 1)$ in difuzni odboj svetlobe na | 
                  
                          |   | 878 | površini. Barvo površine podajamo kar z običajnim ukazom | 
                  
                          |   | 879 | za barvo. Program za izris osenčenega modela kocke je tako v | 
                  
                          |   | 880 | minimalni obliki naslednji: | 
                  
                          |   | 881 |  | 
                  
                          |   | 882 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 883 | subroutine kvadrat() | 
                  
                          |   | 884 | call fglPushMatrix | 
                  
                          |   | 885 | call fglTranslatef(0.0, 0.0, 1.0) | 
                  
                          |   | 886 | call fglNormal3f(0.0, 0.0, 1.0) | 
                  
                          |   | 887 | call fglRectf(-1.0, -1.0, 1.0, 1.0) | 
                  
                          |   | 888 | call fglPopMatrix | 
                  
                          |   | 889 | end | 
                  
                          |   | 890 |  | 
                  
                          |   | 891 | subroutine display | 
                  
                          |   | 892 | implicit none | 
                  
                          |   | 893 | include 'GL/fgl.h' | 
                  
                          |   | 894 | call fglClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT) | 
                  
                          |   | 895 | call fglColor3f(0.7, 0.6, 0.2) | 
                  
                          |   | 896 | call fglPushMatrix | 
                  
                          |   | 897 | call fglScalef(0.5, 0.5, 0.5) | 
                  
                          |   | 898 | call kvadrat | 
                  
                          |   | 899 | call fglRotatef(90.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 900 | call kvadrat | 
                  
                          |   | 901 | call fglRotatef(90.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 902 | call kvadrat | 
                  
                          |   | 903 | call fglRotatef(90.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 904 | call kvadrat | 
                  
                          |   | 905 | call fglRotatef(90.0, 1.0, 0.0, 0.0) | 
                  
                          |   | 906 | call kvadrat | 
                  
                          |   | 907 | call fglRotatef(180.0, 1.0, 0.0, 0.0) | 
                  
                          |   | 908 | call kvadrat | 
                  
                          |   | 909 | call fglPopMatrix | 
                  
                          |   | 910 | call fglFlush | 
                  
                          |   | 911 | end | 
                  
                          |   | 912 |  | 
                  
                          |   | 913 |  | 
                  
                          |   | 914 | program kocka | 
                  
                          |   | 915 | external display | 
                  
                          |   | 916 | external reshape | 
                  
                          |   | 917 | include 'GL/fglut.h' | 
                  
                          |   | 918 | include 'GL/fgl.h' | 
                  
                          |   | 919 | call fglutinit | 
                  
                          |   | 920 | call fglutinitdisplaymode(GLUT_SINGLE+GLUT_DEPTH) | 
                  
                          |   | 921 | call fglutcreatewindow('Osencena kocka') | 
                  
                          |   | 922 | call fglutDisplayFunc(display) | 
                  
                          |   | 923 | call fglutReshapeFunc(reshape) | 
                  
                          |   | 924 | call fglClearColor(1.0, 1.0, 1.0, 1.0) | 
                  
                          |   | 925 | call fglEnable(GL_LIGHTING) | 
                  
                          |   | 926 | call fglEnable(GL_LIGHT0) | 
                  
                          |   | 927 | call fglEnable(GL_DEPTH_TEST) | 
                  
                          |   | 928 | call fglEnable(GL_COLOR_MATERIAL) | 
                  
                          |   | 929 | call fglutMainLoop | 
                  
                          |   | 930 | end | 
                  
                          |   | 931 |  | 
                  
                          |   | 932 | subroutine  reshape (w, h) | 
                  
                          |   | 933 | integer w, h | 
                  
                          |   | 934 | implicit none | 
                  
                          |   | 935 | include 'GL/fgl.h' | 
                  
                          |   | 936 | real*8 l | 
                  
                          |   | 937 | l = 1.0 | 
                  
                          |   | 938 | call fglViewport (0, 0, w, h) | 
                  
                          |   | 939 | call fglMatrixMode (GL_PROJECTION) | 
                  
                          |   | 940 | call fglLoadIdentity | 
                  
                          |   | 941 | call fglOrtho(-l, l, -l, l, -l, l) | 
                  
                          |   | 942 | call fglMatrixMode(GL_MODELVIEW) | 
                  
                          |   | 943 | call fglLoadIdentity | 
                  
                          |   | 944 | call fglRotatef(30.0, 1.0, 0.0, 0.0) | 
                  
                          |   | 945 | call fglRotatef(30.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 946 | end | 
                  
                          |   | 947 | \end{verbatim} | 
                  
                          |   | 948 | } | 
                  
                          |   | 949 |  | 
                  
                          |   | 950 | Razširjeni primitiv smo poenostavili tako, da ne vsebuje več | 
                  
                          |   | 951 | definicije barve, ampak le geometrijo. Obvezno je bilo potrebno podati | 
                  
                          |   | 952 | izračun normale. Za naš primitiv kvadrata je to $(0,0,1)$. | 
                  
                          |   | 953 | Program za izris v bistvu ni spremenjen, le da je sedaj | 
                  
                          |   | 954 | transformacija modela preseljena v podprogram za nastavitev velikosti | 
                  
                          |   | 955 | okna \texttt{reshape}. V glavnem programu pa je potrebno najprej | 
                  
                          |   | 956 | vključiti računanje osvetlitve \emph{GL\_LIGHTING}, | 
                  
                          |   | 957 | prižgati je potrebno luč št 0, ki ima začetni | 
                  
                          |   | 958 | položaj $(0,0,1)$.  | 
                  
                          |   | 959 |  | 
                  
                          |   | 960 | \begin{figure}[htbp] | 
                  
                          |   | 961 |   \centering | 
                  
                          |   | 962 |   \includegraphics[width=2.5in]{cube-l} | 
                  
                          |   | 963 |   \caption{Osenčen model kocke} | 
                  
                          |   | 964 |   \label{fig:cube-l} | 
                  
                          |   | 965 | \end{figure} | 
                  
                          |   | 966 |  | 
                  
                          |   | 967 | Z vključitvijo \emph{GL\_COLOR\_MATERIAL} | 
                  
                          |   | 968 | pa poenostavimo podajanje barve za material površine tako, da vsi | 
                  
                          |   | 969 | klici podprogramov \emph{Color} nastavljajo privzeto difuzno in | 
                  
                          |   | 970 | ambientno barvo površine. Slika \ref{fig:cube-l} prikazuje | 
                  
                          |   | 971 | rezultat upodabljanja z osvetlitvijo.  | 
                  
                          |   | 972 |  | 
                  
                          |   | 973 |  | 
                  
                          |   | 974 |  | 
                  
                          |   | 975 | = Tekst = | 
                  
                          |   | 976 | OpenGL sam ne podpira teksta in je zato potrebno uporabiti razne | 
                  
                          |   | 977 | prijeme za izris teksta v prostoru. Možnih je več načinov | 
                  
                          |   | 978 | za risanje besedila: | 
                  
                          |   | 979 | \begin{description} | 
                  
                          |   | 980 | \item[stroke] črke so izrisane s črtami v prostoru modela | 
                  
                          |   | 981 | \item[bitmap] črke so izrisane na zaslon | 
                  
                          |   | 982 | \item[teksture] črke so izrisane rastrsko v prostoru modela | 
                  
                          |   | 983 | \end{description} | 
                  
                          |   | 984 | V šolskih primerih so najbolj uporabni že izdelani fonti v | 
                  
                          |   | 985 | knjižnici GLUT. Možne so naslednje številke fontov: | 
                  
                          |   | 986 | {\small | 
                  
                          |   | 987 | \begin{enumerate} | 
                  
                          |   | 988 | \item GLUT\_STROKE\_ROMAN | 
                  
                          |   | 989 | \item GLUT\_STROKE\_MONO\_ROMAN | 
                  
                          |   | 990 | \item GLUT\_BITMAP\_9\_BY\_15              | 
                  
                          |   | 991 | \item GLUT\_BITMAP\_8\_BY\_13              | 
                  
                          |   | 992 | \item GLUT\_BITMAP\_TIMES\_ROMAN\_10       | 
                  
                          |   | 993 | \item GLUT\_BITMAP\_TIMES\_ROMAN\_24       | 
                  
                          |   | 994 | \item GLUT\_BITMAP\_HELVETICA\_10         | 
                  
                          |   | 995 | \item GLUT\_BITMAP\_HELVETICA\_12         | 
                  
                          |   | 996 | \item GLUT\_BITMAP\_HELVETICA\_18         | 
                  
                          |   | 997 | \end{enumerate} | 
                  
                          |   | 998 | } | 
                  
                          |   | 999 |  | 
                  
                          |   | 1000 | Za primer razširimo program za izris osenčene kocke z | 
                  
                          |   | 1001 | besedilom na vsaki stranici. Podprogram \emph{kvadrat} kot argument | 
                  
                          |   | 1002 | vzame besedilo. Začetek izpisa premakne za malenkost višje in | 
                  
                          |   | 1003 | začne v koordinati $x=-0.8$. Ker pa ne želimo, da se besedilo | 
                  
                          |   | 1004 | senči je tu potrebno izklapljanje senčenja takrat, ko | 
                  
                          |   | 1005 | izrisujemo posamezne črke. Ker so črke v vnaprej določeni | 
                  
                          |   | 1006 | velikost, jih je potrebno ustrezno pomanjšati s | 
                  
                          |   | 1007 | skaliranjem. Podprogram \texttt{fglutStrokeCharacter} po vsaki | 
                  
                          |   | 1008 | izrisani črti sam nastavi pomik v smeri x za širino izrisane | 
                  
                          |   | 1009 | črke.  | 
                  
                          |   | 1010 |  | 
                  
                          |   | 1011 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 1012 | subroutine kvadrat(s) | 
                  
                          |   | 1013 | include 'GL/fgl.h' | 
                  
                          |   | 1014 | character s*(*), c | 
                  
                          |   | 1015 | call fglPushMatrix | 
                  
                          |   | 1016 | call fglTranslatef(0.0, 0.0, 1.0) | 
                  
                          |   | 1017 | call fglNormal3f(0.0, 0.0, 1.0) | 
                  
                          |   | 1018 | call fglRectf(-1.0, -1.0, 1.0, 1.0) | 
                  
                          |   | 1019 | call fglTranslatef(-0.8, 0.0, 0.01) | 
                  
                          |   | 1020 | call fglDisable(GL_LIGHTING) | 
                  
                          |   | 1021 | call fglScalef(0.003, 0.003, 0.003) | 
                  
                          |   | 1022 | call fglColor3f(1.0, 0.0, 0.0) | 
                  
                          |   | 1023 | lenc = len(s) | 
                  
                          |   | 1024 | do i=1,lenc | 
                  
                          |   | 1025 |   c = s(i:i) | 
                  
                          |   | 1026 |   call fglutStrokeCharacter(1, ichar(c)) | 
                  
                          |   | 1027 | end do | 
                  
                          |   | 1028 | call fglEnable(GL_LIGHTING) | 
                  
                          |   | 1029 | call fglPopMatrix | 
                  
                          |   | 1030 | end | 
                  
                          |   | 1031 |  | 
                  
                          |   | 1032 | subroutine display | 
                  
                          |   | 1033 | implicit none | 
                  
                          |   | 1034 | include 'GL/fgl.h' | 
                  
                          |   | 1035 | real mat(4) | 
                  
                          |   | 1036 | data mat /0.9, 0.6, 0.3, 1.0/  | 
                  
                          |   | 1037 | call fglClear(GL_COLOR_BUFFER_BIT) | 
                  
                          |   | 1038 | call fglClear(GL_DEPTH_BUFFER_BIT) | 
                  
                          |   | 1039 | call fglPushMatrix | 
                  
                          |   | 1040 | call fglRotatef(30.0, 1.0, 0.0, 0.0) | 
                  
                          |   | 1041 | call fglRotatef(30.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 1042 | call fglScalef(0.5, 0.5, 0.5) | 
                  
                          |   | 1043 | call fglMaterialfv(GL_FRONT, GL_DIFFUSE, mat) | 
                  
                          |   | 1044 | call kvadrat('Spredaj') | 
                  
                          |   | 1045 | call fglRotatef(90.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 1046 | call kvadrat('Desno') | 
                  
                          |   | 1047 | call fglRotatef(90.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 1048 | call kvadrat('Zadaj') | 
                  
                          |   | 1049 | call fglRotatef(90.0, 0.0, 1.0, 0.0) | 
                  
                          |   | 1050 | call kvadrat('Levo') | 
                  
                          |   | 1051 | call fglRotatef(90.0, 1.0, 0.0, 0.0) | 
                  
                          |   | 1052 | call kvadrat('Spodaj') | 
                  
                          |   | 1053 | call fglRotatef(180.0, 1.0, 0.0, 0.0) | 
                  
                          |   | 1054 | call kvadrat('Zgoraj') | 
                  
                          |   | 1055 | call fglPopMatrix | 
                  
                          |   | 1056 | call fglFlush | 
                  
                          |   | 1057 | end | 
                  
                          |   | 1058 |  | 
                  
                          |   | 1059 | subroutine reshape(w, h) | 
                  
                          |   | 1060 | include 'GL/fgl.h' | 
                  
                          |   | 1061 | integer w, h | 
                  
                          |   | 1062 | real*8 l | 
                  
                          |   | 1063 | l = 1 | 
                  
                          |   | 1064 | call fglViewPort(0, 0, w, h) | 
                  
                          |   | 1065 | call fglMatrixMode(GL_PROJECTION) | 
                  
                          |   | 1066 | call fglLoadIdentity | 
                  
                          |   | 1067 | call fglOrtho(-l,l,-l,l,-l,l) | 
                  
                          |   | 1068 | call fglMatrixMode(GL_MODELVIEW) | 
                  
                          |   | 1069 | call fglLoadIdentity | 
                  
                          |   | 1070 | end | 
                  
                          |   | 1071 |  | 
                  
                          |   | 1072 | program crta | 
                  
                          |   | 1073 | external display | 
                  
                          |   | 1074 | external reshape | 
                  
                          |   | 1075 | include 'GL/fglut.h' | 
                  
                          |   | 1076 | include 'GL/fgl.h' | 
                  
                          |   | 1077 | call fglutinit | 
                  
                          |   | 1078 | call fglutinitdisplaymode(GLUT_SINGLE+GLUT_DEPTH) | 
                  
                          |   | 1079 | call fglutcreatewindow('Fortran GLUT program') | 
                  
                          |   | 1080 | call fglutDisplayFunc(display) | 
                  
                          |   | 1081 | call fglutReshapeFunc(reshape) | 
                  
                          |   | 1082 | call fglEnable(GL_DEPTH_TEST) | 
                  
                          |   | 1083 | call fglEnable(GL_LIGHTING) | 
                  
                          |   | 1084 | call fglEnable(GL_LIGHT0) | 
                  
                          |   | 1085 | call fglClearColor(1.0, 1.0, 1.0, 1.0) | 
                  
                          |   | 1086 | call fglutmainloop | 
                  
                          |   | 1087 | end | 
                  
                          |   | 1088 | \end{verbatim} | 
                  
                          |   | 1089 | } | 
                  
                          |   | 1090 |  | 
                  
                          |   | 1091 | \begin{figure}[htbp] | 
                  
                          |   | 1092 |   \centering | 
                  
                          |   | 1093 |   \includegraphics[width=2.5in]{cube-f} | 
                  
                          |   | 1094 |   \caption{Osenčen model kocke z napisi} | 
                  
                          |   | 1095 |   \label{fig:cube-f} | 
                  
                          |   | 1096 | \end{figure} | 
                  
                          |   | 1097 |  | 
                  
                          |   | 1098 | Podajanje barve za površino je spremenjeno tako, da se ne uporabi | 
                  
                          |   | 1099 | funkcije \emph{Color} ampak normalno funkcijo za podajanje lastnosti | 
                  
                          |   | 1100 | materialaf \texttt{glMaterialfv}. Rezultat kaže slika | 
                  
                          |   | 1101 | \ref{fig:cube-f}. če bi napisali komentar pred izrisom | 
                  
                          |   | 1102 | štirikotnika, potem bi bilo vidno besedilo tudi za ostale | 
                  
                          |   | 1103 | (skrite) strani. | 
                  
                          |   | 1104 |  | 
                  
                          |   | 1105 | Včasih pa raje želimo, da se besedilo na zaslonu ne | 
                  
                          |   | 1106 | izrisuje rotirano in senčeno, temveč da se le pojavi na | 
                  
                          |   | 1107 | določenem položaju v prostoru in potem izriše v zaslonskih | 
                  
                          |   | 1108 | koordinatah. V ta namen uporabimo \emph{bitmap} fonte in naslednji | 
                  
                          |   | 1109 | podprogram za izpis besedila: | 
                  
                          |   | 1110 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 1111 | subroutine output(x,y,z,s) | 
                  
                          |   | 1112 | character s*(*) | 
                  
                          |   | 1113 | call fglRasterPos3f(x,y,z) | 
                  
                          |   | 1114 | lenc = len(s) | 
                  
                          |   | 1115 | do i=1,lenc | 
                  
                          |   | 1116 |   call fglutBitmapCharacter(6, ichar(s(i:i))) | 
                  
                          |   | 1117 | end do | 
                  
                          |   | 1118 | end | 
                  
                          |   | 1119 | \end{verbatim} | 
                  
                          |   | 1120 | } | 
                  
                          |   | 1121 | Primer izrisa z bitmap fonti kaže slika \ref{fig:cube-b} | 
                  
                          |   | 1122 | \begin{figure}[htbp] | 
                  
                          |   | 1123 |   \centering | 
                  
                          |   | 1124 |   \includegraphics[width=2.5in]{cube-b} | 
                  
                          |   | 1125 |   \caption{Osenčen model kocke z \emph{bitmap} napisi} | 
                  
                          |   | 1126 |   \label{fig:cube-b} | 
                  
                          |   | 1127 | \end{figure} | 
                  
                          |   | 1128 |  | 
                  
                          |   | 1129 |  | 
                  
                          |   | 1130 | = Uporabniški vmesnik = | 
                  
                          |   | 1131 | V nadaljevanju so prikazani primeri programov, ki izkoriščajo | 
                  
                          |   | 1132 | dodatne funkcionalnost knjižnice GLUT za vnos dodatnih podatkov v | 
                  
                          |   | 1133 | program. To je predvsem uporaba tipk in miške.  | 
                  
                          |   | 1134 |  | 
                  
                          |   | 1135 | \subsection{Rotacija s tipkami} | 
                  
                          |   | 1136 | Rotiramo že vgrajeni geometrijski model čajnika s tipkami \textbf{x, | 
                  
                          |   | 1137 | y, z}. Vsak pritisk na tipko poveča kot rotacije za pet stopinj. | 
                  
                          |   | 1138 | Podatke o trenutni rotaciji prenašamo s poljem \texttt{common}. Ker | 
                  
                          |   | 1139 | izrisujemo žični model, podprogram za \emph{reshape} ni | 
                  
                          |   | 1140 | potreben. Podprogram \emph{keyboard} ob pritisku na tipko dobi tudi | 
                  
                          |   | 1141 | informacijo o zaslonskem položaju miške. | 
                  
                          |   | 1142 |  | 
                  
                          |   | 1143 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 1144 | subroutine display | 
                  
                          |   | 1145 | implicit none | 
                  
                          |   | 1146 | include 'GL/fgl.h' | 
                  
                          |   | 1147 | common /rotation/ rx, ry, rz | 
                  
                          |   | 1148 | real rx, ry, rz | 
                  
                          |   | 1149 | call fglClear(GL_COLOR_BUFFER_BIT) | 
                  
                          |   | 1150 | call fglColor3f(0.5, 0.4, 1.0) | 
                  
                          |   | 1151 | call fglPushMatrix | 
                  
                          |   | 1152 | call fglRotatef(rx, 1.0, 0.0, 0.0) | 
                  
                          |   | 1153 | call fglRotatef(ry, 0.0, 1.0, 0.0) | 
                  
                          |   | 1154 | call fglRotatef(rz, 0.0, 0.0, 1.0) | 
                  
                          |   | 1155 | call fglutWireTeapot(dble(r)) | 
                  
                          |   | 1156 | call fglPopMatrix | 
                  
                          |   | 1157 | call fglutSwapBuffers | 
                  
                          |   | 1158 | end | 
                  
                          |   | 1159 |  | 
                  
                          |   | 1160 | subroutine keyboard(key,x,y) | 
                  
                          |   | 1161 | common /rotation/ rx, ry, rz | 
                  
                          |   | 1162 | integer key,x,y | 
                  
                          |   | 1163 | print *, 'Key ', char(key),  key, ' at', x, y | 
                  
                          |   | 1164 | if (key .eq. ichar('x')) rx = rx + 5.0 | 
                  
                          |   | 1165 | if (key .eq. ichar('y')) ry = ry + 5.0 | 
                  
                          |   | 1166 | if (key .eq. ichar('z')) rz = rz + 5.0 | 
                  
                          |   | 1167 | call fglutpostredisplay | 
                  
                          |   | 1168 | end | 
                  
                          |   | 1169 |  | 
                  
                          |   | 1170 | program teapot | 
                  
                          |   | 1171 | external display | 
                  
                          |   | 1172 | external keyboard | 
                  
                          |   | 1173 | include 'GL/fglut.h' | 
                  
                          |   | 1174 | integer window | 
                  
                          |   | 1175 | call fglutInit | 
                  
                          |   | 1176 | call fglutInitDisplayMode(ior(GLUT_DOUBLE,GLUT_RGB)) | 
                  
                          |   | 1177 | window = fglutCreateWindow('Use keys x, y, and z') | 
                  
                          |   | 1178 | call fglutDisplayFunc(display) | 
                  
                          |   | 1179 | call fglutKeyboardFunc(keyboard) | 
                  
                          |   | 1180 | call fglutMainLoop | 
                  
                          |   | 1181 | end | 
                  
                          |   | 1182 | \end{verbatim} | 
                  
                          |   | 1183 | } | 
                  
                          |   | 1184 |  | 
                  
                          |   | 1185 |  | 
                  
                          |   | 1186 | \subsection{Miška in inverzna projekcija} | 
                  
                          |   | 1187 | Za vsak pritisk gumba miške lahko dobimo poleg koordinate tudi | 
                  
                          |   | 1188 | še stanje gumbov. Naslednji primer prikazuje risanje črte v | 
                  
                          |   | 1189 | ravnini (x,y) s tem, da je potrebno zaslonske koordinate pretvoriti | 
                  
                          |   | 1190 | nazaj v modelne. | 
                  
                          |   | 1191 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 1192 | subroutine redraw | 
                  
                          |   | 1193 | implicit none | 
                  
                          |   | 1194 | include 'GL/fgl.h' | 
                  
                          |   | 1195 | common /vertices/ n, vertex(2, 100) | 
                  
                          |   | 1196 | integer n, i | 
                  
                          |   | 1197 | real vertex | 
                  
                          |   | 1198 | call fglClear(GL_COLOR_BUFFER_BIT) | 
                  
                          |   | 1199 | call fglbegin(GL_LINE_STRIP) | 
                  
                          |   | 1200 | do i = 1,n | 
                  
                          |   | 1201 |         call fglVertex2f(vertex(1, i), vertex(2, i)) | 
                  
                          |   | 1202 | end do | 
                  
                          |   | 1203 | call fglend | 
                  
                          |   | 1204 | call fglFlush | 
                  
                          |   | 1205 | end | 
                  
                          |   | 1206 |  | 
                  
                          |   | 1207 | subroutine mouse (button, state, x, y)  | 
                  
                          |   | 1208 | implicit none | 
                  
                          |   | 1209 | include 'GL/fglut.h' | 
                  
                          |   | 1210 | include 'GL/fgl.h' | 
                  
                          |   | 1211 | include 'GL/fglu.h' | 
                  
                          |   | 1212 | common /vertices/ n, vertex(2, 100) | 
                  
                          |   | 1213 | integer n, i | 
                  
                          |   | 1214 | real vertex | 
                  
                          |   | 1215 | integer button, state, x, y | 
                  
                          |   | 1216 | integer viewport(4) | 
                  
                          |   | 1217 | real*8 mvmatrix(16), projmatrix(16) | 
                  
                          |   | 1218 | real*8 wx, wy, wz               ! returned world x, y, z coords | 
                  
                          |   | 1219 | real*8 px, py, pz               ! picked window coortinates | 
                  
                          |   | 1220 | integer status | 
                  
                          |   | 1221 |  | 
                  
                          |   | 1222 | if (button .eq. GLUT_LEFT_BUTTON) then | 
                  
                          |   | 1223 |  if (state .eq. GLUT_DOWN) then | 
                  
                          |   | 1224 |         call fglGetIntegerv (GL_VIEWPORT, viewport) | 
                  
                          |   | 1225 |         call fglGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix) | 
                  
                          |   | 1226 |         call fglGetDoublev (GL_PROJECTION_MATRIX, projmatrix) | 
                  
                          |   | 1227 |         note viewport(4) is height of window in pixels  | 
                  
                          |   | 1228 |         px = x | 
                  
                          |   | 1229 |         py = viewport(4) -  y - 1 | 
                  
                          |   | 1230 |         pz = 0.0 | 
                  
                          |   | 1231 |         print *, ' Coordinates at cursor are ', px, py | 
                  
                          |   | 1232 |         status = fgluUnProject (px, py, pz,  mvmatrix,  | 
                  
                          |   | 1233 |                     projmatrix,  viewport, wx, wy, wz) | 
                  
                          |   | 1234 |         print *, 'World coords at z=0.0 are ', wx, wy, wz | 
                  
                          |   | 1235 |         n = n + 1 | 
                  
                          |   | 1236 |         vertex(1, n) = wx | 
                  
                          |   | 1237 |         vertex(2, n) = wy | 
                  
                          |   | 1238 |         call fglutPostRedisplay | 
                  
                          |   | 1239 |  end if | 
                  
                          |   | 1240 | end if | 
                  
                          |   | 1241 | end | 
                  
                          |   | 1242 |  | 
                  
                          |   | 1243 |  | 
                  
                          |   | 1244 | program main | 
                  
                          |   | 1245 | external redraw | 
                  
                          |   | 1246 | external mouse | 
                  
                          |   | 1247 | include 'GL/fglut.h' | 
                  
                          |   | 1248 | call fglutinit | 
                  
                          |   | 1249 | call fglutinitdisplaymode(ior(GLUT_SINGLE,GLUT_RGB)) | 
                  
                          |   | 1250 | call fglutInitWindowSize (500, 500) | 
                  
                          |   | 1251 | call fglutInitWindowPosition (100, 100) | 
                  
                          |   | 1252 | window = fglutcreatewindow('Click in window') | 
                  
                          |   | 1253 | call fglutdisplayfunc(redraw) | 
                  
                          |   | 1254 | call fglutMouseFunc(mouse) | 
                  
                          |   | 1255 | call fglutmainloop | 
                  
                          |   | 1256 | end | 
                  
                          |   | 1257 | \end{verbatim} | 
                  
                          |   | 1258 | } | 
                  
                          |   | 1259 |  | 
                  
                          |   | 1260 |  | 
                  
                          |   | 1261 |  | 
                  
                          |   | 1262 | \subsection{Kvaternionska rotacija} | 
                  
                          |   | 1263 | Naslednji program prikazuje vrtenje osenčenega čajnika z | 
                  
                          |   | 1264 | miško. V ta namem se uporabi že izdelam podprogram v jeziku C, | 
                  
                          |   | 1265 | ki ga kličemo iz fortrana in nam omogoča kvaternionsko | 
                  
                          |   | 1266 | rotacijo. Za vrtenje enotske krogle je potrebno zaznati tako | 
                  
                          |   | 1267 | začetni pritisk na gumb (podprogram \emph{mouse}) kot vse | 
                  
                          |   | 1268 | naslednje pomike miške (podprogram \emph{motion}). | 
                  
                          |   | 1269 |  | 
                  
                          |   | 1270 |  | 
                  
                          |   | 1271 | {\scriptsize\begin{verbatim} | 
                  
                          |   | 1272 | subroutine display | 
                  
                          |   | 1273 | implicit none | 
                  
                          |   | 1274 | include 'GL/fgl.h' | 
                  
                          |   | 1275 | common /quaternion/ last(4), cur(4) | 
                  
                          |   | 1276 | real last, cur, m(4,4) | 
                  
                          |   | 1277 | call build_rotmatrix(m, cur) | 
                  
                          |   | 1278 | call fglLoadIdentity | 
                  
                          |   | 1279 | call fglMultMatrixf(m) | 
                  
                          |   | 1280 | call fglclear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT) | 
                  
                          |   | 1281 | call fglutSolidTeapot(dble(0.5)) | 
                  
                          |   | 1282 | call fglutSwapBuffers | 
                  
                          |   | 1283 | end | 
                  
                          |   | 1284 |  | 
                  
                          |   | 1285 | subroutine motion (x, y)  | 
                  
                          |   | 1286 | include 'GL/fglut.h' | 
                  
                          |   | 1287 | include 'GL/fgl.h' | 
                  
                          |   | 1288 | implicit none | 
                  
                          |   | 1289 | integer x, y | 
                  
                          |   | 1290 | common /quaternion/ last(4), cur(4) | 
                  
                          |   | 1291 | common /mousestart/ beginx, beginy | 
                  
                          |   | 1292 | common /viewport/ width, height | 
                  
                          |   | 1293 | integer width, height | 
                  
                          |   | 1294 | integer beginx, beginy | 
                  
                          |   | 1295 | real last, cur | 
                  
                          |   | 1296 | real p1x, p1y, p2x, p2y | 
                  
                          |   | 1297 | p1x = (2.0*beginx - width)/width | 
                  
                          |   | 1298 | p1y = (height - 2.0*beginy)/height | 
                  
                          |   | 1299 | p2x = (2.0 * x - width) / width | 
                  
                          |   | 1300 | p2y = (height - 2.0 * y) / height | 
                  
                          |   | 1301 | call trackball(last,p1x, p1y, p2x, p2y) | 
                  
                          |   | 1302 | call add_quats(last, cur, cur) | 
                  
                          |   | 1303 | beginx = x | 
                  
                          |   | 1304 | beginy = y | 
                  
                          |   | 1305 | call fglutPostRedisplay | 
                  
                          |   | 1306 | end | 
                  
                          |   | 1307 |  | 
                  
                          |   | 1308 | subroutine mouse (button, state, x, y)  | 
                  
                          |   | 1309 | implicit none | 
                  
                          |   | 1310 | integer button, state, x, y | 
                  
                          |   | 1311 | include 'GL/fglut.h' | 
                  
                          |   | 1312 | include 'GL/fgl.h' | 
                  
                          |   | 1313 | include 'GL/fglu.h' | 
                  
                          |   | 1314 | common /mousestart/ beginx, beginy | 
                  
                          |   | 1315 | integer beginx, beginy | 
                  
                          |   | 1316 | beginx = x | 
                  
                          |   | 1317 | beginy = y       | 
                  
                          |   | 1318 | end | 
                  
                          |   | 1319 |  | 
                  
                          |   | 1320 | subroutine reshape(w, h) | 
                  
                          |   | 1321 | include 'GL/fgl.h' | 
                  
                          |   | 1322 | integer w, h | 
                  
                          |   | 1323 | real*8 l | 
                  
                          |   | 1324 | common /viewport/ width, height | 
                  
                          |   | 1325 | integer width, height | 
                  
                          |   | 1326 | width=w | 
                  
                          |   | 1327 | height=h | 
                  
                          |   | 1328 | l = 1 | 
                  
                          |   | 1329 | call fglViewPort(0, 0, w, h) | 
                  
                          |   | 1330 | call fglMatrixMode(GL_PROJECTION) | 
                  
                          |   | 1331 | call fglLoadIdentity | 
                  
                          |   | 1332 | call fglOrtho(-l,l,-l,l,-l,l) | 
                  
                          |   | 1333 | call fglMatrixMode(GL_MODELVIEW) | 
                  
                          |   | 1334 | call fglLoadIdentity | 
                  
                          |   | 1335 | end | 
                  
                          |   | 1336 |  | 
                  
                          |   | 1337 | program trackballdemo | 
                  
                          |   | 1338 | implicit none | 
                  
                          |   | 1339 | include 'GL/fglut.h' | 
                  
                          |   | 1340 | include 'GL/fgl.h' | 
                  
                          |   | 1341 | include 'GL/fglu.h' | 
                  
                          |   | 1342 | external display | 
                  
                          |   | 1343 | external motion | 
                  
                          |   | 1344 | external mouse | 
                  
                          |   | 1345 | external reshape | 
                  
                          |   | 1346 | integer window | 
                  
                          |   | 1347 | common /quaternion/ last(4), cur(4) | 
                  
                          |   | 1348 | real last, cur | 
                  
                          |   | 1349 | call trackball(cur, 0.0, 0.0, 0.0, 0.0) | 
                  
                          |   | 1350 | call fglutinit | 
                  
                          |   | 1351 | call fglutinitdisplaymode(GLUT_DOUBLE+GLUT_RGB+GLUT_DEPTH) | 
                  
                          |   | 1352 | window = fglutcreatewindow('Use mouse to rotate') | 
                  
                          |   | 1353 | call fglutdisplayfunc(display) | 
                  
                          |   | 1354 | call fglutmousefunc(mouse) | 
                  
                          |   | 1355 | call fglutmotionfunc(motion) | 
                  
                          |   | 1356 | call fglutreshapefunc(reshape) | 
                  
                          |   | 1357 | call fglEnable(GL_LIGHTING) | 
                  
                          |   | 1358 | call fglEnable(GL_LIGHT0) | 
                  
                          |   | 1359 | call fglEnable(GL_DEPTH_TEST) | 
                  
                          |   | 1360 | call fglutmainloop | 
                  
                          |   | 1361 | end | 
                  
                          |   | 1362 | \end{verbatim} | 
                  
                          |   | 1363 | } | 
                  
                          |   | 1364 | Predstavljeni program je sestavljen iz dveh delov. Kodo za rotacijo v | 
                  
                          |   | 1365 | jeziku C \texttt{trackball.c} uporabimo kod zunanje podprograme.  | 
                  
                          |   | 1366 | Rezultat osenčenega model, ki je bil obrnjen z miško, prikazuje | 
                  
                          |   | 1367 | slika \ref{fig:teapot}. | 
                  
                          |   | 1368 | \begin{figure}[htbp] | 
                  
                          |   | 1369 |   \centering | 
                  
                          |   | 1370 |   \includegraphics[width=2.1in]{teapot} | 
                  
                          |   | 1371 |   \caption{Osenčen model čajnika} | 
                  
                          |   | 1372 | \label{fig:teapot} | 
                  
                          |   | 1373 | \end{figure} | 
                  
                          |   | 1374 |  | 
                  
                          |   | 1375 | = Razvojno okolje = | 
                  
                          |   | 1376 | Za šolske probleme smo pripravili razvojno okolje, ki omogoča | 
                  
                          |   | 1377 | prevajanje kode v jezikih F77, C++ in C za okenski sistem Windows. | 
                  
                          |   | 1378 | Razvojno okolje deluje v načunu ukazne vrstice in nima | 
                  
                          |   | 1379 | priloženega integriranega vmesnika. Vsi ukazi za popravljanje | 
                  
                          |   | 1380 | programov in prevajanje se tako podajajo v ukazni vrstici DOS okna | 
                  
                          |   | 1381 | (\emph{Start-Programs-Command Prompt}).  | 
                  
                          |   | 1382 |  | 
                  
                          |   | 1383 | Osnova okolja je Borlandov C++ prevajalnik, ki ga lahko dobimo | 
                  
                          |   | 1384 | zastonj. Besedilo dogovora uporabe se nahaja v datoteki | 
                  
                          |   | 1385 | \emph{linence.txt}. Prevajanje v jeziku Fortran pa dosežemo z | 
                  
                          |   | 1386 | pretvorbo fortranske kode v C, nato sledi prevajanje v C-ju in | 
                  
                          |   | 1387 | povezovanje v končni program (\emph{.exe}). Končni program | 
                  
                          |   | 1388 | lahko zaženemo z DOS okna ali z dvoklikom na izvršni program.  | 
                  
                          |   | 1389 | Poleg Novega grafičnega okna vsak GLUT program uporablja še | 
                  
                          |   | 1390 | konzolo za morebiten vnos ali izpis z ukazoma \texttt{print *,} ali | 
                  
                          |   | 1391 | \texttt{read *,} | 
                  
                          |   | 1392 |  | 
                  
                          |   | 1393 | \subsection{Namestitev} | 
                  
                          |   | 1394 | Namestitev je možna z CD-ROMA ali datoteke | 
                  
                          |   | 1395 | \texttt{bcc-fgl-full.zip}. V slednjem primeru je potrebno paketno | 
                  
                          |   | 1396 | datoteko odpakirati v začasen imenik, nakar sledi namestitev tako | 
                  
                          |   | 1397 | kot iz CD-ROM-a.  | 
                  
                          |   | 1398 |  | 
                  
                          |   | 1399 | \begin{enumerate} | 
                  
                          |   | 1400 | \item Za namestitev je na disku C potrebnih 60 MB prostora!  | 
                  
                          |   | 1401 | \item Dvolkikni na \texttt{install.bat} | 
                  
                          |   | 1402 | \end{enumerate} | 
                  
                          |   | 1403 |  | 
                  
                          |   | 1404 |  | 
                  
                          |   | 1405 |  | 
                  
                          |   | 1406 | \subsection{Dokumentacija} | 
                  
                          |   | 1407 | Po namestitvi se navodila z nahajajo v imeniku | 
                  
                          |   | 1408 | \verb|c:\bcc55\doc|. Priližena so naslednja navodila v obliki PDF: | 
                  
                          |   | 1409 | \begin{description} | 
                  
                          |   | 1410 | \item[redbook-*.pdf] OpenGL Programming Guide  | 
                  
                          |   | 1411 | \item[opengl-intro.pdf] Ta dokument | 
                  
                          |   | 1412 | \item[fgl.pdf] OpenGL reference | 
                  
                          |   | 1413 | \item[fglu.pdf] OpenGL Utility reference | 
                  
                          |   | 1414 | \item[fglut.pdf] GLUT | 
                  
                          |   | 1415 | \item[f2c.pdf] Prevajalnik za Fortran | 
                  
                          |   | 1416 | \end{description} | 
                  
                          |   | 1417 |  | 
                  
                          |   | 1418 | V datoteki \texttt{} se nahaja ta dokument.  Iskanje | 
                  
                          |   | 1419 | po dokumentaciji za OpenGL ( \texttt{fgl.pdf, fglu.pdf}), izvedemo | 
                  
                          |   | 1420 | tako, da natipkamo npr.  \texttt{fglVertex3f(} | 
                  
                          |   | 1421 |  | 
                  
                          |   | 1422 |  | 
                  
                          |   | 1423 | \subsection{Prevajanje} | 
                  
                          |   | 1424 | Primeri so v imeniku \verb|c:\bcc55\examples|.  | 
                  
                          |   | 1425 |  | 
                  
                          |   | 1426 | Pred prevajanjem je potrebno odpreti okno DOS | 
                  
                          |   | 1427 | \emph{Start-Run-command-OK} in nastaviti pot do prevajalnikov z | 
                  
                          |   | 1428 | ukazom | 
                  
                          |   | 1429 | \begin{verbatim} | 
                  
                          |   | 1430 |         PATH=\BCC55\bin;%PATH% | 
                  
                          |   | 1431 | \end{verbatim} | 
                  
                          |   | 1432 |  | 
                  
                          |   | 1433 |  | 
                  
                          |   | 1434 | Pomik v imenik naredimo z ukazom | 
                  
                          |   | 1435 | \begin{verbatim} | 
                  
                          |   | 1436 |          c: | 
                  
                          |   | 1437 |          cd \bcc55\examples | 
                  
                          |   | 1438 | \end{verbatim} | 
                  
                          |   | 1439 |  | 
                  
                          |   | 1440 |  | 
                  
                          |   | 1441 | Pot lahko nastavimo tudi za celoten sistem: | 
                  
                          |   | 1442 | \emph{Start-Settings-Control Panel-System-evironment->PATH} in dopišemo | 
                  
                          |   | 1443 | \verb|c:\bcc55\bin;| na začetku ali koncu obstoječe poti. | 
                  
                          |   | 1444 |  | 
                  
                          |   | 1445 | Za prevajanje fortranskih datotek ne smemo uporabiti končnice \texttt{.f} | 
                  
                          |   | 1446 | Primer prevajanja začetnega primera \texttt{line.f} za izris črte: | 
                  
                          |   | 1447 | \begin{verbatim} | 
                  
                          |   | 1448 |        f77 line         | 
                  
                          |   | 1449 | \end{verbatim} | 
                  
                          |   | 1450 | Za najzahtevnejši primer čajnika uporabimo hkratno prevajanje | 
                  
                          |   | 1451 | fortranskega in C programa, ki oba med seboj tudi poveže v program | 
                  
                          |   | 1452 | \texttt{tblight.exe} | 
                  
                          |   | 1453 | \begin{verbatim} | 
                  
                          |   | 1454 |        f77 tblight trackball.c         | 
                  
                          |   | 1455 | \end{verbatim} | 
                  
                          |   | 1456 | če imamo več modulov, potem lahko že prevedene podprograme | 
                  
                          |   | 1457 | \texttt{.obj} le povežemo v izvršno kodo. Primer: | 
                  
                          |   | 1458 | \begin{verbatim} | 
                  
                          |   | 1459 |        f77 tblight trackball.obj | 
                  
                          |   | 1460 | \end{verbatim} | 
                  
                          |   | 1461 |  | 
                  
                          |   | 1462 | Prevajanje in povezovanje v jeziku C se izvede z klicem prevajalnika | 
                  
                          |   | 1463 |         \emph{bcc32}.  Primer: | 
                  
                          |   | 1464 | \begin{verbatim} | 
                  
                          |   | 1465 |         bcc32 teapot.c         | 
                  
                          |   | 1466 | \end{verbatim} | 
                  
                          |   | 1467 |  | 
                  
                          |   | 1468 |  | 
                  
                          |   | 1469 | \subsection{Urejanje fortranskih in C programov:} | 
                  
                          |   | 1470 | Na urejanje kode lahko uporabimo DOS-ov urejevalnik EDIT ali Windows | 
                  
                          |   | 1471 | notepad. Oba imata svoje slabosti; EDIT ima težave z daljšimi | 
                  
                          |   | 1472 | imeni datotek, NOTEPAD pa nima prikaza trenutne vrstice in ob prvem | 
                  
                          |   | 1473 | shranjevanju datoteke lepi končnico \texttt{.txt}, tako da moramo | 
                  
                          |   | 1474 | datoteko kasneje preimenovati v \texttt{.f}. Kljub slabostim sta oba | 
                  
                          |   | 1475 | urejevalnika primerna za šolske probleme. | 
                  
                          |   | 1476 |  | 
                  
                          |   | 1477 | V trenutnem imeniku DOS okna odtipkamo izbrani ukaz: | 
                  
                          |   | 1478 | \begin{verbatim} | 
                  
                          |   | 1479 |         notepad teapot.f | 
                  
                          |   | 1480 |         edit teapot.f | 
                  
                          |   | 1481 | \end{verbatim} | 
                  
                          |   | 1482 |  |