//---------------------------------------------------------------------
// Ukazkovy priklad cislo 64
// Autor: Pavel Tisnovsky
//
// Program pro zobrazeni telesa s nanesenou 2D texturou. Textura je
// vytvorena jako mipmapa se zakladnim rozlisenim 64x64 texelu. Pri
// vykreslovani zmenseneho telesa se pouzije vyber nejblizsi velikosti
// textury v mipmape a z teto se vypocte vysledna barva linearni interpolaci.
// Pri zvetsovani vykresleneho telesa se taktez pouzije linearni interpolace
// barev nejblizsich texelu.
// Proto jsou pouzity filtry:
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
// Pomoci leveho tlacitka mysi lze telesem otacet, prave tlacitko
// slouzi k priblizeni nebo vzdaleni telesa od kamery.
//---------------------------------------------------------------------
#include <GL/glut.h> // hlavickovy soubor funkci GLUTu a OpenGL
#define TEXTURE_WIDTH 64 // sirka textury zadana v texelech
#define TEXTURE_HEIGHT 64 // vyska textury zadana v texelech
enum { // operace, ktere se mohou provadet s mysi:
ROTATE, // rotace objektu
TRANSLATE, // posun objektu
} operation=ROTATE;
int xnew=0, ynew=0, znew=30; // soucasna pozice mysi, ze ktere se pocitaji rotace a posuvy
int xold=0, yold=0, 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
unsigned char texture0[TEXTURE_HEIGHT][TEXTURE_WIDTH][3]; // pole pro RGB texturu v plnem rozliseni
unsigned char texture1[TEXTURE_HEIGHT >>1][TEXTURE_WIDTH >>1][3]; // pole pro RGB texturu na prvni urovni v mipmape
unsigned char texture2[TEXTURE_HEIGHT >>2][TEXTURE_WIDTH >>2][3]; // pole pro RGB texturu na druhe urovni v mipmape
unsigned char texture3[TEXTURE_HEIGHT >>3][TEXTURE_WIDTH >>3][3]; // pole pro RGB texturu na treti urovni v mipmape
unsigned char texture4[TEXTURE_HEIGHT >>4][TEXTURE_WIDTH >>4][3]; // pole pro RGB texturu na ctvrte urovni v mipmape
unsigned char texture5[TEXTURE_HEIGHT >>5][TEXTURE_WIDTH >>5][3]; // pole pro RGB texturu na pate urovni v mipmape
unsigned char texture6[TEXTURE_HEIGHT >>6][TEXTURE_WIDTH >>6][3]; // pole pro RGB texturu na seste urovni v mipmape
GLuint textureName; // jmeno textury
//---------------------------------------------------------------------
// Vytvoreni rastroveho vzorku pro textury v mipmape
//---------------------------------------------------------------------
void makeRasterTexture(void)
{
int i,j,c; // pocitadla smycek
unsigned char * P; // ukazatel na zapisovany subtexel
// textura na urovni 0 v mipmape
for (j=0; j<TEXTURE_HEIGHT; j++) { // pro vsechny radky pixmapy
P=texture0[j][0]; // prvni pixel na radku j
for (i=0; i<TEXTURE_WIDTH; i++) { // pro vsechny pixely na radku pixmapy
c=((((i&0x10)==0)^((j&0x10))==0)) * 255;
*P++=(unsigned char)c; // cernobila sachovnice
*P++=(unsigned char)c;
*P++=(unsigned char)c;
}
}
// textura na urovni 1 v mipmape
for (j=0; j<TEXTURE_HEIGHT >> 1; j++) { // pro vsechny radky pixmapy
P=texture1[j][0]; // prvni pixel na radku j
for (i=0; i<TEXTURE_WIDTH >> 1; i++) { // pro vsechny pixely na radku pixmapy
c=((((i&0x08)==0)^((j&0x08))==0)) * 255;
*P++=(unsigned char)c;
*P++=(unsigned char)c;
*P++=(unsigned char)0; // jednu barvu vynechame
}
}
// textura na urovni 2 v mipmape
for (j=0; j<TEXTURE_HEIGHT >> 2; j++) { // pro vsechny radky pixmapy
P=texture2[j][0]; // prvni pixel na radku j
for (i=0; i<TEXTURE_WIDTH >> 2; i++) { // pro vsechny pixely na radku pixmapy
c=((((i&0x04)==0)^((j&0x04))==0)) * 255;
*P++=(unsigned char)c;
*P++=(unsigned char)0; // opet jednu barvu vynechame
*P++=(unsigned char)c;
}
}
// textura na urovni 3 v mipmape
for (j=0; j<TEXTURE_HEIGHT >> 3; j++) { // pro vsechny radky pixmapy
P=texture3[j][0]; // prvni pixel na radku j
for (i=0; i<TEXTURE_WIDTH >> 3; i++) { // pro vsechny pixely na radku pixmapy
c=((((i&0x02)==0)^((j&0x02))==0)) * 255;
*P++=(unsigned char)0;
*P++=(unsigned char)c;
*P++=(unsigned char)c;
}
}
// textura na urovni 4 v mipmape
for (j=0; j<TEXTURE_HEIGHT >> 4; j++) { // pro vsechny radky pixmapy
P=texture4[j][0]; // prvni pixel na radku j
for (i=0; i<TEXTURE_WIDTH >> 4; i++) { // pro vsechny pixely na radku pixmapy
*P++=(unsigned char)c;
*P++=(unsigned char)c;
*P++=(unsigned char)c;
}
}
// textura na urovni 5 v mipmape
for (j=0; j<TEXTURE_HEIGHT >> 5; j++) { // pro vsechny radky pixmapy
P=texture5[j][0]; // prvni pixel na radku j
for (i=0; i<TEXTURE_WIDTH >> 5; i++) { // pro vsechny pixely na radku pixmapy
*P++=(unsigned char)c;
*P++=(unsigned char)0; // opet jednu barvu vynechame
*P++=(unsigned char)c;
}
}
// textura na urovni 6 v mipmape
texture6[0][0][0]=(unsigned char)0; // posledni textura v mipmape
texture6[0][0][1]=(unsigned char)c; // obsahuje pouze jeden texel
texture6[0][0][2]=(unsigned char)0;
}
//---------------------------------------------------------------------
// Nastaveni parametru textur
//---------------------------------------------------------------------
void setTextures(void)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // zpusob ulozeni bytu v texture
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
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_MIPMAP_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, texture0);
glTexImage2D(GL_TEXTURE_2D, 1, 3, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, texture1);
glTexImage2D(GL_TEXTURE_2D, 2, 3, 16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, texture2);
glTexImage2D(GL_TEXTURE_2D, 3, 3, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, texture3);
glTexImage2D(GL_TEXTURE_2D, 4, 3, 4, 4, 0, GL_RGB, GL_UNSIGNED_BYTE, texture4);
glTexImage2D(GL_TEXTURE_2D, 5, 3, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, texture5);
glTexImage2D(GL_TEXTURE_2D, 6, 3, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, texture6);
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); // vylepseni zobrazovani
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // zpusob vykresleni textury
glEnable(GL_TEXTURE_2D); // povoleni texturovani
}
//---------------------------------------------------------------------
// Funkce pro inicializaci vykreslovani
//---------------------------------------------------------------------
void onInit(void)
{
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); // 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
setTextures(); // vytvoreni textur a nastaveni parametru
}
//---------------------------------------------------------------------
// 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;
}
//---------------------------------------------------------------------
// Nastaveni perspektivni projekce
//---------------------------------------------------------------------
void setPerspectiveProjection(void)
{
glMatrixMode(GL_PROJECTION); // zacatek modifikace projekcni matice
glLoadIdentity(); // vymazani projekcni matice (=identita)
gluPerspective(60.0, (double)windowWidth/(double)windowHeight, 2.0f, 190.0f);// nastaveni perspektivni kamery
glMatrixMode(GL_MODELVIEW); // bude se menit modelova matice
glLoadIdentity(); // nahrat jednotkovou matici
}
//--------------------------------------------------------------------
// Vykresleni objektu
//--------------------------------------------------------------------
void drawObject(void)
{
glBegin(GL_QUADS); // vykresleni otevrene krychle - sten domecku
glTexCoord2f(0.0f, 0.0f); glVertex3f(-5.0f, -5.0f, -5.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-5.0f, -5.0f, 5.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 5.0f, -5.0f, 5.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 5.0f, -5.0f, -5.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-5.0f, 5.0f, -5.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-5.0f, 5.0f, 5.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 5.0f, 5.0f, 5.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 5.0f, 5.0f, -5.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-5.0f, -5.0f, -5.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-5.0f, -5.0f, 5.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-5.0f, 5.0f, 5.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-5.0f, 5.0f, -5.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 5.0f, -5.0f, -5.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 5.0f, -5.0f, 5.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 5.0f, 5.0f, 5.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 5.0f, 5.0f, -5.0f);
glEnd();
glBegin(GL_TRIANGLES); // vykresleni strechy domecku z trojuhelniku
glTexCoord2f(0.0, 0.0); glVertex3f(-5.0f, 5.0f, -5.0f);
glTexCoord2f(0.0, 1.0); glVertex3f( 5.0f, 5.0f, -5.0f);
glTexCoord2f(0.5, 0.8); glVertex3f( 0.0f, 11.0f, 0.0f);
glTexCoord2f(0.0, 0.0); glVertex3f( 5.0f, 5.0f, -5.0f);
glTexCoord2f(0.0, 1.0); glVertex3f( 5.0f, 5.0f, 5.0f);
glTexCoord2f(0.5, 0.8); glVertex3f( 0.0f, 11.0f, 0.0f);
glTexCoord2f(0.0, 0.0); glVertex3f( 5.0f, 5.0f, 5.0f);
glTexCoord2f(0.0, 1.0); glVertex3f(-5.0f, 5.0f, 5.0f);
glTexCoord2f(0.5, 0.8); glVertex3f( 0.0f, 11.0f, 0.0f);
glTexCoord2f(0.0, 0.0); glVertex3f(-5.0f, 5.0f, 5.0f);
glTexCoord2f(0.0, 1.0); glVertex3f(-5.0f, 5.0f, -5.0f);
glTexCoord2f(0.5, 0.8); glVertex3f( 0.0f, 11.0f, 0.0f);
glEnd();
}
//--------------------------------------------------------------------
// Tato funkce je volana pri kazdem prekresleni okna
//--------------------------------------------------------------------
void onDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// vymazani barvoveho bufferu i pameti hloubky
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);
glBindTexture(GL_TEXTURE_2D, textureName); // navazani textury na vykreslovany objekt
drawObject(); // vykresleni objektu
glFlush(); // provedeni a vykresleni vsech zmen
glutSwapBuffers(); // a prohozeni predniho a zadniho bufferu
}
//---------------------------------------------------------------------
// Tato funkce je volana pri stlaceni ASCII klavesy
//---------------------------------------------------------------------
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
default: break;
}
}
//---------------------------------------------------------------------
// 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);// nastaveni dvou barvovych bufferu a pameti hloubky
glutInitWindowPosition(30, 30); // pocatecni pozice leveho horniho rohu okna
glutInitWindowSize(500, 500); // pocatecni velikost okna
glutCreateWindow("Priklad na OpenGL cislo 64");// 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
//---------------------------------------------------------------------