//---------------------------------------------------------------------
// Ukazkovy priklad cislo 80
// Autor: Pavel Tisnovsky
//
// Po spusteni tohoto demonstracniho programu se zobrazi cajova konvicka,
// na jejimz povrchu je nanesena jednoducha 2D textura, stejne jako u
// demonstracnich prikladu 78 a 79. Pomoci klavesy [S] se da zapinat a
// vypinat test na Scissor Box, stejne jako u prikladu 79. Pomoci klavesy
// [T] se da zapinat a vypinat Scissor Test. Pri zapnutem Scissor Testu
// prosvita pod konvickou jiny obrazek - modra koule.
// Pomoci leveho tlacitka mysi lze telesem otacet, prave tlacitko
// slouzi k priblizeni nebo vzdaleni telesa od kamery.
//---------------------------------------------------------------------
#ifdef __BORLANDC__
#include <windows.h>
#endif
#include <GL/glut.h> // hlavickovy soubor funkci GLUTu a OpenGL
#define WINDOW_WIDTH 450 // velikost okna
#define WINDOW_HEIGHT 450
#define WINDOW_TITLE "Priklad na OpenGL cislo 80"// titulek okna
#define TEXTURE_WIDTH 64 // rozmery textury
#define TEXTURE_HEIGHT 64
#define GRAY_MATERIAL 1 // symbolicka jmena pouzitych materialu
#define BLUE_MATERIAL 2
enum { // operace, ktere se mohou provadet s mysi:
ROTATE, // rotace objektu
TRANSLATE, // posun objektu
} operation=ROTATE;
int xnew=30, ynew=30, znew=30; // soucasna pozice mysi, ze ktere se pocitaji rotace a posuvy
int xold=30, yold=30, zold=30; // minula pozice mysi, ze ktere se pocitaji rotace a posuvy
int xx, yy, zz; // bod, ve kterem se nachazi kurzor mysi
int windowWidth; // sirka okna
int windowHeight; // vyska okna
int scissorTest=0; // priznak provadeni scissor testu
int stencilTest=1; // priznak provadeni stencil testu
unsigned char texture[TEXTURE_HEIGHT][TEXTURE_WIDTH][4];// pole pro ulozeni pixmapy textury
// parametry sedeho materialu konvicky
GLfloat grayMaterialAmbient[]={0.3f, 0.3f, 0.3f, 1.0f}; // ambientni slozka barvy materialu
GLfloat grayMaterialDiffuse[]={0.8f, 0.4f, 0.4f, 1.0f}; // difuzni slozka barvy materialu
GLfloat grayMaterialSpecular[]={1.0f, 1.0f, 1.0f, 1.0f};// barva odlesku
GLfloat grayMaterialShininess[]={30.0f}; // faktor odlesku
// parametry modreho materialu koule
GLfloat blueMaterialAmbient[]={0.1f, 0.1f, 0.1f, 1.0f}; // ambientni slozka barvy materialu
GLfloat blueMaterialDiffuse[]={0.1f, 0.1f, 0.7f, 1.0f}; // difuzni slozka barvy materialu
GLfloat blueMaterialSpecular[]={0.2f, 1.0f, 1.0f, 1.0f};// barva odlesku
GLfloat blueMaterialShininess[]={30.0f}; // faktor odlesku
// parametry svetel
GLfloat lightPosition[]={1.0f, 1.0f, 1.0f, 0.0f}; // pozice svetla
GLfloat lightAmbient[]={1.0f, 1.0f, 1.0f, 1.0f}; // ambientni slozka svetla
//---------------------------------------------------------------------
// Vytvoreni rastroveho vzorku pro texturu
//---------------------------------------------------------------------
void makeRasterTexture(void)
{
int i,j,c; // pocitadla smycek
unsigned char * P; // ukazatel na zapisovany subtexel
for (j=0; j<TEXTURE_HEIGHT; j++) { // pro vsechny radky pixmapy
P=texture[j][0];
for (i=0; i<TEXTURE_WIDTH; i++) { // pro vsechny texely na radku
c=((((i&0x20)==0)^((j&0x20))==0)) * 255;
*P++=(unsigned char)c; // zapsat barevne slozky RGB
*P++=(unsigned char)c;
*P++=(unsigned char)c;
*P++=(unsigned char)255; // alfa slozka texelu
}
}
}
//---------------------------------------------------------------------
// Nastaveni parametru textury
//---------------------------------------------------------------------
void setTextureParameters(void)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // zpusob ulozeni bytu v texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // opakovani textury
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // volba filtru
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // pri zmene meritka
glTexImage2D(GL_TEXTURE_2D, 0, 4, // nahrani rastrovych dat do textury
TEXTURE_WIDTH, TEXTURE_HEIGHT,
0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);// nastaveni rezimu textury
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);// korektni mapovani textur
glEnable(GL_TEXTURE_2D); // povoleni texturovani
}
//---------------------------------------------------------------------
// Nastaveni parametru svetla
//---------------------------------------------------------------------
void setLightParameters(void)
{
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);// nastaveni pozice svetla
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
glEnable(GL_LIGHTING); // globalni povoleni stinovani
glEnable(GL_LIGHT0); // povoleni prvniho svetla
}
//---------------------------------------------------------------------
// Nastaveni parametru materialu telesa
//---------------------------------------------------------------------
void setMaterialParameters(void)
{
glNewList(GRAY_MATERIAL, GL_COMPILE); // prvni material
glMaterialfv(GL_FRONT, GL_AMBIENT, grayMaterialAmbient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, grayMaterialDiffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, grayMaterialSpecular);
glMaterialfv(GL_FRONT, GL_SHININESS, grayMaterialShininess);
glEndList();
glNewList(BLUE_MATERIAL, GL_COMPILE); // druhy material
glMaterialfv(GL_FRONT, GL_AMBIENT, blueMaterialAmbient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, blueMaterialDiffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, blueMaterialSpecular);
glMaterialfv(GL_FRONT, GL_SHININESS, blueMaterialShininess);
glEndList();
}
//---------------------------------------------------------------------
// Funkce pro inicializaci vykreslovani
//---------------------------------------------------------------------
void onInit(void)
{
glClearColor(0.5f, 0.5f, 0.5f, 0.0f); // barva pozadi obrazku
glClearDepth(1.0f); // implicitni hloubka ulozena v pameti hloubky
glEnable(GL_DEPTH_TEST); // povoleni funkce pro testovani hodnot v pameti hloubky
glDepthFunc(GL_LESS); // funkce pro testovani fragmentu
glShadeModel(GL_SMOOTH); // nastaveni stinovaciho rezimu
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
makeRasterTexture(); // vytvoreni vzorku v texure
setTextureParameters(); // nastaveni parametru textury
setLightParameters(); // nastaveni parametru osvetleni
setMaterialParameters(); // nastaveni parametru materialu telesa
glClearStencil(0x00); // nastaveni mazaci hodnoty stencil bufferu
}
//---------------------------------------------------------------------
// Nastaveni ortogonalni projekce
//---------------------------------------------------------------------
void setOrthogonalProjection(void)
{
glMatrixMode(GL_PROJECTION); // zacatek modifikace projekcni matice
glLoadIdentity(); // vymazani projekcni matice (=identita)
glOrtho(0, windowWidth, 0, windowHeight, -1, 1);
glMatrixMode(GL_MODELVIEW); // bude se menit modelova matice
glLoadIdentity(); // nahrat jednotkovou matici
}
//---------------------------------------------------------------------
// Nastaveni perspektivni projekce
//---------------------------------------------------------------------
void setPerspectiveProjection(void)
{
glMatrixMode(GL_PROJECTION); // zacatek modifikace projekcni matice
glLoadIdentity(); // vymazani projekcni matice (=identita)
gluPerspective(50.0, (double)windowWidth/(double)windowHeight, 0.1f, 90.0f);// nastaveni perspektivni kamery
glMatrixMode(GL_MODELVIEW); // bude se menit modelova matice
glLoadIdentity(); // nahrat jednotkovou matici
}
//---------------------------------------------------------------------
// Vypsani retezce do okna na pozici [x,y]
//---------------------------------------------------------------------
void printString(int x, int y, char *text)
{
glRasterPos2i(x, y); // pozice prvniho znaku retezce
for (; *text; text++) // pruchod retezcem
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, *text);// vykresleni jednoho znaku
}
//---------------------------------------------------------------------
// Vypsani informacniho textu do okna
//---------------------------------------------------------------------
void displayInfoText(void)
{
setOrthogonalProjection(); // nastaveni ortogonalni kamery
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D); // zakaz jakekoli zmeny barvy
glColor3f(1.0, 1.0, 1.0);
printString(10, 24, "Press [S] to enable/disable scissor test");
printString(10, 10, "Press [T] to enable/disable stencil test");
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
}
//---------------------------------------------------------------------
// 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, w, h); // viditelna oblast pres cele okno
windowWidth=w; // zapamatovat si velikost okna
windowHeight=h;
// prekresleni sablony
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w<=h) gluOrtho2D(-3.0, 3.0, -3.0*h/w, 3.0*h/w);
else gluOrtho2D(-3.0*w/h, 3.0*w/h, -3.0, 3.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_STENCIL_BUFFER_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0x01, 0x01); // kreslit do stencil bufferu
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glBegin(GL_QUADS); // vykresleni maskovaci plochy
glVertex2f(-1.5, 0.0);
glVertex2f( 0.0, 1.5);
glVertex2f( 1.5, 0.0);
glVertex2f( 0.0, -1.5);
glEnd();
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // nemenit hodnoty ve stencil bufferu
glFlush();
glutSwapBuffers();
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
}
//--------------------------------------------------------------------
// Tato funkce je volana pri kazdem prekresleni okna
//--------------------------------------------------------------------
void onDisplay(void)
{
if (scissorTest) {
glEnable(GL_SCISSOR_TEST);
if (windowWidth>100 && windowHeight>100)
glScissor(50, 50, windowWidth-100, windowHeight-100);
}
else {
glDisable(GL_SCISSOR_TEST);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// vymazani barvoveho bufferu i pameti hloubky
displayInfoText();
setPerspectiveProjection(); // nastaveni perspektivni kamery
glTranslatef(0.0f, 0.0f, -50.0f); // posun objektu dale od kamery
glTranslatef(0.0f, 0.0f, znew); // priblizeni ci vzdaleni objektu podle pohybu kurzoru mysi
glRotatef(ynew, 1.0f, 0.0f, 0.0f); // rotace objektu podle pohybu kurzoru mysi
glRotatef(xnew, 0.0f, 1.0f, 0.0f);
if (stencilTest)
glEnable(GL_STENCIL_TEST); // povoleni testovani fragmentu vuci stencil bufferu
glStencilFunc(GL_NOTEQUAL, 0x01, 0x01); // zobraz konvicku tam, kde neni stencil roven 1
glCallList(GRAY_MATERIAL); // nastavit modry material
glutSolidTeapot(7.0f); // vykresleni cajove konvicky
glStencilFunc(GL_EQUAL, 0x01, 0x01); // kouli zobraz tam, kde je stencil roven 1
setPerspectiveProjection();
glTranslatef(0.0f, 0.0f, -30.0f); // posun objektu dale od kamery
glDisable(GL_TEXTURE_2D);
glCallList(BLUE_MATERIAL);
glutSolidSphere(7.0f, 64, 64);
glEnable(GL_TEXTURE_2D);
glDisable(GL_STENCIL_TEST);
glFlush(); // provedeni a vykresleni vsech zmen
glutSwapBuffers(); // a prohozeni predniho a zadniho bufferu
}
//---------------------------------------------------------------------
// Tato funkce je volana pri stlaceni ASCII klavesy
//---------------------------------------------------------------------
#ifdef __BORLANDC__
#pragma option -w-par
#endif
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 's': scissorTest=!scissorTest; // povoleni/zakazani scissor testu
glutPostRedisplay();break;
case 't': stencilTest=!stencilTest; // povoleni/zakazani stencil testu
glutPostRedisplay();break;
default: break;
}
}
#ifdef __BORLANDC__
#pragma option -w+par
#endif
//---------------------------------------------------------------------
// Tato funkce je volana pri stisku ci pusteni tlacitka mysi
//---------------------------------------------------------------------
void onMouseButton(int button, int state, int x, int y)
{
if (button==GLUT_LEFT_BUTTON) { // pri zmene stavu leveho tlacitka
operation=ROTATE;
if (state==GLUT_DOWN) { // pri stlaceni tlacitka
xx=x; // zapamatovat pozici kurzoru mysi
yy=y;
}
else { // pri pusteni tlacitka
xold=xnew; // zapamatovat novy pocatek
yold=ynew;
}
glutPostRedisplay(); // prekresleni sceny
}
if (button==GLUT_RIGHT_BUTTON) {
operation=TRANSLATE;
if (state==GLUT_DOWN) zz=y; // pri stlaceni tlacitka zapamatovat polohu kurzoru mysi
else zold=znew; // pri pusteni tlacitka zapamatovat novy pocatek
glutPostRedisplay(); // prekresleni sceny
}
}
//---------------------------------------------------------------------
// Tato funkce je volana pri pohybu mysi se stlacenym tlacitkem.
// To, ktere tlacitko je stlaceno si musime predem zaznamenat do
// globalni promenne stav ve funkci onMouseButton()
//---------------------------------------------------------------------
void onMouseMotion(int x, int y)
{
switch (operation) {
case ROTATE: // stav rotace objektu
xnew=xold+x-xx; // vypocitat novou pozici
ynew=yold+y-yy;
glutPostRedisplay(); // a prekreslit scenu
break;
case TRANSLATE: // stav priblizeni/oddaleni objektu
znew=zold+y-zz; // vypocitat novou pozici
glutPostRedisplay(); // a prekreslit scenu
break;
}
}
//---------------------------------------------------------------------
// Hlavni funkce konzolove aplikace
//---------------------------------------------------------------------
int main(int argc, char **argv)
{
glutInit(&argc, argv); // inicializace knihovny GLUT
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);// nastaveni dvou barvovych bufferu, pameti hloubky a stencil bufferu
glutInitWindowPosition(30, 30); // 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
glutMouseFunc(onMouseButton); // registrace funkce volane pri stlaceni ci pusteni tlacitka
glutMotionFunc(onMouseMotion); // registrace funkce volane pri pohybu mysi se stlacenym tlacitkem
onInit(); // inicializace vykreslovani
glutMainLoop(); // nekonecna smycka, kde se volaji zaregistrovane funkce
return 0; // navratova hodnota vracena operacnimu systemu
}
//---------------------------------------------------------------------
// Konec zdrojoveho souboru
//---------------------------------------------------------------------