//--------------------------------------------------------------------- // Ukazkovy priklad cislo 68 // Autor: Pavel Tisnovsky // // Program pro zobrazeni sceny s otexturocanymi telesy. Textury jsou nejdrive // nacteny z rastrovych souboru typu TGA (Targa) a z techto jsou pote // zobrazovany ve scene. // Ovladani bud mysi: otaceni+tlacitka pohyb vpred (leve) a vzad (prave) // nebo klavesnici: // sipka nahoru, sipka dolu: pohyb vpred/vzad // sipka doprava, sipka doleva: otaceni // CTRL+sipka doprava, doleva: ukroky //--------------------------------------------------------------------- #include <math.h> #include <stdio.h> #include <stdlib.h> #include <gl/glut.h> #ifdef __BORLANDC__ #pragma hdrstop #endif #define MOVE_SCENE_DOWN -5.0 // posun sceny dolu, aby byla videt rovina x-y #define SCENE_SHIFT -11.0 // odsunuti sceny od pozorovatele, aby se provadelo korektne otaceni #define DEFAULT_WINDOW_WIDTH 450 // velikost a pocatecni pozice okna na obrazovce #define DEFAULT_WINDOW_HEIGHT 450 #define DEFAULT_WINDOW_TOP 10 #define DEFAULT_WINDOW_LEFT 10 #define TEXTURE_GROUND 0 // jmena textur pro vyber #define TEXTURE_WALL1 1 #define TEXTURE_WALL2 2 #define TEXTURE_TREASURE 3 int textures[4]; // cisla textur typedef struct Window { // informace o oknu int width; int height; } Window; typedef struct View { // informace o pohledu na scenu float fov; float nearPlane; float farPlane; } View; typedef struct Avatar { // informace o hraci (pozorovateli) float posX; float posY; float angle; float moveSpeed; } Avatar; Window window; View view={45.0, 2.0, 1000.0}; Avatar avatar={0.0, -80.0, 0.0, 0.0}; int btn=0; char mapa[10][10]={ // mapa bludiste {".......###"}, {".#.#### .#"}, {".#.......#"}, {".#...#####"}, {"#*##..#..."}, {"#.#*.....#"}, {"#....#.###"}, {"#.##.#...."}, {".......#.."}, {"########.."}, }; //--------------------------------------------------------------------- // Posun pohledu podle pozice a orientace avatara //--------------------------------------------------------------------- void avatarMoveView(Avatar *avatar) { glTranslatef(0.0, MOVE_SCENE_DOWN, 0.0); // posun sceny dolu, aby byla videt rovina z=0 glRotatef(90.0, 1.0, 0.0, 0.0); // otoceni sceny okolo osy X tak, aby osa Z smerovala nahoru glTranslatef(0.0, SCENE_SHIFT, 0.0); // posun sceny od pozorovatele, aby se provadelo korektne otaceni glRotatef(avatar->angle, 0.0, 0.0, 1.0); // otoceni pozorovatele glTranslatef(avatar->posX, avatar->posY, 0.0); // posun pozorovatele } //--------------------------------------------------------------------- // Kontrola, zda se avatar nachazi uvnitr sceny s pripadnym omezenim pohybu //--------------------------------------------------------------------- void avatarCheckRanges(Avatar *avatar) { if (avatar->posX>90.0) avatar->posX=90.0; if (avatar->posX<-90.0) avatar->posX=-90.0; if (avatar->posY>90.0) avatar->posY=90.0; if (avatar->posY<-90.0) avatar->posY=-90.0; } //--------------------------------------------------------------------- // Posun avatara ve smeru pohybu //--------------------------------------------------------------------- void avatarMove(Avatar *avatar) { avatar->posX+=avatar->moveSpeed*sin(avatar->angle*3.14/180.0); avatar->posY+=avatar->moveSpeed*cos(avatar->angle*3.14/180.0); avatarCheckRanges(avatar); } //--------------------------------------------------------------------- // Posun avatara dopredu (podle jeho orientace) //--------------------------------------------------------------------- void avatarMoveForward(Avatar *avatar) { avatar->posX+=1.0*sin(avatar->angle*3.14/180.0); avatar->posY+=1.0*cos(avatar->angle*3.14/180.0); avatarCheckRanges(avatar); } //--------------------------------------------------------------------- // Posun avatara dozadu (podle jeho orientace) //--------------------------------------------------------------------- void avatarMoveBackward(Avatar *avatar) { avatar->posX-=1.0*sin(avatar->angle*3.14/180.0); avatar->posY-=1.0*cos(avatar->angle*3.14/180.0); avatarCheckRanges(avatar); } //--------------------------------------------------------------------- // Posun avatara doleva (ukrok podle jeho orientace) //--------------------------------------------------------------------- void avatarMoveLeft(Avatar *avatar) { avatar->posX+=1.0*cos(avatar->angle*3.14/180.0); avatar->posY-=1.0*sin(avatar->angle*3.14/180.0); avatarCheckRanges(avatar); } //--------------------------------------------------------------------- // Posun avatara doprava (ukrok podle jeho orientace) //--------------------------------------------------------------------- void avatarMoveRight(Avatar *avatar) { avatar->posX-=1.0*cos(avatar->angle*3.14/180.0); avatar->posY+=1.0*sin(avatar->angle*3.14/180.0); avatarCheckRanges(avatar); } //--------------------------------------------------------------------- // Otoceni avatara smerem doleva //--------------------------------------------------------------------- void avatarTurnLeft(Avatar *avatar) { avatar->angle+=3.0; } //--------------------------------------------------------------------- // Otoceni avatara smerem doprava //--------------------------------------------------------------------- void avatarTurnRight(Avatar *avatar) { avatar->angle-=3.0; } //--------------------------------------------------------------------- // Nacteni bitmapy ze souboru typu TGA //--------------------------------------------------------------------- int bitmapLoadFromTGA(int texture, const char *filename) { FILE *fin; unsigned short int width=0, height=0; // sirka a vyska obrazku unsigned short int palettelength; // delta palety unsigned char bpp=0; // pocet bitu na pixel int size; unsigned char *bitmap; unsigned char tgaHeader[18]; // hlavicka formatu TGA if (!filename) return -1; fin=fopen(filename, "rb"); if (!fin) return -1; // otevreni souboru se nezdarilo if (fread(tgaHeader, 18, 1, fin)!=1) return -1; // nacist hlavicku BMP souboru memcpy(&width, tgaHeader+12, 2); // nacist sirku obrazku v pixelech memcpy(&height, tgaHeader+14, 2); // nacist vysku obrazku v pixelech memcpy(&bpp, tgaHeader+16, 1); // nacist pocet bitu na pixel memcpy(&palettelength, tgaHeader+5, 2); // nacist delku palety glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); switch (bpp) { case 8: size=width*height; bitmap=(unsigned char *)malloc(size*sizeof(unsigned char)); if (fread(bitmap, palettelength, 1, fin)!=1) return -1; if (fread(bitmap, size, 1, fin)!=1) return -1; fclose(fin); glTexImage2D(GL_TEXTURE_2D, 0, 1, width, height,// nacteni textury do GPU 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bitmap); break; case 24: size=width*height*3; bitmap=(unsigned char *)malloc(size*sizeof(unsigned char)); if (fread(bitmap, size, 1, fin)!=1) return -1; fclose(fin); glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height,// nacteni textury do GPU 0, GL_RGB, GL_UNSIGNED_BYTE, bitmap); break; case 32: size=width*height*4; bitmap=(unsigned char *)malloc(size*sizeof(unsigned char)); if (fread(bitmap, size, 1, fin)!=1) return -1; fclose(fin); glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height,// nacteni textury do GPU 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap); break; default: break; } free(bitmap); return 0; } //--------------------------------------------------------------------- // Nacteni a vytvoreni vsech textur //--------------------------------------------------------------------- int loadTextures(void) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // zpusob ulozeni bytu v texure glGenTextures(4, textures); // vytvoreni jmena textur if (bitmapLoadFromTGA(textures[TEXTURE_GROUND], "ground.tga")) exit(0); if (bitmapLoadFromTGA(textures[TEXTURE_WALL1], "wall1.tga")) exit(0); if (bitmapLoadFromTGA(textures[TEXTURE_WALL2], "wall2.tga")) exit(0); if (bitmapLoadFromTGA(textures[TEXTURE_TREASURE], "treasure.tga")) exit(0); } //--------------------------------------------------------------------- // Callback funkce zavolana pri inicializaci aplikace //--------------------------------------------------------------------- void onInit(void) { glClearColor(0.2, 0.2, 0.4, 0.0); // barva pro mazani color-bufferu glShadeModel(GL_SMOOTH); // nastaveni stinovaciho rezimu loadTextures(); // nacist vsechny textury glClearDepth(1.0f); // barva pro mazani z-bufferu glEnable(GL_DEPTH_TEST); // nastaveni funkce pro testovani hodnot v z-bufferu glDepthFunc(GL_LESS); // kterou funkci vybrat pro testovani z-bufferu glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);// vylepseni zobrazovani textur glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); // nastaveni vykresleni vyplnenych polygonu glPointSize(10.0); // nastaveni velikosti vykreslovanych bodu glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); glutSetCursor(GLUT_CURSOR_NONE); } //--------------------------------------------------------------------- // Callback funkce zavolana pri zmene velikosti okna aplikace //--------------------------------------------------------------------- void onResize(int width, int height) { glViewport(0, 0, width, height); // viditelna oblast window.width=width; window.height=height; } //--------------------------------------------------------------------- // Callback funkce zavolana pri zmene prekreslovani okna //--------------------------------------------------------------------- void onDisplay(void) { int i, j, k; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// vymazani barvoveho a z-bufferu // Nastaveni ModelView matice tak, aby se pozorovatel prochazel // scenou ve stylu dungeonu glMatrixMode(GL_PROJECTION); // projekcni matice glLoadIdentity(); gluPerspective(view.fov,(double)window.width/(double)window.height, view.nearPlane, view.farPlane); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); avatarMoveView(&avatar); // nakresleni texturovane podlahy glEnable(GL_TEXTURE_2D); // povoleni texturovani glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE); glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_GROUND]); // navazani textury glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(-100, -100, 1); glTexCoord2f(4.0, 0.0); glVertex3f(+100, -100, 1); glTexCoord2f(4.0, 4.0); glVertex3f(+100, +100, 1); glTexCoord2f(0.0, 4.0); glVertex3f(-100, +100, 1); glEnd(); // nakresleni obvodovych zdi glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_WALL1]); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(-100, 100, 1); glTexCoord2f(9.0, 0.0); glVertex3f( 100, 100, 1); glTexCoord2f(9.0, 1.0); glVertex3f( 100, 100, -10); glTexCoord2f(0.0, 1.0); glVertex3f(-100, 100, -10); glTexCoord2f(0.0, 0.0); glVertex3f(-100, 100, 1); glTexCoord2f(9.0, 0.0); glVertex3f(-100, -100, 1); glTexCoord2f(9.0, 1.0); glVertex3f(-100, -100, -10); glTexCoord2f(0.0, 1.0); glVertex3f(-100, 100, -10); glTexCoord2f(0.0, 0.0); glVertex3f(-100, -100, 1); glTexCoord2f(9.0, 0.0); glVertex3f( 100, -100, 1); glTexCoord2f(9.0, 1.0); glVertex3f( 100, -100, -10); glTexCoord2f(0.0, 1.0); glVertex3f(-100, -100, -10); glTexCoord2f(0.0, 0.0); glVertex3f( 100, 100, 1); glTexCoord2f(9.0, 0.0); glVertex3f( 100, -100, 1); glTexCoord2f(9.0, 1.0); glVertex3f( 100, -100, -10); glTexCoord2f(0.0, 1.0); glVertex3f( 100, 100, -10); glEnd(); // nakresleni vnitrnich zdi a pokladu for (j=0; j<10; j++) { for (i=0; i<10; i++) { if (mapa[i][j]!='.') { // vykreslit zed nebo poklad if (mapa[i][j]=='#') glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_WALL2]); else glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_TREASURE]); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f( -90+i*20, -90+j*20, 1); glTexCoord2f(1.0, 0.0); glVertex3f( -80+i*20, -90+j*20, 1); glTexCoord2f(1.0, 1.0); glVertex3f( -80+i*20, -90+j*20, -10); glTexCoord2f(0.0, 1.0); glVertex3f( -90+i*20, -90+j*20, -10); glTexCoord2f(0.0, 0.0); glVertex3f( -90+i*20, -80+j*20, 1); glTexCoord2f(1.0, 0.0); glVertex3f( -80+i*20, -80+j*20, 1); glTexCoord2f(1.0, 1.0); glVertex3f( -80+i*20, -80+j*20, -10); glTexCoord2f(0.0, 1.0); glVertex3f( -90+i*20, -80+j*20, -10); glTexCoord2f(0.0, 0.0); glVertex3f( -80+i*20, -90+j*20, 1); glTexCoord2f(1.0, 0.0); glVertex3f( -80+i*20, -80+j*20, 1); glTexCoord2f(1.0, 1.0); glVertex3f( -80+i*20, -80+j*20, -10); glTexCoord2f(0.0, 1.0); glVertex3f( -80+i*20, -90+j*20, -10); glTexCoord2f(0.0, 0.0); glVertex3f( -90+i*20, -90+j*20, 1); glTexCoord2f(1.0, 0.0); glVertex3f( -90+i*20, -80+j*20, 1); glTexCoord2f(1.0, 1.0); glVertex3f( -90+i*20, -80+j*20, -10); glTexCoord2f(0.0, 1.0); glVertex3f( -90+i*20, -90+j*20, -10); glEnd(); } } } glDisable(GL_TEXTURE_2D); glFlush(); // provedeni vsech prikazu glutSwapBuffers(); // a prohozeni bufferu } //--------------------------------------------------------------------- // Callback funkce zavolana pri stlaceni ASCII klavesy //--------------------------------------------------------------------- void onKeyPress(unsigned char key, int x, int y) { if (key>='A' && key<='Z') // uprava velkych pismen na mala key+='a'-'A'; switch (key) { // rozeskok podle stlacene klavesy case 27: // klavesa Escape case 'q': case 'x': exit(0); // ukonceni programu break; case 'f': glutFullScreen(); // prepnuti na celou obrazovku break; case 'w': // prepnuti do okna glutReshapeWindow(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT); glutPositionWindow(DEFAULT_WINDOW_LEFT, DEFAULT_WINDOW_TOP); break; default: break; } glutPostRedisplay(); } //--------------------------------------------------------------------- // Callback funkce zavolana pri stlaceni non-ASCII klavesy //--------------------------------------------------------------------- void onKeyDown(int key, int x, int y) { int modifiers=glutGetModifiers(); // ziskat stav klaves ALT, CTRL a SHIFT switch (key) { case GLUT_KEY_UP: avatarMoveForward(&avatar); break; case GLUT_KEY_DOWN: avatarMoveBackward(&avatar); break; case GLUT_KEY_LEFT: if (modifiers & GLUT_ACTIVE_CTRL) // CTRL+sipka je ukrok avatarMoveLeft(&avatar); else avatarTurnLeft(&avatar); break; case GLUT_KEY_RIGHT: if (modifiers & GLUT_ACTIVE_CTRL) // CTRL+sipka je ukrok avatarMoveRight(&avatar); else avatarTurnRight(&avatar); break; default: break; } glutPostRedisplay(); } //--------------------------------------------------------------------- // Callback funkce zavolana pri stlaceni nebo pusteni tlacitka mysi //--------------------------------------------------------------------- void onMouseButton(int button, int state, int x, int y) { if (button==GLUT_LEFT_BUTTON) { if (state==GLUT_DOWN) { btn=1; // zrychleni dopredu } else { btn=0; } } if (button==GLUT_RIGHT_BUTTON) { if (state==GLUT_DOWN) { btn=2; // zrychleni dozadu } else { btn=0; } } } //--------------------------------------------------------------------- // Callback funkce zavolana pri pohybu mysi //--------------------------------------------------------------------- void onMousePassiveMotion(int x, int y) { static int first=1; static int old_x; if (first) { old_x=x; first=0; } else { avatar.angle=-x+old_x; } glutPostRedisplay(); } //--------------------------------------------------------------------- // Callback funkce zavolana pri tiku casovace kazdych 10ms //--------------------------------------------------------------------- void onTimer(int timer) { if (btn==1) avatar.moveSpeed=5.0; // leve tlacitko mysi -> plna rychlost dopredu if (btn==2) avatar.moveSpeed=-5.0; // prave tlacitko mysi -> plna rychlost dozadu if (btn==0) { // zadne tlacitko mysi -> zpomaleni if (avatar.moveSpeed>0.1) avatar.moveSpeed-=0.5; if (avatar.moveSpeed<-0.1) avatar.moveSpeed+=0.5; } if (abs(avatar.moveSpeed)>0.01) { avatarMove(&avatar); glutPostRedisplay(); } else { avatar.moveSpeed=0.0; } glutTimerFunc(10, onTimer, timer); } //--------------------------------------------------------------------- // Callback funkce zavolana pri tiku casovace kazdych 10ms //--------------------------------------------------------------------- int main(int argc, char **argv) { glutInit(&argc,argv); // inicializace knihovny GLUT glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH); // graficky mod okna glutInitWindowSize(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);// pocatecni velikost okna glutInitWindowPosition(DEFAULT_WINDOW_LEFT, DEFAULT_WINDOW_TOP); // pocatecni pozice okna glutCreateWindow("Priklad cislo 68"); // vytvoreni okna pro kresleni glutDisplayFunc(onDisplay); // registrace funkce volane pri prekreslovani glutReshapeFunc(onResize); // registrace funkce volane pri zmene velikosti glutKeyboardFunc(onKeyPress); // registrace funkce volane pri stisku ASCII klavesy glutSpecialFunc(onKeyDown); // registrace funkce volane pri stisku non-ASCII klavesy glutMouseFunc(onMouseButton); // registrace funkce volane pri stisku ci pusteni tlacitka mysi glutPassiveMotionFunc(onMousePassiveMotion); // registrace funkce volane pri pohybu mysi glutTimerFunc(10, onTimer, 0x1234); // registrace funkce volane pri tiku casovace onInit(); // inicializace aplikace glutMainLoop(); // nekonecna smycka, kde se volaji zaregistrovane funkce return 0; // ANSI C potrebuje ukoncit fci main prikazem return // i kdyz se sem program nikdy nedostane } //--------------------------------------------------------------------- // finito //---------------------------------------------------------------------