joi, 30 aprilie 2020

Tutorial

Am fost rugat sa va indic acest tutorial,
care incepe cu UMS.

-------- Mesaj original --------
Subiect: Tutorial Studenti
Data: 30.04.2020 00:18
Expeditor: Andone Vasile <andone.vasile@ub.ro>
Destinatar: Valentin ZICHIL <valentinz@ub.ro>
Copie (CC): enechita@ub.ro

Buna ziua,

Am incarcat un tutorial aici [1] pe


Va rog sa verificati daca am atins toate subiectele si daca am omis
ceva.
Multumesc!

Andone Vasile, SICD

Links:
------
[1]

Qt - Saptamana a 11-a


Buna ziua si bun venit

la intalnirea cu cel mai Qt software.

Planul de astazi:

1) Voi trimte pe e-mail-ul celor care s-au inscris (unii dintre colegii dvs cred ca nu au facut-o, caz in care ii rog s ceara capitolul de carte de la colegi) capitolul al 10-lea al manualului "Introducere in C++ extins folosind Qt Creator". [pg 137-148]

Ati primit deja paginile din carte ale acestui capitol.

2)Am sa va rog sa revedeti capitolul despre Automate din cursul LFA.  Paginile [47-71] din cursul de LFA si comentariile lui de pe acest blog.


Va trimit acum si capitolul din teoria automatelor, din cursul de LFA.
OK. L-ati primit deja.

3) La partea practica vom implementa exemplul despre automate discutat mai inainte (astept ca de obicei codurile arhivate pe e-mail).


Sa parcurgem impreuna paginile, sa incepem cu pg 137.
Pagina va spune in esenta ce va contine capitolul, niste clase Qt care folosesc la implementarea notiunilor de teoria automatelor finite deterministe. Si aminteste cateva utilizari posibile ale automatelor.

Sa mergem la pagina 138. Aici pe scurt e vorba despre ...

1) Implementari ale automatelor in limbaje cu GOTO-uri. Sau in assembler, limbaj care are instructiunea jump/jmp.
In aceste limbaje definiti niste puncte din program marcate cu etichete si
atunci cand este momentul, dupa citirea unui caracter de la intrarea automatului (sau primirea unui semnal de alt fel) se sare la eticheta corespunzatoare starii.
Acolo poate fi o portiune de cod care executa ceea ce are de executat, atunci cand automatul ajunge in acea stare. Si iar se citeste un simbol de la intrare si
ciclul se repeta.

Mecanismul seamana putin cu mecanismul intreruperilor hardware.
Intrebare de control: Este acelasi lucru sau sunt deosebiri intre mecanismul intreruperilor hardware si un automat ?
(A) - Sunt practic la fel ?
(B) - Exista o deosebire ?
(C) - Unul e mai general decat celalalt ? Care ?

2) O alta implementare posibila a automatelor se facea in limbajele structurate si avea la baza:

O bucla ...
...                     /|\
...                      |
...                      |
care se repeta  |

pina cand automatul ajungea iun starea finala. O variabila tinea loc de stare, memora numarul starii.

La inceput, inainte de intrarea in bucla, variabila primea ca valoare numarul starii initiale.
Apoi, in bucla, se citea un simbol de la intrare, si se trecea printr-o succesiune de if-uri care testau:
- daca era o anumita stare curenta si un anumit simbol la intrare caz in care variabila stare isi schimba valoarea(, si bucla se relua.).

Exercitiu:
Schitati in limbajul favorit o astfel de implementare a unui automat.

3) O alta implementare se putea face memorand tabela functiei delta, chiar intr-o tabela (limbajele permit notiunea de vector/matrice).
O bucla merge pina cand ajungem la o stare finala,
in bucla daca este posibil, vechea stare se inlocuieste cu cea obtinuta din tabela functiei delta.
stare = delta (stare, simbol).

Bineinteles, daca ea nu e definita, automatul se blocheaza, se opreste.

Nota: Odata cu trecerea intr-o alta stare, automatul poate sa si execute ceva ce are de executat, ceva coresp acelei stari.

Acest gen de implementari ale automatelor sunt cumva limitate la un singur automat, ceea ce e limitativ. Varianta (3) cu bucla si cu tabela ar putea implementa simultan, sincronizat, schimbarea starilor de la mai multe automate.

Dar implementari mai bune au aparut odata cu POO-ul, programarea orientata pe obiecte. Un mediu de programare modern va poate oferi obiecte pentru a implementa automate care isi schimba starea conform unor semnale venite dinafara si executa ceva cand ajung in aceste stari. Este si cazul Qt-ului.

Dati pagina la pagina:  139.

STL - standard template library nu contine automate, nu are un astfel de sablon. Dar Qt are niste obiecte speciale.

Exercitiu:
Rulati, deocamdata, exemplul States, din colectia de exemple Qt.
Il puteti gasi fie in sectiunea de exemple, fie cautand in index All-examples- si acolo pe lista, exemplul States. Fie cautand in Help States Example.

Veti gasi acolo o aplicatie in care starea unui sistem de widget-uri se schimba la o apasare pe un buton. Cititi codul ei abia la sfarsitul acestei lectii !!

Exercitiu:
Rulati exemplul Stickman. Acolo veti gasi un concept si mai interesant. Higraph-uri.

Dar inainte de a studia codurile acestor exemple (v-am aratat pozele doar ca sa le gasiti mai usor) sa parcurgem lectia despre automate in Qt:

Revedeti intai notiunile de teoria automatelor: pg 139-pg 140.
Acum putem sa implementam in Qt unul din cele mai simple automate.
Rolul exemplului este sa va familiarizeze cu nostiunile fundamentale pe care le veti gasi in exemplele din Help.

Unul din cele mai simple automate ar fi cel asociat butonului ON/OFF cu doua pozitii. Este clar ca avem de-a face cu un automat cu doua stari:

(ON) --------------------> (OFF)
         <--------------------

si cu doua tranzitii, una de la starea ON la OFF si alta invers, AMBELE declansate de acelasi (NUUU simbol) ci  eveniment: apasarea pe buton.

Ca actiuni de executat vom pune actiuni minimale:
- sa se scrie pe buton ON cand ajunge in starea ON
- sa se scrie pe buton OFF cand ajunge in starea OFF

                                                         |          /|\
                                                         |           |
                                     Apasa          |           |   Apasa
                                                        \|/          |


Dupa aceea facem:

Implementarea

Lucrati impreuna cu mine pe baza surselor din carte !

 Incepem un Empty Qt Project, (dar vom scrie noi fisierul .pro).
Dati nume proiectului.
Alegeti kit-ul cu care lucrati. Daca aceasta fereastra nu va apare sau nu aveti kit-ul definit, parcurgeti repede reinstalarea din saptamana a 5-a (sau a 6-a).
Sariti peste aceasta etapa, nu folosim instrumente de Project Management.
Si dati Finish.
Completati fisierul .pro:
 Acum creati un fisier sursa main.cpp:
Si adaugati codul sursa, pe care va rog sa il scrieti de mana si sa il studiati... il vom comenta impreuna in limita timpului:
Asa arata programul principal: main.cpp din proiectul nostru.
Corectati eventualele erori, de ex ghilimele cu probleme samd...daca aveti.
Iar cand rulati programul:
Apasand pe buton observati ca se schimba On cu Off.
 Click !
 Click !

Sa explicam cum se face aceasta, dar inaite de aceasta va rog cititi cu atentie sursa, ea are marcate pozitii care vor corespunde explicatiilor:

Implementarea este comentata pe sectiuni in manual. pg 145-148. Studiati-le va rog ! Pentru detalii despre clasele:
QState
QStateMachine
consultati Help-ul tinand mouse-ul pe numele clasei si apasand F1 sau Fn+F1.

Tema: Rezolvati exercitiile de la finalul capitolului.

Pentru cei care nu au manualul:

Implementarea comentată pe secțiuni:

Dacă nu ați identificat dintr-o privire elementele amintite (QSta-
teMachine, QState, addTransition() etc) în textul de mai sus, a venit
momentul să le discutăm unul câte unul:
La început sunt incluse în proiect bibliotecile necesare (la Qt 4.x am
avut nevoie să includem doar <QtGui> care pe atunci includea toate
elementele necesare. La Qt 5.x bibliotecile au fost separate pe module
și a fost nevoie să includem și clasele <QApplication> și <QPushBut-
ton>.

#include <QtGui>
#include <QApplication>
#include <QpushButton>

Funcția main() începe ca de obicei și primul lucru făcut este să de-
clare existența a trei variabile din tipurile (care sunt clase de obiecte)
QApplication, QPushButton, QStateMachine. Stările mașinii se defi-
nesc în secțiunea următoare:

//! [0]
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QPushButton button;
QStateMachine machine;
//! [0]

Automatul are două stări, corespunzătoare pozițiilor pornit („On”)
și oprit („Off ”) ale butonului. Sunt create dinamic două obiecte din
clasa QState. Nu sunt necesari alți parametri la crearea lor, construc-
torul clasei QState este apelat fără parametri, paranteza sa este goală.
Fiecărui obiect i se atribuie un nume folosindu-se metoda setObject-
Name (...).
Și, mai important, fiecare obiect QState este programat ca atunci
când se ajunge în acea stare, să facă un fel de „atribuire” modificând va-
loarea unui atribut al altui obiect. O asemenea „atribuire” va fi execu-
tată interpretativ, din mers, de metoda assignProperty (...), la intrarea
în acea stare (!).
Aceasta are trei parametri: adresa obiectului în care
se face modificarea, numele atributului modificat – aici este atributul
„text” - și valoarea nouă stabilită pentru acestui atribut.
Observați că atunci când se ajunge în starea off pe buton va fi scris
textul „Off ” și când se ajunge în starea on pe buton va fi scris textul
„On”.

//! [1]
QState *off = new QState();
off->assignProperty(&button, ”text”, ”Off ”);
off->setObjectName(”off ”);
QState *on = new QState();
on->setObjectName(”on”);
on->assignProperty(&button, ”text”, ”On”);
//! [1]

În secțiunea [2] se definesc tranzițiile, acelea care s-ar fi desenat ca
niște săgeți în graful automatului. Primul apel al metodei addTran-
sition(...) spune: Atunci când obiectul buton va lansa semnalul clic-
ked(...), mașina va trece din starea off în starea on. Off este primul cu-
vânt pe rând, on este ultimul, și este pus în paranteza cu argumente.
Așa le țineți mine. Tranziția este atașată obiectului care este starea sa
de pornire („pana” nu vârful săgeții). Mai trebuiesc precizate, la apelul
metodei care definește tranziția: obiectul ce ne dă semnalul, semnalul
și starea destinație a tranziției.

//! [2]
off->addTransition(&button, SIGNAL(clicked()), on);
on->addTransition(&button, SIGNAL(clicked()), off);
//! [2]

Acum spunem mașinii că ei, nu alteia, îi aparțin cele două stări. Este
ca și cum l-am construi pe Q – mulțimea stărilor prin reuniuni succe-
sive cu câte o stare. Practic în secțiunea trei adăugăm cele două stări
on și off – obiecte de clasa QState – la mulțimea stărilor mașinii. Se
folosește în acest scop metoda addState(...) a obiectului de clasă QSta-
teMachine.

//! [3]
machine.addState(off);
machine.addState(on);
//! [3]

După cum spuneam și în introducere, mașina are o stare inițială care
trebuie marcată, declarată, altfel n-ar ști din ce stare să pornească. Și
bineînțeles, programul trebuie să pornească explicit mașina cu stări.
Dacă sunt mai multe mașini conteză care mașină pornește.

//! [4]
machine.setInitialState(off);
machine.start();
//! [4]

În secțiunea [5] a programului se apelează metode ale obiectului bu-
ton pentru a-l redimensiona, a-l afișa și a porni întregul mecanism de
procesare a evenimentelor.

//! [5]
button.resize(100, 50);
button.show();
return app.exec();
}
//! [5]

Și cu asta, gata. Puteți rula programul și vedea cum fiecare apăsare
pe buton duce la schimbarea textului de pe acesta, mărturie a schimbă-
rii stării mașinii cu stări.

Lectura suplimentara: 
Documentatia exemplelor States si Stickman.

