/* melite6b.c - visualizza un pianeta e una navetta in 3D * usando le primitive viste, muove la telecamera usando camera.cpp * aggiornando di conseguenza il radar. * * Autore: Andrea Fusiello, Andrea Colombari 2004 * * arrow keys - muovono la telecamera come un pilota muove un aereo * SPACE key - accellera * - key - decellera * Escape Key - esce dal programma */ #include #include #include /* segue inclusione di una piccola libreria con alcune definizioni di tipo e utils */ #include "eliteutils.h" /* segue file .h dove si definisce la forma e le proprieta' del satellite */ #include "coriolis.h" /* segue inclusione libreria gestione telecamera in C++ */ #include "camera.h" /* Function Prototypes */ void initgfx( void ); void keyboard( GLubyte, GLint, GLint ); void specialkeys( GLint, GLint, GLint ); void drawScene( void ); void drawControlPanel(); void checkError( char * ); void printHelp( char * ); void reshape ( GLsizei, GLsizei ); void animate( void ); void visibility( GLint ); /* Global Definitions */ /* telecamera */ Camera g_camera(0, 0, -8); GLsizei width, height, ctrl_panel_height; long g_frames=0; #define KEY_ESC 27 /* ascii value for the escape key */ #define CAM_SPEED_STEP 0.00005f /* step di incremento velocita' */ #define CAM_ROT_STEP 1.0f /* step di incremento angolo */ #define CAM_POS_STEP 0.005f /* step di incremento posizione */ int main( int argc, char *argv[] ) { glutInit( &argc, argv ); width = glutGet( GLUT_SCREEN_WIDTH ) / 2; height = glutGet( GLUT_SCREEN_HEIGHT ) / 2; ctrl_panel_height = 50; glutInitWindowPosition( width / 2, height / 2 ); glutInitWindowSize( width, height ); /* aggiungiamo double buffering per le animazioni e lo z buffer */ glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH ); glutCreateWindow( argv[0] ); initgfx(); glutKeyboardFunc( keyboard ); glutSpecialFunc( specialkeys ); glutDisplayFunc( drawScene ); /* aggiungiamo l'aggiornameto di width e height per il corretto aspect ratio */ glutReshapeFunc( reshape ); /* aggiungiamo la funzione per animare pianeta e satellite */ glutIdleFunc( animate ); /* aggiungiamo la funzione per gestire la visibilita' della finestra */ glutVisibilityFunc( visibility ); printHelp( argv[0] ); glutMainLoop(); return(0); } /* ----------------------------------------------------------*/ void printHelp( char *progname ) { fprintf(stdout, "\n%s - elite in 3D with a realistic driving that uses pitch and roll\n\n" "arrow keys - move camera as a pilot moves a plane\n" "SPACE key - speed up\n" "- key - slow down\n" "Escape Key - exit the program\n\n", progname); } /* ----------------------------------------------------------*/ void initgfx( void ) { /* set clear color to black */ glClearColor( 0.0, 0.0, 0.0, 1.0 ); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective( 45.0, (GLdouble) width / (GLdouble) (height-ctrl_panel_height), 1.0, 20.0 ); glEnable(GL_DEPTH_TEST); /* enable z buffer */ glEnable(GL_CULL_FACE); /* enable cull face */ glCullFace(GL_BACK); } /* ----------------------------------------------------------*/ void checkError( char *label ) { GLenum error; while ( (error = glGetError()) != GL_NO_ERROR ) printf( "%s: %s\n", label, gluErrorString(error) ); } /* ----------------------------------------------------------*/ void keyboard( GLubyte key, GLint x, GLint y ) { switch (key) { case ' ': g_camera.accelerate(CAM_SPEED_STEP); glutPostRedisplay(); break; case '-': g_camera.accelerate(-CAM_SPEED_STEP); glutPostRedisplay(); break; case 'w': g_camera.step(CAM_POS_STEP); glutPostRedisplay(); break; case 'q': g_camera.step(-CAM_POS_STEP); glutPostRedisplay(); break; case KEY_ESC: /* Exit when the Escape key is pressed */ fprintf(stdout, "\n"); exit(0); } } /* ----------------------------------------------------------*/ void specialkeys( GLint key, GLint u, GLint v ) { switch (key) { case GLUT_KEY_RIGHT: g_camera.roll(CAM_ROT_STEP); glutPostRedisplay(); break; case GLUT_KEY_LEFT: g_camera.roll(-CAM_ROT_STEP); glutPostRedisplay(); break; case GLUT_KEY_DOWN: g_camera.pitch(-CAM_ROT_STEP); glutPostRedisplay(); break; case GLUT_KEY_UP: g_camera.pitch(CAM_ROT_STEP); glutPostRedisplay(); break; } } /* ----------------------------------------------------------*/ void drawScene( void ) { static GLfloat darkgreen[] = { 0.0f, 0.25f, 0.0f }; /* ogni volta che disegno incremento il numero dei frame */ g_frames++; /* Do all your OpenGL rendering here */ /* cancelliamo il buffer video e lo z buffer */ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* ------------------------------------------------------------------------- */ /* attiva il viewport principale */ glViewport( 0, ctrl_panel_height, width, height-ctrl_panel_height); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPushMatrix(); g_camera.look(); /* chiama la gluLookAt con i parametri opportuni */ glPushMatrix(); glRotatef(glutGet(GLUT_ELAPSED_TIME)*0.012, 0.0, 0.0, 1.0); /* ruotante */ glColor3fv( darkgreen ); glutWireSphere( 1.5f, 15, 15 ); glPopMatrix(); glPushMatrix(); glTranslatef( 2, 2, 0 ); glRotatef(glutGet(GLUT_ELAPSED_TIME)*0.012, 0.0, 0.0, 1.0); /* ruotante */ glColor3f( 0.7, 0.7, 0.7 ); drawEliteObject(coriolis_numberOfFaces, coriolis_vertex, coriolis_face, coriolis_material); glPopMatrix(); glPopMatrix(); /* ------------------------------------------------------------------------- */ /* Inseriamo il mirino utilizzando pero' proiezione ortografica */ /* Crea nuova vista ortogonale */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D( 0, (GLdouble) width / (GLdouble) (height-ctrl_panel_height), 0, 1); /* Resetta modelview */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPushMatrix(); /* disegna il mirino */ drawSight((GLdouble) width / (GLdouble) (height-ctrl_panel_height)*0.5, 0.5); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); /* ------------------------------------------------------------------------- */ /* Attiva il viewport del pannello, in basso */ glViewport( 0, 0, width, ctrl_panel_height); /* Salva la projection e costruisce una vista ortogonale */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); /* vista ortgogonale, con fattore d'aspetto corretto, in modo che non ci sia distorsone */ gluOrtho2D(0, (GLfloat)width/ctrl_panel_height, 0, 1); /* Resetta modelview */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPushMatrix(); drawControlPanel(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); checkError( "drawScene" ); glFlush(); /* per non vedere il frame buffer mentre viene disegnato */ glutSwapBuffers(); } /* ----------------------------------------------------------*/ void drawControlPanel() { /* disegna il pannello di controllo in un vieport di altezza 1 e larghezza dipendente da quella della finestra */ GLfloat v; /* velocita' tra 0 e 1; */ float x,y,z; Point3 u; int t; /* barra della velocita' */ glLineWidth( 1 ); glColor3f( 0, 0, 1); glBegin( GL_LINE_LOOP ); /* quadrato */ glVertex2f(1, 0.5); glVertex2f(2, 0.5); glVertex2f(2, 0); glVertex2f(1, 0); glEnd(); v = (g_camera.getSpeed())/(MAXSPEED); if ( v < 0.8 ) glColor3f( 1, 1, 0); else glColor3f( 1, 0, 0); glBegin( GL_QUADS); glVertex3f(1.05+1.0*v, 0, 0.1); glVertex3f(1.05+1.0*v, 0.5, 0.1); glVertex3f(1.05, 0.5, 0.1); glVertex3f(1.05, 0, 0.1); glEnd(); /* posizioniamo la scritta */ glColor3f( 0, 0, 1); glRasterPos2f(2.1, 0.1); renderBitmapString(GLUT_BITMAP_HELVETICA_18, "SP"); /* radar */ glColor3f( 0, 0, 1); glLineWidth( 0.2 ); glBegin( GL_LINES ); /* cerchio */ for(t=0; t< 200; t++) glVertex3f(0.5+0.5*cos(t/200.0*2*PI), 0.5+0.5*sin(t/200.0*2*PI),0.1); glEnd(); /* crocetta */ glColor3f( 1, 1, 1); glLineWidth( 0.2 ); glBegin( GL_LINES); glVertex3f(0.5, 0,-0.1); glVertex3f(0.5, 1,-0.1); glVertex3f(0, 0.5,-0.1); glVertex3f(1, 0.5,-0.1); glEnd(); /* puntino verde (fronte) o rosso (retro) */ u = Normalize(g_camera.getPos()); x = -ProdScal(u,g_camera.getRight()); y = -ProdScal(u,g_camera.getUp()); z = -ProdScal(u,g_camera.getView()); glColor3f( 0, 1, 0); glPointSize(4); glBegin(GL_POINTS); if ( z < 0 ) /* uso la z per disegnarlo dietro */ glColor3f( 0.78, 0.25, 0); else glColor3f( 0, 1, 0); glVertex2f(0.5 + 0.5*x, 0.5+0.5*y); glEnd(); } /* ----------------------------------------------------------*/ void reshape( GLsizei w, GLsizei h ) { /* aggiorniamo dimensioni con i valori correnti */ width = w; height = h; /* aggiornamento settaggi relativi alla visione in soggettiva del gioco */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective( 45.0, (GLdouble) width / (GLdouble) (height-ctrl_panel_height), 1.0, 20.0 ); } /* ----------------------------------------------------------*/ void animate( void ) { long dtime; static long currentTime=0, previousTime=0; static long nearTime=0; /* restituisce il tempo in ms da glutInit o dall'ultima chiamata */ currentTime = glutGet(GLUT_ELAPSED_TIME); dtime = currentTime - previousTime; /* questo serve per calcolare il fps ogni secondo (circa) */ if (dtime > 1000) { fprintf(stdout, "\r%d fps", (int)(1e3 * (double) g_frames/(double) dtime) ); fflush(stdout); g_frames = 0; previousTime = currentTime; } /* muoviamo la nostra navetta spaziale (ossia la telecamera) in base al tempo trascorso dall'ultimo rendering */ dtime = currentTime - nearTime; nearTime = currentTime; g_camera.advance(dtime); glutPostRedisplay(); } /* ----------------------------------------------------------*/ void visibility( int state ) { /* restart the animation function if we were * animated when the window was hidden */ if (state == GLUT_VISIBLE) { glutIdleFunc( animate ); } else { glutIdleFunc( NULL ); } } /* Credits: Riccardo Giannitrapani per la scrittura di bitmap Ben Humphrey (DigiBen@GameTutorials.com) per la texture e la classe camera Tutorial SGI (quello che c'e' sulla pagina web del lab) in generale */