src/Display.cpp

Go to the documentation of this file.
00001 
00008 /*
00009 This file is part of Teapot Colony Wars.
00010 
00011 Teapot Colony Wars is free software: you can redistribute it and/or modify
00012 it under the terms of the GNU General Public License as published by
00013 the Free Software Foundation, either version 2 of the License, or
00014 (at your option) any later version.
00015 
00016 Teapot Colony Wars is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License
00022 along with Teapot Colony Wars.  If not, see <http://www.gnu.org/licenses/>.
00023 */
00024 
00025 #include "Display.h"
00026 
00027 #include <cstdlib>
00028 #include <cmath>
00029 
00030 #include "Constants.h"
00031 #include "Accum.h"
00032 #include "Jitter.h"
00033 
00039 void display_timer(int value) {
00040   Display::instance()->timer(value);
00041 }
00042 
00043 Display* Display::_instance = NULL;
00044 
00045 Display::Display() : _world(12, 12, 2) {
00046   // initialisation du point au centre du champs de vision de la caméra
00047   _center_x = (GLint) (_world.getWidth() / 2) * CELL_SIZE;
00048   _center_y = 0;
00049   _center_z = (GLint) (_world.getHeight() / 2) * CELL_SIZE;
00050 
00051   // positionnement de la caméra
00052   _camera_x = (GLint) _center_x;
00053   _camera_y = (GLint) HEIGHT_MAX / 4;
00054   _camera_z = (GLint) _center_z + 3 * CELL_SIZE;
00055 
00056   // profondeur de champs
00057   _near = 0.1;
00058   _far = HORIZON;
00059 
00060   // angle d'ouverture
00061   _fovy = 45.0;
00062 
00063   // initialisation du timer
00064   _timer = true;
00065   glutTimerFunc(REDISPLAY_NB_MILLI_SEC, display_timer, 0);
00066 }
00067 
00068 GLfloat Display::focal_distance() {
00069   return sqrt((_camera_x - _center_x) * (_camera_x - _center_x) +
00070               (_camera_y - _center_y) * (_camera_y - _center_y) +
00071               (_camera_y - _center_y) * (_camera_y - _center_y));
00072 }
00073 
00074 void Display::translate_camera(GLfloat  inc_x, GLfloat  inc_z) {
00075   GLfloat tmp_x = _center_x + inc_x;
00076   GLfloat tmp_z = _center_z + inc_z;
00077 
00078   if(tmp_x > 0.0 && tmp_x < (_world.getWidth() - 1.0) * CELL_SIZE &&
00079       tmp_z > 0.0 && tmp_z < (_world.getHeight() - 1.0) * CELL_SIZE) {
00080     _camera_x += inc_x;
00081     _center_x = tmp_x;
00082     _camera_z += inc_z;
00083     _center_z = tmp_z;
00084     glutPostRedisplay();
00085   }
00086 }
00087 
00088 void Display::move_camera(GLfloat  inc_y) {
00089   GLfloat tmp_y = _camera_y + inc_y;
00090 
00091   if(tmp_y >= HEIGHT_MIN && tmp_y <= HEIGHT_MAX) {
00092     _camera_y += inc_y;
00093     glutPostRedisplay();
00094   }
00095 }
00096 
00097 void Display::zoom_camera(GLfloat  inc) {
00098   GLfloat tmp = focal_distance();
00099 
00100   if(_camera_y + inc >= HEIGHT_MIN && _camera_y + inc <= HEIGHT_MAX) {
00101     _camera_x = ((_camera_x - _center_x) * (1 + inc / tmp)) + _center_x;
00102     _camera_y = ((_camera_y - _center_y) * (1 + inc / tmp)) + _center_y;
00103     _camera_z = ((_camera_z - _center_z) * (1 + inc / tmp)) + _center_z;
00104     glutPostRedisplay();
00105   }
00106 }
00107 
00108 void Display::rotate_camera(GLfloat  inc) {
00109   GLfloat tmp = _camera_x;
00110   _camera_x = ((_camera_x - _center_x) * cos(inc) -
00111     (_camera_z - _center_z) * sin(inc)) + _center_x;
00112   _camera_z = ((tmp - _center_x) * sin(inc) +
00113     (_camera_z - _center_z) * cos(inc)) + _center_z;
00114   glutPostRedisplay();
00115 }
00116 
00117 Display::~Display() {
00118   destroy();
00119 }
00120 
00121 Display* Display::instance() {
00122   if(_instance == NULL) {
00123     _instance = new Display();
00124   }
00125 
00126   return _instance;
00127 }
00128 
00129 void Display::destroy() {
00130   if(_instance != NULL) {
00131     delete _instance;
00132     _instance = NULL;
00133   }
00134 }
00135 
00136 void Display::init() {
00137   // paramètres d'illumination
00138   GLfloat mat_specular[]   = {1.0, 1.0, 1.0, 1.0};
00139   GLfloat mat_shininess[]  = {100.0};
00140   GLfloat white_light[]    = {1.0, 1.0, 1.0, 1.0};
00141   GLfloat light_position[] = {
00142     _world.getWidth() / 2.0,
00143     HEIGHT_MAX,
00144     _world.getHeight() / 2.0,
00145     0.0
00146   };
00147 
00148   // couleur de vidage des buffers
00149   glClearColor(0.0, 0.0, 0.0, 1.0);
00150 
00151   // model d'ombres pour l'illumination
00152   glShadeModel(GL_FLAT);
00153 
00154   // propriétés de matière des objets
00155   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
00156   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
00157 
00158   // création de la source lumineuse
00159   glLightfv(GL_LIGHT0, GL_POSITION, light_position);
00160   glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
00161   glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
00162 
00163   // activation de l'illumination
00164   glEnable(GL_LIGHTING);
00165   glEnable(GL_LIGHT0);
00166 
00167   // paramètres de génération automatique des coordonnées de texture
00168   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00169   glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
00170 
00171   // permet de prendre en compte la couleur des objets lors de leur illumination
00172   glEnable(GL_COLOR_MATERIAL);
00173 
00174   // initialisation du buffeur de profondeur
00175   glClearDepth(1.0);
00176   glDepthFunc(GL_LESS);
00177   glEnable(GL_DEPTH_TEST);
00178 
00179   // activation de la création automatique de vecteurs normaux normalisés
00180   glEnable(GL_AUTO_NORMAL);
00181   glEnable(GL_NORMALIZE);
00182 }
00183 
00184 void Display::quit() {
00185 
00186 }
00187 
00188 void Display::timer(int value) {
00189   _world.iteration();
00190   glutPostRedisplay();
00191   if(_timer) {
00192     // on relance le timer pour ré-appeler automatiquement la fonction plus tard
00193     glutTimerFunc(REDISPLAY_NB_MILLI_SEC, display_timer, 0);
00194   }
00195 }
00196 
00197 void Display::draw() {
00198   GLint viewport[4];
00199   GLdouble ratio;
00200   int nb_steps = j[ANTIALIASING_LEVEL].nb;
00201   GLdouble step = 1.0 / nb_steps;
00202   jitter_point* jp = j[ANTIALIASING_LEVEL].jitter_points;
00203   int jitter;
00204 
00205   // récupération des paramètres d'affichage à l'écran
00206   glGetIntegerv(GL_VIEWPORT, viewport);
00207   // calcul du ratio de l'image affichée
00208   ratio = (GLdouble) viewport[2] / (GLdouble) viewport[3];
00209 
00210   // vidage du tampon d'accumulation
00211   glClear(GL_ACCUM_BUFFER_BIT);
00212   for(jitter = 0; jitter < nb_steps; jitter++) {
00213     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00214 
00215     // modification de la matrice de projection en fonction du jitter
00216     // (pour l'antialiasing)
00217     accPerspective(_fovy, ratio, _near, _far,
00218                    jp[jitter].x, jp[jitter].y,
00219                    0.0, 0.0, 1.0);
00220 
00221     // passage en mode dessin
00222     glMatrixMode(GL_MODELVIEW);
00223     // chargement de la matrice de transformation identitaire
00224     // (remise à l'origine)
00225     glLoadIdentity();
00226     // positionnement de la caméra
00227     gluLookAt(_camera_x, _camera_y, _camera_z,
00228               _center_x, _center_y, _center_z,
00229               0.0, 1.0, 0.0);
00230 
00231     // affichage du curseur de position
00232     glColor3ub((GLubyte) (0.7 * COLOR_MAX), COLOR_MAX, COLOR_MAX);
00233     glPushMatrix();
00234     glTranslatef(_center_x, _center_y + 0.01 * CELL_SIZE, _center_z);
00235     glRotatef(90.0, 1.0, 0.0, 0.0);
00236     glutSolidTorus (0.03 * CELL_SIZE, 0.75 * CELL_SIZE,
00237       CELL_SIZE, 5 * CELL_SIZE);
00238     glPopMatrix();
00239 
00240     // affichage du monde
00241     _world.draw();
00242 
00243     // ajout de l'image produite dans le tampon d'accumulation
00244     glAccum(GL_ACCUM, step);
00245   }
00246 
00247   // récupération de l'image résultant de l'accumulation
00248   glAccum(GL_RETURN, 1.0);
00249 
00250   // inversion des buffers de dessin : apparition de l'image à l'écran
00251   glutSwapBuffers();
00252 }
00253 
00254 void Display::reshape(int width, int height) {
00255   // division par 0 : pas bô, alors autant l'éviter...
00256   if (height == 0)
00257     height = 1;
00258 
00259   // modification de la taille de la zone d'affichage
00260   glViewport(0, 0, width, height);
00261 
00262   // passage en mode projection
00263   glMatrixMode(GL_PROJECTION);
00264 
00265   // création de la nouvelle transformation de projection
00266   glLoadIdentity();
00267   gluPerspective(_fovy, (float) width / height, _near, _far);
00268 
00269   // réactivation du mode dessin
00270   glMatrixMode(GL_MODELVIEW);
00271 }
00272 
00273 void Display::inputKey(unsigned char key, int x, int y) {
00274   GLint specialKey = glutGetModifiers();
00275 
00276   switch(key) {
00277     case TRANSLATE_LEFT :
00278       translate_camera(-CELL_SIZE, 0.0);
00279       break;
00280     case TRANSLATE_RIGHT :
00281       translate_camera(CELL_SIZE, 0.0);;
00282       break;
00283     case TRANSLATE_UP :
00284       translate_camera(0.0, -CELL_SIZE);
00285       break;
00286     case TRANSLATE_DOWN :
00287       translate_camera(0.0, CELL_SIZE);
00288       break;
00289     case ZOOM_IN :
00290       if(specialKey == GLUT_ACTIVE_CTRL) {
00291         move_camera(MOVE_UP_SPEED);
00292       } else {
00293         zoom_camera(-ZOOM_SPEED);
00294       }
00295       break;
00296     case ZOOM_OUT :
00297       if(specialKey == GLUT_ACTIVE_CTRL) {
00298         move_camera(-MOVE_UP_SPEED);
00299       } else {
00300         zoom_camera(ZOOM_SPEED);
00301       }
00302       break;
00303     case ROTATE_LEFT :
00304       rotate_camera(-ROTATE_ANGLE);
00305       break;
00306     case ROTATE_RIGHT :
00307       rotate_camera(ROTATE_ANGLE);
00308       break;
00309     case PAUSE :
00310       if(_timer) {
00311         _timer = false;
00312       } else {
00313         _timer = true;
00314         // relance le timer
00315         glutTimerFunc(REDISPLAY_NB_MILLI_SEC, display_timer, 0);
00316       }
00317       break;
00318     case VALIDATE :
00319       _world.addGodsGift((unsigned int) _center_z / CELL_SIZE,
00320         (unsigned int) _center_x / CELL_SIZE);
00321       glutPostRedisplay();
00322       break;
00323   }
00324 }
00325 
00326 void Display::inputMouse(int button, int state, int x, int y) {
00327   GLint specialKey = glutGetModifiers();
00328 
00329   /*
00330   GLint viewport[4];
00331   GLdouble modelview[16];
00332   GLdouble projection[16];
00333   GLfloat win_x, win_y, win_z;
00334   GLdouble obj_x, obj_y, obj_z;
00335 
00336   glGetIntegerv(GL_VIEWPORT, viewport);
00337   glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
00338   glGetDoublev(GL_PROJECTION_MATRIX, projection);
00339 
00340   win_x = (GLfloat) x;
00341   win_y = (GLfloat) viewport[3] - (GLfloat) y;
00342   glReadPixels(win_x, win_y , 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &win_z);
00343 
00344   gluUnProject((GLdouble) win_x, (GLdouble) win_y, 0.0, modelview, projection,
00345     viewport, &obj_x, &obj_y, &obj_z);
00346   */
00347 
00348   if(state == GLUT_DOWN) {
00349     switch(button) {
00350       case GLUT_UP_BUTTON :
00351         if(specialKey == GLUT_ACTIVE_CTRL) {
00352           move_camera(MOVE_UP_SPEED);
00353         } else {
00354           zoom_camera(-ZOOM_SPEED);
00355         }
00356         break;
00357       case GLUT_DOWN_BUTTON :
00358         if(specialKey == GLUT_ACTIVE_CTRL) {
00359           move_camera(-MOVE_UP_SPEED);
00360         } else {
00361           zoom_camera(ZOOM_SPEED);
00362         }
00363         break;
00364       case GLUT_LEFT_BUTTON :
00365         if(specialKey == GLUT_ACTIVE_CTRL) {
00366           rotate_camera(-ROTATE_ANGLE);
00367         } else {
00368           _world.iteration();
00369           glutPostRedisplay();
00370         }
00371         break;
00372       case GLUT_RIGHT_BUTTON :
00373         if(specialKey == GLUT_ACTIVE_CTRL) {
00374           rotate_camera(ROTATE_ANGLE);
00375         }
00376         break;
00377     }
00378   }
00379 }

Generated on Sat Feb 2 22:22:54 2008 for Teapot Colony Wars by  doxygen 1.5.4