Sfarsit.

miercuri, 29 aprilie 2020

LFA - Constructia compilatorului - masina virtuala

LFA - Constructia compilatorului - masina virtuala - Cap 6 [pg 56-60]

Continuam explicatiile incepute luni privind implementarea masinii virtuale.
Vedeti postarea anterioara LFA.

Astazi este ora de laborator, din saptamana a 11-a, deschideti manualul de Constr Comp. cu Flex si bison la pagina unde se afla "Modulul "Masina Virtuala cu Stiva", SM.h". aprox pg 56.

Are you ready ?  Sunteti gata ?

Din acest capitol invatam sa implementam efectiv o mica masina virtuala, in fond un emulator de procesor.

Aveti nevoie de dosarul Lab4, cu toate update-urile pe care il copiati in dosarul Lab6.
Acum va rog sa deschideti cu editorul favorit un fisier nou pe care il veti numi SM.h

Ce scriem in el ? Va explic:

Intai o lista a denumirilor instructiunilor. Pentru a defini o serie de constante intregi numite HALT, STORE, JUMP ... nu folosim:
#define HALT 0
#define JUMP 1
samd ca ar fi prea lung.

Folosim: enum

enum code_ops { HALT, STORE, JMP_FALSE, GOTO,
DATA, LD_INT, LD_VAR,
READ_INT, WRITE_INT,
LT, EQ, GT, ADD, SUB, MULT, DIV, PWR };

Acest enum da pe rand valori succesive constantelor de pe lista.

Pentru a lista codul generat am insa nevoie de denumirile tiparibile ale instructiunilor, altfel daca as tipari cu printf sau altceva ar iesi la vedere numerele nu denumirile instructiunilor.

Din acest motiv punem si un vector de stringuri care contine toate numele instructiunilor.

char *op_name[] = {"halt", "store", "jmp_false", "goto",
"data", "ld_int", "ld_var",
"in_int", "out_int",
"lt", "eq", "gt", "add", "sub", "mult", "div", "pwr" };

O instructiune, in acest C in care e facut compilatorul se scrie ca un struct, (o structura, un record, e ca o clasa fara metode).

struct instruction
{
enum code_ops op;
int arg;
};

Memoria este simulata nu ca un vector ci ca doi vectori. De ce ? Fiindca instructiunile sunt compuse si datele din memorie sunt simple.

struct instruction code[999];
int stack[999];

Acum definim registrii procesorului:

int pc = 0 ;
struct instruction ir ;
int ar = 0 ;
int top = 0 ;
char ch ;

Cititi paragraful de la pg 58 de deasupra scrierii lor. Incepe cu Urmeaza...[pg 58].

Ciclul fetch-execute, ciclul adu si executa este poartea cea mai importanta a masinii virtuale, el executa dce fapt instructiunile pe masura ce le aduce din memorie:

Sa explicam un pic din ce este format:
- este o bucla do { ... } while ( conditie ), conditia fiiind [pg 60] ca in registrul IR sa nu fie o instructiune cu codul HALT, adica ir.op != HALT .

Ati gasit conditia ?

Acum sa vedem exact descrierile instructiunilor: [pg 59]

Ce e important sa stiti aici este ca sunt, majoritatea lor, instructiuni care lucreaza cu expresiile de pe stiva, in ideea ca avem de calculat valorile unor expresii scrise in forma poloneza infixata, cu ajutorul unei stive. Se va adauga o instructiune STORE pt stocat rezultatele in memorie si doua pentru citit valorile care intra in expresie, constante sau variabile, LD_INT si LD_VAR.

Calculele nu se fac in acumulator, cum v-ati fi asteptat, ci direct pe stiva, la aceasta masina virtuala.

Instructiunile: LD_INT, ADD, STORE

De exemplu adunarea: x = 3+4 va da un cod (dupa compilare)

LD_INT 3
LD_INT 4
ADD
STORE @X      <- adica "STORE la adresa lui x" , o va sti compilatorul pe adresa

Iar in stiva vom avea

| 3 |
------

apoi vine si 4 deasupra

| 4 |     <- Top indica aici
------
| 3 |     <- Top -1 indica aici
------

apoi vine adunarea, vedeti la case ADD:

case ADD: stack[top-1] = stack[top-1] + stack[top];
                  top--;
                  break;

Si dupa cum aceea vine ADD si aduna  stack[top-1] + stack[top] pune rezultatul in stack[top-1]

| 4 |     <- Top indica aici
------
| 7 |     <- Top -1 indica aici
------

... si indicatorul il scade cu o unitate, ceea ce inseamna ca practic se face un POP si se scoate o valoare din stiva;

------
| 7 |   <- Top indica aici. 
------

Apoi vine STORE @X , adica STORE urmat de adresa lui X. Si scoate acel 7 din stiva si il pune la adresa lui X. Adresa lui X ii vine ca argument al instructiunii STORE, a avut grija compilatorul sa o puna la locul potrivit in instructiune, ca argument al acesteia: ir.arg.

case STORE : stack[ir.arg] = stack[top--]; break;

Si in final stiva ramane astfel si fara 7 si Top indica sub locul unde a fost 7-le.

------
|     |    7 fusese aici.
------
          <- Top indica aici.

Alte instructiuni, folosesc tot stiva ca sursa de parametri:
Ia uitati-va la:

Instructiunea WRITE_INT -  ia ultima valoare din stiva si o tipareste.
Daca am fi avut de compilat:

WRITE (3-4)

Codul generat ar fi fost:

LD_INT 3
LD_INT 4
SUB
WRITE_INT   


Iar in stiva vom avea

| 3 |
------

apoi vine si 4 deasupra

| 4 |     <- Top indica aici
------
| 3 |     <- Top -1 indica aici
------

apoi vine scaderea, vedeti la case SUB:

case SUB: stack[top-1] = stack[top-1] - stack[top];
                  top--;
                  break;

Si dupa cum aceea vine SUB si scade  stack[top-1] - stack[top] pune rezultatul in stack[top-1]

| 4 |     <- Top indica aici
------
|-1 |     <- Top -1 indica aici
------

... si indicatorul il scade cu o unitate, ceea ce inseamna ca practic se face un POP si se scoate o valoare din stiva;

------
|-1 |   <- Top indica aici. 
------

Apoi vine WRITE_INT , care iata ce face:

case WRITE_INT : printf( "Output: %d\n", stack[top--] );

Scoate din stiva rezultatul calcului si il afiseaza folosind, in cazul nostru, "apelul de sistem" printf. In realitate, la alte compilatoare se face un CALL la o anumita adresa speciala de sistem, sau se pun parametrii in niste registri si se porneste o anumita intrerupere. Cei care is mai amintesc acea carte de apeluri de sistem DOS stiu la ce ma refer.

READ_INT este inversul lui write, citeste de la tastatura si pune in stiva.
De obicei apare in situatia compilarii unui:

read (x);

care va genera un cod:

READ_INT @X

adica il citesc pe X de la tastatura, il pun in stiva in locatia destinata lui X.


Sa zicem ca executam acest READ_INT si se tasteaza un 7.

case READ_INT : printf( "Input: " );
                            scanf( "%ld", &stack[ar+ir.arg] );
                            break;

Apare promptul/prompterul Input:
... ... acum tastam pe 7.  Si READ_INT il puned in stiva (ar=0) la locatia data la adresa argument a instructiunii.

Nota: registrul ar s-ar folosi la instructiuni cu variabile locale ale functiilor, ceea ce limbajul Simple nu are.

Instructiunea JUMP_FALSE adresa

Va servi la compilarea if-urilor si while-urilor, atunci cand se sare la o anumita adresa, aceasta va fi pusa de compilator in codul generat, ca argument al instructiunii JUMP_FALSE.

Remarcati cum se executa  JUMP_FALSE:

case JMP_FALSE : if ( stack[top--] == 0 )
                              pc = ir.arg;
                              break;

E bine de stiut: Mai inainte de ea este o bucata de cod care evalueaza conditia, si bineinteles, o pune in stiva (credeti-ma pe cuvant!).

stack[top--]
indica valoarea stack[top]  si o scadere pe urma a lui top cu o unitate !
Deci de fapt scot valoarea conditiei din stiva !

Daca este 0, 0 = conditie falsa, atunci fac saltul , incarcand in PC - program counter, adresa-argument a lui JUMP_FALSE, el ingloband intotdeauna adresa destinatie.

Instructiunea LD_VAR adresa de variabila:

Ati gasit-o pe pagina  [59] ?

Sa citim codul !

case LD_VAR : stack[++top] = stack[ar+ir.arg]; break;

La noi ar=0, deci conteza doar adresa variabilei, ir.arg, furnizata ca argument al instructiunii. De acolo, de pe stiva (variabilele stau la baza stivei) se ia valoarea variabilei, si se pune copia acelei valori taman in varful stivei pentru a participa la calcule.

Instructiunea GOTO.

Pentru salturi, neconditionate, ca la if, cand termini de executat ramura then  si sari peste ramura else, sau e nevoie de ea la alt fel de bucle. Incarca adresa destinatie in reg PC ca executia sa continue de acolo.

case GOTO : pc = ir.arg; break;

Instructiunea DATA.



Este pentru compilarea declaratiilor. Daca am 3 variabile, compilatorul va genera :

DATA 2 (2 = 3-1)

Si la executia:

case DATA : top = top + ir.arg; break;

 Din stiva care initial nu are nimic.

------
| 0 |   <- Top indica aici. 
------

Obtinem:

------
| 0 |   <- Top indica aici. 
-----
| 0 |    
------
| 0 |    
------

facand astfel loc in baza stivei pentru cele 3 variabile.

Restul instructiunilor functioneaza similar cu ADD, comparatiile fiind un fel de adunari care dau 0 sau 1.

Continuati cu paginile 59-60.

Refaceti compilatorul conform indicatiilor din paginile 59-60 si modului de lucru din anexa 2.

Compilati programele din Lab1 cu noul compilator, dar nu va mirati ca nu face mare lucru, fiindca el nu genereaza inca cod.

Astept imagini cu compilatorul ruland !

Atentie: Aveti in vedere ca pot cere compilatorul si coduri compilate cu el la final de semestru si la examen.

Sfarsit.

luni, 27 aprilie 2020

LFA - Constructia compilatorului (pentru TI si IFR) -Cap 6

Buna ziua,

Salutari inginerilor de la TI, astazi reluam constructia compilatorului nostru. Lucreaza cu noi semigrupa I, teoretic grupa aII-a are ora saptamana viitoare. *
Colegii de la Info pot urmari si ei aici, oarecum in avans, comentarii despre lectia curenta despre constructia compilatoarelor.

Luati-va manualul de Constructia compilatoarelor folosind Flex si Bison.

Deschideti manualul la Cap 6, aprox pg 50.(sau pg 51 ed cu coperta verde).
Pentru partea practica aveti nevoie de dosarul Lab4, cu compilatorul construit ca in capitolul al 4-lea al cartii.

Sa incepem sa citim pagina dintai a cap 6. (pg 50 sau 51), [pg 50 pe ebook]

Traducerea primului paragraf nu este ideala, dar ideea este urmatoarea:

Un hardware al unei masini reale este ceva pe care ruleaza un software, executand anumite instructiuni. Ok ?

Masina reala (si echivalenta ei, masina virtuala) trebuie sa:
- inteleaga aceleasi instructiuni ! De acord ?
- sa tina programul si stiva in memorie ! (Vezi lectiile de la materia ASC - Invatam un procesor) tot de pe acest blog. Cititi-le neaparat !
- sa aiba aceiasi registri, chiar daca simulati.
- sa execute un nr minim de "apeluri de sistem" - apeluri la functii complexe ale SO gazda, de obicei pt operatii de I/O (I/O = intrare/iesire).

In esenta, o masina virtuala minimala, care lucreaza doar in mod text trebuie, la modul minimal, sa aiba:
- registrii procesorului, pe care instructiunile ii modifica
- o zona de memorie unde pastreaza programul (si un contor de program PC)
- o zona de memorie care sa fie stiva (si un indicator de stiva SP)

