Main Page | Class Hierarchy | Class List | Directories | File List | Class Members | Related Pages

renderer.cpp

00001 /***************************************************************************
00002                         renderer.cpp  -  description
00003                             -------------------
00004     begin                : jeu mai 29 2003
00005     copyright            : (C) 2003-2006 by Duong-Khang NGUYEN
00006     email                : neoneurone @ users sourceforge net
00007 
00008     $Id: renderer.cpp 65 2006-10-22 09:46:47Z neoneurone $
00009  ***************************************************************************/
00010 
00011 /***************************************************************************
00012  *                                                                         *
00013  *   This program is free software; you can redistribute it and/or modify  *
00014  *   it under the terms of the GNU General Public License as published by  *
00015  *   the Free Software Foundation; either version 2 of the License, or     *
00016  *   any later version.                                                    *
00017  *                                                                         *
00018  ***************************************************************************/
00019 
00020 //========================================================================
00021 /* General development notes.
00022 
00023     Here are the default OpenGL values when the renderer is initialized
00024 for the first time
00025     - Default matrix mode:
00026         glMatrixMode( GL_MODELVIEW );
00027 
00028     - Default color mode:
00029         glEnable( GL_COLOR_MATERIAL );
00030 
00031     - Default blending function:
00032         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00033 
00034     - Default shade mode:
00035         glShadeMode( GL_FLAT );
00036 
00037     - Default structure display translation vector:
00038         glTranslatef( 0., 0.05, 0. );
00039 */
00040 //========================================================================
00041 
00042 #include "renderer.h"
00043 #include "layer.h"
00044 #include "texture.h"                    // Terrain texturing
00045 #include "font_8x8.h"                   // 8x8 font definition
00046 
00047 #include "globalvar.h"
00048 extern GlobalVar gVars;
00049 
00050 
00051    /*=====================================================================*/
00052 Renderer::Renderer
00053 (
00054     const uint cityW,
00055     const uint cityL
00056 ):
00057 boolHeightChange( true ),
00058 bDisplayGrid( true ),
00059 bDisplayCompass( true ),
00060 bWireFrame( false ),
00061 ubProjectionType( OC_PERSPECTIVE ),
00062 _uiSplashTex( 0 ),
00063 _uiCityWidth( cityW ),
00064 _uiCityLength( cityL )
00065 {
00066     OPENCITY_DEBUG( "Renderer ctor" );
00067 
00068 // Load frequently used textures
00069     _uiTerrainTex = Texture::Load( ocHomeDirPrefix( "texture/terrain_plane_128.png" ));
00070     _uiWaterTex = Texture::Load( ocHomeDirPrefix( "graphism/water/texture/blue_water_512.png" ));
00071 
00072 // Initialize the window's size, the viewport
00073 // and set the perspective's ratio
00074     assert( gVars.gpVideoSrf != NULL );
00075     Renderer::SetWinSize( gVars.gpVideoSrf->w, gVars.gpVideoSrf->h );
00076 
00077 // Settle "home" down ;)
00078     this->Home();
00079 
00080 
00081 /* not need for the moment
00082 //--- translate all the scence according to dDeltaX & dDeltaZ
00083     glTranslated( this->dDeltaX, 0.0, this->dDeltaZ );
00084 
00085 //--- rotate the scence to the required angle
00086     glRotated( this->dYRotateAngle, 0.0, 1.0, 0.0 );
00087 */
00088 
00089 
00090 // Enable polygon culling. This can effect the texture alpha blending
00091 /*
00092     glEnable( GL_CULL_FACE );
00093     glCullFace( GL_BACK );
00094     glFrontFace( GL_CCW );
00095 */
00096 
00097 // select the flat rendering mode, default is GL_SMOOTH
00098     glShadeModel( GL_FLAT );
00099 
00100 //debug testing
00101 //the maximal number of lights we can set is: 8
00102 /*  GLint nbLight;
00103     glGetIntegerv( GL_MAX_LIGHTS, &nbLight );
00104     cout << "max lights : " << (int) nbLight << endl;
00105 */
00106 //debug testing end
00107 
00108 // Create 8x8 font
00109     glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
00110     this->_uiFontBase = glGenLists( 256 );
00111     for ( uint i = 0; i < 256; i++ ) {
00112         glNewList( this->_uiFontBase + i, GL_COMPILE );
00113         glBitmap( 8, 8, .0, .0, 10., .0, fontdata_8x8 + i*8 );
00114         glEndList();
00115     }
00116 
00117 // initialize few display lists
00118     _uiGridList = glGenLists( 1 );
00119     _uiTerrainList = glGenLists( 1 );
00120     _uiWaterList = glGenLists( 1 );
00121 
00122 // Define the global ambient light value
00123 // NOTE: we declare the variables here for better readable codes
00124     GLfloat fvLightModelAmbient[] = { OC_LIGHT_MODEL_AMBIENT };
00125     GLfloat fvLightAmbient [] = { .6, .6, .4, 1. };
00126     GLfloat fvLightDiffuse [] = { .8, .8, .6, 1. };
00127     GLfloat fvLightSpecular [] = { .4, .4, .4, 1. };
00128 
00129     glLightModelfv( GL_LIGHT_MODEL_AMBIENT, fvLightModelAmbient );
00130     glLightfv( GL_LIGHT0, GL_AMBIENT, fvLightAmbient );
00131     glLightfv( GL_LIGHT0, GL_DIFFUSE, fvLightDiffuse );
00132     glLightfv( GL_LIGHT0, GL_SPECULAR, fvLightSpecular );
00133     glLighti( GL_LIGHT0, GL_SPOT_CUTOFF, 180 );
00134 
00135 // Enable lighting
00136 // WARNING: the light position is transformed by the current MODELVIEW matrix
00137     static GLint ivLightPos [] = { 0, 2, 1, 0};     // Directional light
00138     static GLint ivLightDir [] = { 0, 2, 0 };
00139     glLightiv( GL_LIGHT0, GL_POSITION, ivLightPos );
00140     glLightiv( GL_LIGHT0, GL_SPOT_DIRECTION, ivLightDir );
00141 
00142     glEnable( GL_LIGHTING );
00143     glEnable( GL_LIGHT0 );
00144 
00145 // Enable the GL automatic normals rescaling it's useful when the user zooms
00146 // in and out ( zooming is uniform here, in OpenCity)
00147 // The surface's normal needs to be unit length
00148     glEnable( GL_RESCALE_NORMAL );
00149 // GL_NORMALIZE is replaced by the RESCALE_NORMAL provided by OpenGL 1.2
00150 //  glEnable( GL_NORMALIZE );
00151 
00152 // Allow the material to track glColor()
00153 // WARNING: glEnable( GL_COLOR_MATERIAL ) tracks immediatly the current color
00154 //          The default settings are GL_FRONT_AND_BACK and GL_AMBIENT_AND_DIFFUSE
00155     glColor4ub( 255, 255, 255, 255 );
00156     glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
00157     glEnable( GL_COLOR_MATERIAL );
00158 
00159 // this can help improving texture lighting
00160 //  glLightModelf( GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR );
00161 
00162 // Enable depth test
00163     glDepthFunc( GL_LEQUAL );
00164     glEnable( GL_DEPTH_TEST );
00165 
00166 // Choose the right blending function
00167     glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00168 }
00169 
00170 
00171    /*=====================================================================*/
00172 Renderer::~Renderer(  )
00173 {
00174     OPENCITY_DEBUG("dtor");
00175 
00176 // Destroy GL list
00177     glDeleteLists( this->_uiFontBase, 256 );
00178 
00179     if (glIsList( this->_uiGridList ))
00180         glDeleteLists( this->_uiGridList, 1 );
00181     if (glIsList( _uiTerrainList ))
00182         glDeleteLists( _uiTerrainList, 1 );
00183     if (glIsList( _uiWaterList ))
00184         glDeleteLists( _uiWaterList, 1 );
00185 
00186 // Free textures
00187     glDeleteTextures( 1, &_uiTerrainTex );
00188     glDeleteTextures( 1, &_uiWaterTex );
00189     glDeleteTextures( 1, &_uiSplashTex );
00190 }
00191 
00192 
00193    /*=====================================================================*/
00194 void
00195 Renderer::RotateLeft( const uint & factor )
00196 {
00197     GLdouble dYCurrentAngle = OC_Y_ROTATE_STEP*factor;
00198     this->dYRotateAngle = (GLint)(this->dYRotateAngle + dYCurrentAngle) % 360;
00199 
00200 // Toggle to the model view matrix
00201     glMatrixMode( GL_MODELVIEW );
00202     glLoadIdentity();
00203 
00204 // Rotate the scence to the required angle
00205     glRotated( dYCurrentAngle, 0.0, 1.0, 0.0 );
00206 
00207 // Translate all the scence according to dDeltaX & dDeltaZ
00208     glTranslated( this->dDeltaX, 0.0, this->dDeltaZ );
00209 
00210 // Apply the new changes to the old rotation's matrix
00211     glMultMatrixd( this->dmatrixRotate );
00212 
00213 // Clear the translation
00214     this->dDeltaX = 0.0;
00215     this->dDeltaZ = 0.0;
00216 
00217 // Save the calculated rotation matrix
00218     glGetDoublev( GL_MODELVIEW_MATRIX, dmatrixRotate );
00219 }
00220 
00221 
00222    /*=====================================================================*/
00223 void
00224 Renderer::RotateRight( const uint & factor )
00225 {
00226     GLdouble dYCurrentAngle = -OC_Y_ROTATE_STEP*factor;
00227     this->dYRotateAngle = (GLint)(this->dYRotateAngle + dYCurrentAngle) % 360;
00228 
00229 // Toggle to the model view matrix
00230     glMatrixMode( GL_MODELVIEW );
00231     glLoadIdentity();
00232 
00233 // Rotate the scence to the required angle
00234     glRotated( dYCurrentAngle, 0.0, 1.0, 0.0 );
00235 
00236 // Translate all the scence according to dDeltaX & dDeltaZ
00237     glTranslated( this->dDeltaX, 0.0, this->dDeltaZ );
00238 
00239 // Apply the new changes to the old rotation's matrix
00240     glMultMatrixd( this->dmatrixRotate );
00241 
00242 // Clear the translation
00243     this->dDeltaX = 0.0;
00244     this->dDeltaZ = 0.0;
00245 
00246 // Save the calculated rotation matrix
00247     glGetDoublev( GL_MODELVIEW_MATRIX, dmatrixRotate );
00248 }
00249 
00250 
00251    /*=====================================================================*/
00252 void
00253 Renderer::MoveLeft( const uint & factor )
00254 {
00255     this->dDeltaX -= fXTransDelta*factor;
00256 }
00257 
00258 
00259    /*=====================================================================*/
00260 void
00261 Renderer::MoveRight( const uint & factor )
00262 {
00263     this->dDeltaX += fXTransDelta*factor;
00264 }
00265 
00266 
00267    /*=====================================================================*/
00268 void
00269 Renderer::MoveUp( const uint & factor )
00270 {
00271     this->dDeltaZ -= fZTransDelta*factor;
00272 }
00273 
00274 
00275    /*=====================================================================*/
00276 void
00277 Renderer::MoveDown( const uint & factor )
00278 {
00279     this->dDeltaZ += fZTransDelta*factor;
00280 }
00281 
00282 
00283    /*=====================================================================*/
00284 void
00285 Renderer::Home()
00286 {
00287     this->fScaleRatio = 1.0;
00288     this->fXTransDelta = OC_DELTA_X_STEP;
00289     this->fZTransDelta = OC_DELTA_Z_STEP;
00290     this->dEyeX = OC_EYE_X_START;
00291     this->dEyeY = OC_EYE_Y_START;
00292     this->dEyeZ = OC_EYE_Z_START;
00293     this->dDeltaX = OC_DELTA_X_START;
00294     this->dDeltaZ = OC_DELTA_Z_START;
00295     this->dYRotateAngle = OC_Y_ROTATE_ANGLE;
00296 
00297 //--- reinit the rotation matrix
00298     glMatrixMode( GL_MODELVIEW );
00299     glLoadIdentity();
00300     glGetDoublev( GL_MODELVIEW_MATRIX, dmatrixRotate );
00301 }
00302 
00303 
00304    /*=====================================================================*/
00305 void
00306 Renderer::ZoomIn(  )
00307 {
00308     if (this->fScaleRatio < 15.) {
00309         this->fScaleRatio += .1;
00310         if (this->fScaleRatio < 3.) {
00311             this->fXTransDelta -= .09;
00312             this->fZTransDelta -= .09;
00313         }
00314     }
00315 }
00316 
00317 
00318    /*=====================================================================*/
00319 void Renderer::ZoomOut(  )
00320 {
00321     if (this->fScaleRatio > .1) {
00322         this->fScaleRatio -= .1;
00323         if (this->fScaleRatio < 3.) {
00324             this->fXTransDelta += .09;
00325             this->fZTransDelta += .09;
00326         }
00327     }
00328 }
00329 
00330 
00331    /*=====================================================================*/
00332    /*
00333     Divide the map to something like this :
00334     _________
00335     | A | B |
00336     _________
00337     | C | D |
00338     _________
00339 
00340     A: 1, B: 2, C: 3, D: 4
00341     This algorithm help speed up a lot while calculating the selected
00342     map W,H on a big big map
00343    */
00344 //TOKILL, for future reference
00345 /*
00346 const bool
00347 Renderer::GetSelectedWHFromLayer(
00348         const uint & rcuiMouseX,
00349         const uint & rcuiMouseY,
00350         uint & ruiMapW, uint & ruiMapH,
00351         const Layer & rcLayer,
00352         const uint & rcW1, const uint & rcH1,
00353         const uint & rcW2, const uint & rcH2 ) const
00354 {
00355 #define MAX_MAP_DELTA 20 // cut the map WH down to this size in the worst case
00356 
00357 //debug
00358 //  cout << "W1,H1,W2,H2: " << rcW1 << "," << rcH1 << "," << rcW2 << "," << rcH2 << endl;
00359 //debug
00360     if ((rcW2 - rcW1 > MAX_MAP_DELTA)
00361      && (rcH2 - rcH1 > MAX_MAP_DELTA)) {
00362 //debug
00363 //  cout << "W1,H1,W2,H2: " << rcW1 << "," << rcH1 << "," << rcW2 << "," << rcH2 << endl;
00364 //debug
00365         uint aW1 = rcW1; uint aH1 = rcH1;
00366         uint aW2 = (rcW1+rcW2) / 2; uint aH2 = (rcH1 + rcH2) / 2;
00367 
00368         uint bW1 = aW2 + 1; uint bH1 = aH1;
00369         uint bW2 = rcW2; uint bH2 = aH2;
00370 
00371         uint cW1 = aW1; uint cH1 = aH2 + 1;
00372         uint cW2 = aW2; uint cH2 = rcH2;
00373 
00374         uint dW1 = aW2 + 1; uint dH1 = aH2 + 1;
00375         uint dW2 = rcW2; uint dH2 = rcH2;
00376 
00377         GLubyte rgbTab[3];
00378 
00379     //---- prepare the world for rendering
00380         _PrepareView();
00381 
00382     //---- save the current ModelView matrix ----
00383         glPushMatrix();
00384 
00385     //---- clear the color buffer ( the screen )
00386         glClearColor( 0.0, 0.0, 0.0, 0.0 );
00387         glClear( GL_COLOR_BUFFER_BIT );
00388 
00389         glBegin( GL_QUADS );
00390         glColor3ub( 0, 0, 10 ); // 10 for polygon A
00391         glVertex3d( aW1 * OC_SQUARE_WIDTH, 0.0, aH1 * OC_SQUARE_HEIGHT );
00392         glVertex3d( aW1 * OC_SQUARE_WIDTH, 0.0, (aH2+1) * OC_SQUARE_HEIGHT );
00393         glVertex3d( (aW2+1) * OC_SQUARE_WIDTH, 0.0, (aH2+1) * OC_SQUARE_HEIGHT );
00394         glVertex3d( (aW2+1) * OC_SQUARE_WIDTH, 0.0, aH1 * OC_SQUARE_HEIGHT );
00395 
00396         glColor3ub( 0, 0, 20 ); // 20 for polygon B
00397         glVertex3d( bW1 * OC_SQUARE_WIDTH, 0.0, bH1 * OC_SQUARE_HEIGHT );
00398         glVertex3d( bW1 * OC_SQUARE_WIDTH, 0.0, (bH2+1) * OC_SQUARE_HEIGHT );
00399         glVertex3d( (bW2+1) * OC_SQUARE_WIDTH, 0.0, (bH2+1) * OC_SQUARE_HEIGHT );
00400         glVertex3d( (bW2+1) * OC_SQUARE_WIDTH, 0.0, bH1 * OC_SQUARE_HEIGHT );
00401 
00402         glColor3ub( 0, 0, 30 ); // 30 for polygon C
00403         glVertex3d( cW1 * OC_SQUARE_WIDTH, 0.0, cH1 * OC_SQUARE_HEIGHT );
00404         glVertex3d( cW1 * OC_SQUARE_WIDTH, 0.0, (cH2+1) * OC_SQUARE_HEIGHT );
00405         glVertex3d( (cW2+1) * OC_SQUARE_WIDTH, 0.0, (cH2+1) * OC_SQUARE_HEIGHT );
00406         glVertex3d( (cW2+1) * OC_SQUARE_WIDTH, 0.0, cH1 * OC_SQUARE_HEIGHT );
00407 
00408         glColor3ub( 0, 0, 40 ); // 40 for polygon D
00409         glVertex3d( dW1 * OC_SQUARE_WIDTH, 0.0, dH1 * OC_SQUARE_HEIGHT );
00410         glVertex3d( dW1 * OC_SQUARE_WIDTH, 0.0, (dH2+1) * OC_SQUARE_HEIGHT );
00411         glVertex3d( (dW2+1) * OC_SQUARE_WIDTH, 0.0, (dH2+1) * OC_SQUARE_HEIGHT );
00412         glVertex3d( (dW2+1) * OC_SQUARE_WIDTH, 0.0, dH1 * OC_SQUARE_HEIGHT );
00413 
00414         glEnd();
00415         glPopMatrix();
00416 
00417     //---- read the back buffer, double-buffering must be supported ! ----
00418         glReadBuffer( GL_BACK );
00419         glReadPixels( rcuiMouseX, iWinHeight-rcuiMouseY, 1, 1,
00420                 GL_RGB, GL_UNSIGNED_BYTE, rgbTab );
00421 
00422         switch (rgbTab[2]) {
00423             case 0: return false;
00424             case 10: // polygon A;
00425                 return GetSelectedWHFromLayer(
00426                     rcuiMouseX, rcuiMouseY,
00427                     ruiMapW, ruiMapH,
00428                     rcLayer,
00429                     aW1, aH1, aW2, aH2 );
00430 
00431             case 20: // polygon B;
00432                 return GetSelectedWHFromLayer(
00433                     rcuiMouseX, rcuiMouseY,
00434                     ruiMapW, ruiMapH,
00435                     rcLayer,
00436                     bW1, bH1, bW2, bH2 );
00437 
00438             case 30: // polygon C;
00439                 return GetSelectedWHFromLayer(
00440                     rcuiMouseX, rcuiMouseY,
00441                     ruiMapW, ruiMapH,
00442                     rcLayer,
00443                     cW1, cH1, cW2, cH2 );
00444 
00445             case 40: // polygon D;
00446                 return GetSelectedWHFromLayer(
00447                     rcuiMouseX, rcuiMouseY,
00448                     ruiMapW, ruiMapH,
00449                     rcLayer,
00450                     dW1, dH1, dW2, dH2 );
00451         }  // end of switch (rgbTab[2])
00452     }
00453     else {
00454 // the layer size is small enough so we consider each square as a polygon
00455         DisplayLayerSelection( rcLayer,
00456                     rcW1, rcH1, rcW2, rcH2 );
00457         return GetSelectedMapWH( rcuiMouseX, rcuiMouseY,
00458                          ruiMapW, ruiMapH );
00459     }
00460 // never reached
00461 }
00462 */
00463 
00464 
00465    /*=====================================================================*/
00466 /* TOKILL, unused 6 august 06
00467 void
00468 Renderer::SetGrid( const bool & rcbState )
00469 {
00470     this->bDisplayGrid = rcbState;
00471 }
00472 */
00473 
00474 
00475    /*=====================================================================*/
00476 void
00477 Renderer::ToggleGrid()
00478 {
00479     this->bDisplayGrid = bDisplayGrid ? false : true;
00480 
00481 // If we turn the grid display back on, we need to update the display list
00482     this->boolHeightChange = true;
00483 }
00484 
00485 
00486    /*=====================================================================*/
00487 void
00488 Renderer::ToggleCompass()
00489 {
00490     this->bDisplayCompass = !(bDisplayCompass);
00491 }
00492 
00493 
00494    /*=====================================================================*/
00495 void
00496 Renderer::ToggleProjection()
00497 {
00498     if (this->ubProjectionType == OC_PERSPECTIVE) {
00499         ubProjectionType = OC_ORTHOGONAL;
00500     }
00501     else {
00502         ubProjectionType = OC_PERSPECTIVE;
00503     }
00504 
00505 // reinit the projection matrix;
00506     SetWinSize( this->iWinWidth, this->iWinHeight );
00507 }
00508 
00509    /*=====================================================================*/
00510 void
00511 Renderer::ToggleWireFrame()
00512 {
00513     this->bWireFrame = !(bWireFrame);
00514     if (this->bWireFrame) {
00515         glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
00516     }
00517     else {
00518         glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
00519     }
00520 }
00521 
00522 
00523    /*=====================================================================*/
00524 void
00525 Renderer::DisplaySplash(
00526     const uint & rcuiX,
00527     const uint & rcuiY )
00528 {
00529     static uint w, h;
00530 
00531     if (!glIsTexture(_uiSplashTex))
00532         _uiSplashTex = Texture::Load( ocHomeDirPrefix( "graphism/gui/splash.png"), w, h );
00533 
00534 // Store and translate the splash to the specified OpenGL coordinates
00535     glPushAttrib( GL_ENABLE_BIT );
00536     glDisable( GL_LIGHTING );
00537     glEnable( GL_BLEND );
00538 //  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); already choosen
00539     glEnable( GL_TEXTURE_2D );
00540     glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
00541     glBindTexture( GL_TEXTURE_2D, _uiSplashTex );
00542 
00543     glPushMatrix();
00544     glLoadIdentity();
00545     glTranslatef(
00546         rcuiX + (this->iWinWidth-w) / 2, 
00547         rcuiY + (this->iWinHeight-h) / 2,
00548         0 );
00549     glMatrixMode( GL_PROJECTION );
00550     glPushMatrix();
00551     glLoadIdentity();
00552     gluOrtho2D( 0, this->iWinWidth-1, 0, this->iWinHeight-1 );
00553 
00554 //debug cout << "W: " << w << " /H: " << h << endl;
00555 
00556 // Display the textured quad
00557     glBegin( GL_QUADS );
00558     glTexCoord2i( 0, 0 ); glVertex2i( 1, 1 );
00559     glTexCoord2i( 0, 1 ); glVertex2i( 1, h );
00560     glTexCoord2i( 1, 1 ); glVertex2i( w, h );
00561     glTexCoord2i( 1, 0 ); glVertex2i( w, 1 );
00562     glEnd();
00563 
00564 // Retore the old matrix and attribs
00565     glPopMatrix();
00566     glMatrixMode( GL_MODELVIEW );
00567     glPopMatrix();
00568     glPopAttrib();  
00569 }
00570 
00571 
00572    /*=====================================================================*/
00573 void
00574 Renderer::Display(
00575     const Map* pcMap,
00576     const Layer* pcLayer )
00577 {
00578     static uint linear;
00579     static int w, l;
00580     static const Structure* pStructure;
00581 
00582 // Clear the color buffer ( the screen ) and the depth buffer
00583     glClearColor( OC_CLEAR_COLOR );
00584     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
00585 
00586 //---- prepare the world for rendering
00587     _PrepareView();
00588 
00589 // Display all the structure
00590     glPushMatrix();
00591     glTranslatef( 0., 0.05, 0. );
00592     linear = 0;
00593 // IF the graphic manager is created THEN draw
00594     if (gVars.gpGraphicMgr != NULL)
00595     for (l = 0; l < (int)_uiCityLength; l++) {
00596         for (w = 0; w < (int)_uiCityWidth; w++) {
00597             pStructure = pcLayer->GetLinearStructure( linear++ );
00598             if (pStructure != NULL)
00599                 gVars.gpGraphicMgr->DisplayStructure( pStructure, w, l );
00600         }
00601     }
00602     glPopMatrix();
00603 
00604 // Displays the grids of the map if the user wants it
00605 // it is translated up a little along the Oz axis
00606     if (this->bDisplayGrid) {
00607         _DisplayMapGrid( pcMap );
00608     }
00609 
00610 // Display the status bar
00611     _DisplayStatusBar();
00612 
00613 // Call the private method to display the height map
00614     _DisplayTerrain();
00615 
00616 // Display the water texture
00617     _DisplayWater();
00618 
00619     glFlush();
00620 
00621 // The height map changes have been memorized
00622 // in the grid and the terrain displaylist
00623     boolHeightChange = false;
00624 
00625 // GL error checking
00626     static GLint glerr;
00627     glerr = glGetError();
00628     if (glerr != GL_NO_ERROR) {
00629         OPENCITY_DEBUG( "GL ERROR" );
00630         cerr << "GLError was: " << glerr << endl;
00631     }
00632 }
00633 
00634 
00635    /*=====================================================================*/
00636 void
00637 Renderer::DisplayHighlight(
00638     const Map* pcMap,
00639     const Layer* pcLayer,
00640     const OPENCITY_TOOL_CODE & enumTool )
00641 {
00642     DisplayHighlight(
00643         pcMap, pcLayer,
00644         0, 0,
00645         _uiCityWidth-1, _uiCityLength-1,
00646         enumTool );
00647 }
00648 
00649 
00650    /*=====================================================================*/
00651 void
00652 Renderer::DisplayHighlight(
00653     const Map* pcMap,
00654     const Layer* pcLayer,
00655     uint uiW1,
00656     uint uiL1,
00657     uint uiW2,
00658     uint uiL2,
00659     const OPENCITY_TOOL_CODE & enumTool )
00660 {
00661     uint linear;
00662     uint w, l;
00663     const Structure * pStructure;
00664 
00665 // Doing some swapping
00666     OPENCITY_SWAP( uiW1, uiW2, uint );
00667     OPENCITY_SWAP( uiL1, uiL2, uint );
00668 
00669 // Display the current layer & map first
00670     Display( pcMap, pcLayer );
00671 
00672 // Prepare the world for rendering
00673     _PrepareView();
00674 
00675 // Now let's display all the structures in selection mode
00676     glPushMatrix();
00677     glTranslatef( 0., 0.1, 0. );
00678     for (l = uiL1; l <= uiL2; l++) {
00679         linear = l*_uiCityWidth + uiW2;
00680         for (w = uiW1; w <= uiW2; w++) {
00681             pStructure = pcLayer->GetLinearStructure( linear );
00682         // display the correction structure/terrain
00683         // with "linear" as objectID
00684             if ( pStructure == NULL)
00685                 gVars.gpGraphicMgr->DisplayTerrainHighlight( w, l, enumTool );
00686             else
00687                 gVars.gpGraphicMgr->
00688                 DisplayStructureHighlight( pStructure, w, l, enumTool );
00689 
00690             ++linear;
00691         }
00692     }
00693     glPopMatrix();
00694 }
00695 
00696 
00697    /*=====================================================================*/
00698 void
00699 Renderer::DisplayBuildPreview(
00700     const uint & uiW,
00701     const uint & uiL,
00702     const GLubyte & rcubR,
00703     const GLubyte & rcubG,
00704     const GLubyte & rcubB,
00705     const OPENCITY_GRAPHIC_CODE & gcode ) const
00706 {
00707     static uint sw, sl, sh;
00708     static int iH;
00709 
00710 // Save the current model view matrix
00711     glPushMatrix();
00712 
00713 // Display the graphic code
00714     glTranslatef( 0., 0.15, 0. );
00715     gVars.gpGraphicMgr->DisplayGC( gcode, uiW, uiL );
00716 
00717 // Get the maximum square height
00718     iH = gVars.gpMapMgr->GetSquareMaxHeight( uiW, uiL );
00719 
00720 // Get the graphic code dimensions in order to draw the bounding rectangle
00721     gVars.gpPropertyMgr->GetWLH( gcode, sw, 4, sl, 4, sh, 1 );
00722     glEnable( GL_BLEND );
00723     glTranslatef( .0f, 0.1f, .0f );
00724     glColor4ub( rcubR, rcubG, rcubB, 64 );
00725     glBegin( GL_QUADS );
00726         glVertex3i( uiW,    iH, uiL   );
00727         glVertex3i( uiW,    iH, uiL+sl );
00728         glVertex3i( uiW+sw, iH, uiL+sl );
00729         glVertex3i( uiW+sw, iH, uiL );
00730     glEnd();
00731     glDisable( GL_BLEND );
00732 
00733 // Restore the model view matrix
00734     glPopMatrix();
00735 }
00736 
00737 
00738    /*=====================================================================*/
00739 void
00740 Renderer::DisplaySelection(
00741     const Map* pcMap,
00742     const Layer* pcLayer )
00743 {
00744     DisplaySelection(
00745         pcMap, pcLayer,
00746         0, 0,
00747         _uiCityWidth-1, _uiCityLength-1 );
00748 }
00749 
00750 
00751    /*=====================================================================*/
00752 void
00753 Renderer::DisplaySelection(
00754     const Map* pcMap,
00755     const Layer* pcLayer,
00756     const uint & rcuiW1,
00757     const uint & rcuiL1,
00758     const uint & rcuiW2,
00759     const uint & rcuiL2 )
00760 {
00761 
00762 }
00763 
00764 
00765    /*=====================================================================*/
00766 /* TOKILL, old selection method, kept for reference
00767 void
00768 Renderer::DisplaySelection2(
00769     const Map* pcMap,
00770     const Layer* pcLayer,
00771     const uint & rcuiW1,
00772     const uint & rcuiL1,
00773     const uint & rcuiW2,
00774     const uint & rcuiL2 )
00775 {
00776     uint linear;
00777     uint w, l;
00778     const Structure * pStructure;
00779 
00780 // Save all the enabled states
00781     glPushAttrib( GL_ENABLE_BIT );
00782     glDisable( GL_LIGHTING );
00783 
00784 // Clear the color buffer ( the screen )
00785     glClearColor( 0.0, 0.0, 0.0, 0.0 );
00786     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
00787 
00788 // Prepare the world for rendering
00789     _PrepareView();
00790 
00791 // Now let's display all the structures in selection mode
00792     glBegin( GL_QUADS );
00793     linear = 0;
00794     for (l = 0; l < this->uiCityLength; l++) {
00795         for (w = 0; w < this->uiCityWidth; w++) {
00796             pStructure = pcLayer->GetLinearStructure( linear );
00797         // display the correction structure/terrain
00798         // with "linear" as objectID
00799         // note: linear = 0 is not used since it means blank
00800         // bland = there's no structure under the selection
00801             if ( pStructure == NULL)
00802                 gVars.gpGraphicMgr->DisplayTerrainSelection( w, l, ++linear );
00803             else
00804                 gVars.gpGraphicMgr->DisplayStructureSelection( pStructure, w, l, ++linear );
00805             //ATTENTION: "linear++;" already done !
00806         }
00807     }
00808     glEnd();
00809 
00810 // Restore all the enabled states
00811     glPopAttrib();
00812     glFlush();
00813 
00814 // GL error checking
00815     if (glGetError() != GL_NO_ERROR) {
00816         OPENCITY_DEBUG( "GL ERROR" );
00817     }
00818 }
00819 */
00820 
00821 
00822    /*=====================================================================*/
00823 void
00824 Renderer::DisplayText(
00825     const uint & rcuiX,
00826     const uint & rcuiY,
00827     const GLubyte & rcubR,
00828     const GLubyte & rcubG,
00829     const GLubyte & rcubB,
00830     const string & rcText)
00831 {
00832 // Render in 2D, orthogonal projection
00833     glPushMatrix();
00834     glLoadIdentity();
00835     glMatrixMode( GL_PROJECTION );
00836     glPushMatrix();
00837     glLoadIdentity();
00838     gluOrtho2D( 0, this->iWinWidth-1, 0, this->iWinHeight-1 );
00839 
00840 // Save the list base
00841     glTranslatef( .0, .0, .1 );
00842     glPushAttrib( GL_LIST_BIT | GL_ENABLE_BIT );
00843     glDisable( GL_LIGHTING );
00844     glListBase( this->_uiFontBase );
00845 
00846     glColor4ub( rcubR, rcubG, rcubB, 255 );
00847     glRasterPos2i( rcuiX, rcuiY );
00848     glCallLists( (GLsizei)rcText.size(), GL_UNSIGNED_BYTE, (GLubyte*)rcText.c_str() );
00849     glPopAttrib();
00850 
00851     glPopMatrix();
00852     glMatrixMode( GL_MODELVIEW );
00853     glPopMatrix();
00854 }
00855 
00856 
00857    /*=====================================================================*/
00858 const bool
00859 Renderer::GetSelectedWHFrom(
00860     const uint & rcuiMouseX,
00861     const uint & rcuiMouseY,
00862     uint & ruiW,
00863     uint & ruiL,
00864     const Map* pcMap,
00865     const Layer* pcLayer )
00866 {
00867 // call the right method with appropriate values
00868     return GetSelectedWHFrom(
00869         rcuiMouseX,
00870         rcuiMouseY,
00871         ruiW,
00872         ruiL,
00873         pcMap,
00874         pcLayer,
00875         0, 0,
00876         _uiCityWidth-1, _uiCityLength-1 );
00877 }
00878 
00879 
00880    /*=====================================================================*/
00881 const bool
00882 Renderer::GetSelectedWHFrom(
00883     const uint & rcuiMouseX,
00884     const uint & rcuiMouseY,
00885     uint & ruiW,
00886     uint & ruiL,
00887     const Map* pcMap,
00888     const Layer* pcLayer,
00889     const uint & rcuiW1,
00890     const uint & rcuiL1,
00891     const uint & rcuiW2,
00892     const uint & rcuiL2 )
00893 {
00894     static uint id;
00895     static uint linear;
00896     static uint w, l;
00897     static const Structure * pStructure;
00898 
00899     #define OC_SELECT_BUFFER_SIZE 100
00900     static GLuint selectBuffer[OC_SELECT_BUFFER_SIZE];
00901     static GLuint uiDepthMin;
00902     static GLint iHits;
00903     static GLint viewport[4] = {0, 0, 0, 0};
00904 
00905 // Prepare the select buffer and enter selection mode
00906     glSelectBuffer( OC_SELECT_BUFFER_SIZE, selectBuffer );
00907     (void)glRenderMode( GL_SELECT );
00908     glInitNames();
00909     glPushName(0);
00910 
00911 // Create the pick matrix
00912     glMatrixMode( GL_PROJECTION );
00913     glPushMatrix();
00914     glLoadIdentity();
00915     viewport[2] = this->iWinWidth;
00916     viewport[3] = this->iWinHeight;
00917     gluPickMatrix( rcuiMouseX, this->iWinHeight-rcuiMouseY, 2, 2, viewport );
00918     if ( this->ubProjectionType == OC_PERSPECTIVE ) {
00919         gluPerspective(
00920             OC_VIEW_ANGLE,
00921             (GLfloat)this->iWinWidth / (GLfloat)this->iWinHeight,
00922             OC_Z_NEAR, OC_Z_FAR );
00923     }
00924     else {
00925         glOrtho(
00926             0.0, (GLdouble)this->iWinWidth,
00927             0.0, (GLdouble)this->iWinHeight,
00928             OC_Z_NEAR_ORTHO, OC_Z_FAR);
00929     }
00930 
00931 // Save all the enabled states
00932     glPushAttrib( GL_ENABLE_BIT );
00933     glDisable( GL_LIGHTING );
00934 
00935 // Clear the color buffer ( the screen )
00936     glClearColor( 0.0, 0.0, 0.0, 0.0 );
00937     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
00938 
00939 // Prepare the world for rendering
00940     _PrepareView();
00941 
00942 // Now let's display all the structures in selection mode
00943     linear = 0;
00944     for (l = 0; l < _uiCityLength; l++) {
00945         for (w = 0; w < _uiCityWidth; w++) {
00946             pStructure = pcLayer->GetLinearStructure( linear );
00947         // display the correction structure/terrain
00948         // with "linear" as objectID
00949         // note: linear = 0 is not used since it means blank
00950         // bland = there's no structure under the selection
00951             if ( pStructure == NULL)
00952                 gVars.gpGraphicMgr->DisplayTerrainSelection( w, l, ++linear );
00953             else
00954                 gVars.gpGraphicMgr->DisplayStructureSelection( pStructure, w, l, ++linear );
00955             //ATTENTION: "linear++;" already done !
00956         }
00957     }
00958 
00959 // Restore all the enabled states
00960     glPopAttrib();
00961     glMatrixMode( GL_PROJECTION );
00962     glPopMatrix();
00963     glMatrixMode( GL_MODELVIEW );
00964     glFlush();
00965 
00966 // GL error checking
00967     if (glGetError() != GL_NO_ERROR) {
00968         OPENCITY_DEBUG( "GL ERROR" );
00969     }
00970 
00971 // Process the hits
00972     iHits = glRenderMode( GL_RENDER );
00973 //debug cout << "Number of hits: " << iHits << endl;
00974     if (iHits > 0) {
00975     // We only consider the hit which is nearest to the user
00976         uiDepthMin = 0xFFFFFFFF - 1;
00977         while (iHits-- > 0) {
00978             if (uiDepthMin > selectBuffer[ iHits*4 + 1 ]) {
00979                 uiDepthMin = selectBuffer[ iHits*4 + 1 ];
00980                 id = selectBuffer[ iHits*4 + 3 ] - 1;
00981             }
00982         }
00983 //debug // cout << "Min depth: " << uiDepthMin << endl;
00984         ruiL = id / _uiCityWidth;
00985         ruiW = id % _uiCityWidth;
00986         return true;
00987     }
00988 
00989     return false; // couldn't determine the W & L values
00990 }
00991 
00992 
00993    /*=====================================================================*/
00994 void
00995 Renderer::SetWinSize(
00996     const int & rciWidth,
00997     const int & rciHeight )
00998 {
00999     this->iWinWidth = rciWidth;
01000     this->iWinHeight = rciHeight;
01001 
01002 // Set the view port
01003     glViewport( 0, 0, rciWidth, rciHeight );
01004 
01005 
01006 // Set the projection matrix
01007     glMatrixMode( GL_PROJECTION );
01008     glLoadIdentity();
01009     if ( this->ubProjectionType == OC_PERSPECTIVE ) {
01010         gluPerspective(
01011             OC_VIEW_ANGLE,
01012             (GLfloat)this->iWinWidth / (GLfloat)this->iWinHeight,
01013             OC_Z_NEAR, OC_Z_FAR );
01014     }
01015     else {
01016         glOrtho(
01017             0.0, (GLdouble)this->iWinWidth,
01018             0.0, (GLdouble)this->iWinHeight,
01019             OC_Z_NEAR_ORTHO, OC_Z_FAR);
01020     }
01021 }
01022 
01023 
01024    /*=====================================================================*/
01025 void
01026 Renderer::_DisplayTerrain() const
01027 {
01028     if (boolHeightChange == false)
01029         goto displayterrain_return;
01030 
01031     static OC_BYTE tabH [4];
01032     static GLfloat ax, ay, az;
01033     static GLfloat bx, by, bz;
01034     static GLfloat n1x, n1y, n1z;       // normal 1 coordinates
01035     static GLfloat n2x, n2y, n2z;       // normal 2 coordinates
01036     static int l, w;                    // WARNING: yes, we use INT not UINT
01037 
01038 // Reserve a new display list for the terrain
01039     glNewList( _uiTerrainList, GL_COMPILE );
01040 
01041 // WARNING: this is used to calculated the final textured fragment.
01042     glColor4f( .3, .25, .2, 1. );
01043 
01044 // Enable terrain texturing
01045     glPushAttrib( GL_ENABLE_BIT );
01046     glEnable( GL_TEXTURE_2D );
01047     glBindTexture( GL_TEXTURE_2D, _uiTerrainTex );
01048     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
01049     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
01050     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
01051 
01052 // BEGIN, draw the terrain as an unique TRIANGLE_STRIP
01053 // which is known as the fastest figure in OpenGL
01054 /* This is the secret formula: c = a^b ;)
01055         cx = ay * bz - by * az;
01056         cy = bx * az - ax * bz;
01057         cz = ax * by - bx * ay;
01058 */
01059     glBegin( GL_TRIANGLE_STRIP );
01060 
01061     for (l = 0; l < (int)_uiCityLength; l++) {
01062     // IF we draw the squares from left to right THEN
01063         if (l % 2 == 0) {
01064         // Get the 4 heights of the current square
01065             w = 0;
01066             gVars.gpMapMgr->GetSquareHeight( w, l, tabH );
01067         // calculate the new normal 1 (the cross product)
01068             ax = 0.;   ay = (GLfloat)(tabH[1]-tabH[0]); az = 1.;
01069             bx = 1.;   by = (GLfloat)(tabH[3]-tabH[0]); bz = .0;
01070             n1x = -by; n1y = 1.;                        n1z = -ay;
01071         // calculate the new normal 2 (the cross product)
01072             ax = 1.;   ay = (GLfloat)(tabH[2]-tabH[1]); az = .0;
01073             bx = .0;   by = (GLfloat)(tabH[3]-tabH[2]); bz = -1.;
01074             n2x = -ay; n2y = 1.;                        n2z = by;
01075 
01076         // Set the first normal and the first pair of vertices
01077             glNormal3f( n1x, n1y, n1z );
01078             glTexCoord2i( w, l );
01079             glVertex3i( w, tabH[0], l );
01080             glTexCoord2i( w, l+1 );
01081             glVertex3i( w, tabH[1], l+1 );
01082 
01083             for (w = 1; w < (int)_uiCityWidth; w++) {
01084             // Get the 4 heights of the current square
01085                 gVars.gpMapMgr->GetSquareHeight( w, l, tabH );
01086             // draw the stuff
01087                 glNormal3f( n1x, n1y, n1z );
01088                 glTexCoord2i( w, l );
01089                 glVertex3i( w, tabH[0], l );
01090                 glNormal3f( n2x, n2y, n2z );
01091                 glTexCoord2i( w, l+1 );
01092                 glVertex3i( w, tabH[1], l+1 );
01093 
01094             // calculate the new normal 1 (the cross product)
01095                 ax = 0.;   ay = (GLfloat)(tabH[1]-tabH[0]); az = 1.;
01096                 bx = 1.;   by = (GLfloat)(tabH[3]-tabH[0]); bz = .0;
01097                 n1x = -by; n1y = 1.;                        n1z = -ay;
01098             // calculate the new normal 2 (the cross product)
01099                 ax = 1.;   ay = (GLfloat)(tabH[2]-tabH[1]); az = .0;
01100                 bx = .0;   by = (GLfloat)(tabH[3]-tabH[2]); bz = -1.;
01101                 n2x = -ay; n2y = 1.;                        n2z = by;
01102             } // for
01103 
01104         // Draw the last edge
01105             glNormal3f( n1x, n1y, n1z );
01106             glTexCoord2i( w, l );
01107             glVertex3i( w, tabH[3], l );
01108             glNormal3f( n2x, n2y, n2z );
01109             glTexCoord2i( w, l+1 );
01110             glVertex3i( w, tabH[2], l+1 );
01111         // Then prepare the triangles for the next line
01112             glVertex3i( w, tabH[2], l+1 );
01113         }
01114         else {
01115         // WARNING: repeated codes as above ================================
01116         // We draw the square from right to left
01117         // Get the 4 heights of the current square
01118             w = _uiCityWidth-1;
01119             gVars.gpMapMgr->GetSquareHeight( w, l, tabH );
01120 
01121         // calculate the new normal 1 (the cross product)
01122             ax = -1.;  ay = (GLfloat)(tabH[0]-tabH[3]); az = .0;
01123             bx =  .0;  by = (GLfloat)(tabH[2]-tabH[3]); bz = 1.;
01124             n1x = ay;  n1y = 1.;                        n1z = -by;
01125         // calculate the new normal 2 (the cross product)
01126             ax = 1.;   ay = (GLfloat)(tabH[2]-tabH[1]); az = .0;
01127             bx = .0;   by = (GLfloat)(tabH[0]-tabH[1]); bz = -1.;
01128             n2x = -ay; n2y = 1.;                        n2z = by;
01129 
01130         // Set the first normal and the first pair of vertices
01131             glNormal3f( n1x, n1y, n1z );
01132             glTexCoord2i( w+1, l );
01133             glVertex3i( w+1, tabH[3], l );
01134             glTexCoord2i( w+1, l+1 );
01135             glVertex3i( w+1, tabH[2], l+1 );
01136 
01137             for (w = _uiCityWidth-2; w >= 0; w--) {
01138         // Get the 4 heights of the current square
01139                 gVars.gpMapMgr->GetSquareHeight( w, l, tabH );
01140         // draw the stuff
01141                 glNormal3f( n1x, n1y, n1z );
01142                 glTexCoord2i( w+1, l );
01143                 glVertex3i( w+1, tabH[3], l );
01144                 glNormal3f( n2x, n2y, n2z );
01145                 glTexCoord2i( w+1, l+1 );
01146                 glVertex3i( w+1, tabH[2], l+1 );
01147 
01148             // calculate the new normal 1 (the cross product)
01149                 ax = -1.;  ay = (GLfloat)(tabH[0]-tabH[3]); az = .0;
01150                 bx =  .0;  by = (GLfloat)(tabH[2]-tabH[3]); bz = 1.;
01151                 n1x = ay;  n1y = 1.;                        n1z = -by;
01152             // calculate the new normal 2 (the cross product)
01153                 ax = 1.;   ay = (GLfloat)(tabH[2]-tabH[1]); az = .0;
01154                 bx = .0;   by = (GLfloat)(tabH[0]-tabH[1]); bz = -1.;
01155                 n2x = -ay; n2y = 1.;                        n2z = by;
01156             }
01157 
01158         // Draw the last edge
01159             glNormal3f( n1x, n1y, n1z );
01160             glTexCoord2i( w+1, l );
01161             glVertex3i( w+1, tabH[0], l );
01162             glNormal3f( n2x, n2y, n2z );
01163             glTexCoord2i( w+1, l+1 );
01164             glVertex3i( w+1, tabH[1], l+1 );
01165         // Then prepare the triangles for the next line
01166             glVertex3i( w+1, tabH[1], l+1 );
01167         }
01168     }
01169 // then restore the default normal
01170     glNormal3f( 0., 0., 1. );
01171     glEnd();
01172 // END: Draw the terrain by using GL_TRIANGLE_STRIP
01173 
01174 // Restore old attribs
01175     glPopAttrib();
01176     glEndList();
01177 
01178 displayterrain_return:
01179     glCallList( _uiTerrainList );
01180 }
01181 
01182 
01183    /*=====================================================================*/
01184 void
01185 Renderer::_DisplayWater() const
01186 {
01187 #define WATER_HEIGHT    -.15
01188 
01189     static bool initialized = false;
01190 
01191 // IF the display list is already initialized THEN
01192     if (initialized)
01193         goto displaywater_return;
01194     else
01195         initialized = true;
01196 
01197     static GLfloat ax, ay, az;
01198     static GLfloat bx, by, bz;
01199     static GLfloat n1x, n1y, n1z;       // normal 1 coordinates
01200     static GLfloat n2x, n2y, n2z;       // normal 2 coordinates
01201     static int l, w;                    // WARNING: yes, we use INT not UINT
01202 
01203 // Reserve a new display list for the terrain
01204     glNewList( _uiWaterList, GL_COMPILE );
01205 
01206 // WARNING: this is used to calculated the final textured fragment.
01207     glColor4f( .3, .25, .2, 1. );
01208 
01209 // Enable terrain texturing
01210     glPushAttrib( GL_ENABLE_BIT );
01211     glEnable( GL_TEXTURE_2D );
01212     glBindTexture( GL_TEXTURE_2D, _uiWaterTex );
01213     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
01214     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
01215     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
01216 
01217 // BEGIN, draw the terrain as an unique TRIANGLE_STRIP
01218 // which is known as the fastest figure in OpenGL
01219 /* This is the secret formula: c = a^b ;)
01220         cx = ay * bz - by * az;
01221         cy = bx * az - ax * bz;
01222         cz = ax * by - bx * ay;
01223 */
01224     glBegin( GL_TRIANGLE_STRIP );
01225 
01226     for (l = 0; l < (int)_uiCityLength; l++) {
01227     // IF we draw the squares from left to right THEN
01228         if (l % 2 == 0) {
01229         // Get the 4 heights of the current square
01230             w = 0;
01231         // calculate the new normal 1 (the cross product)
01232             ax = 0.;   ay = WATER_HEIGHT; az = 1.;
01233             bx = 1.;   by = WATER_HEIGHT; bz = .0;
01234             n1x = -by; n1y = 1.; n1z = -ay;
01235         // calculate the new normal 2 (the cross product)
01236             ax = 1.;   ay = WATER_HEIGHT; az = .0;
01237             bx = .0;   by = WATER_HEIGHT; bz = -1.;
01238             n2x = -ay; n2y = 1.; n2z = by;
01239 
01240         // Set the first normal and the first pair of vertices
01241             glNormal3f( n1x, n1y, n1z );
01242             glTexCoord2i( w, l );
01243             glVertex3f( w, WATER_HEIGHT, l );
01244             glTexCoord2i( w, l+1 );
01245             glVertex3f( w, WATER_HEIGHT, l+1 );
01246 
01247             for (w = 1; w < (int)_uiCityWidth; w++) {
01248             // draw the stuff
01249                 glNormal3f( n1x, n1y, n1z );
01250                 glTexCoord2i( w, l );
01251                 glVertex3f( w, WATER_HEIGHT, l );
01252                 glNormal3f( n2x, n2y, n2z );
01253                 glTexCoord2i( w, l+1 );
01254                 glVertex3f( w, WATER_HEIGHT, l+1 );
01255 
01256             // calculate the new normal 1 (the cross product)
01257                 ax = 0.;   ay = WATER_HEIGHT; az = 1.;
01258                 bx = 1.;   by = WATER_HEIGHT; bz = .0;
01259                 n1x = -by; n1y = 1.; n1z = -ay;
01260             // calculate the new normal 2 (the cross product)
01261                 ax = 1.;   ay = WATER_HEIGHT; az = .0;
01262                 bx = .0;   by = WATER_HEIGHT; bz = -1.;
01263                 n2x = -ay; n2y = 1.; n2z = by;
01264             } // for
01265 
01266         // Draw the last edge
01267             glNormal3f( n1x, n1y, n1z );
01268             glTexCoord2i( w, l );
01269             glVertex3f( w, WATER_HEIGHT, l );
01270             glNormal3f( n2x, n2y, n2z );
01271             glTexCoord2i( w, l+1 );
01272             glVertex3f( w, WATER_HEIGHT, l+1 );
01273         // Then prepare the triangles for the next line
01274             glVertex3f( w, WATER_HEIGHT, l+1 );
01275         }
01276         else {
01277         // WARNING: repeated codes as above ================================
01278         // We draw the square from right to left
01279         // Get the 4 heights of the current square
01280             w = _uiCityWidth-1;
01281 
01282         // calculate the new normal 1 (the cross product)
01283             ax = -1.;  ay = WATER_HEIGHT; az = .0;
01284             bx =  .0;  by = WATER_HEIGHT; bz = 1.;
01285             n1x = ay;  n1y = 1.; n1z = -by;
01286         // calculate the new normal 2 (the cross product)
01287             ax = 1.;   ay = WATER_HEIGHT; az = .0;
01288             bx = .0;   by = WATER_HEIGHT; bz = -1.;
01289             n2x = -ay; n2y = 1.; n2z = by;
01290 
01291         // Set the first normal and the first pair of vertices
01292             glNormal3f( n1x, n1y, n1z );
01293             glTexCoord2i( w+1, l );
01294             glVertex3f( w+1, WATER_HEIGHT, l );
01295             glTexCoord2i( w+1, l+1 );
01296             glVertex3f( w+1, WATER_HEIGHT, l+1 );
01297 
01298             for (w = _uiCityWidth-2; w >= 0; w--) {
01299         // draw the stuff
01300                 glNormal3f( n1x, n1y, n1z );
01301                 glTexCoord2i( w+1, l );
01302                 glVertex3f( w+1, WATER_HEIGHT, l );
01303                 glNormal3f( n2x, n2y, n2z );
01304                 glTexCoord2i( w+1, l+1 );
01305                 glVertex3f( w+1, WATER_HEIGHT, l+1 );
01306 
01307             // calculate the new normal 1 (the cross product)
01308                 ax = -1.;  ay = WATER_HEIGHT; az = .0;
01309                 bx =  .0;  by = WATER_HEIGHT; bz = 1.;
01310                 n1x = ay;  n1y = 1.; n1z = -by;
01311             // calculate the new normal 2 (the cross product)
01312                 ax = 1.;   ay = WATER_HEIGHT; az = .0;
01313                 bx = .0;   by = WATER_HEIGHT; bz = -1.;
01314                 n2x = -ay; n2y = 1.; n2z = by;
01315             }
01316 
01317         // Draw the last edge
01318             glNormal3f( n1x, n1y, n1z );
01319             glTexCoord2i( w+1, l );
01320             glVertex3f( w+1, WATER_HEIGHT, l );
01321             glNormal3f( n2x, n2y, n2z );
01322             glTexCoord2i( w+1, l+1 );
01323             glVertex3f( w+1, WATER_HEIGHT, l+1 );
01324         // Then prepare the triangles for the next line
01325             glVertex3f( w+1, WATER_HEIGHT, l+1 );
01326         }
01327     }
01328 // then restore the default normal
01329     glNormal3f( 0., 0., 1. );
01330     glEnd();
01331 // END: Draw the terrain by using GL_TRIANGLE_STRIP
01332 
01333 // Restore old attribs
01334     glPopAttrib();
01335     glEndList();
01336 
01337 displaywater_return:
01338     glCallList( _uiWaterList );
01339 }
01340 
01341 
01342    /*=====================================================================*/
01343 void
01344 Renderer::_DisplayMapGrid( const Map* pcmap )
01345 {
01346     if (boolHeightChange == false)
01347         goto displaymapgrid_return;
01348 
01349     uint linear;
01350     uint w, l;
01351 
01352 // Create a new display list for the grid
01353     glNewList( _uiGridList, GL_COMPILE );
01354 
01355 // Enable line stipple
01356     glPushAttrib( GL_ENABLE_BIT );
01357     glDisable( GL_LIGHTING );
01358     glDisable( GL_BLEND );
01359     glLineStipple( 1, 0x3333 );
01360     glEnable( GL_LINE_STIPPLE );
01361 
01362 // Translate it a bit for a better view
01363     glPushMatrix();
01364     glTranslatef( 0.0, 0.05, 0.0 );
01365     glColor3ub( 120, 120, 120 ); // bright silver
01366 
01367 //--- horizontal lines ---
01368     linear = 0;
01369     for (l = 0; l <= _uiCityLength; l++) {
01370         glBegin( GL_LINE_STRIP );
01371         for (w = 0; w <= _uiCityWidth; w++) {
01372             glVertex3s( w, pcmap->GetLinearHeight( linear++ ), l );
01373         }
01374         glEnd();
01375     }
01376 
01377 //--- vertical lines ---
01378     for (w = 0; w <= _uiCityWidth; w++) {
01379         glBegin( GL_LINE_STRIP );
01380         linear = w;
01381         for (l = 0; l <= _uiCityLength; l++) {
01382             glVertex3s( w, pcmap->GetLinearHeight( linear ), l );
01383             linear += _uiCityWidth + 1;
01384         }
01385         glEnd();
01386     }
01387 
01388 // Restore the old matrix and attribs
01389     glPopMatrix();
01390     glPopAttrib();
01391     glEndList();
01392 
01393 displaymapgrid_return:
01394     glCallList( _uiGridList );
01395 }
01396 
01397 
01398    /*=====================================================================*/
01399 void
01400 Renderer::_DisplayCompass() const
01401 {
01402 // Display a simple compass
01403     glMatrixMode( GL_MODELVIEW );
01404     glTranslatef( iWinWidth-30, 30, 0 );
01405     glRotated( this->dYRotateAngle, .0, .0, 1. );
01406     glBegin( GL_LINES );
01407         glColor4f( .5, .5, .5, 1. );
01408         glVertex2i( -20, 0 );
01409         glVertex2i(  20, 0 );
01410         glColor4f( .8, .8, .8, 1. );
01411         glVertex2i( 0, -20 );
01412         glVertex2i( 0,  20 );
01413     glEnd();
01414     glBegin( GL_TRIANGLES );
01415         glVertex2i( -5, 14 );
01416         glVertex2i(  5, 14 );
01417         glVertex2i(  0, 20 );
01418     glEnd();
01419     glLoadIdentity();
01420     glMatrixMode( GL_PROJECTION );
01421 }
01422 
01423 
01424    /*=====================================================================*/
01425 void
01426 Renderer::_DisplayStatusBar() const
01427 {
01428 // We save the modelview matrix
01429     glPushMatrix();
01430     glLoadIdentity();
01431 
01432 // Save the old projection matrix before processing
01433     glMatrixMode( GL_PROJECTION );
01434     glPushMatrix();
01435     glLoadIdentity();
01436     gluOrtho2D( 0, this->iWinWidth-1, 0, this->iWinHeight-1 );
01437 
01438 // Draw the compass
01439     if (this->bDisplayCompass) {
01440         _DisplayCompass();
01441     }
01442 
01443 // Enable alpha blending
01444     glPushAttrib( GL_ENABLE_BIT );
01445     glDisable( GL_LIGHTING );
01446     glEnable( GL_BLEND );
01447 
01448 // Draw the blended status rectangle
01449     glColor4f( .1, .1, .1, .8 );
01450     glBegin( GL_QUADS );
01451         glVertex2i( 0, iWinHeight );
01452         glVertex2i( 0, iWinHeight-20 );
01453         glVertex2i( iWinWidth, iWinHeight-20 );
01454         glVertex2i( iWinWidth, iWinHeight );
01455     glEnd();
01456 //  glDisable( GL_BLEND );
01457     glPopAttrib();
01458 
01459 // Restore the projection matrix
01460     glPopMatrix();
01461 
01462 // Restore the modelview matrix
01463     glMatrixMode( GL_MODELVIEW );
01464     glPopMatrix();
01465 }
01466 
01467 
01468    /*=====================================================================*/
01469 void
01470 Renderer::_PrepareView() const
01471 {
01472 // Clear the ModelView matrix
01473     glMatrixMode( GL_MODELVIEW );
01474     glLoadIdentity();
01475 
01476 // Translate & rotate the map to create an view angle
01477     if ( ubProjectionType == OC_PERSPECTIVE ) {
01478         glRotated( 35, 1., .0, .0 );
01479         glTranslated( .0, -14.0, -20.0 );
01480     }
01481     else {
01482         glRotated( 45, 1., .0, .0 );
01483     // Center the world
01484         glTranslatef( iWinWidth / 2, -5., -iWinHeight / 2 );
01485     // Zoom a bit
01486         glScalef( 24., 24., 24. );
01487     }
01488     glScalef( fScaleRatio, fScaleRatio, fScaleRatio );
01489 
01490 
01491 /* you can replace the above commands by this // absolete, outdated
01492     gluLookAt( 0.0, 80.0, 200.0,
01493            0.0, 0.0, 0.0,
01494            0.0, 1.0, 0.0 );
01495 */
01496 
01497 // Translate all the scence according to dDeltaX & dDeltaZ
01498 // this translation is due to the direction keys
01499     glTranslated( this->dDeltaX, 0.0, this->dDeltaZ );
01500 
01501 // Rotate the scence to the required angle
01502     glMultMatrixd( this->dmatrixRotate );
01503 }
01504 
01505 
01506 
01507 
01508 
01509 
01510 
01511 
01512 
01513 
01514 
01515 
01516 
01517 
01518 
01519 
01520 
01521 
01522 
01523 
01524 
01525 
01526 
01527 
01528 
01529 
01530 
01531 
01532 
01533 
01534 

Generated on Sat Nov 11 10:21:10 2006 for OpenCity by  doxygen 1.4.2