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

TerrainManager.cpp

Go to the documentation of this file.
00001 /*
00002  * TerrainManager.cpp
00003  *
00004  * Part of Fly! Legacy project
00005  *
00006  * Copyright 2003-2005 Chris Wallace
00007  *
00008  * Fly! Legacy is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU General Public License as published by
00010  *   the Free Software Foundation; either version 2 of the License, or
00011  *   (at your option) any later version.
00012  *
00013  * Fly! Legacy is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  *   along with Fly! Legacy; if not, write to the Free Software
00020  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00032 #include "../Include/Globals.h"
00033 #include "../Include/Terrain.h"
00034 #include "../Include/Ui.h"
00035 #include "../Include/LogFile.h"
00036 
00037 using namespace std;
00038 
00039 //
00040 // CTerrainManager
00041 //
00042 CTerrainManager::CTerrainManager (void)
00043 {
00044   int i;
00045 
00046   // Instantiate SSG root for all terrain
00047   root = new ssgRoot;
00048   root->setName ("TerrainRoot");
00049 
00050   top = new ssgTransform;
00051   top->setName ("TerrainTop");
00052   root->addKid (top);
00053 
00054   // Open log file if INI setting is enabled
00055   log = NULL;
00056   i = 0;
00057   GetIniVar ("Logs", "logTerrainManager", &i);
00058   if (i != 0) {
00059     log = new CLogFile ("Logs\\TerrainManager.log", "w");
00060   }
00061 
00062   // Get terrain debug level
00063   debugLevel = 0;
00064   GetIniVar ("Debug", "terrainDebugLevel", &debugLevel);
00065 
00066   // Instantiate elevation database
00067   tedb = new CTileElevationDatabase;
00068 
00069   // Instantiate terrain type database
00070   ttdb = new CTerrainTypeDatabase;
00071 
00072   // Instantiate default texture database
00073   dtdb = new CDefaultTextureDatabase;
00074 
00075   // Instantiate scenery models database
00076   smdb = new CSceneryModelDatabase;
00077 
00078   // Instantiate transition mask database
00079   tmdb = new CTransitionMaskDatabase;
00080 
00081   // Instantiate water mask database
00082   wmdb = new CWaterMaskDatabase;
00083 
00084   // Instantiate scenery set database
00085   ssdb = new CScenerySetDatabase;
00086 
00087   // Update visibility settings from INI
00088   UpdateMaxVisibility ();
00089   UpdateMediumDetailRange ();
00090   UpdateHighDetailRange ();
00091 
00092   // WARNING : Cannot instantiate any terrain tile class instances here, since
00093   //   CTerrainManager must be instantiated and assigned to the globals in order
00094   //   for the tile classes to get the terrain debug level.
00095 
00096   // Set 'last' QGT indices so that first call to SetPosition will trigger a transition
00097   xLast = zLast = -1;
00098 }
00099 
00100 
00101 CTerrainManager::~CTerrainManager (void)
00102 {
00103   Log ("TerrainManager destructor starting\n");
00104 
00105   root->removeAllKids();
00106   delete root;
00107 
00108   // Delete CQuarterGlobeTiles
00109   set<CQuarterGlobeTile*>::iterator i;
00110   for (i=qFree.begin(); i!=qFree.end(); i++) {
00111     CQuarterGlobeTile *qgt = *i;
00112     if (qgt != NULL) ssgDeRefDelete (qgt);
00113   }
00114   for (i=qBusy.begin(); i!=qBusy.end(); i++) {
00115     CQuarterGlobeTile *qgt = *i;
00116     if (qgt != NULL) ssgDeRefDelete (qgt);
00117   }
00118 
00119   // Delete elevation database
00120   delete tedb;
00121   tedb = NULL;
00122 
00123   // Delete terrain type database
00124   delete ttdb;
00125   ttdb = NULL;
00126 
00127   // Delete default texture database
00128   delete dtdb;
00129   dtdb = NULL;
00130 
00131   // Delete scenery models database
00132   delete smdb;
00133   smdb = NULL;
00134 
00135   // Delete transition mask database
00136   delete tmdb;
00137   tmdb = NULL;
00138 
00139   // Delete water mask database
00140   delete wmdb;
00141   wmdb = NULL;
00142 
00143   // Delete scenery set database
00144   delete ssdb;
00145   ssdb = NULL;
00146 
00147   // Shut down log file if created
00148   if (log != NULL) {
00149     delete log;
00150   }
00151 }
00152 
00153 void CTerrainManager::SetCamera (SPosition pos, SPosition lookat, SVector orient)
00154 {
00155 /*
00156   char debug[80];
00157   sprintf (debug, "Eye pos : lat=%f  lon=%f  alt=%f  scale=%f",
00158     pos.lat, pos.lon, pos.alt, scale);
00159   DrawNoticeToUser (debug, 1);
00160 */
00161 
00162   // Set eye position
00163   SVector v;
00164   v = PosToScaledFlatCartesianQgt (pos);
00165   sgVec3 eye;
00166   sgSetVec3 (eye, v.x, v.y, v.z);
00167 
00168   // Set lookat position
00169   v = PosToScaledFlatCartesianQgt (lookat);
00170   sgVec3 tgt;
00171   sgSetVec3 (tgt, v.x, v.y, v.z);
00172 
00173   // Set up vector
00174   sgVec3 up;
00175   sgSetVec3 (up, 0, 0, 1);
00176 
00177   ssgSetCameraLookAt (eye, tgt, up);
00178 
00179   // Set clipping distance to visibility limit
00181   float scale = TerrainScale (pos);
00182   float nearClip = 25.0f;
00183   float visScaled = vis_feet / scale;
00184 //  float farClip = sqrt ((visScaled * visScaled) + (pos.alt * pos.alt));
00185   float farClip = visScaled * 1.2f;
00186   ssgSetNearFar (nearClip, farClip); 
00187 }
00188 
00189 /*
00190 void CTerrainManager::LoadQuarterGlobeTile (int x, int z, SPosition base)
00191 {
00192   bool loaded = false;
00193 
00194   // Check to see if QGT is already instantiated
00195 
00196   // If so, then reset the translation matrix for the new base position
00197 
00198   // Instantiate the QGT
00199 
00200   // Check QGT is already loaded
00201   vector<CQuarterGlobeTile*>::iterator i;
00202   for (i=qgtPool.begin(); i!=qgtPool.end(); i++) {
00203     CQuarterGlobeTile *qgt = *i;
00204     if (qgt->IsAssigned ()) {
00205       qgt->GetIndices (&qx, &qz);
00206       if (
00207       qgt->AssignIndices (x, z);
00208     }
00209   }
00210   int n = qgtList->getNumEntities();
00211   for (int i=0; i<n; i++) {
00212     CGlobeTile *globetile = (CGlobeTile *) gtList->getEntity(i);
00213     if ((globetile->GetX() == x) && (globetile->GetZ() == z)) {
00214       // Reset translation matrix of the GT for the new base position
00215       loaded = true;
00216       break;
00217     }
00218   }
00219 
00220   // Instantiate new globe tile
00221   if (!loaded) {
00222     CGlobeTile *globetile = new CGlobeTile (x, z);
00223     if (globetile != NULL) {
00224       // Translate from base coordinates
00225       gtList->addEntity (globetile);
00226 //      top->addKid (globetile->GetSSGEntity());
00227     } else {
00228       gtfo ("CTerrainManager::LoadGlobeTile : Bad globe tile %d,%d", x, z);
00229     }
00230   }
00231 }
00232 */
00233 
00234 
00235 void CTerrainManager::Prepare (void)
00236 {
00237   // Instantiate pool of QGTs
00238   int i;
00239   for (i=0; i<25; i++) {
00240     CQuarterGlobeTile *qgt = new CQuarterGlobeTile;
00241     qFree.insert (qgt);
00242   }
00243 
00244   // Set initial user position
00245   SPosition pos = globals->sit->GetUserVehicle()->GetPosition();
00246   SetPosition (pos);
00247 }
00248 
00249 #define QGT_INDEX(x,z)    (unsigned long)(x << 16 | z)
00250 
00251 void CTerrainManager::SetPosition (SPosition pos)
00252 {
00253   DEBUGLOG ("CTerrainManager::SetPosition lat=%f lon=%f", pos.lat, pos.lon);
00254 
00255   // Get QGT indices for new position
00256   int x, z;
00257   lat_lon_to_qgt (pos.lat, pos.lon, x, z);
00258 
00259   // If current QGT has changed, update QGT array pointers
00260   if ((x != xLast) || (z != zLast)) {
00261     set<unsigned long> setVisible;
00262     xLast = x;
00263     zLast = z;
00264 
00265     // Determine set of visible QGT indices
00266     int i, j;
00267     for (i=0; i<5; i++) {
00268       for (j=0; j<5; j++) {
00269         unsigned int qx = x + i - 2;
00270         unsigned int qz = z + j - 2;
00271         unsigned long index = QGT_INDEX (qx, qz);
00272         setVisible.insert (index);
00273       }
00274     }
00275 
00276     // Iterate over all loaded QGTs, removing any which are not potentially
00277     //   visible, and removing from the visible set any which are already loaded
00278     set<CQuarterGlobeTile*>::iterator qIter = qBusy.begin();
00279     while (qIter != qBusy.end()) {
00280       CQuarterGlobeTile *qgt = *qIter;
00281       unsigned int qx, qz;
00282       qgt->GetIndices (qx, qz);
00283       unsigned long index = QGT_INDEX (qx, qz);
00284       set<unsigned long>::iterator sIter = setVisible.find(index);
00285       if (sIter == setVisible.end()) {
00286         // This QGT is not in the potentially visible set; destroy it
00287         qgt->Destroy();
00288         qgt->UnassignIndices ();
00289         set<CQuarterGlobeTile*>::iterator eraseIter = qIter;
00290         qIter++;
00291         qBusy.erase (eraseIter);
00292         qFree.insert (qgt);
00293 //        top->removeKid (qgt);
00294       } else {
00295         // This QGT is already in the potentially visible set.  Remove the indices
00296         //   from the visible set since we don't need to check for it anymore
00297         setVisible.erase (sIter);
00298         qIter++;
00299       }
00300     }
00301 
00302     // All remaining members of the visible set must be loaded
00303     set<unsigned long>::iterator sIter;
00304     for (sIter=setVisible.begin(); sIter!=setVisible.end(); sIter++) {
00305       unsigned long index = *sIter;
00306       unsigned int qx = (index & 0xFFFF0000) >> 16;
00307       unsigned int qz = index & 0x0000FFFF;
00308 
00309       // Get a QTR from the free set and move it to the busy set
00310       if (qFree.size() == 0) {
00311         gtfo ("CTerrainManager::SetPosition : No free QGT available");
00312       }
00313       set<CQuarterGlobeTile*>::iterator qIter = qFree.begin();
00314       CQuarterGlobeTile *qgt = *qIter;
00315       qFree.erase (qIter);
00316       qBusy.insert (qgt);
00317 
00318       // Assign new indices and create geometry
00319       qgt->AssignIndices (qx, qz);
00320       qgt->Create();
00321       top->addKid (qgt);
00322     }
00323   }
00324 
00325   // Update position for all loaded QGTs
00326   set<CQuarterGlobeTile*>::iterator i;
00327   for (i=qBusy.begin(); i!=qBusy.end(); i++) {
00328     CQuarterGlobeTile *qgt = *i;
00329     if (qgt->IsAssigned()) qgt->UpdatePosition (pos);
00330   }
00331 
00332   // Update top-level scaling
00333   float scale = TerrainScale (pos);
00334   sgMat4 S;
00335   sgMakeIdentMat4 (S);
00336   S[0][0] = scale;
00337   S[1][1] = scale;
00338   top->setTransform (S);
00339 }
00340 
00341 
00342 //
00343 // Return the maximum terrain range in statute miles
00344 //
00345 float CTerrainManager::GetMaxVisibility (void)
00346 {
00347   return (visibility);
00348 }
00349 
00350 //
00351 // Return the range for medium-detail terrain textures in statute miles
00352 //
00353 float CTerrainManager::GetMediumDetailRange (void)
00354 {
00355   return (medium_detail);
00356 }
00357 
00358 //
00359 // Return the range for high-detail terrain textures in statute miles
00360 //
00361 float CTerrainManager::GetHighDetailRange (void)
00362 {
00363   return (high_detail);
00364 }
00365 
00366 void CTerrainManager::UpdateMaxVisibility (void)
00367 {
00368   // Get maximum visibility from INI setting
00369   float miles = 20;
00370   GetIniFloat ("Graphics", "maxUserVisibility", &miles);
00371 
00372   // Store visibility in feet
00373   visibility = miles;
00374   vis_feet = visibility * FEET_PER_MILE;
00375   vis_check = vis_feet * 1.5f;
00376 }
00377 
00378 void CTerrainManager::UpdateMediumDetailRange (void)
00379 {
00380   // Get medium detail texture range from INI setting
00381   float miles = 0;
00382   GetIniFloat ("Graphics", "medDetailRadius", &miles);
00383 
00384   // Store medium detail radius in feet
00385   medium_detail = miles;
00386 }
00387 
00388 void CTerrainManager::UpdateHighDetailRange (void)
00389 {
00390   // Get high detail texture range from INI setting
00391   float miles = 0;
00392   GetIniFloat ("Graphics", "highDetailRadius", &miles);
00393 
00394   // Store medium detail radius in feet
00395   high_detail = miles;
00396 }
00397 
00398 void CTerrainManager::Draw (void)
00399 {
00400   // Get user position, this is the origin point for the rendered world
00401   SPosition pos = globals->sit->GetUserVehicle()->GetPosition();
00402   float scale = TerrainScale (pos);
00403   SetPosition (pos);
00404 
00405   // Wireframe mode for testing
00406   if (globals->settings->terrainWireframe) {
00407     glPushAttrib (GL_ENABLE_BIT | GL_FOG_BIT | GL_TRANSFORM_BIT | GL_POLYGON_BIT);
00408     glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
00409   } else {
00410     glPushAttrib (GL_ENABLE_BIT | GL_FOG_BIT | GL_TRANSFORM_BIT);
00411   }
00412 
00413   // Enable fog
00414 
00416   
00420   
00421   glEnable (GL_FOG);
00422   GLint fogMode = GL_EXP;
00423   glFogi (GL_FOG_MODE, fogMode);
00424   GLfloat fogColour[4] = {1.0, 1.0, 1.0, 1.0};
00425   glFogfv (GL_FOG_COLOR, fogColour);
00426   glFogf (GL_FOG_DENSITY, 5.0E-6);
00427   glHint (GL_FOG_HINT, GL_DONT_CARE);
00428   glFogf (GL_FOG_START, 20.0);
00429   glFogf (GL_FOG_END, (vis_feet / scale) * 1.2f);
00430 
00431   glEnable (GL_DEPTH_TEST);
00432 
00434 
00435   // Draw terrain root
00436   ssgCullAndDraw (root);
00437 
00438   // Restore GL attributes
00439   glPopAttrib ();
00440 }
00441 
00442 void CTerrainManager::Log (const char *fmt, ...)
00443 {
00444   if (log) {
00445     va_list argp;
00446     va_start(argp, fmt);
00447     log->Write (fmt, argp);
00448     va_end(argp);
00449   }
00450 }
00451 
00452 void CTerrainManager::Print (FILE* f)
00453 {
00454   root->print (f, " ", 4);
00455 }
00456 
00457 /*********************************************************
00458  * Experimental code to export very large terrain area
00459  *   textures for debugging of algorithms.  These are not
00460  *   currently being used, they are candidates for eventual
00461  *   removal.
00462  
00463 //
00464 // Custom error handling for JPEG library routines
00465 //
00466 struct my_error_mgr {
00467   struct jpeg_error_mgr pub;
00468   jmp_buf setjmp_buffer;
00469 };
00470 
00471 typedef struct my_error_mgr * my_error_ptr;
00472 
00473 METHODDEF(void)
00474 my_error_exit (j_common_ptr cinfo)
00475 {
00476   // cinfo->err really points to a my_error_mgr struct, so coerce pointer
00477   my_error_ptr myerr = (my_error_ptr) cinfo->err;
00478 
00479   //  Always display the message.
00480   // We could postpone this until after returning, if we chose.
00481   (*cinfo->err->output_message) (cinfo);
00482 
00483   // Return control to the setjmp point
00484   longjmp(myerr->setjmp_buffer, 1);
00485 }
00486 
00487 
00488 void CTerrainManager::ExportElevationTileTexture (int tile)
00489 {
00490   int resolution = 8192;
00491 
00492   // Determine globe tile x, z indices of south-west corner in elevation tile
00493   int base_gt_x = (tile & 0x1F) * 8;
00494   int base_gt_z = (32 - ((tile >> 5) & 0x1F) - 1) * 8;
00495 
00496   // Declare storage for the complete bitmap...192 MB!!
00497   GLubyte *image = new GLubyte[resolution * resolution * 3];
00498 
00499   // Loop over the 8x8 globe tile grid
00500   for (int gz = 7; gz >= 0; gz--) {
00501     int gt_z = base_gt_z + gz;
00502     for (int gx = 0; gx < 8; gx++) {
00503       int gt_x = base_gt_x + gx;
00504 
00505       // Loop over the 64x64 grid of detail tiles in the globe tile
00506       for (int z = 63; z >= 0; z--) {
00507         int dt_z = (gt_z * 64) + z;
00508         for (int x = 0; x < 64; x++) {
00509           int dt_x = (gt_x * 64) + x;
00510           // Get raw image data for the detail tile
00511 
00512           // TEMP : Comment out code to get fully transitioned detail tile
00513 //          CRawImage *r = GetDetailTileTexture (dt_x, dt_z, TILE_DETAIL_LOW);
00514 
00515           // TEMP : Just get basic terrain tile without transitioning
00516           ETerrainType tt = ttdb->GetTerrainType (dt_x, dt_z);
00517           CRawImage *r = new CRawImage (*(dtdb->GetRawImage (dt_x, dt_z, tt, TILE_DETAIL_LOW)));
00518 
00519           GLubyte *dt_image = r->GetRGBImageData();
00520           int dt_span = (64 * 3);
00521 
00522           // Transfer/compress detail tile to elevation tile texture images
00523           // Don't invert z-loop since we are copying from north-up image
00524           //   data in the detail tile texture to north-up image data
00525           //   in the elevation texture
00526           int scale = 16;
00527           for (int sz = 0; sz < scale; sz++) {
00528             for (int sx = 0; sx < scale; sx++) {
00529               // Calculate pixel colour by averaging detail tile texels
00530               int pixelscale = sqrt(scale);
00531               GLuint r = 0;
00532               GLuint g = 0;
00533               GLuint b = 0;
00534 
00535               // TEMP, just take one pixel for testing
00536               int detailRow = (sz * 4);
00537               int detailCol = (sx * 4);
00538               int iDetail;
00539 //              int iDetail = ((detailRow * 64) + detailCol) * 3;
00540 //              r = dt_image[iDetail + 0];
00541 //              g = dt_image[iDetail + 1];
00542 //              b = dt_image[iDetail + 2];
00543 
00544               for (int pz = 0; pz < pixelscale; pz++) {
00545                 for (int px = 0; px < pixelscale; px++) {
00546                   iDetail = ((detailRow * 64) + detailCol) * 3;
00547                   r += dt_image[iDetail + 0];
00548                   g += dt_image[iDetail + 1];
00549                   b += dt_image[iDetail + 2];
00550                   detailCol++;
00551                 }
00552                 detailRow++;
00553               }
00554 
00555               r /= scale;
00556               g /= scale;
00557               b /= scale;
00558 
00559               // Store in elevation tile texel
00560               int imageRow = ((7 - gz) * 1024) + ((63 - z) * 16) + (15 - sz);
00561               int imageCol = (gx * 1024) + (x * 16) + sx;
00562               int iImage = ((imageRow * resolution) + imageCol) * 3;
00563               image[iImage + 0] = r;
00564               image[iImage + 1] = g;
00565               image[iImage + 2] = b;
00566             }
00567           }
00568 
00569           // Free detail tile image data
00570           delete dt_image;
00571           delete r;
00572         }
00573       }
00574 
00575       // Purge detail tile database to free memory
00576       dtdb->Purge ();
00577     }
00578   }
00579 
00580   // Create the JPG context
00581   struct jpeg_compress_struct cinfo;
00582 
00583   // Set error handler
00584   struct my_error_mgr     jerr;
00585 
00586   // Format the .jpg filename
00587   char jpgFilename[80];
00588   sprintf (jpgFilename, "ET%03X.jpg", tile);
00589 
00590   // Open the .jpg file for writing as a binary file
00591   FILE *fJpg = fopen (jpgFilename, "wb");
00592   if (!fJpg) {
00593     // File open failed...display error message to user
00594     DrawNoticeToUser ("ExportElevationTileTexture : Could not open output .jpg file", 5);
00595     return;
00596   }
00597 
00598   // We set up the normal JPEG error routines, then override error_exit.
00599   cinfo.err = jpeg_std_error(&jerr.pub);
00600   jerr.pub.error_exit = my_error_exit;
00601   // Establish the setjmp return context for my_error_exit to use.
00602   if (setjmp(jerr.setjmp_buffer)) {
00603     // If we get here, the JPEG code has signaled an error.
00604     // We need to clean up the JPEG object, close the input file, and return.
00605     jpeg_destroy_compress(&cinfo);
00606     fclose(fJpg);
00607     return;
00608   }
00609 
00610   // Create compress context
00611   jpeg_create_compress (&cinfo);
00612 
00613   // Assign the file as the output target for the compress context
00614   jpeg_stdio_dest (&cinfo, fJpg);
00615 
00616   // Set parameters for compression
00617   cinfo.image_width = resolution;
00618   cinfo.image_height = resolution;
00619   cinfo.input_components = 3;
00620   cinfo.in_color_space = JCS_RGB;
00621   jpeg_set_defaults (&cinfo);
00622   cinfo.dct_method = JDCT_ISLOW;
00623   jpeg_set_quality (&cinfo, 50, TRUE);
00624   jpeg_start_compress (&cinfo, TRUE);
00625 
00626   for (int i=0; i<resolution; i++) {
00627     JSAMPROW pRow[1];
00628     pRow[0] = &image[i * resolution * 3];
00629     jpeg_write_scanlines (&cinfo, pRow, 1);
00630   }
00631 
00632   // Finish and clean up
00633   jpeg_finish_compress (&cinfo);
00634   jpeg_destroy_compress (&cinfo);
00635   fclose (fJpg);
00636 
00637   delete image;
00638 }
00639 
00640 
00641 void CTerrainManager::ExportGlobeTileTexture (int x, int z, ETileDetail detail)
00642 {
00643   int tile_resolution;
00644   int tile_overlap;
00645   switch (detail) {
00646   case TILE_DETAIL_LOW:
00647     tile_resolution = 64;
00648     tile_overlap = 0;
00649     break;
00650 
00651   case TILE_DETAIL_MEDIUM:
00652     tile_resolution = 128;
00653     tile_overlap = 8;
00654     break;
00655     
00656   case TILE_DETAIL_HIGH:
00657     tile_resolution = 256;
00658     tile_overlap = 4;
00659     break;
00660 
00661   default:
00662     tile_resolution = 64;
00663     tile_overlap = 0;
00664     break;
00665   }
00666 
00667   int extract_resolution = tile_resolution - (2 * tile_overlap);
00668   int resolution = extract_resolution * 64;
00669 
00670   // Create the JPG context
00671   struct jpeg_compress_struct cinfo;
00672 
00673   // Set error handler
00674   struct my_error_mgr     jerr;
00675 
00676   // Format the .jpg filename
00677   char jpgFilename[80];
00678   sprintf (jpgFilename, "GT%03d%03d_%d.jpg", x, z, resolution);
00679 
00680   // Open the .jpg file for writing as a binary file
00681   FILE *fJpg = fopen (jpgFilename, "wb");
00682   if (!fJpg) {
00683     // File open failed...display error message to user
00684     DrawNoticeToUser ("Export Globe Tile Texture : Could not open output .jpg file", 5);
00685     return;
00686   }
00687 
00688   // We set up the normal JPEG error routines, then override error_exit.
00689   cinfo.err = jpeg_std_error(&jerr.pub);
00690   jerr.pub.error_exit = my_error_exit;
00691   // Establish the setjmp return context for my_error_exit to use.
00692   if (setjmp(jerr.setjmp_buffer)) {
00693     // If we get here, the JPEG code has signaled an error.
00694     // We need to clean up the JPEG object, close the input file, and return.
00695     jpeg_destroy_compress(&cinfo);
00696     fclose(fJpg);
00697     return;
00698   }
00699 
00700   // Create compress context
00701   jpeg_create_compress (&cinfo);
00702 
00703   // Assign the file as the output target for the compress context
00704   jpeg_stdio_dest (&cinfo, fJpg);
00705 
00706   // Set parameters for compression
00707   cinfo.image_width = resolution;
00708   cinfo.image_height = resolution;
00709   cinfo.input_components = 3;
00710   cinfo.in_color_space = JCS_RGB;
00711   jpeg_set_defaults (&cinfo);
00712   cinfo.dct_method = JDCT_ISLOW;
00713   jpeg_set_quality (&cinfo, 50, TRUE);
00714   jpeg_start_compress (&cinfo, TRUE);
00715 
00716   // Allocate storage for a single scan line
00717   int rowStride = resolution * 3;
00718   BYTE *row = new BYTE[rowStride];
00719 
00720   // Each GT consists of a 64x64 grid of detail tiles, processed row by row
00721   //   from north to south.
00722   CRawImage* raw[64][64];
00723   GLubyte* rowImage[64][64];
00724   int xCount, zCount;
00725   for (zCount = 63; zCount >= 0; zCount--) {
00726     // Get first row of 64 detail tiles
00727     int dt_z = (z * 64) + zCount;
00728 
00729     for (xCount = 0; xCount < 64; xCount++) {
00730       int dt_x = (x * 64) + xCount;
00731       CRawImage *r = GetDetailTileTexture (dt_x, dt_z, detail);
00732       raw[xCount][zCount] = r;
00733       rowImage[xCount][zCount] = r->GetRGBImageData();
00734     }
00735 
00736     // Construct data for each scan line and send to JPEG compressor
00737     for (int rowCount = 0; rowCount < extract_resolution; rowCount++)
00738     {
00739       int extract_stride = extract_resolution * 3;
00740       int iImage = (rowCount * tile_resolution + tile_overlap) * 3;
00741 
00742       // Extract row data from each of the detail textures
00743       for (xCount=0; xCount<64; xCount++) {
00744         GLubyte *image = rowImage[xCount][zCount];
00745         int iRow = xCount * extract_stride;
00746         memcpy (&row[iRow], &image[iImage], extract_stride);
00747       }
00748 
00749       // Send scan line data to JPEG compressor
00750       JSAMPROW pRow[1];
00751       pRow[0] = row;
00752       jpeg_write_scanlines (&cinfo, pRow, 1);
00753     }
00754   }
00755 
00756   // Finish and clean up
00757   jpeg_finish_compress (&cinfo);
00758   jpeg_destroy_compress (&cinfo);
00759   fclose (fJpg);
00760   delete row;
00761 
00762   for (zCount=0; zCount<64; zCount++) {
00763     for (xCount=0; xCount<64; xCount++) {
00764       delete rowImage[xCount][zCount];
00765       delete raw[xCount][zCount];
00766     }
00767   }
00768 }
00769 
00770 */
00771 
00772 
SourceForge.net Logo Documentation generated by doxygen