Dati un pic pagina la pagina 58, la implementare, si observati:
- numele instructiunilor in vectorul op_name
- structura unei instructiuni: struct instruction { ....  }
- stiva de adrese intregi : int stack[999].
- vectorul de instructiuni care formeaza programul:
struct instruction code[999];

Nota: Va trebui sa existe si o bucla (numita "fetch execution loop" = bucla citeste si executa) care sa ia rand pe rand cate o instructiune la executat.

Sa revenim la paginile 51-52, cititi paragraful despre run-time system-ul pentru limbajul Simple.

Treceti la pg 53: Cititi The Stack Machine  pg 53-54 ! Revin imediat cu comentarii.

Comentarii la pg 53:
S-masina a fost inventata pentru a rula limbaje cum era Pascal-ul lui N.Wirth.
Acel Pascal ca si C-ul avea functii (si blocuri). Inregistrarile de activare din stiva si instructiunile care opereaza cu ele noi nu le vom folosi la acest proiect.

Organizarea masinii:
Este un simulator de procesor, care are elementele principale ale procesoarelor cu registri dedicati/specializati.

Exercitiu (de memorie din anul I): La ce se foloseau registrii ?
PC -
SP -
AF -
IR - reg ascuns - 
la un procesor cu registri ?

Avem de studiat limbajul masina al acestei masini virtuale... pg 54-56. Detaliez:

Comentarii (la Comentarii pg 54):
Instructiunile arata cam asa (memoria creste ca adresa in jos):

---------------------------------
| Cod instructiune     |                de exemplu   JP    sau READ   sau STORE
---------------------------------
| subcod de instr.      |                                       C              0                  L
--------------------------------
| data L                     |                                     nn              nn               nn
--------------------------------
| data H                    |                  Formeaza un numar cu de 2 ori mai multi biti.
--------------------------------                    nn e exprimat prin doua parti binare, L si H
                                                    in ordinea HL.
                                                           
Atentie: In practica vom comasa codul de instructiune si subcodul.
Instructiunile noastre vor avea:


---------------------------------
| Cod instructiune     |                de exemplu   JP C    sau READ   sau STORE
---------------------------------
| data L                     |                                     nn              nn               nn
--------------------------------
| data H                    |                  Formeaza un numar cu de 2 ori mai multi biti.
--------------------------------                    nn e exprimat prin doua parti binare, L si H
                                                    in ordinea HL.
Partea grea acum urmeaza:
1) Luati si studiati fiecare instructiune, de la [pg 54-57], cu exceptia lui OPR, CAL L,N. Cautati eventualele greseli de tipar ! Prof Anthony ne asigura ca sunt !
2) Desenati stiva inainte si dupa executia instructiunii:

Ex: ADD

-------                  execut
|   7 |                 ADD                                   <----             T indica aici
-------               ---------->       --------
|   3 |                                   | 10 |                < ----            T-1 indica aici  
--------                                  --------

Aici aveti mult de lucru ! Luati-va timp sa studiati limbajul masinii,
altfel NU veti intelege codul generat de compilator.

Functionarea: pg 57 sus.
Masina ia cate o instructiune pe rand in registrul IR.  = Fetch !=
Mareste contorul instructiunilor PC.
Executa dupa felul ei, instructiunea.
Pina cand da de HALT sau epuieaza memoria (si o ia de la capat).

Acum puteti face implementarea:

1) Adaugati in dosarul Lab4 fisierul SM.h
2) Adaugati la inceputul buclei fetch-execute randul de la pagina 60,
pentru depanare (in bucla!)
3) Modificati Simple.y  ca:
 - sa includa print_code() dar sa nu o foloseasca. (Este in anexa!) pg 61.
 - sa includa fetch_execute_cycle() si sa o execute.

Reconstruiti compilatorul: Anexa A2 pg  89.
Dati-i sa compileza ceva... dar sa nu va impresioneze executia, - care nu exista - fiindca compilatorul inca NU genereaza cod !

Trimiteti pe e-mail imaginea executiei. Nu e nimic impresionant!

Succes ! Spor la studiat instructiunile si la implementare.

Ne revedem miercuri cu colegii de la Info.

* Daca alegeti sa lucrati saptamana viitoare este posibil, sau nu, sa aveti o pagina de explicatii mai scurta ca aceasta, sau sa reveniti tot la ea.

Sfarsit pt azi.

LFA - Curs,Saptamana a 11-a

Buna ziua,

Astazi in saptamana a 11-a va rog sa cititi, pentru inceput ceea ce am numit "Cursul din saptamana a 10-a", in realitate notitele sunt scrise tot azi, dar am separat pe o pagina noua o tema tehnica, Minimizarea automatelor. Continutul e in manual, pe blog aveti explicatii.

Aici este continuarea:deschideti maualul la pagina 65 [mergem pina la pg 68]

Automate finite cu epsilon-miscari (eu le mai zic, cu epsilon-tranzitii) [pg65]

De ce ne ocupam de ele ? Fiindca ajuta in procesul de definire al automatului echivalent cu o expresie regulara. Da, acele reg-exp-uri folosite de programatori.

Cititi def 2.12 pg 65.
Va las sa va ganditi oleaca la ea. Ce inseamna formula:

    δ :Q x ( Σ U {ε} ) -> P(Q)

unde P(Q) sunt partile lui Q, ca la AFN-uri. Unde este modificarea fata de AFN-uri (automate finite nedeterministe)?

Indicatie: acolo aveam:
     δ :Q x ( Σ ) -> P(Q)

Este evident ca mai avem ceva, un epsilon, sirul vid, care "se adauga" alfabetului.Ca si cum automatul ar putea trece dintr-o stare in alta, nu prin citirea UNEI litere (simbol) de la intrare ci prin citirea a nimic (stringul vid "", notat epsilon) de la intrare.

Grafic locul unde va avea loc epsilon tranzitia se deseneaza exact cum erati
obisnuiti dar nu e o litera pe "sageata" ci un epsilon. ε
                
                   ε
(p) ------------------ > (q)

 linia e continua, iar p si q sunt incercuite cu cercuri complete nu cu paranteze.

Ce e cu teorema 2.6 ?

Cititi va rog teorema 2.6. [pg 65]

Ea ne spune ca desi ni se pare ca aceste automate "pot" mai mult, in materie de recunoastere a limbajelor, ele nu aduc de fapt nimic nou, sunt echivalente cu
cele fara epsilon-tranzitii.

Demonstratia este constructiva, iar pentru a construi acea multime, "I indice epsilon de delta" de la pg 67 jos, putem folosi un tabel cum este cel de la pagina 67 sus.

Considerati pagina 66 un exemplu de pregatiri pentru a construi automatul echivalent.

 Plan:

Observati ca daca luam automatul (de la pg 66 sus), ca exemplu,
putem elimina din el arcele cu litere si raman numai cele cu epsilon,
(pagina 66 mijloc) si fiindca starile legate prin epsilon-uri sunt impreuna  ;) , putem sa facem o tabela cum este cea de la pagina 67 sus.

 Un exemplu clasic de automat (e in multe carti):

Acum am inlaturat arcele cu litere pe ele.
 Iar aceasta tabela care imi da valoarea de adevar a predicatului: "Exista drum in graf de la i la j ?"

Acum  puteti citi algoritmul general de transformare,la punctul 2 pg 67-pg 68.

In final, automatul din ultima tabela se poate desena, vedeti desenul alaturi.

Exercitiul 1: Refaceti , intai dupa carte, apoi dupa formulele de la pagina 68 sus toate calculele pentru D si delta1 de la pagina  68.

Exercitiul 2:  Luati alt automat cu epsilon tranzitii, dat prin tabela ca la pg 68 sus si transformati-l, ca la pg 68 jos.

Urmeaza laboratorul de compilatoare, pagina noua.

LFA - Curs Saptamana a 10- a

Buna ziua,

Acest curs este  inclus in cursul saptamanii 11. Desi are pagina web separata.
Aceasta pagina web sprijina citirea paginilor :58-65 din manual.

In saptamana a 10- a au fost sarbatorile Pascale si zi libera.
In mod normal predam aici niste rezultate tehnice, cum ar fi :

MINIMIZAREA AUTOMATELOR

Continut:
2.6 Minimizarea automatelor finite (deterministe) [pg 58]
 Un algoritm pentru a determina daca doua stari sunt echivalente [pg61-62]
Def 2.11. Defineste un AFD redus.
2.7  Constructia unui AFD redus.
2.8 Automate cu epsilon-miscari [pg 65-68]


Cateva comentarii despre ele, atentie, partea matematica este mai dificila aici, incerc sa dau niste explicatii intuitive:

2.6 Minimizarea automatelor finite (deterministe) [pg 58]
Ideea de aici:

Fie un automat:
       x
 (A)----->(B) 
   |          |
y |          | z
   |          |
  \|/        \|/
 (D)      (E)
   |       /
a |      / a
  \|/  |/_
  (F)

Unde (F)  este starea finala.

Observati ca in raport cu starea finala, cele doua stari (D) si (E) sunt cumva echivalente, "de grad 1".
Se vede ca exista un cuvant de lungime 1, cu proprietatea:

( D, a)  |--* (F, epsilon)
( E, a)  |--* (F, epsilon)

Si in acest caz automatul poate fi cumva "impaturit" folosind aceasta relatie de echivalenta, suprapunand nodurile echivalente...

       x
 (A)----->(B) 
   |          |
y |          | z
   |          |
  \|/        \|/
     (DE)
      |     
   a |     
     \|/ 
    (F)

Deabia acum puteti citi definitia 2.7. Care este inspirata dar nu identica cu ceea ce am desenat mai sus ... vedeti pg[58].

Abia acum puteti vedea def 2.7, 2.8, 2.9.

Def 2.7. [pg 58] Defineste doua stari q1,q2, ca fiind diferentiate de un x din sigma stelat, daca avem :

  (q1,x) |---* (q3,epsilon)                (1)
  (q2,x) |---* (q4,epsilon)

si daca impartim starile in doua parti, F si Q-F, se mai impune o conditie:
q3 si q4 nu apartin simultan lui F sau lui Q-F, ori cel putin una dintre relatiile (1) nu are loc.

Din pacate, acest fel de diferentiabilitate / echivalenta depinde de lungimea cuvintelor implicate. De aici definitia 2.8.

Def 2.8 [pg 59] Doua stari q1,q2 sunt k-diferentiate de un cuvant x din sigma stelat , |x| < k, daca si numai daca au loc conditiile definitiei 2.7.

Cumva, daca gasim un cuvant de lungime |x| <k, pt care starile sunt diferentiabile, deci evolutia automatului din cele doua stari cu acel cuvant la intrare NU se termina la fel (fie in F fie in Q-F), atunci pot spune ca starile sunt k diferentiate..

Obs: k-diferentiate  implica k+1 diferentiate. Invers, in termeni de echivalenta de stari (se def in def 2.9):
 k+1 echivalente implica faptul ca sunt  k echivalente
k echivalente implica faptul ca sunt k-1 echivalente
samd.

Obsercati ca diferentiabilitatea depinde de existenta unor cuvinte cu anumite proprietati. Atunci echivalenta depinde de INexistenta unor cuvinte cu acele proprietati.

De aici ajungem usor la def 2.9:

Def 2.9: Doua stari q1 si q2 sunt echivalente daca nu gasim nici o secventa care sa le diferentieze.
 Adica pt orice k, ele nu sunt k-diferentiate.

Atunci cand luam in considerare si pe k, obtinem o notiune de k-echivalenta.

Def 2.10: Pt un automat M si un numar natural nenengativ, doua stari q1 q2 sunt k-echivalente daca si numai daca nu exista nici o secventa x, |x| <= k care sa le diferentieze.
                 
                 k      
                 _
Notam q1 = q2.  [pg 60 sus].

Urmeaza o serie de proprietati tehnice ale relatiei de echivalenta:

Cititi pg [60, 61,62,63,64]

Si in final putem construi un automat:  [pg 63-64]
- fara stari inaccesibile
- fara stari neproductive
- si pe multimea partilor multimii Q in raport cu relatia de echivalenta.
(Relatia de echivalenta imparte Q in clase de echivalenta).

Pauza.
Trecem la o alta pagina.

Grafica - Teste

Salutare,

