//---------------------------------------------------------------------
// Ukazkovy priklad k serii clanku OpenGL evaluatorech
//
// Autor: Pavel Tisnovsky
// Cislo clanku: 9
// Cislo prikladu: 1
//
// Po spusteni tohoto demonstracniho prikladu se vykresli Bezierova
// bikubicka plocha, ktera je vypoctena s pouzitim evaluatoru.
// Vypocet probiha ve funkci drawBezierSurfaceUsingEvaluators().
// Bezierova plocha se zobrazi pomoci plosek vykreslovanych primitivou
// GL_QUADS.
// Pro kazdou plosku se automaticky vypocita jeji normalovy vektor,
// ktery je pouzit pri vypoctu osvetleni pomoci Phongova osvetlovaciho
// modelu.
// Pohled na Bezierovu plochu je animovany, animaci lze spustit a
// zastavit pomoci klavesy S. Pomoci klavesy A lze zapnout ci vypnout
// automaticke generovani normalovych vektoru.
// Klavesou ESC je mozne program ukoncit, klavesa F prepina zobrazeni
// na celou obrazovku, klavesou W se zobrazeni prepne zpet do okna.
//---------------------------------------------------------------------
#ifdef __BORLANDC__
#include <windows.h> // oprava chyby v nekterych Borlandskych prekladacich
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h> // hlavickovy soubor funkci GLUTu a OpenGL
#ifdef __BORLANDC__
#pragma hdrstop // konec predkompilovanych hlavicek pro Borlandske prekladace
#endif
#define WINDOW_WIDTH 450 // velikost okna
#define WINDOW_HEIGHT 450
#define WINDOW_LEFT 30 // pozice leveho horniho rohu okna na desktopu
#define WINDOW_TOP 30
#define WINDOW_TITLE "OpenGL evaluatory, priklad cislo 9.1" // titulek okna
#define TEXTURE_WIDTH 64 // sirka textury zadana v texelech
#define TEXTURE_HEIGHT 64 // vyska textury zadana v texelech
typedef struct { // novy datovy typ zapouzdrujici velikost okna
unsigned int width;
unsigned int height;
} Window;
Window window;
GLfloat ctrlPoints[4][4][3] = { // ridici body Bezierovy plochy v 3D prostoru
{ {-2.5,-1.5, 4.0}, {-0.5,-1.5, 2.0}, {0.5,-1.5,-1.0}, { 2.5,-1.5, 2.0} },
{ {-2.5,-0.5, 1.0}, {-0.5,-0.5, 3.0}, {0.5,-0.5, 0.0}, { 2.5,-0.5,-1.0} },
{ {-2.5, 0.5, 4.0}, {-0.5, 0.5, 0.0}, {0.5, 0.5, 3.0}, { 2.5, 0.5, 4.0} },
{ {-2.5, 1.5,-2.0}, {-0.5, 1.5,-2.0}, {0.5, 1.5, 0.0}, { 2.5, 1.5,-1.0} }
};
static float angle1=0; // uhel natoceni modelu
static float angle2=0; // ve vsech trech osach
static float angle3=0;
static int animation=1; // priznak ridici animaci
static int autonormal=1; // priznak ridici generovani normalovych vektoru
// parametry, ktere ovlivnuji osvetleni
GLfloat materialAmbient[]={0.4f, 0.4f, 0.4f, 1.0f}; // ambientni slozka barvy materialu
GLfloat materialDiffuse[]={0.8f, 0.4f, 0.4f, 1.0f}; // difuzni slozka barvy materialu
GLfloat materialSpecular[]={1.0f, 1.0f, 1.0f, 1.0f};// barva odlesku
GLfloat materialShininess[]={50.0f}; // faktor odlesku
GLfloat light_position[]={1.0f, 1.0f, 1.0f, 0.0f}; // pozice svetla
//---------------------------------------------------------------------
// Tato funkce vykresli Bezierovu plochu pomoci evaluatoru
//---------------------------------------------------------------------
void drawBezierSurfaceUsingEvaluators(
GLfloat ctrlPoints[][4][3])
{
#define DELENI 20
int i,j;
glEnable(GL_MAP2_VERTEX_3); // povoleni 2D evaluatoru
if (autonormal)
glEnable(GL_AUTO_NORMAL); // automaticky vypocet normalovych vektoru
else
glDisable(GL_AUTO_NORMAL);
// predani ridicich bodu Bezierovy plochy
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4,
0, 1,12, 4, &ctrlPoints[0][0][0]);
// vykresleni Bezierovy plochy
glMapGrid2f(DELENI, 0.0f, 1.0f, DELENI, 0.0f, 1.0f);
glEvalMesh2(GL_FILL, 0, DELENI, 0, DELENI);
// zakaz aplikace obou typu evaluatoru
glDisable(GL_MAP2_VERTEX_3);
}
//---------------------------------------------------------------------
// Funkce pro inicializaci vykreslovani
//---------------------------------------------------------------------
void onInit(void)
{
// nastaveni vlastnosti framebufferu
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // barva pozadi obrazku
glClearDepth(1.0f); // implicitni hloubka ulozena v pameti hloubky
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS); // povoleni a nastaveni testu hloubky fragmentu
// styl vykreslovani
glPointSize(2.0f); // velikost vykreslovanych ridicich bodu
glLineWidth(2.0f); // sirka vykreslovanych car
glEnable(GL_POINT_SMOOTH); // povoleni antialiasingu bodu
glEnable(GL_LINE_SMOOTH); // povoleni antialiasingu car
glShadeModel(GL_SMOOTH); // nastaveni Gouraudova stinovani
// prace s materialy
glPolygonMode(GL_FRONT, GL_FILL); // nastaveni rezimu vykresleni modelu
glPolygonMode(GL_BACK, GL_FILL); // jak pro predni tak pro zadni steny
glDisable(GL_CULL_FACE); // zadne hrany ani steny se nebudou odstranovat
glMaterialfv(GL_FRONT, GL_AMBIENT, materialAmbient); // nastaveni ambientni slozky barvy materialu
glMaterialfv(GL_FRONT, GL_DIFFUSE, materialDiffuse); // nastaveni difuzni slozky barvy materialu
glMaterialfv(GL_FRONT, GL_SPECULAR, materialSpecular); // nastaveni barvy odlesku
glMaterialfv(GL_FRONT, GL_SHININESS, materialShininess);// nastaveni faktoru odlesku
glLightfv(GL_LIGHT0, GL_POSITION, light_position); // nasstaveni pozice svetla
glEnable(GL_LIGHTING); // globalni povoleni stinovani
glEnable(GL_LIGHT0); // povoleni prvniho svetla
}
//---------------------------------------------------------------------
// Nastaveni souradneho systemu v zavislosti na velikosti okna
//---------------------------------------------------------------------
void onResize(int w, int h) // argumenty w a h reprezentuji novou velikost okna
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h); // viditelna oblast pres cele okno
glMatrixMode(GL_PROJECTION); // zacatek modifikace projekcni matice
glLoadIdentity(); // vymazani projekcni matice (=identita)
if (w<=h) { // jestlize je okno nastaveno na vysku
glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0);
}
else { // jestlize je okno nastaveno na sirku
glOrtho(-5.0*(GLfloat)w/(GLfloat)h,5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0);
}
window.width=w; // zapamatovat si velikost okna
window.height=h;
glMatrixMode(GL_MODELVIEW); // zacatek modifikace modelove matice
glLoadIdentity(); // vymazani modelove matice (=identita)
}
//--------------------------------------------------------------------
// Tato funkce je volana pri kazdem prekresleni okna
//--------------------------------------------------------------------
void onDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// smazani barvoveho a Z-bufferu
glMatrixMode(GL_MODELVIEW); // bude se menit modelova matice
glLoadIdentity(); // vymazat predchozi transformace
glRotatef(angle1, 0.0, 0.0, 1.0); // rotace modelu kolem z-ove osy
glRotatef(angle2, 0.0, 1.0, 0.0); // rotace modelu kolem y-ove osy
glRotatef(angle3, 1.0, 0.0, 0.0); // rotace modelu kolem x-ove osy
drawBezierSurfaceUsingEvaluators(ctrlPoints); // vykresleni Bezierovy plochy pomoci evaluatoru
glFlush(); // provedeni a vykresleni vsech zmen
glutSwapBuffers(); // a prohozeni predniho a zadniho bufferu
}
//---------------------------------------------------------------------
// Tato funkce je volana pri volnem casovem slotu
//---------------------------------------------------------------------
void onIdle(void)
{
if (animation) {
angle1++; // zmena uhlu rotace okolo z-ove osy
angle2+=1.6f; // zmena uhlu rotace okolo y-ove osy
angle3+=2.1f; // zmena uhlu rotace okolo x-ove osy
glutPostRedisplay(); // prekresleni sceny
}
}
//---------------------------------------------------------------------
// Tato funkce je volana pri stlaceni ASCII klavesy
//---------------------------------------------------------------------
#ifdef __BORLANDC__
#pragma option -w-par // aby Borlandi prekladace nehlasily
#endif // warningy ze argumenty nejsou pouzity
void onKeyboard(unsigned char key, int x, int y)
{
if (key>='A' && key<='Z') // uprava velkych pismen na mala
key+='a'-'A'; // pro zjednoduseni prikazu switch
switch (key) {
case 27: exit(0); break; // ukonceni aplikace
case 'q': exit(0); break; // ukonceni aplikace
case 'f': glutFullScreen(); break; // full screen
case 'w': glutReshapeWindow(WINDOW_WIDTH, WINDOW_HEIGHT);// prepnuti zpet do okna
glutPositionWindow(WINDOW_LEFT, WINDOW_TOP);
break;
case 's': animation=!animation; break; // zapnuti/vypnuti animace
case 'a': autonormal=!autonormal; break; // zapnuti/vypnuti generovani normalovych vektoru
default: break;
}
}
#ifdef __BORLANDC__
#pragma option -w+par
#endif
//---------------------------------------------------------------------
// Hlavni funkce konzolove aplikace
//---------------------------------------------------------------------
int main(int argc, char **argv)
{
glutInit(&argc, argv); // inicializace knihovny GLUT
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); // nastaveni dvou barvovych bufferu a pameti hloubky
glutInitWindowPosition(WINDOW_LEFT, WINDOW_TOP);// pocatecni pozice leveho horniho rohu okna
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);// pocatecni velikost okna
glutCreateWindow(WINDOW_TITLE); // vytvoreni okna pro kresleni
glutDisplayFunc(onDisplay); // registrace funkce volane pri prekreslovani okna
glutReshapeFunc(onResize); // registrace funkce volane pri zmene velikosti okna
glutKeyboardFunc(onKeyboard); // registrace funkce volane pri stlaceni klavesy
glutIdleFunc(onIdle); // registrace funkce volane pri volnem casovem slotu
onInit(); // inicializace vykreslovani
glutMainLoop(); // nekonecna smycka, kde se volaji zaregistrovane funkce
return 0; // navratova hodnota vracena operacnimu systemu
}
//---------------------------------------------------------------------
// Konec zdrojoveho souboru
//---------------------------------------------------------------------