Changes between Version 9 and Version 10 of opengl-intro


Ignore:
Timestamp:
Feb 13, 2009, 5:09:32 PM (12 years ago)
Author:
msitar
Comment:

Urejeno do poglavja Miška in inverzna projekcija, vključno s pripadajočimi programi

Legend:

Unmodified
Added
Removed
Modified
  • opengl-intro

    v9 v10  
    294294okenskega sistema. Ker imamo v našem primeru le enostaven izris,
    295295smo se odločili le za en slikovni pomnilnik
    296 (''GLUT\_SINGLE''), ki je primeren le za statične slike. Za
     296(''GLUT_SINGLE''), ki je primeren le za statične slike. Za
    297297aplikacije pri katerih se vsebina zaslona pogosto spreminja, je
    298298primerneje uporabiti okno z dvema grafičnima pomnilnikoma
    299 ''GLUT\_DOUBLE''. Prednost slednjega je v tem, da v en pomnilnik
     299''GLUT_DOUBLE''. Prednost slednjega je v tem, da v en pomnilnik
    300300rišemo, drugega pa prikazujemo. Rišemo v ravnino, ki je v ozadju.
    301301Ob koncu risanja pa le zamenjamo ravnini. Ker pa je to odvisno od
     
    392392vozliščih nastajajo povsod tam kjer imajo ploskvice skupen rob,
    393393za katerega želimo, da ima gladek prehod. To pa je povsod tam, kjer
    394 aproksimiramo ´´gladko`` površino z osnovnimi gradniki.  Slika
     394aproksimiramo 'gladko' površino z osnovnimi gradniki.  Slika
    3953952 kaže splošno postavitev treh točk v
    396396prostoru. Normalo za trikotnik
    397 z vozlišči $\vec{r}_0, \vec{r}_1, \vec{r}_2$ izračunamo z
     397z vozlišči '''r,,0,,''', '''r,,1,,''', '''r,,2,,''' izračunamo z
    398398vektorskim produktom
    399 $$ \vec{n} = \frac{  (\vec{r}_1-\vec{r}_0)\times (\vec{r}_2-\vec{r}_0) }
    400     {|(\vec{r}_1-\vec{r}_0)\times (\vec{r}_2-\vec{r}_0)|}
    401 $$
    402    
    403 Imenovalec zgornje enačbe je dolžina vektorja $\vec{n}$.
     399
     400'''n''' = [('''r,,1,,''' - '''r,,0,,''')×('''r,,2,,''' - '''r,,0,,''')] / |('''r,,1,,''' - '''r,,0,,''')×('''r,,2,,''' - '''r,,0,,''')|
     401
     402Imenovalec zgornje enačbe je dolžina vektorja '''n'''.
    404403Normala je pravokotna na razliko vektorjev, ki podajajo
    405404vozlišče gradnika.
    406405
     406[[Image(color-triangle.png)]]
     407
     408Slika 1: Trikotnik s podanimi barvami v vozliščih
     409
     410[[Image(normal.eps)]]
     411
     412Slika 2: Normala
     413
    407414
    408415= Geometrijske transformacije =
     416
    409417Osnova vseh grafičnih knjižnic so tudi osnovne geometrijske
    410418transformacije, kot so: 
    411 \begin{description}
    412 \item[Translate(x, y, z)] Premik v smeri vektorja
    413 \item[Rotate(fi, x, y, z)]  Rotacija za \emph{fi} stopinj okoli osi
    414   podane z  (x, y, z)
    415 \item[Scale(x, y, z)] Skaliranje po posameznih oseh
    416 \end{description}
    417 Ukazi za transformacije se ne smejo pojavljati med \emph{Begin/End},
     419
     420'''Translate(x, y, z)''' Premik v smeri vektorja
     421
     422'''Rotate(fi, x, y, z)'''  Rotacija za ''fi'' stopinj okoli osi
     423podane z  (x, y, z)
     424
     425'''Scale(x, y, z)''' Skaliranje po posameznih oseh
     426
     427Ukazi za transformacije se ne smejo pojavljati med ''Begin/End'',
    418428saj bi to pomenilo, da se transformacija spreminja med izrisom.
    419429Geometrijske transformacije nam pomagajo pri modeliranju, saj lahko
    420430podajamo vozlišča gradnikov v nekem poljubnem koordinatnem
    421431sistemu. To je lahko svetovni koordinatni sistem ali lokalni
    422 koordinatni sistem. Za primer izberimo izris krivulje $y(x)=\sin(x)$ v
     432koordinatni sistem. Za primer izberimo izris krivulje ''y(x)=sin(x)'' v
    423433jeziku GL. Kot smo že opazili, je prednastavljeno okno v GLUT
    424434obliki kvadrata, velikosti (-1,-1) do (1,1). Vsega skupaj torej dve
    425435enoti. V zaslonskih koordinatah je prednastavljena velikost okna
    426 $300\times 300$ pikslov. Za nas je pomembno, da sinus narišemo v
     436300×300 pikslov. Za nas je pomembno, da sinus narišemo v
    427437mejah od -1 do 1. Vzemimo primer, ko predvidimo število točk.
    428438Podprogram za izris je naslednji:
    429439
    430 {\scriptsize\begin{verbatim}
    431 subroutine display
    432 include 'GL/fgl.h'
    433 call fglClear(GL_COLOR_BUFFER_BIT)
    434 call fglBegin(GL_LINE_STRIP)
    435 do i=0,10
    436   y = sin((i-5)/5.0*3.14)
    437   call fglVertex2f((i-5)/5.0, y/3.14)
    438 end do
    439 call fglEnd
    440 call fglFlush
    441 end
    442 \end{verbatim}}
     440{{{
     441#!c
     442void display()
     443{
     444  glClear(GL_COLOR_BUFFER_BIT);
     445  glBegin(GL_LINE_STRIP);
     446  for(i=0;i<=10;i++)
     447  {
     448    y=sin((i-5)/5.0*3.14);
     449    glVertex2f((i-5)/5.0, y/3.14);
     450  }
     451  glEnd();
     452  glFlush();
     453}
     454}}}
     455
    443456Da smo spravili naših 11 točk lomljenke v okvir -1, 1 je bilo
    444 potrebno premakniti koordinatni sistem osi $x$ za 5, ga nato še
     457potrebno premakniti koordinatni sistem osi ''x'' za 5, ga nato še
    445458skalirati tako, da smo iz območja [0,10] dobili območje [-3.14,
    4464593.14]. čeprav smo za izračun koordinate y potrebovali na osi x
    447 območje [-3.14, 3.14] pa je potrebna os $x$ za izris v območju
    448 [-1,1]. Zato pri izrisu podajamo os $x$ tako, da ponovno
    449 poračunavamo območje [0,10] v območje [-1,1], tako da \texttt{i}-ju
     460območje [-3.14, 3.14] pa je potrebna os ''x'' za izris v območju
     461[-1,1]. Zato pri izrisu podajamo os ''x'' tako, da ponovno
     462poračunavamo območje [0,10] v območje [-1,1], tako da ''i''-ju
    450463odštejemo 5 in delimo z 5. Lahko bi tudi delili s 5 in odšteli
    4514641. Nekoliko bi poenostavili stvari, če bi imeli vsaj en kordinatni
    452 sistem že takoj uporaben. Recimo os $x$. Zanka se nekoliko
     465sistem že takoj uporaben. Recimo os ''x''. Zanka se nekoliko
    453466poenostavi, še vedno pa je potrebno vse koordinate pomanjšati
    454467za 3.14 oziroma poskalirati.
    455 {\scriptsize\begin{verbatim}
    456 do x=-3.14, 3.14, 0.6
    457 y = sin(x)
    458 call fglVertex2f(x/3.14, y/3.14)
    459 end do
    460 \end{verbatim}}
     468
     469{{{
     470#!c
     471for(x=-3.14;x<=3.14;i+=0.6)
     472{
     473  y=sin(x);
     474  glVertex2f(x/3.14, y/3.14);
     475}
     476}}}
     477
    461478Bolj razumljivo bi bilo risati kar v lokalnem koordinatnem sistemu in
    462479prednastaviti pomanjšavo modela. Za pomanjšavo uporabimo
    463480ukaz za skaliranje, ki posamezne koordinate množi s konstanto 1/3.14,
    464481preden se izriše. Podprogram za izris je naslednji:
    465 {\scriptsize\begin{verbatim}
    466 subroutine display
    467 include 'GL/fgl.h'
    468 call fglClear(GL_COLOR_BUFFER_BIT)
    469 call fglScalef(1/3.14, 1/3.14, 1.0)
    470 call fglBegin(GL_LINE_STRIP)
    471 do x=-3.14, 3.14, 0.6
    472 y = sin(x)
    473 call fglVertex2f(x, y)
    474 end do
    475 call fglEnd
    476 call fglFlush
    477 end
    478 \end{verbatim}}
     482
     483{{{
     484#!c
     485void display()
     486{
     487  glClear(GL_COLOR_BUFFER_BIT);
     488  glScalef(1/3.14, 1/3.14, 1.0);
     489  glBegin(GL_LINE_STRIP);
     490  for(x=-3.14;x<=3.14;i+=0.6)
     491  {
     492    y=sin(x);
     493    glVertex2f(x, y);
     494  }
     495  glEnd();
     496  glFlush();
     497}
     498}}}
     499
    479500Prednost takega načina razmišljanja se pokaže, že ko
    480501želimo pod sinusom narisati še krivuljo kosinusa. Seveda ni
    481 možno obeh krivulj risati z \emph{GL\_LINE\_STRIP} v isti
     502možno obeh krivulj risati z ''GL_LINE_STRIP'' v isti
    482503zanki. Zato se odločimo za ponovno risanje v lokalnem
    483504koordinatnem sistemu in prednastavimo pomik navzdol za 1.5 enote.
    484 {\scriptsize\begin{verbatim}
    485 subroutine display
    486 include 'GL/fgl.h'
    487 call fglClear(GL_COLOR_BUFFER_BIT)
    488 call fglScalef(1/3.14, 1/3.14, 1.0)
    489 call fglBegin(GL_LINE_STRIP)
    490 do x=-3.14, 3.14, 0.6
    491 y = sin(x)
    492 call fglVertex2f(x, y)
    493 end do
    494 call fglEnd
    495 call fglTranslatef(0.0, -1.5, 0.0)
    496 call fglBegin(GL_LINE_STRIP)
    497 do x=-3.14, 3.14, 0.6
    498 y = cos(x)
    499 call fglVertex2f(x, y)
    500 end do
    501 call fglEnd
    502 call fglFlush
    503 end
    504 \end{verbatim}}
     505
     506{{{
     507#!c
     508void display()
     509{
     510  glClear(GL_COLOR_BUFFER_BIT);
     511  glScalef(1/3.14, 1/3.14, 1.0);
     512  glBegin(GL_LINE_STRIP);
     513  for(x=-3.14;x<=3.14;i+=0.6)
     514  {
     515    y=sin(x);
     516    glVertex2f(x, y);
     517  }
     518  glEnd();
     519  glTranslatef(0.0, -1.5, 0.0);
     520  glBegin(GL_LINE_STRIP);
     521  for(x=-3.14;x<=3.14;i+=0.6)
     522  {
     523    y=cos(x);
     524    glVertex2f(x, y);
     525  }
     526  glEnd(); 
     527  glFlush();
     528}
     529}}}
     530
    505531Podani program za kosinus ne nastavlja ponovno skaliranja, saj je ukaz
    506532že pred tem nastavil pomanjšavo. Translacija za -1.5 se izvede
     
    510536vzgor. Transformacija, ki se izvede zadnja je torej napisana na prvem
    511537mestu v programu. Tak način transformiranja točk nam
    512 omogoča enostavnejše modeliranje. Koordinata $y$ kosinusa se
    513 izračuna tako, da se pred izrisom najprej vsaki točki $y$
     538omogoča enostavnejše modeliranje. Koordinata ''y'' kosinusa se
     539izračuna tako, da se pred izrisom najprej vsaki točki ''y''
    514540prišteje translacija -1.5 in potem se še izvede skaliranje
    515541tako, da se ta vmesna točka pomnoži še z 1/3.14.
    516542
    517 
    518 \subsection{Nadzor transformacijske matrike}
     543== Nadzor transformacijske matrike ==
     544
    519545OpenGL pa za izračun koordinat ne hrani vse zgodovine posameznih
    520546transformacij za nazaj, saj bi bilo to računsko potratno. Vse te
     
    524550Prva matrika je modelna, druga pa je projekcijska. Mi bomo
    525551uporabljali le modelno transformacijo in upoštevali, da
    526 projekcijska matrika omogoča prikaz ravnine $(x,y)$ v področju
     552projekcijska matrika omogoča prikaz ravnine ''(x,y)'' v področju
    527553[-1,1]. Modelna matrika je tudi stalno aktivna, če se ne
    528554izbere projekcijsko.
     
    530556Modelna matrika se ob vsakem klicu transformacijskega podprograma
    531557popravi. Začetna oblika modelne matrike je enotska. Vsak klic
    532 podprograma \emph{Translate}, \emph{Scale} in \emph{Rotate} pa matriko
     558podprograma ''Translate'', ''Scale'' in ''Rotate'' pa matriko
    533559popravi tako, da so upoštevane vse prejšnje transformacije in
    534560nad njimi še novo podana transformacija. Matrika je torej stalna,
     
    537563lahko preverimo tako, da okno prekrijemo s kakim drugim oknom in ga
    538564potem ponovno odkrijemo. Kot že omenjeno, je na začetku
    539 programa matrika enotska. S podprogramom \emph{fglLoadIdentity} na
     565programa matrika enotska. S podprogramom ''glLoadIdentity'' na
    540566začetku bi lahko to tudi zagotovili ob vsakem izrisu.
    541567
     
    543569shraniti in obnoviti. OpenGL ima v ta namen poseben pomnilnik v obliki
    544570sklada, v katerega lahko shranjujemo trenutno
    545 transformacijsko matriko. V pomnilniku oblike LIFO (\emph{Last In,
    546   First Out}) je prostora je za najmanj 32 matrik. Pomnilnik si lahko
     571transformacijsko matriko. V pomnilniku oblike LIFO (''Last In,
     572First Out'') je prostora je za najmanj 32 matrik. Pomnilnik si lahko
    547573predstavljamo kot hladilnik, v katerega shranjujemo matrike. Matriko, ki
    548574jo želimo shraniti, potisnemo na začetek in to tako, da
     
    550576iz hladilnika, je to lahko le zadnja matrika. če
    551577želimo predzadnjo, moramo poprej vzeti zadnjo. Za shranitev
    552 trenutne matrike se uporabi \textbf{glPushMatrix}, za ponastavitev iz
    553 sklada pa uporabimo \textbf{glPopMatrix}. Izkaže se, da je za
     578trenutne matrike se uporabi '''glPushMatrix''', za ponastavitev iz
     579sklada pa uporabimo '''glPopMatrix'''. Izkaže se, da je za
    554580modeliranje taka oblika pomnilnika povsem primerna.
    555581
    556582Za primer vzemimo primer kocke sestavljene iz šestih ploskev. Za
    557 izris kvadrata obstaja že krajša funkcija \texttt{glRectf(x1,
    558   y1, x2, y2)} za ravnino $z=0$. če želimo imeti kvadrat v
     583izris kvadrata obstaja že krajša funkcija ''glRectf(x1,
     584y1, x2, y2)'' za ravnino ''z=0''. če želimo imeti kvadrat v
    559585poljubni ravnini, pa uporabimo transformacije.
    560 {\scriptsize
    561 \begin{verbatim}
    562 subroutine kvadrat(i)
    563 real r(6), g(6), b(6)
    564 data r /1,0,0,1,1,1/, g /0,1,0,1,0,0/
    565 data b /0,0,1,0,1,1/
    566 call fglPushMatrix
    567 call fglColor3f(r(i), g(i), b(i))
    568 call fglTranslatef(0.0, 0.0, 1.0)
    569 call fglRectf(-1.0, -1.0, 1.0, 1.0)
    570 call fglPopMatrix
    571 end
    572 
    573 subroutine display
    574 implicit none
    575 include 'GL/fgl.h'
    576 call fglClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT)
    577 call fglPushMatrix
    578 call fglRotatef(30.0, 1.0, 0.0, 0.0)
    579 call fglRotatef(30.0, 0.0, 1.0, 0.0)
    580 call fglScalef(0.5, 0.5, 0.5)
    581 call kvadrat(1)
    582 call fglRotatef(90.0, 0.0, 1.0, 0.0)
    583 call kvadrat(2)
    584 call fglRotatef(90.0, 0.0, 1.0, 0.0)
    585 call kvadrat(3)
    586 call fglRotatef(90.0, 0.0, 1.0, 0.0)
    587 call kvadrat(4)
    588 call fglRotatef(90.0, 1.0, 0.0, 0.0)
    589 call kvadrat(5)
    590 call fglRotatef(180.0, 1.0, 0.0, 0.0)
    591 call kvadrat(6)
    592 call fglPopMatrix
    593 call fglFlush
    594 end
    595 
    596 program kocka
    597 external display
    598 include 'GL/fglut.h'
    599 include 'GL/fgl.h'
    600 call fglutinit
    601 call fglutInitDisplayMode(GLUT_SINGLE+GLUT_DEPTH)
    602 call fglutCreateWindow('Fortran GLUT program')
    603 call fglutDisplayFunc(display)
    604 call fglEnable(GL_DEPTH_TEST)
    605 call fglutmainloop
    606 end
    607 \end{verbatim}
    608 } Podprogram \emph{kvadrat} je narejen tako, da riše transliran
    609 kvadrat v ravnini $z=1$. To lahko razumemo kot nov primitiv, saj par
     586
     587{{{
     588#!c
     589float kvadrat(int i)
     590{
     591  float r[6]={1,0,0,1,1,1}, g[6]={0,1,0,1,0,0}, b[6]={0,0,1,0,1,1};
     592  glPushMatrix();
     593  glColor3f(r[i], g[i], b[i]);
     594  glTranslatef(0.0, 0.0, 1.0);
     595  glRectf(-1.0, -1.0, 1.0, 1.0);
     596  glPopMatrix();
     597}
     598
     599void display()
     600{
     601  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
     602  glPushMatrix();
     603  glRotatef(30.0, 1.0, 0.0, 0.0);
     604  glRotatef(30.0, 0.0, 1.0, 0.0);
     605  glScalef(0.5, 0.5, 0.5);
     606  kvadrat(1);
     607  glRotatef(90.0, 0.0, 1.0, 0.0);
     608  kvadrat(2);
     609  glRotatef(90.0, 0.0, 1.0, 0.0);
     610  kvadrat(3);
     611  glRotatef(90.0, 0.0, 1.0, 0.0);
     612  kvadrat(4);
     613  glRotatef(90.0, 1.0, 0.0, 0.0);
     614  kvadrat(5);
     615  glRotatef(180.0, 1.0, 0.0, 0.0);
     616  kvadrat(6);
     617  glPopMatrix();
     618  glFlush();
     619}
     620
     621int main(int argc, char *argv[])
     622{
     623  glutInit(&argc, argv);
     624  glutInitDisplayMode(GLUT_SINGLE|GLUT_DEPTH);
     625  glutCreateWindow("C GLUT program");
     626  glutDisplayFunc(display);
     627  glEnable(GL_DEPTH_TEST);
     628  glutMainLoop();
     629  return 0;
     630
     631}}}
     632
     633Podprogram ''kvadrat'' je narejen tako, da riše transliran
     634kvadrat v ravnini ''z=1''. To lahko razumemo kot nov primitiv, saj par
    610635ukazov Push/Pop ne popravlja transformacije ob klicu podprograma.
    611 šest stranic se riše z rotacijo osnovne stranice okoli osi y
    612 in x. Modelna matrika se shani z začetnim ukazom \emph{Push} in
    613 potem ponovno obnovi z ukazom \emph{Pop}.
    614 
    615 
    616 \subsection{Globinski pomilnik}
     636Šest stranic se riše z rotacijo osnovne stranice okoli osi y
     637in x. Modelna matrika se shani z začetnim ukazom ''Push'' in
     638potem ponovno obnovi z ukazom ''Pop''.
     639
     640== Globinski pomilnik ==
     641
    617642Da se ploskve v prostoru pravilno izrisujejo tudi takrat, ko
    618643rišemo ploskvice za drugimi, je potrebno uporabiti globinski
    619 pomnilnik ali \emph{z-buffer}. To pa mora omogočati že sam
     644pomnilnik ali ''z-buffer''. To pa mora omogočati že sam
    620645okenski sistem, zato je potrebno tak način prikaza zahtevati že
    621 pri \texttt{fglutInitDisplayMode} in kasneje še dopovedati GL
    622 stroju, da poleg barve točk na zaslonu shranjuje še koordinato
    623 $z$ v svoj pomnilnik. S tem pomnilnikom GL ob rasterizaciji lika za
    624 vsako točko ugotovi, če je že kakšna točka po
    625  globini pred njim in jo zato ne riše. Z ukazom
    626 \texttt{fglEnable(GL\_DEPTH\_TEST)} se zahteva izračunavanje
    627 globine, ki jo je potrebno tako kot barvo pred vsakim začetkom
    628 risanja pobrisati z ukazom \texttt{fglClear}.
    629 
    630 \begin{figure}[htbp]
    631   \centering
    632   \includegraphics{half-cube}
    633   \caption{Kocka brez spodnjega in zgornjega pokrova (kvadrat(5) in kvadrat(6)}
    634   \label{fig:half-cube}
    635 \end{figure}
     646pri ''fglutInitDisplayMode'' in kasneje še dopovedati GL
     647stroju, da poleg barve točk na zaslonu, shranjuje še koordinato
     648''z'' v svoj pomnilnik. S tem pomnilnikom GL ob rasterizaciji lika za
     649vsako točko ugotovi, če je že kakšna točka po
     650globini pred njim in jo zato ne riše. Z ukazom
     651''glEnable(GL_DEPTH_TEST)'' se zahteva izračunavanje
     652globine, ki jo je potrebno, tako kot barvo, pred vsakim začetkom
     653risanja pobrisati z ukazom ''glClear''.
     654
     655[[Image(half-cube.png)]]
     656
     657Slika 3: Kocka brez spodnjega in zgornjega pokrova (kvadrat(5) in kvadrat(6)
    636658
    637659če rišemo zaprte modele, potem notranjosti ni možno
    638 videti. Primer odprtega modela kaže slika \ref{fig:half-cube}. V
     660videti. Primer odprtega modela kaže slika 3. V
    639661takih primerih se ob uporabi prostorskega pomnilnika običajno kar
    640662polovica ploskvic modela prekrije v celoti in kasneje na zaslonu ni
    641663vidna. Skupna značilnost vseh teh ploskvic, ki se prekrijejo je,
    642 da imajo normalo površine negativno ($n_z < 0$). Da se izogemo
     664da imajo normalo površine negativno (''n,,z,, < 0''). Da se izognemo
    643665nepotrebni rasterizaciji teh ploskvic, vključimo
    644 \texttt{GL\_CULL\_FACE}. Da pa bo izločanje delovalo, mora imeti
     666''GL_CULL_FACE''. Da pa bo izločanje delovalo, mora imeti
    645667GL podatek za normalo površine, ki jo je potrebno podati pred
    646668podatki v vozliščih. Za pravilno delovanje globinskega
    647 pomnilnika je potrebna tudi nastavitev projekcijske matrike kot je to
    648 opisano v \S\ref{sec:viewing}.
    649 
    650 \subsection{Animacija}
    651 \label{sec:animate}
     669pomnilnika je potrebna tudi nastavitev projekcijske matrike, kot je to
     670opisano v poglavju Transformacije pogleda.
     671
     672== Animacija ==
     673
    652674Imejmo primer animacije vozil na avtocesti. Predstavljeno bo
    653675cestišče v eno smer z dvema pasovoma, voznim in prehitevalnim.
     
    655677vozišče dolžine 500 metrov. Hitrost vozila med vožnjo se ne
    656678spreminja. Spreminja se le položaj vozil (x, y) na
    657 cestišču, ki jih izriše  podprogram \texttt{vozilo}.
    658 
    659 {\scriptsize\begin{verbatim}
    660 subroutine display
    661 implicit none
    662 include 'GL/fgl.h'
    663 common /vozila/ y(5), v(5)
    664 real y, v, pas
    665 integer i
    666 data y /0,50,120,170,200/
    667 data v /50,30,45,31,33/
    668 call fglClear(GL_COLOR_BUFFER_BIT)
    669 call fglPushMatrix
    670 call fglRotatef(-45.0, 0.0, 0.0, 1.0)
    671 call fglTranslatef(0.0, -1.0, 0.0)
    672 call fglScalef(0.004, 0.004, 0.004)
    673 call fglColor3f(0.0, 0.0, 0.0)
    674 call fglRectf(-4.0, 0.0, 4.0, 500.0)
    675 call fglTranslatef(0.0, -50.0, 0.0)
    676 do i=1,5
    677    if (i.ne.5 .and. y(i+1)-y(i).lt.10.0) then
    678      pas=-2.0
    679    else
    680       pas = 2.0
    681    end if
    682    call vozilo(y(i), pas)
    683 end do
    684 call fglPopMatrix
    685 call fglutSwapBuffers
    686 end
    687 
    688 subroutine vozilo(y, pas)
    689 call fglPushMatrix
    690 call fglColor3f(1.0, 1.0, 1.0)
    691 call fglTranslatef(pas, y, 0.5)
    692 call fglRectf(-2.0, 0.0, 2.0, 6.0)
    693 call fglPopMatrix
    694 end
    695 
    696 subroutine ura(n)
    697 common /vozila/ y(5), v(5)
    698 real y, v, dt
    699 dt = 0.1
    700 do i=1,5
    701   y(i)=y(i)+v(i)*dt
    702 end do
    703 call fglutPostRedisplay
    704 call fglutTimerfunc(100, ura, 0)
    705 end
    706 
    707 program Mad Max
    708 external display
    709 external ura
    710 include 'GL/fglut.h'
    711 integer window
    712 call fglutInit
    713 call fglutInitDisplayMode(GLUT_RGB+GLUT_DOUBLE)
    714 call fglutCreateWindow('Avtocesta')
    715 call fglClearColor(0.0, 0.5, 0.0, 0.0)
    716 call fglutDisplayFunc(display)
    717 call fglutTimerFunc(100, ura, 0)
    718 call fglutMainLoop
    719 end
    720 \end{verbatim}
    721 }
    722 
    723 Pas predstavlja odmik v smeri $x$ od sredine cestišča. Vse
     679cestišču, ki jih izriše  podprogram ''vozilo''.
     680
     681{{{
     682#!c
     683#include <GL/glut.h>
     684
     685float y[5]={0,50,120,170,200};
     686float v[5]={50,30,45,31,33};
     687float pas;
     688
     689void ura()
     690{
     691  float dt;
     692  int i;
     693  dt=0.1;
     694  for(i=1;i<6;i++)
     695  {
     696    y[i]=y[i]+v[i]*dt;
     697  }
     698  glutPostRedisplay();
     699  glutTimerFunc(100, ura, 0);
     700}
     701
     702float vozilo(float y, float pas)
     703{
     704  glPushMatrix();
     705  glColor3f(1.0, 1.0, 1.0);
     706  glTranslatef(pas, y, 0.5);
     707  glRectf(-2.0, 0.0, 2.0, 6.0);
     708  glPopMatrix();
     709}
     710
     711void display()
     712{
     713  int i;
     714  glClear(GL_COLOR_BUFFER_BIT);
     715  glPushMatrix();
     716  glRotatef(-45.0, 0.0, 0.0, 1.0);
     717  glTranslatef(0.0, -1.0, 0.0);
     718  glScalef(0.004, 0.004, 0.004);
     719  glColor3f(0.0, 0.0, 0.0);
     720  glRectf(-4.0, 0.0, 4.0, 500.0);
     721  glTranslatef(0.0, -50.0, 0.0);
     722  for(i=1;i<6;i++)
     723  {
     724    if (i<5 && (y[i+1]-y[i])>10.0)
     725      pas=-2.0;
     726    else
     727      pas=2.0;
     728
     729    vozilo(y[i], pas);
     730  }
     731  glPopMatrix();
     732  glutSwapBuffers();
     733}
     734
     735int main(int argc, char *argv[])
     736{
     737  glutInit(&argc, argv);
     738  glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
     739  glutCreateWindow("Avtocesta");
     740  glClearColor(0.0, 0.5, 0.0, 0.0);
     741  glutDisplayFunc(display);
     742  glutTimerFunc(100, ura, 0);
     743  glutMainLoop();
     744  return 0;
     745}
     746}}}
     747
     748Pas predstavlja odmik v smeri ''x'' od sredine cestišča. Vse
    724749enote so v metrih. Vozilo je zaradi sorazmerja narisano
    725750nekoliko večje. Za animacije je primernejša uporaba dvojnega
    726 pomnilnika \texttt{GLUT\_DOUBLE}. S tem se izognemo težavam izrisa,
     751pomnilnika ''GLUT_DOUBLE''. S tem se izognemo težavam izrisa,
    727752saj v trenutku, ko se zgornja plast izrisuje, nemoteno rišemo v
    728753spodnjo plast. Ko je spodnja plast izdelana z ukazom
    729 \emph{fglutSwapBuffers}, zamenjamo trenutni prikaz.
    730 
    731 Za animacijo, pri kateri je zahtevano točno časovno zaporedje je
    732 primerno uporabiti uro (\emph{timer}), ki program opozori, da je
     754''glutSwapBuffers'', zamenjamo trenutni prikaz.
     755
     756Za animacijo, pri kateri je zahtevano točno časovno zaporedje, je
     757primerno uporabiti uro (''timer''), ki program opozori, da je
    733758pretekel predpisani čas in da je potrebno izračunati nov
    734 položaj vozil. V našem primeru je podana spremeba vsakih 100~ms
    735 in zato nov položaj v smeri $y$ linearno narašča za $v(i)
    736 dt$, kjer je hitrost podana v metrih na sekundo. Izbor 0.1s za premik
     759položaj vozil. V našem primeru je podana spremeba vsakih 100 ms
     760in zato nov položaj v smeri ''y'' linearno narašča za ''v(i)
     761dt'', kjer je hitrost podana v metrih na sekundo. Izbor 0.1s za premik
    737762pomeni 1/0.1=10 posnetkov na sekundo, kar je spodnja meja pri
    738763animacijah. Po poračunu novih položajev pošljemo
    739 sporočilo \emph{fglutPostRedisplay}, da se na novo izriše
    740 scena. Lahko bi tudi neposredno klicali \texttt{display}, vendar bi
     764sporočilo ''glutPostRedisplay'', da se na novo izriše
     765scena. Lahko bi tudi neposredno klicali ''display'', vendar bi
    741766bilo potem potrebno zagotoviti še kompenzacijo hitrosti, saj
    742 že v podprogramu ura izgubimo nekaj časa pri izrečunu
     767že v podprogramu ura izgubimo nekaj časa pri izračunu
    743768novih položajev. Prostorski pomnilnik v tem primeru ni potreben,
    744769saj je zagotovljeno, da se izrisi prekrijejo v pravilnem vrstnem redu.
    745770
    746 \subsection{Transformacije pogleda}
    747 \label{sec:viewing}
     771== Transformacije pogleda ==
     772
    748773Za zahtevnejše načine gledanja na model je potrebno nastaviti
    749774projekcijo modela iz svetovnih koordinat v normalizirane oz. zaslonske
     
    753778želimo poudariti bližino in oddaljenost določenih
    754779objektov, se uporablja tudi perspektivna projekcija.
    755 \begin{figure}[htbp]
    756   \centering
    757   \includegraphics[width=3in]{viewing}
    758   \caption{Zaporedje pretvorbe koordinat vozlišč}
    759   \label{fig:viewing}
    760 \end{figure}
     780
     781[[Image(viewing.eps)]]
     782
     783Slika 4: Zaporedje pretvorbe koordinat vozlišč
    761784
    762785OpenGL ločuje projekcijsko matriko in modelno matriko zato,
    763 da ni potrebno nastavljati projekcije pri vsakem izrisu.  Slika
    764 \ref{fig:viewing} kaže zaporedje transformacij iz svetovnih
     786da ni potrebno nastavljati projekcije pri vsakem izrisu.  Slika 
     7874 kaže zaporedje transformacij iz svetovnih
    765788koordinat v zaslonske. Pri risanju modela običajno začnemo z
    766 enotsko \emph{ModelView} matriko.
     789enotsko ''ModelView'' matriko.
    767790
    768791Najpreprostejši način prikaza, kot je bil prikazan tudi v
     
    777800pri sistemu GLUT le enovrstičen ukaz:
    778801
    779 {\scriptsize\texttt{call fglViewport (0, 0, width, height)}}
     802{{{
     803#!c
     804glViewport (0, 0, width, height);
     805}}}
    780806
    781807Nekoliko zahtevnejša je sorazmerna sprememba,
    782808ki ne bo anamorfično popravljala velikosti okna:
    783 {\scriptsize\begin{verbatim}
    784 subroutine  reshape (w, h)
    785 integer w, h
    786 implicit none
    787 include 'GL/fgl.h'
    788 common /viewport/ width, height
    789 integer width, height
    790 real*8 left, right, bottom, top, znear, zfar
    791 width = w
    792 height = h
    793 if (w .ge. h) then
    794         left = -width/(1.0*height)
    795         right = width/(1.0*height)
    796         bottom = -1.0
    797         top = 1.0
    798 else
    799         left = -1.0
    800         right = 1.0
    801         bottom = -height/(1.0*width)
    802         top = height/(1.0*width)
    803 end if
    804 znear = -1.0
    805 zfar = 1.0
    806 call fglViewport (0, 0, width, height)
    807 call fglMatrixMode (GL_PROJECTION)
    808 call fglLoadIdentity
    809 call fglOrtho(left, right, bottom, top, znear, zfar)
    810 call fglMatrixMode(GL_MODELVIEW)
    811 end
    812 \end{verbatim}
    813 }
    814    
     809
     810{{{
     811#!c
     812void reshape (int w, int h)
     813{
     814
     815  int width, height;
     816  double left, right, bottom, top, znear, zfar;
     817  width = w;
     818  height = h;
     819
     820  if (w == h)
     821  {
     822    left = -width/(1.0*height);
     823    right = width/(1.0*height);
     824    bottom = -1.0;
     825    top = 1.0;
     826  }
     827  else
     828  {
     829    left = -1.0;
     830    right = 1.0;
     831    bottom = -height/(1.0*width);
     832    top = height/(1.0*width);
     833  }
     834  znear = -1.0;
     835  zfar = 1.0;
     836  glViewport (0, 0, width, height);
     837  glMatrixMode (GL_PROJECTION);
     838  glLoadIdentity();
     839  glOrtho(left, right, bottom, top, znear, zfar);
     840  glMatrixMode(GL_MODELVIEW);
     841}
     842}}}
     843 
    815844Predstavljeni podprogram se priporoča v uporabo za vse programe,
    816 ki pripravljajo model v velikosti [-1,~1] za \emph{ModelView}. če
    817 bi želeli dodati modelno transformacijo v \emph{reshape}, potem za
     845ki pripravljajo model v velikosti [-1, 1] za ''ModelView''. Če
     846bi želeli dodati modelno transformacijo v ''reshape'', potem za
    818847zadnjo vrstico dopišemo še modelno transformacijo in nato v
    819848programu za izris pred začetkom le obnovimo stanje modelne
    820 matrike. Primer animacije \ref{sec:animate} bi tako imel namesto
    821 nastavitve modelne transformacije slednje v podprogramu \emph{reshape}.
     849matrike. Primer animacije bi tako imel namesto
     850nastavitve modelne transformacije slednje v podprogramu ''reshape''.
    822851Začetna nastavitev modelne matrike pred začetkom izrisa v
    823 podprogramu \emph{display} pa bi bila:
    824 {\scriptsize\begin{verbatim}
    825 call fglClear(GL_COLOR_BUFFER_BIT)
    826 call fglPushMatrix
     852podprogramu ''display'' pa bi bila:
     853
     854{{{
     855#!c
     856glClear(GL_COLOR_BUFFER_BIT);
     857glPushMatrix();
    827858... izris
    828 call fglPopMatrix
    829 \end{verbatim}
    830 }
    831 Takoj za brisanjem zaslona z ukazom \emph{Push} shranimo modelno
     859glPopMatrix();
     860}}}
     861
     862Takoj za brisanjem zaslona z ukazom ''Push'' shranimo modelno
    832863matriko in jo ob koncu ponovno nastavimo na začetno vrednost.
    833 V podprogramu \emph{reshape}, pa modelno matriko popravljamo:
    834 {\scriptsize\begin{verbatim}
    835 call fglMatrixMode(GL_MODELVIEW)
    836 call fglLoadIdentity
    837 call fglRotatef(-45.0, 0.0, 0.0, 1.0)
    838 call fglTranslatef(0.0, -1.0, 0.0)
    839 call fglScalef(0.004, 0.004, 0.004)
    840 \end{verbatim}
    841 }
     864V podprogramu ''reshape'', pa modelno matriko popravljamo:
     865
     866{{{
     867#!c
     868glMatrixMode(GL_MODELVIEW);
     869glLoadIdentity();
     870glRotatef(-45.0, 0.0, 0.0, 1.0);
     871glTranslatef(0.0, -1.0, 0.0);
     872glScalef(0.004, 0.004, 0.004);
     873}}}
     874
    842875Tak pristop nekoliko jasneje predstavi program, saj so vse enote, s
    843876katerimi manipuliramo, v programu za izris v svetovnih oz. modelnih
     
    845878vse modele, ki uporabljajo izris ploskev. To pa zaradi tega, ker je
    846879privzeta projekcijska matrika enotska. Poglejmo to na primeru
    847 paralelne projekcije \emph{glOrtho(l,r,b,,n,f)}:
    848 $$
    849    PM = \left[
    850      \begin{array}{cccc}
    851        \frac{2}{r-l} &      0        &       0        & \frac{r+l}{l-r} \cr
    852                0     & \frac{2}{t-b} &       0        & \frac{t+b}{t-b} \cr
    853                0     &      0        & \frac{2}{f-n}  & \frac{f+n}{f-n} \cr
    854                0     &      0        &       0        &      1          \cr
    855      \end{array}
    856      \right]\quad .
    857 $$
     880paralelne projekcije ''glOrtho(l,r,b,,n,f)'':
     881       
     882  ''PM = [2/(r-l), 0, 0, (r+l)/(l-r); 0, 2/(t-b), 0, (t+b)/(t-b); 0, 0, 2/(f-n), (f+n)/f-n); 0, 0, 0, 1]''
     883
    858884Za primer normalizacijskega prostora v obsegu [-1,1] je tako matrika paralelne
    859885projekcije
    860 $$
    861    PM(-1, 1, -1, 1, -1, 1) = \left[
    862      \begin{array}{cccc}
    863        1 &   0   &   0   & 0 \cr
    864        0 &   1   &   0   & 0 \cr
    865        0 &   0   &  -1   & 0 \cr
    866        0 &   0   &   0   & 1 \cr
    867      \end{array}
    868      \right]\quad ,
    869 $$
    870 kar se razlikuje od enotske prav v koordinati $z$. če bi
     886
     887   ''PM(-1, 1, -1, 1, -1, 1) = [1, 0, 0, 0; 0, 1, 0, 0; 0, 0, -1, 0; 0, 0, 0, 1]''
     888
     889kar se razlikuje od enotske prav v koordinati ''z''. Če bi
    871890projekcijsko matriko ohranili enotsko, potem bi to pomenilo, da objekt
    872891gledamo kot zrcalno sliko zadnje strani. Nastavitev projekcijske matrike
     
    875894nelogično postavil v ospredje modro stranico in ne rdečo.
    876895
     896
    877897= Osvetlitev =
     898
    878899Do sedaj predstavljeni primeri so uporabljali le sintetične barve.
    879900To pomeni, da se barva vsake ploskvice ne spreminja v odvisnosti od
     
    881902omejen nabor prostorskih modelov. Neprimeren je že za vse modele,
    882903ki imajo površine sestavljene iz primitivov in te površine
    883 niso ravninske. Za primer kocke (slika \ref{fig:half-cube}) je bilo
     904niso ravninske. Za primer kocke (slika 3) je bilo
    884905potrebno za vsako stranico nastaviti svojo barvo, da smo lahko dobili
    885 vtis prostora. če bi kocko risali le z eno barvo, potem bi dobili
     906vtis prostora. Če bi kocko risali le z eno barvo, potem bi dobili
    886907na zaslon le obris.
    887908
    888909Za bolj realističen izris je potrebno vključiti računanje
    889 osvetlitve.  žal osvetlitev zajema veliko parametrov, ki jih je
     910osvetlitve. Žal osvetlitev zajema veliko parametrov, ki jih je
    890911potrebno nastaviti preden lahko karkoli dobimo na zaslonu. Tako je
    891912potrebno nastavljati položaj in lastnosti luči, osvetlitveni
     
    899920barvo. S tem vpeljemo veliko  predpostavk, ki pa so za šolsko rabo
    900921povsem uporabne. Predpostavljena je le ena luč bele svetlobe s
    901 položajem $(0, 0, 1)$ in difuzni odboj svetlobe na
     922položajem ''(0, 0, 1)'' in difuzni odboj svetlobe na
    902923površini. Barvo površine podajamo kar z običajnim ukazom
    903924za barvo. Program za izris osenčenega modela kocke je tako v
    904925minimalni obliki naslednji:
    905926
    906 {\scriptsize\begin{verbatim}
    907 subroutine kvadrat()
    908 call fglPushMatrix
    909 call fglTranslatef(0.0, 0.0, 1.0)
    910 call fglNormal3f(0.0, 0.0, 1.0)
    911 call fglRectf(-1.0, -1.0, 1.0, 1.0)
    912 call fglPopMatrix
    913 end
    914 
    915 subroutine display
    916 implicit none
    917 include 'GL/fgl.h'
    918 call fglClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT)
    919 call fglColor3f(0.7, 0.6, 0.2)
    920 call fglPushMatrix
    921 call fglScalef(0.5, 0.5, 0.5)
    922 call kvadrat
    923 call fglRotatef(90.0, 0.0, 1.0, 0.0)
    924 call kvadrat
    925 call fglRotatef(90.0, 0.0, 1.0, 0.0)
    926 call kvadrat
    927 call fglRotatef(90.0, 0.0, 1.0, 0.0)
    928 call kvadrat
    929 call fglRotatef(90.0, 1.0, 0.0, 0.0)
    930 call kvadrat
    931 call fglRotatef(180.0, 1.0, 0.0, 0.0)
    932 call kvadrat
    933 call fglPopMatrix
    934 call fglFlush
    935 end
    936 
    937 
    938 program kocka
    939 external display
    940 external reshape
    941 include 'GL/fglut.h'
    942 include 'GL/fgl.h'
    943 call fglutinit
    944 call fglutinitdisplaymode(GLUT_SINGLE+GLUT_DEPTH)
    945 call fglutcreatewindow('Osencena kocka')
    946 call fglutDisplayFunc(display)
    947 call fglutReshapeFunc(reshape)
    948 call fglClearColor(1.0, 1.0, 1.0, 1.0)
    949 call fglEnable(GL_LIGHTING)
    950 call fglEnable(GL_LIGHT0)
    951 call fglEnable(GL_DEPTH_TEST)
    952 call fglEnable(GL_COLOR_MATERIAL)
    953 call fglutMainLoop
    954 end
    955 
    956 subroutine  reshape (w, h)
    957 integer w, h
    958 implicit none
    959 include 'GL/fgl.h'
    960 real*8 l
    961 l = 1.0
    962 call fglViewport (0, 0, w, h)
    963 call fglMatrixMode (GL_PROJECTION)
    964 call fglLoadIdentity
    965 call fglOrtho(-l, l, -l, l, -l, l)
    966 call fglMatrixMode(GL_MODELVIEW)
    967 call fglLoadIdentity
    968 call fglRotatef(30.0, 1.0, 0.0, 0.0)
    969 call fglRotatef(30.0, 0.0, 1.0, 0.0)
    970 end
    971 \end{verbatim}
    972 }
     927{{{
     928#!c
     929#include <GL/glut.h>
     930
     931float kvadrat()
     932{
     933  glPushMatrix();
     934  glTranslatef(0.0, 0.0, 1.0);
     935  glNormal3f(0.0, 0.0, 1.0);
     936  glRectf(-1.0, -1.0, 1.0, 1.0);
     937  glPopMatrix();
     938}
     939
     940void display()
     941{
     942  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
     943  glColor3f(0.7, 0.6, 0.2);
     944  glPushMatrix();
     945  glScalef(0.5, 0.5, 0.5);
     946  kvadrat();
     947  glRotatef(90.0, 0.0, 1.0, 0.0);
     948  kvadrat();
     949  glRotatef(90.0, 0.0, 1.0, 0.0);
     950  kvadrat();
     951  glRotatef(90.0, 0.0, 1.0, 0.0);
     952  kvadrat();
     953  glRotatef(90.0, 1.0, 0.0, 0.0);
     954  kvadrat();
     955  glRotatef(180.0, 1.0, 0.0, 0.0);
     956  kvadrat();
     957  glPopMatrix();
     958  glFlush();
     959}
     960
     961void reshape (int w, int h)
     962{
     963  double l;
     964  l = 1.0;
     965  glViewport (0, 0, w, h);
     966  glMatrixMode (GL_PROJECTION);
     967  glLoadIdentity();
     968  glOrtho(-l, l, -l, l, -l, l);
     969  glMatrixMode(GL_MODELVIEW);
     970  glLoadIdentity();
     971  glRotatef(30.0, 1.0, 0.0, 0.0);
     972  glRotatef(30.0, 0.0, 1.0, 0.0);
     973}
     974
     975int main(int argc, char *argv[])
     976{
     977  glutInit(&argc, argv);
     978  glutInitDisplayMode(GLUT_SINGLE|GLUT_DEPTH);
     979  glutCreateWindow("Osencena kocka");
     980  glutDisplayFunc(display);
     981  glutReshapeFunc(reshape);
     982  glClearColor(1.0, 1.0, 1.0, 1.0);
     983  glEnable(GL_LIGHTING);
     984  glEnable(GL_LIGHT0);
     985  glEnable(GL_DEPTH_TEST);
     986  glEnable(GL_COLOR_MATERIAL);
     987  glutMainLoop();
     988  return 0;
     989
     990}}}
    973991
    974992Razširjeni primitiv smo poenostavili tako, da ne vsebuje več
    975993definicije barve, ampak le geometrijo. Obvezno je bilo potrebno podati
    976 izračun normale. Za naš primitiv kvadrata je to $(0,0,1)$.
     994izračun normale. Za naš primitiv kvadrata je to ''(0,0,1)''.
    977995Program za izris v bistvu ni spremenjen, le da je sedaj
    978996transformacija modela preseljena v podprogram za nastavitev velikosti
    979 okna \texttt{reshape}. V glavnem programu pa je potrebno najprej
    980 vključiti računanje osvetlitve \emph{GL\_LIGHTING},
     997okna ''reshape''. V glavnem programu pa je potrebno najprej
     998vključiti računanje osvetlitve ''GL_LIGHTING'',
    981999prižgati je potrebno luč št 0, ki ima začetni
    982 položaj $(0,0,1)$.
    983 
    984 \begin{figure}[htbp]
    985   \centering
    986   \includegraphics[width=2.5in]{cube-l}
    987   \caption{Osenčen model kocke}
    988   \label{fig:cube-l}
    989 \end{figure}
    990 
    991 Z vključitvijo \emph{GL\_COLOR\_MATERIAL}
     1000položaj ''(0,0,1)''.
     1001
     1002[[Image(cube-l.png)]]
     1003
     1004Slika 5: Osenčen model kocke
     1005
     1006Z vključitvijo ''GL_COLOR_MATERIAL''
    9921007pa poenostavimo podajanje barve za material površine tako, da vsi
    993 klici podprogramov \emph{Color} nastavljajo privzeto difuzno in
    994 ambientno barvo površine. Slika \ref{fig:cube-l} prikazuje
     1008klici podprogramov ''Color'' nastavljajo privzeto difuzno in
     1009ambientno barvo površine. Slika 5 prikazuje
    9951010rezultat upodabljanja z osvetlitvijo.
    9961011
    9971012
    998 
    9991013= Tekst =
     1014
    10001015OpenGL sam ne podpira teksta in je zato potrebno uporabiti razne
    10011016prijeme za izris teksta v prostoru. Možnih je več načinov
    10021017za risanje besedila:
    1003 \begin{description}
    1004 \item[stroke] črke so izrisane s črtami v prostoru modela
    1005 \item[bitmap] črke so izrisane na zaslon
    1006 \item[teksture] črke so izrisane rastrsko v prostoru modela
    1007 \end{description}
     1018
     1019'''stroke''' črke so izrisane s črtami v prostoru modela
     1020
     1021'''bitmap''' črke so izrisane na zaslon
     1022
     1023'''teksture''' črke so izrisane rastrsko v prostoru modela
     1024
    10081025V šolskih primerih so najbolj uporabni že izdelani fonti v
    10091026knjižnici GLUT. Možne so naslednje številke fontov:
    1010 {\small
    1011 \begin{enumerate}
    1012 \item GLUT\_STROKE\_ROMAN
    1013 \item GLUT\_STROKE\_MONO\_ROMAN
    1014 \item GLUT\_BITMAP\_9\_BY\_15             
    1015 \item GLUT\_BITMAP\_8\_BY\_13             
    1016 \item GLUT\_BITMAP\_TIMES\_ROMAN\_10     
    1017 \item GLUT\_BITMAP\_TIMES\_ROMAN\_24     
    1018 \item GLUT\_BITMAP\_HELVETICA\_10       
    1019 \item GLUT\_BITMAP\_HELVETICA\_12       
    1020 \item GLUT\_BITMAP\_HELVETICA\_18       
    1021 \end{enumerate}
    1022 }
     1027
     1028 1. GLUT_STROKE_ROMAN
     1029
     1030 2. GLUT_STROKE_MONO_ROMAN
     1031
     1032 3. GLUT_BITMAP_9_BY_15
     1033             
     1034 4. GLUT_BITMAP_8_BY_13
     1035             
     1036 5. GLUT_BITMAP_TIMES_ROMAN_10   
     1037   
     1038 6. GLUT_BITMAP_TIMES_ROMAN_24
     1039     
     1040 7. GLUT_BITMAP_HELVETICA_10
     1041       
     1042 8. GLUT_BITMAP_HELVETICA_12
     1043       
     1044 9. GLUT_BITMAP_HELVETICA_18       
    10231045
    10241046Za primer razširimo program za izris osenčene kocke z
    1025 besedilom na vsaki stranici. Podprogram \emph{kvadrat} kot argument
     1047besedilom na vsaki stranici. Podprogram ''kvadrat'' kot argument
    10261048vzame besedilo. Začetek izpisa premakne za malenkost višje in
    1027 začne v koordinati $x=-0.8$. Ker pa ne želimo, da se besedilo
    1028 senči je tu potrebno izklapljanje senčenja takrat, ko
     1049začne v koordinati ''x=-0.8''. Ker pa ne želimo, da se besedilo
     1050senči, je tu potrebno izklapljanje senčenja takrat, ko
    10291051izrisujemo posamezne črke. Ker so črke v vnaprej določeni
    10301052velikost, jih je potrebno ustrezno pomanjšati s
    1031 skaliranjem. Podprogram \texttt{fglutStrokeCharacter} po vsaki
     1053skaliranjem. Podprogram ''glutStrokeCharacter'' po vsaki
    10321054izrisani črti sam nastavi pomik v smeri x za širino izrisane
    10331055črke.
    10341056
    1035 {\scriptsize\begin{verbatim}
    1036 subroutine kvadrat(s)
    1037 include 'GL/fgl.h'
    1038 character s*(*), c
    1039 call fglPushMatrix
    1040 call fglTranslatef(0.0, 0.0, 1.0)
    1041 call fglNormal3f(0.0, 0.0, 1.0)
    1042 call fglRectf(-1.0, -1.0, 1.0, 1.0)
    1043 call fglTranslatef(-0.8, 0.0, 0.01)
    1044 call fglDisable(GL_LIGHTING)
    1045 call fglScalef(0.003, 0.003, 0.003)
    1046 call fglColor3f(1.0, 0.0, 0.0)
    1047 lenc = len(s)
    1048 do i=1,lenc
    1049   c = s(i:i)
    1050   call fglutStrokeCharacter(1, ichar(c))
    1051 end do
    1052 call fglEnable(GL_LIGHTING)
    1053 call fglPopMatrix
    1054 end
    1055 
    1056 subroutine display
    1057 implicit none
    1058 include 'GL/fgl.h'
    1059 real mat(4)
    1060 data mat /0.9, 0.6, 0.3, 1.0/
    1061 call fglClear(GL_COLOR_BUFFER_BIT)
    1062 call fglClear(GL_DEPTH_BUFFER_BIT)
    1063 call fglPushMatrix
    1064 call fglRotatef(30.0, 1.0, 0.0, 0.0)
    1065 call fglRotatef(30.0, 0.0, 1.0, 0.0)
    1066 call fglScalef(0.5, 0.5, 0.5)
    1067 call fglMaterialfv(GL_FRONT, GL_DIFFUSE, mat)
    1068 call kvadrat('Spredaj')
    1069 call fglRotatef(90.0, 0.0, 1.0, 0.0)
    1070 call kvadrat('Desno')
    1071 call fglRotatef(90.0, 0.0, 1.0, 0.0)
    1072 call kvadrat('Zadaj')
    1073 call fglRotatef(90.0, 0.0, 1.0, 0.0)
    1074 call kvadrat('Levo')
    1075 call fglRotatef(90.0, 1.0, 0.0, 0.0)
    1076 call kvadrat('Spodaj')
    1077 call fglRotatef(180.0, 1.0, 0.0, 0.0)
    1078 call kvadrat('Zgoraj')
    1079 call fglPopMatrix
    1080 call fglFlush
    1081 end
    1082 
    1083 subroutine reshape(w, h)
    1084 include 'GL/fgl.h'
    1085 integer w, h
    1086 real*8 l
    1087 l = 1
    1088 call fglViewPort(0, 0, w, h)
    1089 call fglMatrixMode(GL_PROJECTION)
    1090 call fglLoadIdentity
    1091 call fglOrtho(-l,l,-l,l,-l,l)
    1092 call fglMatrixMode(GL_MODELVIEW)
    1093 call fglLoadIdentity
    1094 end
    1095 
    1096 program crta
    1097 external display
    1098 external reshape
    1099 include 'GL/fglut.h'
    1100 include 'GL/fgl.h'
    1101 call fglutinit
    1102 call fglutinitdisplaymode(GLUT_SINGLE+GLUT_DEPTH)
    1103 call fglutcreatewindow('Fortran GLUT program')
    1104 call fglutDisplayFunc(display)
    1105 call fglutReshapeFunc(reshape)
    1106 call fglEnable(GL_DEPTH_TEST)
    1107 call fglEnable(GL_LIGHTING)
    1108 call fglEnable(GL_LIGHT0)
    1109 call fglClearColor(1.0, 1.0, 1.0, 1.0)
    1110 call fglutmainloop
    1111 end
    1112 \end{verbatim}
    1113 }
    1114 
    1115 \begin{figure}[htbp]
    1116   \centering
    1117   \includegraphics[width=2.5in]{cube-f}
    1118   \caption{Osenčen model kocke z napisi}
    1119   \label{fig:cube-f}
    1120 \end{figure}
     1057{{{
     1058#!c
     1059#include <GL/glut.h>                                                 
     1060                                                                                                               
     1061float kvadrat(char *s)
     1062{
     1063  char *c;
     1064  glPushMatrix();
     1065  glTranslatef(0.0, 0.0, 1.0);
     1066  glNormal3f(0.0, 0.0, 1.0);
     1067  glRectf(-1.0, -1.0, 1.0, 1.0);
     1068  glTranslatef(-0.8, 0.0, 0.01);
     1069  glDisable(GL_LIGHTING);
     1070  glScalef(0.003, 0.003, 0.003);
     1071  glColor3f(1.0, 0.0, 0.0);
     1072  for(c=s; *c; c++)
     1073  {
     1074    glutStrokeCharacter(GLUT_STROKE_ROMAN, *c);
     1075  }
     1076  glEnable(GL_LIGHTING);
     1077  glPopMatrix();
     1078}
     1079
     1080void display()
     1081{
     1082  float mat[4]={0.9, 0.6, 0.3, 1.0};
     1083  glClear(GL_COLOR_BUFFER_BIT);
     1084  glClear(GL_DEPTH_BUFFER_BIT);
     1085  glPushMatrix();
     1086  glRotatef(30.0, 1.0, 0.0, 0.0);
     1087  glRotatef(30.0, 0.0, 1.0, 0.0);
     1088  glScalef(0.5, 0.5, 0.5);
     1089  glMaterialfv(GL_FRONT, GL_DIFFUSE, mat);
     1090  kvadrat("Spredaj");
     1091  glRotatef(90.0, 0.0, 1.0, 0.0);
     1092  kvadrat("Desno");
     1093  glRotatef(90.0, 0.0, 1.0, 0.0);
     1094  kvadrat("Zadaj");
     1095  glRotatef(90.0, 0.0, 1.0, 0.0);
     1096  kvadrat("Levo");
     1097  glRotatef(90.0, 1.0, 0.0, 0.0);
     1098  kvadrat("Spodaj");
     1099  glRotatef(180.0, 1.0, 0.0, 0.0);
     1100  kvadrat("Zgoraj");
     1101  glPopMatrix();
     1102  glFlush();
     1103}
     1104
     1105void reshape (int w, int h)
     1106{
     1107  double l;
     1108  l = 1;
     1109  glViewport (0, 0, w, h);
     1110  glMatrixMode (GL_PROJECTION);
     1111  glLoadIdentity();
     1112  glOrtho(-l, l, -l, l, -l, l);
     1113  glMatrixMode(GL_MODELVIEW);
     1114  glLoadIdentity();
     1115}
     1116
     1117int main(int argc, char *argv[])
     1118{
     1119  glutInit(&argc, argv);
     1120  glutInitDisplayMode(GLUT_SINGLE|GLUT_DEPTH);
     1121  glutCreateWindow("C GLUT program");
     1122  glutDisplayFunc(display);
     1123  glutReshapeFunc(reshape);
     1124  glEnable(GL_DEPTH_TEST);
     1125  glEnable(GL_LIGHTING);
     1126  glEnable(GL_LIGHT0);
     1127  glClearColor(1.0, 1.0, 1.0, 1.0);
     1128  glutMainLoop();
     1129  return 0;
     1130}
     1131}}}
    11211132
    11221133Podajanje barve za površino je spremenjeno tako, da se ne uporabi
    1123 funkcije \emph{Color} ampak normalno funkcijo za podajanje lastnosti
    1124 materialaf \texttt{glMaterialfv}. Rezultat kaže slika
    1125 \ref{fig:cube-f}. če bi napisali komentar pred izrisom
     1134funkcije ''Color'' ampak normalno funkcijo za podajanje lastnosti
     1135materialaf ''glMaterialfv''. Rezultat kaže slika
     11366. Če bi napisali komentar pred izrisom
    11261137štirikotnika, potem bi bilo vidno besedilo tudi za ostale
    11271138(skrite) strani.
     1139
     1140[[Image(cube-f.png)]]
     1141
     1142Slika 6: Osenčen model kocke z napisi
    11281143
    11291144Včasih pa raje želimo, da se besedilo na zaslonu ne
    11301145izrisuje rotirano in senčeno, temveč da se le pojavi na
    11311146določenem položaju v prostoru in potem izriše v zaslonskih
    1132 koordinatah. V ta namen uporabimo \emph{bitmap} fonte in naslednji
     1147koordinatah. V ta namen uporabimo ''bitmap'' fonte in naslednji
    11331148podprogram za izpis besedila:
    1134 {\scriptsize\begin{verbatim}
    1135 subroutine output(x,y,z,s)
    1136 character s*(*)
    1137 call fglRasterPos3f(x,y,z)
    1138 lenc = len(s)
    1139 do i=1,lenc
    1140   call fglutBitmapCharacter(6, ichar(s(i:i)))
    1141 end do
    1142 end
    1143 \end{verbatim}
    1144 }
    1145 Primer izrisa z bitmap fonti kaže slika \ref{fig:cube-b}
    1146 \begin{figure}[htbp]
    1147   \centering
    1148   \includegraphics[width=2.5in]{cube-b}
    1149   \caption{Osenčen model kocke z \emph{bitmap} napisi}
    1150   \label{fig:cube-b}
    1151 \end{figure}
     1149
     1150{{{
     1151#!c
     1152float output(x,y,z,char *s)
     1153{
     1154  char *c;
     1155  glRasterPos3f(x,y,z);
     1156  for(c=s; *c; c++)
     1157  {
     1158    glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *c);
     1159  }
     1160}
     1161}}}
     1162
     1163Primer izrisa z bitmap fonti kaže slika 7.
     1164
     1165[[Image(cube-b.png)]]
     1166
     1167Slika 7: Osenčen model kocke z ''bitmap'' napisi
    11521168
    11531169
    11541170= Uporabniški vmesnik =
     1171
    11551172V nadaljevanju so prikazani primeri programov, ki izkoriščajo
    11561173dodatne funkcionalnost knjižnice GLUT za vnos dodatnih podatkov v
    11571174program. To je predvsem uporaba tipk in miške.
    11581175
    1159 \subsection{Rotacija s tipkami}
    1160 Rotiramo že vgrajeni geometrijski model čajnika s tipkami \textbf{x,
    1161 y, z}. Vsak pritisk na tipko poveča kot rotacije za pet stopinj.
    1162 Podatke o trenutni rotaciji prenašamo s poljem \texttt{common}. Ker
    1163 izrisujemo žični model, podprogram za \emph{reshape} ni
    1164 potreben. Podprogram \emph{keyboard} ob pritisku na tipko dobi tudi
     1176== Rotacija s tipkami ==
     1177
     1178Rotiramo že vgrajeni geometrijski model čajnika s tipkami '''x,
     1179y, z'''. Vsak pritisk na tipko poveča kot rotacije za pet stopinj.
     1180Ker
     1181izrisujemo žični model, podprogram za ''reshape'' ni
     1182potreben. Podprogram ''keyboard'' ob pritisku na tipko dobi tudi
    11651183informacijo o zaslonskem položaju miške.
    11661184
    1167 {\scriptsize\begin{verbatim}
    1168 subroutine display
    1169 implicit none
    1170 include 'GL/fgl.h'
    1171 common /rotation/ rx, ry, rz
    1172 real rx, ry, rz
    1173 call fglClear(GL_COLOR_BUFFER_BIT)
    1174 call fglColor3f(0.5, 0.4, 1.0)
    1175 call fglPushMatrix
    1176 call fglRotatef(rx, 1.0, 0.0, 0.0)
    1177 call fglRotatef(ry, 0.0, 1.0, 0.0)
    1178 call fglRotatef(rz, 0.0, 0.0, 1.0)
    1179 call fglutWireTeapot(dble(r))
    1180 call fglPopMatrix
    1181 call fglutSwapBuffers
    1182 end
    1183 
    1184 subroutine keyboard(key,x,y)
    1185 common /rotation/ rx, ry, rz
    1186 integer key,x,y
    1187 print *, 'Key ', char(key),  key, ' at', x, y
    1188 if (key .eq. ichar('x')) rx = rx + 5.0
    1189 if (key .eq. ichar('y')) ry = ry + 5.0
    1190 if (key .eq. ichar('z')) rz = rz + 5.0
    1191 call fglutpostredisplay
    1192 end
    1193 
    1194 program teapot
    1195 external display
    1196 external keyboard
    1197 include 'GL/fglut.h'
    1198 integer window
    1199 call fglutInit
    1200 call fglutInitDisplayMode(ior(GLUT_DOUBLE,GLUT_RGB))
    1201 window = fglutCreateWindow('Use keys x, y, and z')
    1202 call fglutDisplayFunc(display)
    1203 call fglutKeyboardFunc(keyboard)
    1204 call fglutMainLoop
    1205 end
    1206 \end{verbatim}
    1207 }
    1208 
    1209 
    1210 \subsection{Miška in inverzna projekcija}
     1185{{{
     1186#!c
     1187#include <stdio.h>
     1188#include <GL/glut.h>
     1189
     1190float rx, ry, rz;
     1191
     1192void display()
     1193{
     1194  glClear(GL_COLOR_BUFFER_BIT);
     1195  glColor3f(0.5, 0.4, 1.0);
     1196  glPushMatrix();
     1197  glRotatef(rx, 1.0, 0.0, 0.0);
     1198  glRotatef(ry, 0.0, 1.0, 0.0);
     1199  glRotatef(rz, 0.0, 0.0, 1.0);
     1200  glutWireTeapot(0.5);
     1201  glPopMatrix();
     1202  glutSwapBuffers();
     1203}
     1204
     1205void keyboard(unsigned char key, int x, int y)
     1206{
     1207  fprintf (stderr,"Key %c at %d, %d\n", key, x, y);
     1208  if (key=='x')
     1209    rx = rx + 5.0;
     1210  if (key=='y')
     1211    ry = ry + 5.0;
     1212  if (key=='z')
     1213    rz = rz + 5.0;
     1214  glutPostRedisplay();
     1215}
     1216
     1217int main(int argc, char *argv[])
     1218{
     1219  glutInit(&argc, argv);
     1220  glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
     1221  glutCreateWindow("Use keys x, y, and z");
     1222  glutDisplayFunc(display);
     1223  glutKeyboardFunc(keyboard);
     1224  glutMainLoop();
     1225  return 0;
     1226
     1227}}}
     1228
     1229== Miška in inverzna projekcija ==
     1230
    12111231Za vsak pritisk gumba miške lahko dobimo poleg koordinate tudi
    12121232še stanje gumbov. Naslednji primer prikazuje risanje črte v
     
    14941514Na urejanje kode lahko uporabimo DOS-ov urejevalnik EDIT ali Windows
    14951515notepad. Oba imata svoje slabosti; EDIT ima težave z daljšimi
    1496 imeni datotek, NOTEPAD pa nima pri
     1516imeni datotek, NOTEPAD pa nima prikaza trenutne vrstice in ob prvem
     1517shranjevanju datoteke lepi konŔnico \texttt{.txt}, tako da moramo
     1518datoteko kasneje preimenovati v \texttt{.f}. Kljub slabostim sta oba
     1519urejevalnika primerna za Üolske probleme.
     1520
     1521V trenutnem imeniku DOS okna odtipkamo izbrani ukaz:
     1522\begin{verbatim}
     1523        notepad teapot.f
     1524        edit teapot.f
     1525\end{verbatim}
     1526