Notez aici doar faptul ca ieri am petrecut o buna parte din zi incercand sa descarc si sa folosesc alte instrumente de grafica, stiti bine ca exista.

Din pacate, conditiile de a alege altceva inafara de OpenGL sunt, in cazul acestui curs, urmatoarele:
1- sa fie multiplatforma, Linux si Windows cel putin
2- sa fie instalabil din repository pe Linux
3- sa aiba un manual de dimensiuni rezonabile (<= 220 pg)
4- sa aiba primul program, Hello World-ul de dimensiuni rezonabile
5- IDE-ul sa fie intuitiv.
6- sa nu fie bazat pe Java. (chestie personala)
7- sa nu aiba un kit mai mare ca un CD
8- sa aiba un manual disponibil liber
9-tot softul sa se instaleze dintr-o singura comanda.

Toate mediile pe care le-am incercat incalaca cel putin una dintre acestea, de exemplu Vulkan indeplineste 1,2,3,8 dar incalca 4, OpenGLES indeplineste 1,6,8 dar nu ma multumeste la cap 2,3,5,7. Si asa mai departe. O zi pierduta pentru cercetare, o zi pierduta pentru pregatirea cursurilor, o zi de weekend pierduta (era duminica). Si nu este prima de acest gen.

Anul trecut am mai petrecut niste ore in niste zile in compania platformei Vulkan si a manualului acesta. S-a instalat si pe Linux, am putut rula codul, dar cand am vazut cate linii de cod erau necesare pentru un simplu cub texturat, concluzia mea a fost ca se va folosi un API de nivel superior, macar un OpenGL implementat peste Vulkan sau ceva asemanator, care sa ofere programatorilor ceva mai mult decat "low level".

Constat ca profesorilor trebuie sa li se acorde destul timp pentru experimente nereusite si tentative de a aborda alte tehnologii, lucru imposibil in actualele conditii de normare.

Concluzia: cand restrictiile care ni se impun sunt din ce in ce mai multe, multimea solutiilor pe care vi le putem da devine de la un loc incolo multimea vida. 

vineri, 24 aprilie 2020

Grafica - IFR

Buna ziua si bine v-am gasit
la intalnirea cu grafica on-line, in OpenGL, pe Linux

Este prima intalnire de acest gen deci urmeaza sa ne organizam un pic,
cel putin in prima jumatate de ora.

PLANUL DE LUCRU:

1) Instalarea: Aveti nevoie de un Linux (Ubuntu 18 este ok) cu instrumentele OpenGl
Teoria spune ca trebuie sa instalati:
- gl,
- glut, (freeglut)
- mesa
- si compilatorul gcc
- (eventual si un IDE) de Linux cum este Codeblocks. Desi va recomand sa lucrati in cea mai simpla maniera, cu:
- un terminal in care veti da comenzile de compilare
- si un editor de texte (Gedit, TextEditor, Kate, Kwrite, sau cele clasice in mod text: mc, nano, pico - editoare)

2) Dat fiind ca in fiecare an distributia se schimba putin, in urmatoarea jumatate de ora voi face setup-ul din nou, si va anunt ce indicatii mai sunt necesare.

3) Va trimit capitolul de manual pe e-mail.

4) Voi face o recapitulare

5) Voi comenta pe blog, a doua parte a manualului, atat cat se poate.

Nota: Aveti nevoie de acel Manual introductiv de OpenGL de la Editura Alma Mater, editia 2014 (tradus de Dan P. - nu editia 2007)  care traduce manualul spaniol, pe care vi l-am prezentat: Curso de introducción a OpenGL (v1.1).Seful de grupa a primit deja manualul pe e-mail.


ACTIVITATEA

1) Instalarea:

Ubuntu: 18.04
Incercati intai varianta: sudo apt-get install gcc g++ codeblocks build-essential  freeglut3-dev mesa-utils

O varianta minimala, in cazul in care ati programat deja cu gcc pe Linux, ar fi sa instalati: mesa-utils si freeglut3-dev

Dintr-un an anterior aveam o notita:
sudo apt-get install libgl1-mesa-dev freeglut3-dev messa-common-dev 
(cred ca am folosit-o pentru Ubuntu 14.x sau 16.)

Fedora 25 (ar trebui s amearga si la urmatoarele):
Daca nu stiti exact numele pachetelor incercati:

yum install mesa*
yum install freeglut

2) Testarea:
Daca ati fost la orele anterioare ar trebui sa aveti setul de exemple deja lucrate:

Ar trebui sa puteti lucra, dupa codul existent, exemplele:

Exemplul 1:
Compilarea se facea cu:  gcc ex1.c -lglut -lGL -lGLU -o ex1-2020.exe
la promptul $, in directorul sursei.
Rularea se facea la acelasi prompt $: ./ex1-2020.exe
adica rulam din directorul curent outputul compilatorului.
Obs: Numele cu .exe nu este obligatoriu, am vrut sa sugerez ca este executabil, stiam ca o sa ma intrebati.


Iar sursa era:
#include <GL/gl.h>
#include <GL/glut.h>

#include <unistd.h>

/*
A. myfirstopenglprogram.c  (ex1.c)
Capitolul1: Concepte fundamentale despre OpenGL
*/

/*
Am inclus doua biblioteci “gl.h” si “glut.h”.
*/

void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
// Culoarea de pefundal: negru, netransparent
glClear(GL_COLOR_BUFFER_BIT);
// Am sters continutul din fereastra
glMatrixMode(GL_PROJECTION);
// Modul de lucru OpenGL - Proiectie
glLoadIdentity();
// Am incarcat in masina cu stiva elementul neutru la inmultirea matricelor
glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
// Spatiu de vizualizat in proiectie "ortographica", este un cub
glMatrixMode(GL_MODELVIEW);
// Modul de lucru OpenGl - Model pt a fi vazut

// Vom incepe desenarea - punctele vor semnifica triunghiuri
glBegin(GL_TRIANGLES);
// Dand trei puncte desenam un triunghi
glColor3f(1.0,0.0,0.0);
// Dam intai culoarea primului varf:rosu
glVertex3f(0.0,0.8,0.0);
// si coordonatele sale
glColor3f(0.0,1.0,0.0);
// Dam apoi culoarea  varfului al II-lea :verde
glVertex3f(-0.6,-0.2,0.0);
// si coordonatele varfului
glColor3f(0.0,0.0,1.0);
// Dam apoi culoarea  varfului al III-lea :albastru
glVertex3f(0.6,-0.2,0.0);
//  si coordonatele varfului
glEnd();
// Terminam seria de date destinate desenului
glFlush();
// Impunem procesarea lor
sleep(10);
// Asteptam 10 secunde
exit(0);
// Oprim programul,dupa aceste 10 secunde.
}


int main(int argc, char ** argv)
{
 glutInit(&argc,argv);
 // Freeglut are nevoie si de initializare 
 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
 // Display-ul va functiona single-buffer si pe culori RGBA
 glutInitWindowPosition(20,20);
 // Fereastra va fi fixata cu coltul stang in pct. 20,20
 glutInitWindowSize(500,500);
 // Si va avea dimensiunea 500 x 500
 glutCreateWindow("Ex1.c");  //in loc de argv[0]
 // La crearea ferestrei se specifica si titlul
 glutDisplayFunc(display);
 // Comunicam OpenGL-ului ce functie display sa foloseasca
 glutMainLoop();
 return 0;
}

/* sleep cere <unistd.h> pe Unix.

radacina@computer:~/practica/opengl$ gcc ex1.c -lglut -lGL -lGLU -o ex1.exe
radacina@computer:~/practica/opengl$ ./ex1.exe
radacina@computer:~/practica/opengl$
*/

Explicatiile s-au dat la intalnirea precedenta.

Exemplul Nr 2:

Este din Cap 3.5.2, Afisarea in perspectiva, si reprezinta ... oare ce ?

Sursa:

#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>

/*
A.b quadortho.c (ex2.c)
Am inclus doua biblioteci “gl.h” si “glut.h”.
*/


void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
// Culoare de fundal: negru netransparent
glClear(GL_COLOR_BUFFER_BIT);
// Stergem ecranul
glMatrixMode(GL_PROJECTION);
// Trecem OpenGL in mod: Proiectie
glLoadIdentity();
// Initializam stiva calculatorului cu matricea identitate
glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
// Spatiul e proiectat orthografic, in cubul specificat
glMatrixMode(GL_MODELVIEW);
// Trecem OpenGL la definirea modelelor
/*
Aici vom descrie modelele intre GLBegin si GLEnd.
*/
// Coordonatele vor fi considerate varfuri de patrate
glBegin(GL_QUADS);
// Vom desena  patrat(e) in sens antiorar.@
glColor3f(0.0,1.0,1.0);
// Culoarea aleasa:verde-albastru
glVertex3f(-0.5,0.5,-0.5);
// Coordonatele primului varf (superior-stanga)
glVertex3f(-0.5,-0.5,0.5);
// Coordonatele celui de-al doilea varf (inferior-stanga)
glVertex3f(0.5,-0.5,0.5);
// Coordonatele celui de-al treilea varf (inferior-dreapta)
glVertex3f(0.5,0.5,-0.5);
// Coordonatele celui de-al patrulea varf (superior-dreapta)
glEnd();
// Terminarea definirii punctelor de sprijin
glFlush();
// Declansam desenarea sprijinita pe puncte
sleep(10);
// Asteptam  10 secunde
exit(0);
// Oprim programul.
}


int main(int argc, char ** argv)
{
glutInit(&argc,argv);      // Freeglut are nevoie si de initializare 
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex2.c");  //in loc de argv[0]
glutDisplayFunc(display);
glutMainLoop();
return 0;
}


/*
radacina@computer:~/practica/opengl$ gcc ex2.c -lglut -lGL -lGLU -o ex2.exe
radacina@computer:~/practica/opengl$ ./ex2.exe
radacina@computer:~/practica/opengl$
*/



Desenati dvs un cub, ca la geometrie, in jurul axelor XOY, atat in partea cu plus cat si in cea cu minus. (-0,5 , +0,5) sunt pe fiecare axa. Coordonatele le luati din cod !

Marcati pe cub cele patru varfuri si directia de privire, axa OZ.

Ati remarcat ca patrulaterul este de fapt un dreptunghi, avand o latura mai aproape de observator si una mai departe ?

Intrebare de control: Care este mai aproape, cea de sus sau cea de jos ?

Chestia se vede daca activati proiectia perspectiva, vedeti codul modificat:

#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>

/*
A.c quadpersp.c (ex3.c)
Am inclus doua biblioteci “gl.h” si “glu.h”.
*/

void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
// Culoare de fundal: negru netransparent
glClear(GL_COLOR_BUFFER_BIT);
// Stergem ecranul
glMatrixMode(GL_PROJECTION);
// Trecem OpenGL in mod: Proiectie
glLoadIdentity();
// Initializam stiva calculatorului cu matricea identitate

// Dar nu se va vedea nimic din aceasta perspectiva -> Ex4.c
gluPerspective(60.0,1.0,1.0,100.0);                            
// Proiectie perspectiva. Unghiul de vizualizare este de 60 de
// grade, raportul latime/inaltime (aspect ratio) este 1 (1:1 fiind egale),
// la distanta minima este z=1.0, si distanta maxima este z=100.0

glMatrixMode(GL_MODELVIEW);
// Trecem OpenGL in modul: reprezentare modele
/*
Aici vom descrie modelele intre GLBegin si GLEnd.
*/
// Coordonatele vor fi considerate varfuri de patrate
glBegin(GL_QUADS);
// Vom desena  patrat(e) in sens antiorar.@
glColor3f(0.0,1.0,1.0);
// Culoarea aleasa:verde-albastru
glVertex3f(-0.5,0.5,-0.5);
// Coordonatele primului varf (superior-stanga)
glVertex3f(-0.5,-0.5,0.5);
// Coordonatele celui de-al doilea varf (inferior-stanga)
glVertex3f(0.5,-0.5,0.5);
// Coordonatele celui de-al treilea varf (inferior-dreapta)
glVertex3f(0.5,0.5,-0.5);
// Coordonatele celui de-al patrulea varf (superior-dreapta)
glEnd();
// Terminarea definirii punctelor de sprijin
glFlush();
// Declansam desenarea sprijinita pe puncte
sleep(10);
// Asteptam  10 secunde
exit(0);
// Oprim programul.
}


int main(int argc, char * argv)
{
glutInit(&argc,&argv);      // Freeglut are nevoie si de initializare 
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex3.c");  //in loc de argv[0]
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

/*
radacina@computer:~/practica/opengl$ gcc ex3.c -lglut -lGL -lGLU -o ex3.exe
radacina@computer:~/practica/opengl$ ./ex3.exe
radacina@computer:~/practica/opengl$
Tema: Explicati de ce nu se vede nimic ! Unde e patratul si unde este
trunchiul de piramida al spatiului proiectat, vizibil noua ?
*/


Atentie la compilarea acestui exemplu, este necesar sa aveti toate cele trei biblioteci in linia de comanada specificate:


Totusi ati vazut ca nu se vede nimic cand rulam programul:

Ceea ce se intampla din cauza faptului ca suntem in origine, chiar in planul prin care trece dreptunghiul, dar daca ne dam doua unitati mai in spate, iata:

#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>

/*
A.c quadpersp.c (ex4.c)
Am inclus doua biblioteci “gl.h” si “glu.h”.
*/

void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
// Culoare de fundal: negru netransparent
glClear(GL_COLOR_BUFFER_BIT);
// Stergem ecranul
glMatrixMode(GL_PROJECTION);
// Trecem OpenGL in mod: Proiectie
glLoadIdentity();
// Initializam stiva calculatorului cu matricea identitate

// Dar nu se va vedea nimic din aceasta perspectiva
gluPerspective(60.0,1.0,1.0,100.0);                            
// Proiectie perspectiva. Unghiul de vizualizare este de 60 de
// grade, raportul latime/inaltime (aspect ratio) este 1 (1:1 fiind egale),
// la distanta minima este z=1.0, si distanta maxima este z=100.0

glTranslatef(0.0,0.0,-2.0);
// Ne dam inapoi doi pasi, adica supunem pozitia observatorului,
// (a aparatului sau foto) unei translatii pe axa z cu -2.0 unitati.

glMatrixMode(GL_MODELVIEW);
// Trecem OpenGL in modul: reprezentare modele
/*
Aici vom descrie modelele intre GLBegin si GLEnd.
*/
// Coordonatele vor fi considerate varfuri de patrate
glBegin(GL_QUADS);
// Vom desena  patrat(e) in sens antiorar.@
glColor3f(0.0,1.0,1.0);
// Culoarea aleasa:verde-albastru
glVertex3f(-0.5,0.5,-0.5);
// Coordonatele primului varf (superior-stanga)
glVertex3f(-0.5,-0.5,0.5);
// Coordonatele celui de-al doilea varf (inferior-stanga)
glVertex3f(0.5,-0.5,0.5);
// Coordonatele celui de-al treilea varf (inferior-dreapta)
glVertex3f(0.5,0.5,-0.5);
// Coordonatele celui de-al patrulea varf (superior-dreapta)
glEnd();
// Terminarea definirii punctelor de sprijin
glFlush();
// Declansam desenarea sprijinita pe puncte
sleep(10);
// Asteptam  10 secunde
exit(0);
// Oprim programul.
}


int main(int argc, char * argv)
{
glutInit(&argc,&argv);      // Freeglut are nevoie si de initializare 
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex4.c");  //in loc de argv[0]
glutDisplayFunc(display);
glutMainLoop();
return 0;
}


/*
radacina@computer:~/practica/opengl$ gcc ex4.c -lglut -lGL -lGLU -o ex4.exe
radacina@computer:~/practica/opengl$ ./ex4.exe
radacina@computer:~/practica/opengl$
*/


De data aceasta se vede in perspectiva:


Capitolul 3.5.3 Suprapunerea obiectelor si asanumitul Z-buffer.
Daca adaugam un triunghi, care ar trebui sa se intersecteze cu patrulaterul constatam ca totusi OpenGl le deseneaza unul peste altul, cel putin cu setarile curente:

Iata un exemplu cu setarile curente:

#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>

/*
A.e simpleguy.c (ex5.c)
Am inclus doua biblioteci “gl.h” si “glu.h”.
Am corectat ! DEPTH
*/

void display(void)
{
glClearColor(0.0,0.0,0.0,0.0);
// Culoare de fundal: negru netransparent
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  //!
// Stergem ecranul
glMatrixMode(GL_PROJECTION);
// Trecem OpenGL in mod: Proiectie
glLoadIdentity();
// Initializam stiva calculatorului cu matricea identitate

gluPerspective(60.0,1.0,1.0,100.0);                            
// Proiectie perspectiva. Unghiul de vizualizare este de 60 de
// grade, raportul latime/inaltime (aspect ratio) este 1 (1:1 fiind egale),
// la distanta minima este z=1.0, si distanta maxima este z=100.0

glTranslatef(0.0,0.0,-2.0);
// Ne dam inapoi doi pasi, adica supunem pozitia observatorului,
// (a aparatului sau foto) unei translatii pe axa z cu -2.0 unitati.

glMatrixMode(GL_MODELVIEW);
// Trecem OpenGL in modul: reprezentare modele

// Inainte de desenare adaugam
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glClearDepth(1.0);

// Aici am adaugat triunghul tricolor intre GLBegin si GLEnd.

// Vom incepe desenarea - punctele vor semnifica triunghiuri
glBegin(GL_TRIANGLES);
// Dand trei puncte desenam un triunghi
glColor3f(1.0,0.0,0.0);
// Dam intai culoarea primului varf:rosu
glVertex3f(0.0,0.8,0.0);
// si coordonatele sale
//glColor3f(0.0,1.0,0.0);
// Dam apoi culoarea  varfului al II-lea :verde
glVertex3f(-0.6,-0.2,0.0);
// si coordonatele varfului
//glColor3f(0.0,0.0,1.0);
// Dam apoi culoarea  varfului al III-lea :albastru
glVertex3f(0.6,-0.2,0.0);
//  si coordonatele varfului
glEnd();

// Coordonatele vor fi considerate varfuri de patrate
glBegin(GL_QUADS);
// Vom desena  patrat(e) in sens antiorar.@, nn. este doar o conventie.
glColor3f(0.0,1.0,1.0);
// Culoarea aleasa:verde-albastru
glVertex3f(-0.5,0.5,-2.5);   //-1.5);  //-0.5);
// Coordonatele primului varf (superior-stanga)
glVertex3f(-0.5,-0.5,-1.5);  //-0.5); //0.5);
// Coordonatele celui de-al doilea varf (inferior-stanga)
glVertex3f(0.5,-0.5,-1.5);   //-0.5);  //0.5);
// Coordonatele celui de-al treilea varf (inferior-dreapta)
glVertex3f(0.5,0.5,-2.5);    //-1.5);   //-0.5);
glEnd();
// Terminarea definirii punctelor de sprijin
glFlush();
// Declansam desenarea sprijinita pe puncte
sleep(10);
// Asteptam  10 secunde
exit(0);
// Oprim programul.
}


int main(int argc, char * argv)
{
glutInit(&argc,&argv);      // Freeglut are nevoie si de initializare 
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA| GLUT_DEPTH); //!
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex5.c");  //in loc de argv[0]
glutDisplayFunc(display);
glutMainLoop();
return 0;
}


/*
radacina@computer:~/practica/opengl$ gcc ex5.c -lglut -lGL -lGLU -o ex5.exe
radacina@computer:~/practica/opengl$ ./ex5.exe
radacina@computer:~/practica/opengl$
*/


Imagine cu poligoanele suprapuse incorect din cauza neactivarii optiunii Z-Buffer:
 

Si acum o varianta corecta, in care Z-Bufferul fiind activat, se vad cele doua poligoane intrepatrunse:

#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>

/*
A.d zbuffer-yes.c (ex5v2.c)
Am inclus doua biblioteci “gl.h” si “glu.h”.
*/

void display(void)
{
// Activam Z-Buffer-ul pt ordonarea in perspectiva
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glClearDepth(1.0);

glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Golim atat buffer-ul de culori cat si Z-Buffer-ul
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
// Proiectie perspectiva. Unghiul de vizualizare este de 60 de
// grade, raportul latime/inaltime (aspect ratio) este 1 (1:1 fiind egale),
// la distanta minima este z=1.0, si distanta maxima este z=100.0
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.0,0.0,-2.0);
// Coordonatele vor fi considerate varfuri de patrate
glBegin(GL_QUADS);
// Vom desena  patrat(e) in sens antiorar.@
glColor3f(0.0,1.0,1.0);
// Culoarea aleasa:verde-albastru
glVertex3f(-0.5,0.5,-0.5);
// Coordonatele primului varf (superior-stanga)
glVertex3f(-0.5,-0.5,0.5);
// Coordonatele celui de-al doilea varf (inferior-stanga)
glVertex3f(0.5,-0.5,0.5);
// Coordonatele celui de-al treilea varf (inferior-dreapta)
glVertex3f(0.5,0.5,-0.5);
glEnd();
// Terminarea definirii punctelor de sprijin

// Acum desenam alt triunghi care "inteapa" patratul
glBegin(GL_TRIANGLES);
glColor3f(1.0,0.0,0.0);
glVertex3f(0.0,0.5,0.0);
glVertex3f(-0.7,-0.5,0.0);
glVertex3f(0.7,-0.5,0.0);
glEnd();
glFlush();
sleep(20);
exit(0);
}


int main(int argc, char * argv)
{
glutInit(&argc,&argv);      // Freeglut are nevoie si de initializare 
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH); //Cerem si adancime
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex5v2.c");
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

/*
radacina@computer:~/practica/opengl$ gcc ex5v2.c -lglut -lGL -lGLU -o ex5v2.exe
radacina@computer:~/practica/opengl$ ./ex5v2.exe
radacina@computer:~/practica/opengl$
*/


Imagine cu Z-Buffer activat! Acum fragmentele sunt corect desenate si impresia este de poligoane care se inteapa.

In capitolul 3.5.4 este vorba de ierarhii de componente grafice.
Ideea esentiala este ca pentru a desena ceva, (exemplul clasic este o mana de robot) sau un arbore cu ramificatii, sau o piesa pe care sunt montate alte piese, sau o mina marina, sau un coronavirus,
ei bine,
se deseneaza piesa centrala cu reperul mutat in centrul ei,
se face un PushMatrix pt a salva matricea transformarii
se muta reperul in centrul primului subansablu (deget, etc)
(ceea ce poate presupune translatie dar si rotatie )
se deeneaza acel deget / piesa cu tot ce are el
se face un PopMatrix pt a reveni la reperul din centrul piesei de baza.

si se continua cu al doilea deget / varf / subansamblu.
In final se revine la reperul initial, al centrului piesei de baza.

Iata un exemplu de cod cu o ierarhie 2D , de patrate:

Si codul pentru crearea ei:

#include "GL/glut.h"

//A.f jerarquia-cuadro.c (ex6.c)

void desenarePatrat(float lat)
{
glBegin(GL_QUADS);
glVertex3f(-lat/2.0,lat/2.0,0.0);
glVertex3f(-lat/2.0,-lat/2.0,0.0);
glVertex3f(lat/2.0,-lat/2.0,0.0);
glVertex3f(lat/2.0,lat/2.0,0.0);
glEnd();
}

void display()
{
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-6.0);
glColor4f(1.0,0.0,0.0,1.0);
desenarePatrat(1.0);
glPushMatrix();
glTranslatef(0.0, 2.0, 0.0);
desenarePatrat(0.5);
glPopMatrix();
glPushMatrix();
glTranslatef(0.0, -2.0, 0.0);
desenarePatrat(0.5);
glPopMatrix();
glPushMatrix();
glTranslatef(2.0, 0.0, 0.0);
desenarePatrat(0.5);
glPopMatrix();
glPushMatrix();
glTranslatef(-2.0, 0.0, 0.0);
desenarePatrat(0.5);
glPopMatrix();
glFlush();
}

int main(int argc, char **argv)
{
glutInit(&argc,argv);      // Freeglut are nevoie si de initializare 
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex6.c");
glutDisplayFunc(display);
glutMainLoop();
return 0;
}


/*
radacina@computer:~/practica/opengl$ gcc ex6.c -lglut -lGL -lGLU -o ex6.exe
radacina@computer:~/practica/opengl$ ./ex6.exe
radacina@computer:~/practica/opengl$
*/


Pauza s-a terminat.

Exercitiu de control:
Desenati, dupa aceleasi reguli, o mana cu 5 degete diferit colorate, in 2D, de
aceasta forma, v-o desenez in stil ASCII ART:

---------------------------------------------------------------------------
|                                           |                                  |
-                                           ----------------------------------
|                                           |                                  |
-                                           ----------------------------------
|                                           |                                  |
-                                           ----------------------------------
|                                           |                                  |
---------------------------------------------------------------------------
                               |                                     |
                               ------------------------------------




3) Seful de grupa a primit deja manualul pe e-mail. Scrieti la adresa autorului blog-ului pentru a-l primi si dumneavoastra.

In acest moment va fac o selectie de pagini de manual , de la acest capitol incolo , e vorba de paginile 33-75. Nu include explicatiile de la prima intalnire, dar aveti pagina de blog, aceasta.

In final setul dvs de materiale va include cel putin:
- Aceasta pagina de blog: video4linux.blogspot.com - Pagina intitulata Grafica - IFR
- Selectia din manual cu pg 35-75,123
- Codurile sursa din editia spaniola.
- Manualul tiparit de la Alma Mater, tradus de Dan P.
- Alte carti de Open Gl: RedBook, OrangeBook

Ok, aveti 10 minute pauza de cafea si ca sa examinati materialele trimise,
continuam dupa pauza de la capitolul 3.5.4


3.5.4 Ierarhii

Cititi va rog din materialul trimis pe e-mail (OpenGLv12-[pg1-6,33-75,123].pdf) inceputul capitolului 3.5.4 pina la:

void desenarePatrat(float lat)
{
glBegin(GL_QUADS);
glVertex3f(­lat/2.0,lat/2.0,0.0);
glVertex3f(­lat/2.0,­lat/2.0,0.0);
glVertex3f(lat/2.0,­lat/2.0,0.0);
glVertex3f(lat/2.0,lat/2.0,0.0);
glEnd(); }

Si treceti la pg -35- fizica, pg 9 in e-bookul selectie. Aveti aici o selectie din codul de mai sus.Desenarea decurge in felul urmator,

[atentie, in editia electronica a draftului cartii pe care ati primit-o este o greseala de tipar (-2.0 boldit, sunt doar 2.0 -uri), corectati, ce gasiti -2.0 bold mai jos:]

- primul apel al functiei desenarePatrat()   deseneaza patratul central:

glLoadIdentity();
glTranslatef(0.0,0.0,­6.0);
glColor4f(1.0,0.0,0.0,1.0);

desenarePatrat(1.0);     <-   deseneaza patratul central

- Acum se salveaza matricea !

glPushMatrix();                     <-- Acum se salveaza matricea !

- si acum ne deplasa me axa Y in sus

glTranslatef(0.0, 2.0, 0.0);        <- si acum ne deplasa pe axa Y in sus
desenarePatrat(0.5);                 <-   deseneaza patratul
glPopMatrix();                           <- revenim la reperul initial


glPushMatrix();
glTranslatef(0.0, ­-2.0, 0.0);      <- si acum ne deplasa pe axa Y in jos
desenarePatrat(0.5);                 <-   deseneaza patratul
glPopMatrix();                           <- revenim la reperul initial

glPushMatrix();
glTranslatef(2.0, 0.0, 0.0);        <- si acum ne deplasa pe axa X la dreapta 
desenarePatrat(0.5);                 <-   deseneaza patratul
glPopMatrix();                           <- revenim la reperul initial
...
glPushMatrix();                          <- si acum ne deplasa pe axa X la stanga
glTranslatef(­-2.0, 0.0, 0.0);       <-   deseneaza patratul
desenarePatrat(0.5);                  <-   revenim
glPopMatrix();
...
glFlush();

Folositi aceeasi idee pentru rezolvarea exercitiului anterior.

Imaginea 3.15, cu ierarhia fractala, pg -36-, explicatii:

In anumite sitiuatii in care ceea ce vrem sa desenam este un fractal, o structura arborescenta in care substructurile sunt asemenea cu piesa de baza, subrutina care deseneaza sub-componentele , componentele subordonate - se apeleaza pe ea insasi in mod recursiv.

Se pot desena astfel: copaci, plante, (uneori cladiri - rar), nori, pietre, munti, valuri (rar). Pentru detalii cautati fractali. Cu exceptia unor fractali speciali, o mare parte dintre ei pot fi desenati cu astfel de functii recursive - si ma refer aici la fractalii autoasemenea.

In imagine: Exemplu de copac fractal, vom reveni la el, va fi un viitor exercitiu pentru dvs.

Totusi autorul manualului si al setului initial de exemple opteaza pentru o ierarhie de patrate 2D, recursiva, pe aceeasi idee a fractalului.
- In loc de un trunchi de planta paralelipipedic in 3D pune un patrat in 2D,
- in loc de cele 4 ramuri 3D (paralelipipezi articulati pe mijloacele laturilor de sus, in repere rotite) pune  cele 4 patrate 2D mai mici,
ideea este insa aceeasi.

 De data aceasta mergem mai departe... cu desenarea recursiva, astfel incat sa ajungem la acest fel de imagine:


Cdul sursa este:

#include <GL/gl.h>
#include <GL/glut.h>

// A.g jerarquia-cuadro-recursivo.c (ex6v2.c)

void desenarePatrat(float lat)
{
  glBegin(GL_QUADS);
  glVertex3f(-lat/2.0,lat/2.0,0.0);
  glVertex3f(-lat/2.0,-lat/2.0,0.0);
  glVertex3f(lat/2.0,-lat/2.0,0.0);
  glVertex3f(lat/2.0,lat/2.0,0.0);
  glEnd();
}

void desenarePatrateRecursive(float lat)
{
if (lat > 0.005)
 {
  desenarePatrat(lat);
  glPushMatrix();
  glTranslatef(0.0, lat * 2.0, 0.0);
  desenarePatrateRecursive(lat / 2.0);
  glPopMatrix();
  glPushMatrix();
  glTranslatef(0.0, -lat * 2.0, 0.0);
  desenarePatrateRecursive(lat / 2.0);
  glPopMatrix();
  glPushMatrix();
  glTranslatef(lat * 2.0, 0.0, 0.0);
  desenarePatrateRecursive(lat / 2.0);
  glPopMatrix();
  glPushMatrix();
  glTranslatef(-lat * 2.0, 0.0, 0.0);
  desenarePatrateRecursive(lat / 2.0);
  glPopMatrix();
 }
}

void display()
{
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-6.0);
glColor4f(1.0,0.0,0.0,1.0);
desenarePatrateRecursive(1.0);
glFlush();
}

int main(int argc, char *argv)
{
glutInit(&argc,&argv);      // Freeglut are nevoie si de initializare
 
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex6v2.c");
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

/*
radacina@computer:~/practica/opengl$ gcc ex6v2.c -lglut -lGL -lGLU -o ex6v2.exe
radacina@computer:~/practica/opengl$ ./ex6v2.exe
radacina@computer:~/practica/opengl$
*/

Exercitiul nr 2: Transformati acest cod in codul care sa deseneze un copac asa cum este cel din imaginea de mai sus.

Indicatii: Aveti nevoie de o subrutina pt desenat cubul, care prin scalare va deveni un paralelipiped.

Puteti stabili niste constante pt dim tulpinii:

#define TULP_HEIGHT  20
#define TULP_WIDTH 2
#define TULP_DEPTH 2

Asa se deseneaza cubul in OpenGL, folosind o functie GLUT:

void desenareCub(float lat)
{
  glPushMatrix();
   glScalef(TULP_WIDTH,TULP_DEPTH,TULP_HEIGHT);
   glutSolidCube(lat);
  glPopMatrix();
}

Ne vom uita in perspectiva , in directia copacului nostru:

gluPerspective(60.0,1.0,1.0,100.0);
glTranslatef(0.0,0.0,-1.6*TULP_HEIGHT);
gluLookAt(0,0,0, TULP_HEIGHT,TULP_HEIGHT,TULP_HEIGHT,0.0,0.0,1.0);

Vom folosi desenareCub pentru a desena paralelipipedul initial:
(in reper scalat insa, dar de asta se ocupa desenareCub() !):

glColor4f(0.2,0.8,0.0,0.0);
desenareCub(1.0);

Si apoi ne ducem in partea de sus a tulpinii, pe un mijloc de latura, rotim reperul, ne ducem pe "oblica" pina la jumatatea ramurii (sfertul tulpinii) cu o translatie si desenam "cubul" pardon, ramura, la scara 1/2.


glPushMatrix();                                          //sus
  glTranslatef(0.0, TULP_DEPTH/2, TULP_HEIGHT/2);
  glRotatef(-35.0, 1.0, 0.0, 0.0);
  glTranslatef(0.0,0.0, TULP_HEIGHT/4);
  desenareCub(0.5);
glPopMatrix();

Si asemanator se procedeaza pentru toate cele 4 ramuri. pentru aceasta nu v-ar strica niste manuale ale API-urilor OpenGL si GLUT, cum este
The OpenGL Utility Toolkit (GLUT),Programming Interface,API Version 3,Mark J. Kilgard,Silicon Graphics, Inc.
In orice caz caz va trebuie niste carti in care sa gasiti toti parametrii acestor functii.

Succes!

Pauza ...

Exemplul numarul 7, umanoidul colorat: pg -36- -37- -38- -39-

Sursa este, in editia spaniola, in anexa: simpleguy.c la pagina 73, pdf -ul in spaniola.

Exercitiu: Printati pe o foaie A4 imaginea de mai sus la scara mare, cat foaia,
si desenati pe ea, sub forma de vectori  -----> cum se misca originea sistemului de coordonate, si sub forma de unghiuri
  /|
 / |
-30 grade
sau
  |\
  | \
30 grade
felul cum se misca prin rotire reperul.

Nota: La acel popMatrix de dupa scalare, bineinteles ca reperul revine la norml, de exemplu se restaureaza si dimensiunile vectorilor unitate.
Fotografiati foaia cu desenul si trimiteti-o.

Capitolul al 4-lea: Animatii  [pg -40- -> pg 46]
Se ocupa cu animatia... cititi va rog capitolul al 4-lea. Programul va anima o sfera aflata in interiorul uni cub. Programul este facut in maniera poo in C++, deoarece mai tarziu vom anima mai multe sfere.

Sfera e definita astfel:

/////////////////////////////////////////////////////////
// Ex8: Fisierul sphere.h
/////////////////////////////////////////////////////////
#ifndef sphere_h
#define sphere_h
#include <stdlib.h>
#include <time.h>
#include <math.h>

typedef
class TSphere
{
  private:
    float maxpos;
    float pos[3];
    float dir[3];
    float speed;
  public:
    TSphere(float maxpos, float speed);
    void test();
    void modifySpeed(float inc);
    float * getPosv();
} TSphere;

#endif

Si este implementata astfel:

/////////////////////////////////////////////////////////
// Fisierul sphere.cpp
/////////////////////////////////////////////////////////
#include "sphere.h"

int pass=0;

TSphere::TSphere(float maxpos, float speed)
{
this->maxpos = maxpos;
if (!pass)
  {
   srandom(time(NULL));
   pass = 1;
  }
pos[0] = (random() % (int)maxpos) - maxpos/2;
pos[1] = (random() % (int)maxpos) - maxpos/2;
pos[2] = (random() % (int)maxpos) - maxpos/2;
dir[0] = random();
dir[1] = random();
dir[2] = random();
float dirmod = sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]);
dir[0] /= dirmod;
dir[1] /= dirmod;
dir[2] /= dirmod;
dir[0] *= speed;
dir[1] *= speed;
dir[2] *= speed;
}

void TSphere::test()
{
((pos[0] < -maxpos) || (pos[0] > maxpos))?dir[0]*=-1:0;
((pos[1] < -maxpos) || (pos[1] > maxpos))?dir[1]*=-1:0;
((pos[2] < -maxpos) || (pos[2] > maxpos))?dir[2]*=-1:0;
pos[0] += dir[0];
pos[1] += dir[1];
pos[2] += dir[2];
}

void TSphere::modifySpeed(float inc)
{
float factor = (speed+inc)/speed;
speed += inc;
dir[0] *= factor;
dir[1] *= factor;
dir[2] *= factor;
}

float * TSphere::getPosv()
{
return pos;
}

Remarcati ca asa este implementata doar geometria si miscarea sferei, pe o directie aleatoare normalizata. De asemenea , sfera se va misca intre niste limite maxpos, -maxpos pe toate directiile, adica intr-un cub. Iar daca iese din cubul acesta i se schimba ca semn vectorul de viteza, pe componenta aceea, ca sa reintre in cub.

Programul principal este acesta:

/////////////////////////////////////////////////////////
// Fisierul Ex8.cpp
/////////////////////////////////////////////////////////
#include <GL/gl.h>
#include <GL/glut.h>
#include <unistd.h>
#include "sphere.h"

float * pos;
TSphere * sphere = NULL;

void initgl()
{
glEnable(GL_DEPTH_TEST);
glClearColor(0.0,0.0,0.0,0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Folosind proiectia orthografica sau o...
glOrtho(-12.0,12.0,-12.0,12.0,-30.0,30.0);
// gluPerspective(60.0,1.0,1.0,100.0);
// ...proiectie perspectiva. Unghiul de vizualizare este de 60 de
// grade, raportul latime/inaltime (aspect ratio) este 1 (1:1 fiind egale),
// la distanta minima este z=1.0, si distanta maxima este z=100.0
sphere = new TSphere(5,0.1);
glMatrixMode(GL_MODELVIEW);
gluLookAt(3,3,14,0,0,0,0,1,0);
}

void display(void)
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glColor3f(1.0,1.0,1.0);
  glutWireCube(10);
  glPushMatrix();
  glColor3f(0.0,0.0,1.0);
  pos = sphere->getPosv();            // afla parametrii sferei
  glTranslatef(pos[0],pos[1],pos[2]); // aplica o translatie
  glutSolidSphere(1,10,10);           // o deseneaza acolo
  glPopMatrix();
  glFlush();
}

void idle(void)
{
sphere->test();
usleep(33);
glutPostRedisplay();
}

int main(int argc, char ** argv)
{
glutInit(&argc,argv);      // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow("Ex8.cpp");
initgl();
glutDisplayFunc(display);
glutIdleFunc(idle);
glutMainLoop();
return 0;
}

// De notat si faptul ca programul nu are functie care sa faca
// redimensionarea ferestrei (pastrand forma cubului)


/* Ubuntu 14.04 (aprox)
Compilati cu:
 radacina@computer:~/practica/opengl$ gcc -c  sphere.cpp
 radacina@computer:~/practica/opengl$ gcc -c  Ex8.cpp
 radacina@computer:~/practica/opengl$ gcc   -o Ex8.exe Ex8.o sphere.o  -lglut -lGL -lGLU
 radacina@computer:~/practica/opengl$ ./Ex8.exe
*/


/*
 Ubuntu 18.04

matlab@computer66:~/!practica cu cartev5/opengl/Ex8$ g++ -c Ex8.cpp
matlab@computer66:~/!practica cu cartev5/opengl/Ex8$ g++ -c sphere.cpp
matlab@computer66:~/!practica cu cartev5/opengl/Ex8$ g++ -o Ex8.exe Ex8.o sphere.o -lglut -lGL -lGLU

*/
Dar fiind C++ va trebui sa il compilati cu g++

Directorul meu cu fisiere arata asa:

Iar app. in executie arata asa:
Bineinteles ca bila se va misca, ceea ce nu se vede in imagine.

Cap 4.2. desenarea cu doua buffere. pg -45-

Exercitiu: Verificati daca programul de mai sus lucreaza cu doua buffere si in caz contrar faceti modificarile necesare.
Cum se vede deosebirea pe un display LCD ?


Exercitiu: Modificati programul astfel incat sa anime mai multe sfere ca in Fig 4.5
Indicatie: Modificati call-back-ul, functia,  display() al OpenGl-ului.

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0,1.0,1.0);   // alb = rosu + verde + albastru
glutWireCube(10);
for (int i=0;i<NUM_SPHERES;i++)
{
  glPushMatrix();
  glColor3f(0.0,0.0,1.0);
  pos = sphere[i]->getPosv();
  glTranslatef(pos[0],pos[1],pos[2]);
  glutSolidSphere(SPHERE_RADIUS,10,10);
  glPopMatrix();
  sphere[i]->test();
}
glFlush();
glutSwapBuffers();
}

Constantele trebuiesc definite inainte:

#define NUM_SPHERES 55
#define SPHERE_RADIUS 0.4

Si nu uitati modificarile din paragraful  4.2.

Capitolul al 5-lea : Lumina , pg -47-
Incepeti sa cititi de la pg -47- incolo ...deocamdata pina la pagina 54, paragraful 5.1.3

In principiu,pe partea de lumina, OpenGl este un calculator vectorial al vectorilor de culoare a luminii care vin pe anumite directii, de la anumite surse, se reflecta, geometric sau difuz, totul intr-un mediu care are implicit o constanta (a anumita lumina) in toate punctele - lumina de culoarea umbrei.

Ca efect sunt 4 feluri de lumina:

- ambietala: lumina de la umbra, cea care, ca in Biblie, a facut-o Dzeu sa umple spatiul, si ea nu provenea de la luminatori (soare luna si alte surse de lumina), care atunci, spune legenda, nu existau inca.
-  emisa: lumina venita de la sursele de lumina, indiferent ce lumini sunt in jur, sursele  emit lumina lor proprie
- speculara: lumina care se reflecta ca la geometrie, raza incidenta si cea care pleaca sunt in acelasi plan, la unghi eglal. Asa se reflecta lumina in oglinzi, pe suprafete metalice lustruite.
- difuza: lumina care se reflecta dar in toate directiile, difuz, nu formeaza imagine in oglinda.

5.1.2 Materiale.
Veti gasi in alte colectii de exemple OpenGL si exemple cu materiale de culori diferite. Nu sunt inclus aici.

5.1.3Normala la suprafata este importanta. Schimbarea directiei ei provoaca o schimbare de efect de culoare, un fel de falsa texturare, fiindca lumina se va reflecta in raport cu normala perturbata.
Vom reveni la exemplul numarul 11a.

Ex11a.c

// EX11A.c - normals-perp.c ok
#include <GL/glut.h>
#include <stdlib.h>

#include <unistd.h>              //  <- Ubunt 18, pentru functia sleep            
#define SINGLE_NORMAL   //comentati linia

void display(void)
{
GLfloat mat_color [] = {0.0,1.0,1.0,1.0};
GLfloat light_color [] = {1.0,1.0,1.0,1.0};
GLfloat light_ambient [] = {0.0,0.0,0.0,1.0};
GLfloat normal [] = {0.0,1.0,0.0};
GLfloat light_dir [] = {0.0,1.0,0.0,0.0};
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_color);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_color);
glEnable(GL_LIGHT0);
glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_color);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glTranslatef(-0.3,-0.6,-4.0);
glLightfv(GL_LIGHT0,GL_POSITION,light_dir);
glBegin(GL_QUADS);

glVertex3f(-1.0,0.0,-1.0);
#ifdef SINGLE_NORMAL
  glNormal3fv(normal);
#else
  glNormal3f(1.0,1.0,-1.0);
#endif

glVertex3f(-1.0,0.0,1.0);
glNormal3fv(normal);

glVertex3f(1.0,0.0,1.0);
#ifdef SINGLE_NORMAL
  glNormal3fv(normal);
#else
  glNormal3f(-1.0,1.0,-1.0);
#endif
glNormal3fv(normal);
glVertex3f(1.0,0.0,-1.0);

glEnd();
glFlush();
sleep(20);
exit(0);
}

int main(int argc, char ** argv)
{
glutInit(&argc,argv);      // Freeglut are nevoie si de initializare 
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

/*
radacina@computer:~/practica/opengl$ gcc  ex11a.c -lglut -lGL -lGLU -o ex11a.exe

*/


Observati perturbarea, fata de o suprafata uniform colorata.

Dar pentru ca in acest exemplu apar deja mai multe notiuni despre iluminat, cititi va rog:

Capitolul 5.2 Utilizarea luminilor: pg -49-

 ... va las timp sa il cititi !

Sa rezumam cateva chestiuni:
- Iluminatul ca si alte optiuni OpenGl se activeaza: glEnable(GL_LIGHTING).
- Numarul de surse de lumina e o putere a lui doi, initial a fost 2 la a 3-a = 8
- Fiecare sursa de lumina se va seta separat folosind un apel glLight*() unde * indica o continuare a numelui functiei care ne sufla cu ce tip de argumente lucram, de exemplu:

glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_color);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_color);

...
glLightfv(GL_LIGHT0,GL_POSITION,light_dir);

- Functiile glLight*() sunt un fel de atribuiri de parametri care descriu o sursa de lumina: primul argument este indica, sursa (aici sursa 0), al doilea spune carei variabile a sursei ii setam valoarea, abia al treilea argument e valoarea.

- Pozitionarea sursei de lumina presupune setarea valorii pentru "variabila" (ganditi "atributul") GL_POSITION al sursei de lumina.

glLightfv(GL_LIGHT0,GL_POSITION,light_dir);

- In cazul spoturilor care arunca un con de lumina din focar (lumina focala-le-am zis noi), folosim doua informatii, vectorul 3D al directiei (val_prt aici)  si unghiul conului de lumina emis:

glLightfv(GL_LIGHTn,GL_SPOT_DIRECTION,val_prt);
 
glLightf(GL_LIGHTn,GL_SPOT_CUTOFF,val);

- Un vector 3D cu 4 componente,cum e bineinteles val_prt si alti vectori se defineste dinainte cam asa:
 GLfloat val_prt [] = {0.0, 1.0, 0.0, 0.0}; 

Vedeti la pg -52- alte exemple  de parametri:
- GL_SPOT_EXPONENT - pt atenuarea luminii - valoarea setata e un coef
- GL_AMBIENT  - valoarea setata e un vector de culori
- GL_DIFUSE     - valoarea setata e un vector de culori
- GL_SPECULAR  - valoarea setata e un vector de culori
(pentru aceste trei tipuri de componente ale unei lumini)
- GL_CONSTANT
- GL_LINEAR
- GL_QUADRATIC
Acestia din urma modifica felul cum se atenueaza lumina in ceata. Ar mai fi multe de spus aici.

- Aprinderea luminii cu numarul n:
glEnable(GL_LIGHTn);

Exercitiu: In codul de mai sus, comentati toate instructiunile, fiecare pe un rand separat, folosind explicatiile din capitolul 5.2.1. Trimiteti pe e-mail fisierul de mai sus cu (ex11a.c) cu tot cu comentarii.

Exercitiu:
Rulati varianta "sphere-rebotes-multi.c", cu tot cu setari de iluminat si cu culori.Va arata asa:

Cap 5.2.2. Materiale
Cititi ceva despre materiale, de aici dar si din alte carti de OpenGL!

Cap 5.2.3 Iluminarea directa pe o suprafata
Abia aici este exemplul Ex11a.c de mai inainte, cu toate explicatiile.

Daca nu ati facut exercitiul anterior, cu comentarea ex11a.c, puteti lua cu copy -paste din carte tot subcapitolul si sa il transformati intr-un exemplu comentat.

Cap 5.2.4 Miscarea unei surse in jurul unei sfere
Veti scrie un program in care conul se invarte in jurul sferei si animatia este de tip dual-buffer.

Codul este:

//Ex10.c - A.k lit-sphere.c

#include <GL/glut.h>
#include <unistd.h>
#define ROT_INC 1.0
float light_ambient [] = {0.0,0.2,0.0,1.0};
float light_diffuse_specular [] = {0.8,0.8,0.8,1.0};
float light_pos [] = {0.0,0.0,2.0,1.0};
float spot_dir [] = {0.0,0.0,-1.0};
float spot_cutoff = 30.0;
float spot_exponent = 1.0;
float mat_ambient_diffuse [] = {0.0,0.8,1.0,1.0};
float mat_specular [] = {0.7,0.0,0.0,1.0};
float mat_emission [] = {0.0,0.0,0.0,1.0};
float mat_shininess = 0.4;
float focus_emission [] = {0.8,0.8,0.8,1.0};
float rot_angle_y = 0.0;
float rot_angle_x = 0.0;

void initgl()
{
glEnable(GL_DEPTH_TEST);
glClearColor(0.0,0.0,0.0,0.0);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_FALSE);
glEnable(GL_LIGHTING);

glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse_specular);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_diffuse_specular);
glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,spot_cutoff);
glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,spot_exponent);
glEnable(GL_LIGHT0);

glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_ambient_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialf(GL_FRONT,GL_SHININESS,mat_shininess);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.0,0.0,-5.0);
}

void idle(void)
{
rot_angle_y = (rot_angle_y > 360.0)?0:rot_angle_y + ROT_INC;
rot_angle_x = (rot_angle_x > 360.0)?0:rot_angle_x + ROT_INC/(2*3.1416);
glutPostRedisplay();
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(30.0,0.0,0.0,1.0);
glRotatef(rot_angle_y,0.0,1.0,0.0);
glRotatef(rot_angle_x,1.0,0.0,0.0);
glLightfv(GL_LIGHT0,GL_POSITION,light_pos);
glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,spot_dir);
glTranslatef(light_pos[0],light_pos[1],light_pos[2]);
glColorMaterial(GL_FRONT,GL_EMISSION);
glEnable(GL_COLOR_MATERIAL);
glColor4fv(focus_emission);
glutSolidCone(0.2,0.5,7,7);
glColor4fv(mat_emission);
glDisable(GL_COLOR_MATERIAL);
glPopMatrix();
glutSolidSphere(1.0,20,20);
glFlush();
glutSwapBuffers();
}

int main(int argc, char ** argv)
{
glutInit(&argc,argv);      // Freeglut are nevoie si de initializare 
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowPosition(20,20);
glutInitWindowSize(350,350);
glutCreateWindow(argv[0]);
initgl();
glutDisplayFunc(display);
glutIdleFunc(idle);
glutMainLoop();
return 0;
}

// Compilati cu:
// radacina@computer:~/practica/opengl$ gcc  Ex10.c -lglut -lGL -lGLU -o Ex10.exe
// Apoi: radacina@computer:~/practica/opengl$ ./Ex10.exe


Explicatii: Pg -56- pina la  -59-.
De citit explicatiile, de scris un fisier de cod completat cu comentarii.


Cap 6. Texturi, pg -63- pina la -pg 70-

Trebuie sa ne grabim, citit-l dvs.
Nota: Coordonatele unei texturi sunt numite coordonate (u,v) spre deosebire de cele (x,y,z) ale spatiului si sunt intr-un reper:

-|------------------->
 | O                      u
 |
 |
\|/ 
   v

Pentru a rula exemplul cu aplicarea texturii aveti nevoie si de ... texturi si de programul GIMP (www.gimp.org) care poate salva fisierele grafice sub forma de surse C.

 bricktexture.png

 grasstexture.png

Toate, inclusiv imaginea capturata dintr-un vechi joc video, se pot extrage sub Linux din fisierul .pdf al manualului spaniol.
game.png, (salvati-o in formatul C cu GIMP).

Atentie: Acest exemplu cu texturi are nevoie de o optiune speciala la compilatorul gcc: -trigraphs
Linia de comanda ar putea fi:
 gcc  ex11.c -lglut -lGL -lGLU -o ex11-2020.exe -trigraphs
 

Codul sursa, atentie, aveti nevoie si de fisierul "textura1.c", obtinut cu GIMP, prin salvarea texturii sa zicem game.png in format .c

//Ex11: normals-perp-texture.c  nt
#include <GL/glut.h>
#include <stdlib.h>
#include <unistd.h>

//88
//dupa
//Curso de introducción a OpenGL (v1.1)

#include "textura1.c"

void display(void)
{
GLfloat mat_color [] = {0.5,1.0,1.0,1.0};
GLfloat light_color [] = {1.0,1.0,1.0,1.0};
GLfloat light_ambient [] = {0.2,0.2,0.2,1.0};
GLfloat normal [] = {0.0,1.0,0.0};
GLfloat light_dir [] = {0.0,1.0,0.0,0.0};
int texture;
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_2D,texture);
//Aici puteti folosi GL_REPLACE sau GL_MODULATE
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// Comentati aceasta linie --^ si  decomentati-o pe cea similara,
// care urmeaza atunci cand vreti sa folositi  GL_REPLACE--v
//glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
gluBuild2DMipmaps( GL_TEXTURE_2D, gimp_image.bytes_per_pixel,
gimp_image.width, gimp_image.height,GL_RGB, GL_UNSIGNED_BYTE,
gimp_image.pixel_data );
glEnable(GL_TEXTURE_2D);
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_color);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_color);
glEnable(GL_LIGHT0);
glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_color);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
glTranslatef(-0.3,-0.6,-4.0);
glRotatef(90.0,1.0,0.0,0.0);
glLightfv(GL_LIGHT0,GL_POSITION,light_dir);
glBegin(GL_QUADS);
glNormal3f(1.0,-1.0,1.0);
glTexCoord2d(0.0,0.0);
glVertex3f(-1.5,0.0,-1.5);
glNormal3fv(normal);
glTexCoord2d(0.0,1.0);
glVertex3f(-1.5,0.0,1.5);
glNormal3f(1.0,-1.0,1.0);
glTexCoord2d(1.0,1.0);
glVertex3f(1.5,0.0,1.5);
glNormal3fv(normal);
glTexCoord2d(1.0,0.0);
glVertex3f(1.5,0.0,-1.5);
glEnd();
glFlush();
sleep(20);
exit(0);
}

int main(int argc, char ** argv)
{
glutInit(&argc,argv);      // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(350,350);
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

/* Fisierul cu imaginea cere o optiune speciala: -trigraphs
radacina@computer:~/practica/opengl$ gcc  Ex11.c -lglut -lGL -lGLU -o Ex11.exe -trigraphs
radacina@computer:~/practica/opengl$ ./Ex11.exe
*/


Iar la executie, daca totul merge bine, textura ajunge in fereastra:

Exercitiu: Dimensiunile nu corespund, faceti ca textura sa incapa exact in fereastra.

Cap 6.2 Multiplicarea unei texturi
Atunci cand multiplicam o textura, efectul in prim plan poate fi deranjant.


 Codul:
// Ex12-texture-no-clamp.c + texture-yes-clamp.c
#include <unistd.h>
#include <GL/glut.h>

// Cele doua fisiere de inclus contin si
// datele care descriu imaginea texturilor
// precum si declaratiile structurilor
// formatelor de date
// asa cum le salveaza in format .c GIMP-ul

#include "grass_texture.c"
//Dupa exportul din GIMP in format .c
// editati fisierul obtinut si inlocuiti
/* gimp_image -> grass_texture */

#include "brick_texture.c"
//Dupa exportul din GIMP in format c.
//editati fisierul obtinut si inlocuiti
/* gimp_image -> brick_texture */

void display(void)
{
int texture_floor;
int texture_wall;
glGenTextures(1,&texture_floor);
glBindTexture(GL_TEXTURE_2D,texture_floor);
gluBuild2DMipmaps( GL_TEXTURE_2D,grass_texture.bytes_per_pixel,
 grass_texture.width,grass_texture.height,GL_RGB, GL_UNSIGNED_BYTE,
 grass_texture.pixel_data );
glGenTextures(1,&texture_wall);
glBindTexture(GL_TEXTURE_2D,texture_wall);
gluBuild2DMipmaps( GL_TEXTURE_2D,brick_texture.bytes_per_pixel,
 brick_texture.width,brick_texture.height,GL_RGB, GL_UNSIGNED_BYTE,
 brick_texture.pixel_data );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// In cazul cand nu doriti sa se repete textura, comentati
// aceste doua linii cu GL_REPEAT iar mai jos dati numerele necesare
// pentru a preciza de cate ori sa se repete texturile
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
glEnable(GL_TEXTURE_2D);
glClearColor(0.1,0.6,1.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(-0.0,3.0,6.0,0.0,2.0,0.0,0.0,1.0,0.0);
// In cazul in care  nu cereti sa se repete textura de pe
// intervalul 0 .. 1 (schimbati 6 cu 1 in glTextCoord2d).
glBindTexture(GL_TEXTURE_2D,texture_floor);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3f(-6.0,0.0,-6.0);
glTexCoord2d(0.0,1.0);    // 1<->6
glVertex3f(-6.0,0.0,6.0);
glTexCoord2d(1.0,1.0);    // 1<->6
glVertex3f(6.0,0.0,6.0);
glTexCoord2d(1.0,0.0);    // 1<->6
glVertex3f(6.0,0.0,-6.0);
glEnd();
// In cazul cand  nu  cereti sistemului sa repete textura de pe
// intervalul 0..1  (schimbati 3 cu 1 in glTexCoord2d).
glBindTexture(GL_TEXTURE_2D,texture_wall);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3f(-6.0,4.0,-6.0);
glTexCoord2d(0.0,1.0);
glVertex3f(-6.0,0.0,-6.0);
glTexCoord2d(1.0,1.0);     // 1<->3
glVertex3f(6.0,0.0,-6.0);
glTexCoord2d(1.0,0.0);     // 1<->3
glVertex3f(6.0,4.0,-6.0);
glEnd();
glFlush();
sleep(20);
exit(0);
}

int main(int argc, char ** argv)
{
glutInit(&argc,argv);      // Freeglut are nevoie si de initializare
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(20,20);
glutInitWindowSize(300,300);
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

/*
radacina@computer:~/practica/opengl$ gcc  Ex12.c -lglut -lGL -lGLU -o Ex12.exe -trigraphs
radacina@computer:~/practica/opengl$ ./Ex12.exe
*/
 

Folositi modificarile indicate  la pagina -69- si pg -70-, pentru a elimina efectul deranjant. Pe cod sunt indicate ca schimbari 1 <->6.

Ar trebui sa obtineti nu o textura expandata de 6x4 = 24 de ori ci aceeasi textura, plasata de 24 de ori, ca 24 de piese de gresie cu desen similar.

Efectul vizual este altul:


In imagine textura ierbii de jos este multiplicata!

Pauza...

Urmeaza:

Cap 7: Bazele comunicarii cu GLUT.

Va rog sa il cititi dvs. si sa rulati programul dat ca exemplu.
Miscati conul de lumina prin rotatii in jurul axei x si in jurul axei y cu ajutorul tastelor cu sageti.




 Rotiti conul in jurul sferei folosind tasetel cu sageti.

Ce ati mai putea face in continuare, daca sunteti pasionati de grafica.

1) Cititi o carte romaneasca despre OpenGL
2) Lucrati dupa RedBook
3) Eventual lucrati dupa OrangeBook
4) Studiati OpenGLES, exista o carte buna, "OpenGL ES  Programming Guide" de Aaftab Munsh ,Dan Ginsburg, Dave Shreiner la editura Addison Wesley, au aparut si alte editii mai noi 2.0, 3.0 etc
5) Unii vor dori sa se apuce de Vulkan, dar atentie, este un API de nivel inferior, si desi ruleaza si pe Linux si pe Windows cantitatea de cod care se scrie pentru niste programe simple este proportional mai mare. Am fost surprins cate linii de cod mi-au trebuit ca sa obtin un cib texturat cu sigla Vulkan.
6) Urmariti revistele de specialitate. SIGGRAF.
7) Treceti la niste medii de dezvoltare care se bazeaza pe OpenGL, cum sunt Unity 3D, Unreal Engine etc.
8) Treceti pe la Khronos Ag.

Sunt enorm de multe resurse si continuari in zona graficii, ceea ce ati vazut aici  este doar un curs introductiv. La ora actuala se folosesc foarte mult modele 3D obtinute cu diferite tehnologii si incarcate ca atare in software.

Sfarsit. Deocamdata.

Weekend placut !
Nota: Toate exemplele comentate in limba romana sunt sub licenta libera Creative Common Non Comercial. Au fost stranse intr-un volum in limba spaniola de Jorge García.