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

ElevationDatabase.cpp

Go to the documentation of this file.
00001 /*
00002  * ElevationDatabase.cpp
00003  *
00004  * Part of Fly! Legacy project
00005  *
00006  * Copyright 2003 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 
00029 #include "../Include/Globals.h"
00030 #include "../Include/Terrain.h"
00031 #include "../Include/Utility.h"
00032 #include "../Include/Ui.h"
00033 #include "../Include/Qtr.h"
00034 #include "../Include/VTP.h"
00035 #include "../Include/Endian.h"
00036 
00037 //
00038 // CElevationLookup
00039 //
00040 CElevationLookup::CElevationLookup (void)
00041 {
00042   glType = 0;
00043   points = NULL;
00044 }
00045 
00046 CElevationLookup::~CElevationLookup (void)
00047 {
00048   int i, n;
00049 
00050   if (points != NULL) {
00051     n = points->getNumEntities();
00052     for (i=0; i<n; i++) {
00053       SElevationLookupPoint *p = (SElevationLookupPoint *)points->getEntity(i);
00054       delete p;
00055     }
00056     points->removeAllEntities();
00057     delete points;
00058   }
00059 }
00060 
00061 
00062 //
00063 // CElevationBlock
00064 //
00065 CElevationBlock::CElevationBlock (int x, int z, int size)
00066 {
00067   this->x = x;
00068   this->z = z;
00069   this->size = size;
00070   type = ELEVATION_TYPE_UNKNOWN;
00071 }
00072 
00073 CElevationBlock::~CElevationBlock (void)
00074 {
00075 }
00076 
00077 int CElevationBlock::GetSize (void)
00078 {
00079   return size;
00080 }
00081 
00082 bool CElevationBlock::DetailTileInBlock (int x, int z)
00083 {
00084   bool rc = false;
00085 
00086   // Find block bounds at the specified level
00087   int minX = this->x;
00088   int maxX = minX + size;
00089   int minZ = this->z;
00090   int maxZ = minZ + size;
00091 
00092   rc = ((x >= minX) && (x < maxX) && (z >= minZ) && (z < maxZ));
00093 
00094   return rc;
00095 }
00096 
00097 EElevationType CElevationBlock::GetElevationType (void)
00098 {
00099   return type;
00100 }
00101 
00102 
00103 //
00104 // CElevationBlockQTR
00105 //
00106 CElevationBlockQTR::CElevationBlockQTR (int x, int z, const char* qtrFilename)
00107 : CElevationBlock (x, z, 512)
00108 {
00109   type = ELEVATION_TYPE_CENTER;
00110   qtrFile = new CQTRFile (qtrFilename);
00111 }
00112 
00113 CElevationBlockQTR::~CElevationBlockQTR (void)
00114 {
00115   delete qtrFile;
00116 }
00117 
00118 //
00119 // Currently, the only supported resolution is 1 sample per detail tile
00120 //   (512 x 512 per QTR).  This will be relaxed in the future
00121 //
00122 int CElevationBlockQTR::GetDetailTileResolution (void)
00123 {
00124   return 1;
00125 }
00126 
00127 void CElevationBlockQTR::GetDetailTileElevations (int x, int z, float **data)
00128 {
00129   // Search the QTR file for the desired elevation value.
00130   
00136   int gx = x % 512;
00137   int gz = 511 - (z % 512);
00138   if (qtrFile != NULL) {
00139     int depth = TERRAIN_SUBDIVISION_DETAIL_TILE - TERRAIN_SUBDIVISION_QTR;
00140     data[0][0] =
00141       qtrFile->Search (depth, 0, gx, gz);
00142   }
00143 }
00144 
00145 //
00146 // CElevationBlockBT
00147 //
00148 CElevationBlockBT::CElevationBlockBT (int x, int z, const char* btFilename)
00149 : CElevationBlock (x, z, 512)
00150 {
00151   type = ELEVATION_TYPE_CENTER;
00152 
00154 }
00155 
00156 CElevationBlockBT::~CElevationBlockBT (void)
00157 {
00158 }
00159 
00160 //
00161 // Currently, the only supported resolution is 1 sample per detail tile
00162 //   (512 x 512 per QTR).  This will be relaxed in the future
00163 //
00164 int CElevationBlockBT::GetDetailTileResolution (void)
00165 {
00166   return 1;
00167 }
00168 
00169 void CElevationBlockBT::GetDetailTileElevations (int x, int z, float **data)
00170 {
00171   data[0][0] = 0.0f;
00172 }
00173 
00174 
00175 void CElevationBlockBT::Load (const char* btFilename)
00176 {
00177   // Open the .bt file for input
00178   PODFILE* pbt = popen (&globals->pfs, btFilename);
00179   if (!pbt) {
00180     globals->logWarning->Write ("ERROR reading %s\n", btFilename);
00181     return;
00182   }
00183 
00184   // Read BT header
00185   SBTHeader btHeader;
00186   pread (&btHeader, 1, SIZEOF_BT_HEADER, pbt);
00187 
00188   // Binary fields in BT header are little-Endian
00189   btHeader.columns = LittleEndian (btHeader.columns);
00190   btHeader.rows = LittleEndian (btHeader.rows);
00191   btHeader.size = LittleEndian (btHeader.size);
00192   btHeader.fp = LittleEndian (btHeader.fp);
00193   btHeader.space_units = LittleEndian (btHeader.space_units);
00194   btHeader.utm_zone = LittleEndian (btHeader.utm_zone);
00195   btHeader.datum = LittleEndian (btHeader.datum);
00196   btHeader.left = LittleEndian (btHeader.left);
00197   btHeader.right = LittleEndian (btHeader.right);
00198   btHeader.bottom = LittleEndian (btHeader.bottom);
00199   btHeader.top = LittleEndian (btHeader.top);
00200   btHeader.prj = LittleEndian (btHeader.prj);
00201   btHeader.scale = LittleEndian (btHeader.scale);
00202 
00203   // Sanity check on header fields
00204   if (btHeader.columns != btHeader.rows) {
00205     gtfo ("ERROR : BT is not square, cols=%d rows=%d\n",
00206       btHeader.columns, btHeader.rows);
00207     pclose (pbt);
00208     gtfo ();
00209   }
00210 
00212   if (btHeader.columns != 513) {
00213     gtfo ("ERROR : BT must be 513 elements square (not %d)\n",
00214       btHeader.columns);
00215     pclose (pbt);
00216     gtfo ();
00217   }
00218 
00219   int bt_size = btHeader.columns * btHeader.rows;
00220   int i;
00221 
00222   // Allocate array for short data
00223   short *bt_data = new short[bt_size];
00224 
00225   if (btHeader.fp) {
00226     // Values are floating point
00227     switch (btHeader.size) {
00228     case 2:
00229       {
00230         // Single-precision float
00231         float *fdata = new float[bt_size];
00232         pread (fdata, sizeof(float), bt_size, pbt);
00233         for (i=0; i<bt_size; i++) {
00234           bt_data[i] = (short)(fdata[i] * FEET_PER_METRE);
00235         }
00236         delete fdata;
00237       }
00238       break;
00239     case 4:
00240       {
00241         // Double-precision float
00242         double *ddata = new double[bt_size];
00243         pread (ddata, sizeof(double), bt_size, pbt);
00244         for (i=0; i<bt_size; i++) {
00245           bt_data[i] = (short)(ddata[i] * FEET_PER_METRE);
00246         }
00247         delete ddata;
00248       }
00249       break;
00250     }
00251   } else {
00252     // Values are integers
00253     switch (btHeader.size) {
00254     case 2:
00255       {
00256         // Short integer
00257         short *sdata = new short[bt_size];
00258         pread (sdata, sizeof(short), bt_size, pbt);
00259         for (i=0; i<bt_size; i++) {
00260           bt_data[i] = (short)(sdata[i] * FEET_PER_METRE);
00261         }
00262         delete sdata;
00263       }
00264       break;
00265 
00266     case 4:
00267       {
00268         // Integer
00269         int *idata = new int[bt_size];
00270         pread (idata, sizeof(int), bt_size, pbt);
00271         for (i=0; i<bt_size; i++) {
00272           bt_data[i] = (short)(idata[i] * FEET_PER_METRE);
00273         }
00274         delete idata;
00275       }
00276       break;
00277     }
00278   }
00279 
00280   // Close .bt file
00281   pclose (pbt);
00282 /*
00283   // Calculate detail tile bounds for this QTR tile
00284   int qtrX = qtr % 32;
00285   int qtrZ = qtr / 32;
00286 
00287   int dtW = qtrX * 512;     // West
00288   int dtE = dtW + 511;      // East
00289   int dtS = (31 - qtrZ) * 512;  // South
00290   int dtN = dtS + 511;      // North
00291 
00292   // Create elevation block and add it to the database
00293   CElevationGrid *grid = new CElevationGrid (dtW, dtE, dtS, dtN, bt_span);
00294 
00295   // Copy .bt elevation data to the elevation grid object
00296   grid->FillElevationData (bt_data);
00297 
00298   // Add the grid to the elevation database
00299   db.addEntity (grid);
00300 */
00301   // Free temporary buffers
00302   delete bt_data;
00303 }
00304 
00305 //
00306 // CElevationBlockGrid
00307 //
00308 // The Grid elevation block contains a square array of 2^n+1 x 2^n+1
00309 //   elevation samples representing the corners of an arbitrarily
00310 //   subdivided area of detail tiles.
00311 //
00312 // The 'size' parameter indicates the size in detail tiles of the area.
00313 // The 'subdivision' parameter indicates the level of subdivision per
00314 //   detail tile:
00315 //        AreaSize     SubdivisionLevel    ArraySize
00316 //         4x4 DT             1              5 x 5    <elev> in SuperTile object
00317 //         1x1 DT             4              5 x 5    <hdtl> object with <dimn>=4
00318 //         1x1 DT             8              9 x 9    <hdtl> object with <dimn>=8
00319 //
00320 // In general, elevation array is n x n where n = [(size * subdivision) + 1]
00321 //
00322 CElevationBlockGrid::CElevationBlockGrid (int x, int z,
00323                                           int size, int subdivision,
00324                                           float** data)
00325 : CElevationBlock (x, z, size)
00326 {
00327   type = ELEVATION_TYPE_CORNER;
00328 
00329   this->subdivision = subdivision;
00330   this->data = data;
00331 }
00332 
00333 CElevationBlockGrid::~CElevationBlockGrid (void)
00334 {
00335 }
00336 
00337 int CElevationBlockGrid::GetDetailTileResolution (void)
00338 {
00339   return subdivision+1;
00340 }
00341 
00342 //
00343 // Extracts elevations for a single Detail Tile.  The application is
00344 //   responsible for determining the required array size by calling
00345 //   GetDetailTileResolution(), allocating the float array and freeing
00346 //   the data when it is no longer needed.
00347 //
00348 //       AreaSize     SubdivisionLevel     ArraySize
00349 //        4x4 DT             1                2x2
00350 //        1x1 DT             4                5x5
00351 //        1x1 DT             8                9x9
00352 //
00353 // In general, detail tile array is n x n where n = (subdivision + 1)
00354 //
00355 void CElevationBlockGrid::GetDetailTileElevations (int x, int z, float **data)
00356 {
00357   // Calculate detail tile offsets
00358   int dx = x - this->x;
00359   int dz = z - this->z;
00360 
00361   // Allocate storage for elevations
00362   int dimn = GetDetailTileResolution();
00363   for (int i=0; i<dimn; i++) {
00364     for (int j=0; j<dimn; j++) {
00365       data[i][j] = this->data[i + dz][j + dx];
00366     }
00367   }
00368 }
00369 
00370 
00371 //
00372 // CElevationTRNSuperTile
00373 //
00374 CElevationTRNSuperTile::CElevationTRNSuperTile (int x, int z, int subdivision)
00375 {
00376   this->x = x;
00377   this->z = z;
00378   this->subdivision = subdivision;
00379   elev = NULL;
00380   dtArray = new CElevationBlockGrid**[subdivision];
00381   for (int i=0; i<subdivision; i++) {
00382     dtArray[i] = new CElevationBlockGrid*[subdivision];
00383     for (int j=0; j<subdivision; j++) {
00384       dtArray[i][j] = NULL;
00385     }
00386   }
00387 }
00388 
00389 CElevationTRNSuperTile::~CElevationTRNSuperTile (void)
00390 {
00391   if (elev != NULL) delete elev;
00392   for (int i=0; i<subdivision; i++) {
00393     for (int j=0; j<subdivision; j++) {
00394       delete dtArray[i][j];
00395     }
00396     delete[] dtArray[i];
00397   }
00398   delete[] dtArray;
00399 }
00400 
00401 
00402 //
00403 // CElevationTRNQuarterGlobeTile
00404 //
00405 CElevationTRNQuarterGlobeTile::CElevationTRNQuarterGlobeTile (int x, int z, int subdivision)
00406 {
00407   this->x = x;
00408   this->z = z;
00409   this->subdivision = subdivision;
00410   stArray = new CElevationTRNSuperTile**[subdivision];
00411   for (int i=0; i<subdivision; i++) {
00412     stArray[i] = new CElevationTRNSuperTile*[subdivision];
00413     for (int j=0; j<subdivision; j++) {
00414       stArray[i][j] = NULL;
00415     }
00416   }
00417 }
00418 
00419 CElevationTRNQuarterGlobeTile::~CElevationTRNQuarterGlobeTile (void)
00420 {
00421   for (int i=0; i<subdivision; i++) {
00422     for (int j=0; j<subdivision; j++) {
00423       delete stArray[i][j];
00424     }
00425     delete[] stArray[i];
00426   }
00427   delete[] stArray;
00428 }
00429 
00430 
00431 //
00432 // CTileElevationDatabase
00433 //
00434 CTileElevationDatabase::CTileElevationDatabase (void)
00435 {
00436   qtrList = new ulList (8);
00437   trnList = new ulList (64);
00438 
00440   btList = NULL;
00441 }
00442 
00443 CTileElevationDatabase::~CTileElevationDatabase (void)
00444 {
00445   int i, n;
00446 
00447   // Delete all entries in the TRN elevation block list
00448   if (trnList != NULL) {
00449     n = trnList->getNumEntities();
00450     for (i=0; i<n; i++) {
00451       CElevationTRNQuarterGlobeTile *trn =
00452         (CElevationTRNQuarterGlobeTile *)trnList->getEntity(i);
00453       delete trn;
00454     }
00455     delete trnList;
00456   }
00457 
00458   // Delete all entries in the BT elevation block list
00459   if (btList != NULL) {
00460     n = btList->getNumEntities();
00461     for (i=0; i<n; i++) {
00462       CElevationBlock *block = (CElevationBlock *)btList->getEntity(i);
00463       delete block;
00464     }
00465     delete btList;
00466   }
00467 
00468   // Delete all entries in the QTR elevation block list
00469   if (qtrList != NULL) {
00470     n = qtrList->getNumEntities();
00471     for (i=0; i<n; i++) {
00472       CElevationBlock *block = (CElevationBlock *)qtrList->getEntity(i);
00473       delete block;
00474     }
00475     delete qtrList;
00476   }
00477 }
00478 
00479 //
00480 // Add the specified elevation block to the database
00481 //
00482 void CTileElevationDatabase::AddQTRBlock (CElevationBlockQTR *block)
00483 {
00484   qtrList->addEntity (block);
00485 }
00486 
00487 //
00488 // Create a new placeholder for TRN elevation data.  A TRN covers an entire QGT
00489 //
00490 CElevationTRNQuarterGlobeTile *CTileElevationDatabase::AddTRN (int x, int z, 
00491                                                                int subdivision)
00492 {
00493   CElevationTRNQuarterGlobeTile *rc = new CElevationTRNQuarterGlobeTile (x, z, subdivision);
00494   trnList->addEntity (rc);
00495   return rc;
00496 }
00497 
00498 //
00499 // Remove a TRN elevation data placeholder, including all embedded super tile blocks
00500 //
00501 void CTileElevationDatabase::RemoveTRN (int x, int z)
00502 {
00503   CElevationTRNQuarterGlobeTile *trn = SearchTRN (x, z);
00504   if (trn != NULL) {
00505     delete trn;
00506     trnList->removeEntity (trn);
00507   }
00508 }
00509 
00510 CElevationTRNQuarterGlobeTile *CTileElevationDatabase::SearchTRN (int x, int z)
00511 {
00512   CElevationTRNQuarterGlobeTile *rc = NULL;
00513 
00514   int i, n;
00515   n = trnList->getNumEntities();
00516   for (i=0; (i<n) && (rc==NULL); i++) {
00517     CElevationTRNQuarterGlobeTile *trn =
00518       (CElevationTRNQuarterGlobeTile *)trnList->getEntity(i);
00519     if ((trn->x == x) && (trn->z == z)) {
00520       rc = trn;
00521     }
00522   }
00523 
00524   return rc;
00525 }
00526 
00527 //
00528 // Remove the specified elevation block from the database
00529 //
00530 bool CTileElevationDatabase::RemoveQTRBlock (CElevationBlockQTR *block)
00531 {
00532   bool found = false;
00533   int i, n;
00534   n = qtrList->getNumEntities();
00535   for (i=0; i<n && !found; i++) {
00536     CElevationBlockQTR *b = (CElevationBlockQTR *)qtrList->getEntity(i);
00537     found = (block == b);
00538   }
00539   
00540   if (found) {
00541     qtrList->removeEntity (i);
00542   }
00543 
00544   return found;
00545 }
00546 
00547 //
00548 // Convert detail tile x,z indices into the corresponding QTR tile index
00549 //
00550 int CTileElevationDatabase::DetailTileToQtrTile (int x, int z)
00551 {
00552   int qtr_x = x / 512;
00553   int qtr_z = 31 - (z / 512);
00554   return (qtr_z * 32) + qtr_x;
00555 }
00556 
00557 //
00558 // Find the lower-left (south-west) detail tile in the given QTR tile
00559 //
00560 void CTileElevationDatabase::QtrBaseDetailTile (int qtr, int *x, int *z)
00561 {
00562   int qtr_x = qtr % 32;
00563   int qtr_z = 31 - (qtr / 32);
00564   *x = qtr_x * 512;
00565   *z = qtr_z * 512;
00566 }
00567 
00568 //
00569 // Load one QTR of elevations from an Enviro .bt format file
00570 //
00571 CElevationBlockBT *CTileElevationDatabase::LoadBT (int qtr)
00572 {
00573   CElevationBlockBT *rc = NULL;
00574 
00575   // Get lower-left detail tile indices for this qtr
00576   int x, z;
00577   QtrBaseDetailTile (qtr, &x, &z);
00578 
00579   // If the .bt file exists, instantiate a new CElevationBlockBT and
00580   //   add it to the database list
00581   char btFilename[64];
00582   sprintf (btFilename, "BT\\FMQTR%03X.BT", qtr);
00583   if (pexists (&globals->pfs, btFilename)) {
00584     rc = new CElevationBlockBT (x, z, btFilename);
00585   }
00586 
00587   return rc;
00588 }
00589 
00590 //
00591 // Load one QTR of elevations from a Fly! II QTR format file
00592 //
00593 CElevationBlockQTR *CTileElevationDatabase::LoadQTR (int qtr)
00594 {
00595   CElevationBlockQTR *rc = NULL;
00596 
00597   // Get lower-left detail tile indices for this qtr
00598   int x, z;
00599   QtrBaseDetailTile (qtr, &x, &z);
00600 
00601   // If the .qtr file exists, instantiate a new CElevationBlockQTR and
00602   //   add it to the database list
00603   char qtrFilename[64];
00604   sprintf (qtrFilename, "DATA\\%03X.QTR", qtr);
00605   if (pexists (&globals->pfs, qtrFilename)) {
00606     rc = new CElevationBlockQTR (x, z, qtrFilename);
00607   }
00608 
00609   return rc;
00610 }
00611 
00612 //
00613 // Search for smallest cached elevation block that contains the desired detail tile
00614 //
00615 CElevationBlock *CTileElevationDatabase::Search (int x, int z)
00616 {
00617   CElevationBlock *block = NULL;
00618   int i, n;
00619 
00620   // First check TRN elevation list
00621   int qx = x / 32;
00622   int qz = z / 32;
00623   CElevationTRNQuarterGlobeTile *trn = SearchTRN (qx, qz);
00624   if (trn != NULL) {
00625     // TRN data exists for the quarter globe tile
00626     int sx = (x / 4) % 8;
00627     int sz = (z / 4) % 8;
00628     CElevationTRNSuperTile *stTrn = trn->stArray[sx][sz];
00629     if (stTrn != NULL) {
00630       // TRN data exists for the super tile
00631       int dx = x % 4;
00632       int dz = z % 4;
00633       if (stTrn->dtArray[dx][dz] != NULL) {
00634         // High-detail elevations exists for the detail tile
00635         block = stTrn->dtArray[dx][dz];
00636       } else {
00637         // Use base resolution block from the super tile
00638         block = stTrn->elev;
00639       }
00640     }
00641   }
00642 
00644 
00645   // Finally search QTR list
00646   if (block == NULL) {
00647     n = qtrList->getNumEntities();
00648     for (i=0; i<n; i++) {
00649       CElevationBlock *testBlock = (CElevationBlock *)qtrList->getEntity(i);
00650       if (testBlock->DetailTileInBlock(x, z)) {
00651         // Found a QTR block that contains this detail tile
00652         block = testBlock;
00653         break;
00654       }
00655     }
00656   }
00657 
00658   // If no block was found, load the default QTR elevation block
00659   if (block == NULL) {
00660     block = LoadQTR (DetailTileToQtrTile (x, z));
00661     qtrList->addEntity (block);
00662   }
00663 
00664   return block;
00665 }
00666 
00667 //
00668 // Get the type of elevation data that is available for the desired tile
00669 //
00670 EElevationType CTileElevationDatabase::GetElevationType (int x, int z)
00671 {
00672   EElevationType rc = ELEVATION_TYPE_UNKNOWN;
00673   CElevationBlock *block = Search (x, z);
00674   if (block != NULL) rc = block->GetElevationType();
00675   return rc;
00676 }
00677 
00678 int CTileElevationDatabase::GetDetailTileResolution (int x, int z)
00679 {
00680   int rc = 0;
00681 
00682   CElevationBlock *block = Search (x, z);
00683   if (block != NULL) {
00684     rc = block->GetDetailTileResolution();
00685   }
00686 
00687   return rc;
00688 }
00689 
00690 static void AllocateElevationArray (int dimn, float ***array)
00691 {
00692   *array = new float*[dimn];
00693   for (int i=0; i<dimn; i++) {
00694     (*array)[i] = new float[dimn];
00695   }
00696 }
00697 
00698 static void FreeElevationArray (int dimn, float **array)
00699 {
00700   for (int i=0; i<dimn; i++) {
00701     delete[] array[i];
00702   }
00703   delete[] array;
00704 }
00705 
00706 static float max3 (float f1, float f2, float f3)
00707 {
00708   float rc = f1;
00709 
00710   if (f2 > rc) rc = f2;
00711   if (f3 > rc) rc = f3;
00712 
00713   return rc;
00714 }
00715 
00716 //
00717 // Return an interpolated elevation from the specified grid.
00718 //
00719 // See http://www.geovista.psu.edu/sites/geocomp99/Gc99/082/gc_082.htm
00720 //   for details re: bilinear interpolation function (and others)
00721 //
00722 float InterpolatedData (float x, float z, int res, float **data)
00723 {
00724   float rc = 0.0f;
00725 
00726   float fres = (float)(res-1);
00727 
00728   // Calculate indices of the interpolation points in the tile data
00729   int ix0, ix1, iz0, iz1;
00730 
00731   if (z == 0.0f) {
00732     iz0 = iz1 = 0;
00733   } else if (z == 1.0f) {
00734     iz0 = iz1 = res-1;
00735   } else {
00736     iz0 = (int)(floorf(fres * z));
00737     iz1 = iz0 + 1;
00738   }
00739 
00740   if (x == 0.0f) {
00741     ix0 = ix1 = 0;
00742   } else if (x == 1.0f) {
00743     ix0 = ix1 = res-1;
00744   } else {
00745     ix0 = (int)(floorf(fres * x));
00746     ix1 = ix0 + 1;
00747   }
00748 
00749   // Get the four height (elevation) values to be interpolated
00750   //
00751   //   h3  ----------  h4
00752   //      |          |
00753   //      |          |
00754   //      |          |
00755   //      |          |
00756   //   h1  ----------  h2
00757   //
00758   float h1 = data[iz0][ix0];
00759   float h2 = data[iz0][ix1];
00760   float h3 = data[iz1][ix0];
00761   float h4 = data[iz1][ix1];
00762 
00763   // Adjust x, z distance by distance to h1
00764   float delta = 1.0f / fres;
00765   x -= ix0 * delta;
00766   z -= iz0 * delta;
00767 
00768   // Interpolate
00769   rc = h1 + ((h2 - h1) * x) + ((h3 - h1) * z) + ((h1 - h2 - h3 + h4) * x * z);
00770 
00771   return rc;
00772 }
00773 
00774 
00775 //
00776 // Primary lookup method for the tile elevation database.  Given a tile
00777 //   subdivision level and the x,z coordinates, returns an array of
00778 //   elevation points for the tile, in feet.
00779 //
00780 // The returned CElevationLookup instance must be deleted by the calling application.
00781 //
00782 CElevationLookup *CTileElevationDatabase::GetDetailTileElevations (int x, int z)
00783 {
00784   int i, j;
00785 
00786   CElevationLookup *rc = NULL;
00787 
00788   // Declare locals for surrounding corner elevations required for interpolation
00789   float **nwTile = NULL;
00790   float **wTile = NULL;
00791   float **swTile = NULL;
00792   float **sTile = NULL;
00793   float **seTile = NULL;
00794   float **eTile = NULL;
00795   float **neTile = NULL;
00796   float **nTile = NULL;
00797 
00798   int nwResolution = 0;
00799   int wResolution = 0;
00800   int swResolution = 0;
00801   int sResolution = 0;
00802   int seResolution = 0;
00803   int eResolution = 0;
00804   int neResolution = 0;
00805   int nResolution = 0;
00806 
00807   CElevationBlock *nwBlock = NULL;
00808   CElevationBlock *wBlock = NULL;
00809   CElevationBlock *swBlock = NULL;
00810   CElevationBlock *sBlock = NULL;
00811   CElevationBlock *seBlock = NULL;
00812   CElevationBlock *eBlock = NULL;
00813   CElevationBlock *neBlock = NULL;
00814   CElevationBlock *nBlock = NULL;
00815 
00816   // Search for elevation block for this tile
00817   CElevationBlock *thisBlock = Search (x, z);
00818   float **thisTile = NULL;
00819   int thisResolution;
00820 
00821   // Finally search the elevation block for the data
00822   if (thisBlock != NULL) {
00823     // Determine type of elevation data for this detail tile
00824     thisResolution = thisBlock->GetDetailTileResolution();
00825     EElevationType type = thisBlock->GetElevationType();
00826     switch (type) {
00827     case ELEVATION_TYPE_CENTER:
00828       {
00829         // Elevation lookup will be in the form of a fan, consisting of a center
00830         //   elevation plus a minimum of four other vertices, one for each corner.
00831         //   Additional vertices may be present along the borders to align with
00832         //   adjacent high-detail tiles
00833 
00834         bool nwDone = false, swDone = false, seDone = false, neDone = false;
00835         int nWest = 0, nSouth = 0, nEast = 0, nNorth = 0;
00836         float westEdge[7], southEdge[7], eastEdge[7], northEdge[7];
00837         float centerElev = 0, nwElev = 0, swElev = 0, seElev = 0, neElev = 0;
00838 
00839         // Get center elevation for this tile
00840         AllocateElevationArray (thisResolution, &thisTile);
00841         thisBlock->GetDetailTileElevations (x, z, thisTile);
00842         centerElev = thisTile[0][0];
00843         FreeElevationArray (thisResolution, thisTile);
00844 
00845         // Check if W adjacent tile has corner elevations in database
00846         wBlock = Search (x-1, z);
00847         wResolution = wBlock->GetDetailTileResolution();
00848         if (wBlock->GetElevationType () == ELEVATION_TYPE_CORNER) {
00849           // Get tile elevations
00850           AllocateElevationArray (wBlock->GetDetailTileResolution(), &wTile);
00851           wBlock->GetDetailTileElevations (x-1, z, wTile);
00852 
00853           // NW corner of this tile is NE corner of W tile
00854           nwElev = wTile[wResolution-1][wResolution-1];
00855           nwDone = true;
00856           // SW corner of this tile is SE corner of W tile
00857           swElev = wTile[0][wResolution-1];
00858           swDone = true;
00859 
00860           // Extract intermediate edge vertices if resolution is higher than 2x2
00861           if (wResolution > 2) {
00862             nWest = wResolution - 2;
00863 
00864             // Copy edges from E edge of tile , N->S, into edge array
00865             for (int i=0; i<nWest; i++) {
00866               westEdge[i] = wTile[wResolution-2-i][wResolution-1];
00867             }
00868           }
00869         }
00870 
00871         // Check if E adjacent tile has corner elevations in database
00872         eBlock = Search (x+1, z);
00873         eResolution = eBlock->GetDetailTileResolution();
00874         if (eBlock->GetElevationType () == ELEVATION_TYPE_CORNER) {
00875           // Get tile elevations, extract corners
00877           AllocateElevationArray (eResolution, &eTile);
00878           eBlock->GetDetailTileElevations (x+1, z, eTile);
00879 
00880           // NE corner of this tile is NW corner of E tile
00881           neElev = eTile[eResolution-1][0];
00882           neDone = true;
00883           // SE corner of this tile is SW corner of E tile
00884           seElev = eTile[0][0];
00885           seDone = true;
00886 
00887           // Extract intermediate edge vertices if resolution is higher than 2x2
00888           if (eResolution > 2) {
00889             nEast = eResolution - 2;
00890 
00891             // Copy edges from W edge of tile , S->N, into edge array
00892             for (int i=0; i<nEast; i++) {
00893               eastEdge[i] = eTile[i+1][0];
00894             }
00895           }
00896         }
00897 
00898         // Check N adjacent tile for corner elevations higher than 2x2 resolution
00899         nBlock = Search (x, z+1);
00900         nResolution = nBlock->GetDetailTileResolution();
00901         if (nBlock->GetElevationType () == ELEVATION_TYPE_CORNER) {
00902           // Get tile elevations, extract corners
00904           AllocateElevationArray (nBlock->GetDetailTileResolution(), &nTile);
00905           nBlock->GetDetailTileElevations (x, z+1, nTile);
00906 
00907           // NE corner of this tile is SE corner of N tile
00908           neElev = nTile[0][nResolution-1];
00909           neDone = true;
00910           // NW corner of this tile is SW corner of N tile
00911           nwElev = nTile[0][0];
00912           nwDone = true;
00913 
00914           // Extract intermediate edge vertices if resolution is higher than 2x2
00915           if (nResolution > 2) {
00916             nNorth = nResolution - 2;
00917 
00918             // Copy edges from S edge of tile , E->W, into edge array
00919             for (int i=0; i<nNorth; i++) {
00920               northEdge[i] = nTile[0][nResolution-2-i];
00921             }
00922           }
00923         }
00924 
00925         // Check S adjacent tile for corner elevations higher than 2x2 resolution
00926         sBlock = Search (x, z-1);
00927         sResolution = sBlock->GetDetailTileResolution();
00928         if (sBlock->GetElevationType () == ELEVATION_TYPE_CORNER) {
00929           // Get tile elevations, extract corners
00931           AllocateElevationArray (sResolution, &sTile);
00932           sBlock->GetDetailTileElevations (x, z-1, sTile);
00933 
00934           // SE corner of this tile is NE corner of S tile
00935           seElev = sTile[sResolution-1][sResolution-1];
00936           seDone = true;
00937           // SW corner of this tile is NW corner of S tile
00938           swElev = sTile[sResolution-1][0];
00939           swDone = true;
00940 
00941           // Extract intermediate edge vertices if resolution is higher than 2x2
00942           if (sResolution > 2) {
00943             nSouth = sResolution - 2;
00944 
00945             // Copy edges from N edge of tile , W->E, into edge array
00946             for (int i=0; i<nSouth; i++) {
00947               southEdge[i] = sTile[sResolution-1][i+1];
00948             }
00949           }
00950         }
00951 
00952         // Determine NW corner if it has not already been done
00953         if (!nwDone) {
00954           // Check NW adjacent tile to see if it has corner vertices
00955           if (nwBlock == NULL) {
00956             nwBlock = Search (x-1, z+1);
00957             nwResolution = nwBlock->GetDetailTileResolution();
00958           }
00959           switch (nwBlock->GetElevationType()) {
00960           case ELEVATION_TYPE_CORNER:
00961             {
00962               // Get elevations for NW corner tile
00963               AllocateElevationArray (nwResolution, &nwTile);
00964               nwBlock->GetDetailTileElevations (x-1, z+1, nwTile);
00965 
00966               // Extract SE corner from elevation block
00967               nwElev = nwTile[0][nwResolution-1];
00968               nwDone = true;
00969             }
00970             break;
00971 
00972           case ELEVATION_TYPE_CENTER:
00973             // All surrounding tiles have center elevations only
00974             if (nTile == NULL) {
00975               nBlock = Search (x, z+1);
00976               nResolution = nBlock->GetDetailTileResolution();
00977               AllocateElevationArray (nResolution, &nTile);
00978               nBlock->GetDetailTileElevations (x, z+1, nTile);
00979             }
00980             if (nwTile == NULL) {
00981               nwBlock = Search (x-1, z+1);
00982               nwResolution = nwBlock->GetDetailTileResolution();
00983               AllocateElevationArray (nwResolution, &nwTile);
00984               nwBlock->GetDetailTileElevations (x-1, z+1, nwTile);
00985             }
00986             if (wTile == NULL) {
00987               wBlock = Search (x-1, z);
00988               wResolution = wBlock->GetDetailTileResolution();
00989               AllocateElevationArray (wResolution, &wTile);
00990               wBlock->GetDetailTileElevations (x-1, z, wTile);
00991             }
00992             nwElev = (centerElev + nTile[0][0] + nwTile[0][0] + wTile[0][0]) / 4.0f;
00993             nwDone = true;
00994             break;
00995 
00996           default:
00997             globals->logWarning->Write ("No elevation data for NW corner of %d,%d", x, z);
00998             nwElev = centerElev;
00999           }
01000         }
01001 
01002         // Determine SW corner if it has not already been done
01003         if (!swDone) {
01004           // Check SW adjacent tile to see if it has corner vertices
01005           if (swBlock == NULL) {
01006             swBlock = Search (x-1, z-1);
01007           }
01008           switch (swBlock->GetElevationType()) {
01009           case ELEVATION_TYPE_CORNER:
01010             {
01011               // Get elevations for SW corner tile
01012               swResolution = swBlock->GetDetailTileResolution();
01013               AllocateElevationArray (swResolution, &swTile);
01014               swBlock->GetDetailTileElevations (x-1, z-1, swTile);
01015 
01016               // Extract NE corner from elevation block
01017               swElev = swTile[swResolution-1][swResolution-1];
01018               swDone = true;
01019             }
01020             break;
01021 
01022           case ELEVATION_TYPE_CENTER:
01023             // All surrounding tiles have center elevations only
01024             if (wTile == NULL) {
01025               wBlock = Search (x-1, z);
01026               wResolution = wBlock->GetDetailTileResolution();
01027               AllocateElevationArray (wResolution, &wTile);
01028               wBlock->GetDetailTileElevations (x-1, z, wTile);
01029             }
01030             if (swTile == NULL) {
01031               swBlock = Search (x-1, z-1);
01032               swResolution = swBlock->GetDetailTileResolution();
01033               AllocateElevationArray (swResolution, &swTile);
01034               swBlock->GetDetailTileElevations (x-1, z-1, swTile);
01035             }
01036             if (sTile == NULL) {
01037               sBlock = Search (x, z-1);
01038               sResolution = sBlock->GetDetailTileResolution();
01039               AllocateElevationArray (sResolution, &sTile);
01040               sBlock->GetDetailTileElevations (x, z-1, sTile);
01041             }
01042             swElev = (centerElev + wTile[0][0] + swTile[0][0] + sTile[0][0]) / 4.0f;
01043             swDone = true;
01044             break;
01045 
01046           default:
01047             globals->logWarning->Write ("No elevation data for SW corner of %d,%d", x, z);
01048             swElev = centerElev;
01049           }
01050         }
01051 
01052         // Determine SE corner if it has not already been done
01053         if (!seDone) {
01054           // Check SE adjacent tile to see if it has corner vertices
01055           if (seBlock == NULL) {
01056             seBlock = Search (x+1, z-1);
01057           }
01058           switch (seBlock->GetElevationType()) {
01059           case ELEVATION_TYPE_CORNER:
01060             {
01061               // Get elevations for SE corner tile
01062               seResolution = seBlock->GetDetailTileResolution();
01063               AllocateElevationArray (seResolution, &seTile);
01064               seBlock->GetDetailTileElevations (x+1, z-1, seTile);
01065 
01066               // Extract NW corner from elevation block
01067               seElev = seTile[seResolution-1][0];
01068               seDone = true;
01069             }
01070             break;
01071 
01072           case ELEVATION_TYPE_CENTER:
01073             // All surrounding tiles have center elevations only
01074             if (sTile == NULL) {
01075               sBlock = Search (x, z-1);
01076               sResolution = sBlock->GetDetailTileResolution();
01077               AllocateElevationArray (sResolution, &sTile);
01078               sBlock->GetDetailTileElevations (x, z-1, sTile);
01079             }
01080             if (seTile == NULL) {
01081               seBlock = Search (x+1, z-1);
01082               seResolution = seBlock->GetDetailTileResolution();
01083               AllocateElevationArray (seResolution, &seTile);
01084               seBlock->GetDetailTileElevations (x+1, z-1, seTile);
01085             }
01086             if (eTile == NULL) {
01087               eBlock = Search (x+1, z);
01088               eResolution = eBlock->GetDetailTileResolution();
01089               AllocateElevationArray (eResolution, &eTile);
01090               eBlock->GetDetailTileElevations (x+1, z, eTile);
01091             }
01092             seElev = (centerElev + sTile[0][0] + seTile[0][0] + eTile[0][0]) / 4.0f;
01093             seDone = true;
01094             break;
01095 
01096           default:
01097             globals->logWarning->Write ("No elevation data for SE corner of %d,%d", x, z);
01098             seElev = centerElev;
01099           }
01100         }
01101 
01102         // Determine NE corner if it has not already been done
01103         if (!neDone) {
01104           if (neBlock == NULL) {
01105             neBlock = Search (x+1, z+1);
01106           }
01107           switch (neBlock->GetElevationType()) {
01108           case ELEVATION_TYPE_CORNER:
01109             {
01110               // Get elevations for NE corner tile
01111               neResolution = neBlock->GetDetailTileResolution();
01112               AllocateElevationArray (neResolution, &neTile);
01113               neBlock->GetDetailTileElevations (x+1, z+1, neTile);
01114 
01115               // Extract SW corner from elevation block
01116               neElev = neTile[0][0];
01117               neDone = true;
01118             }
01119             break;
01120 
01121           case ELEVATION_TYPE_CENTER:
01122             // All surrounding tiles have center elevations only
01123             if (eTile == NULL) {
01124               eBlock = Search (x+1, z);
01125               eResolution = eBlock->GetDetailTileResolution();
01126               AllocateElevationArray (eResolution, &eTile);
01127               eBlock->GetDetailTileElevations (x+1, z, eTile);
01128             }
01129             if (neTile == NULL) {
01130               neBlock = Search (x+1, z+1);
01131               neResolution = neBlock->GetDetailTileResolution();
01132               AllocateElevationArray (neResolution, &neTile);
01133               neBlock->GetDetailTileElevations (x+1, z+1, neTile);
01134             }
01135             if (nTile == NULL) {
01136               nBlock = Search (x, z+1);
01137               nResolution = nBlock->GetDetailTileResolution();
01138               AllocateElevationArray (nResolution, &nTile);
01139               nBlock->GetDetailTileElevations (x, z+1, nTile);
01140             }
01141             neElev = (centerElev + eTile[0][0] + neTile[0][0] + nTile[0][0]) / 4.0f;
01142             neDone = true;
01143             break;
01144 
01145           default:
01146             globals->logWarning->Write ("No elevation data for NE corner of %d,%d", x, z);
01147             neElev = centerElev;
01148           }
01149         }
01150 
01151         // Clean up surrounding tile data
01152         if (nwTile != NULL) FreeElevationArray (nwResolution, nwTile);
01153         if (wTile != NULL)  FreeElevationArray (wResolution,   wTile);
01154         if (swTile != NULL) FreeElevationArray (swResolution, swTile);
01155         if (sTile != NULL)  FreeElevationArray (sResolution,   sTile);
01156         if (seTile != NULL) FreeElevationArray (seResolution, seTile);
01157         if (eTile != NULL)  FreeElevationArray (eResolution,   eTile);
01158         if (neTile != NULL) FreeElevationArray (neResolution, neTile);
01159         if (nTile != NULL)  FreeElevationArray (nResolution,   nTile);
01160 
01161         // Combine all elevation values into triangle fan lookup class instance
01162         int i;
01163         float dx, dz;
01164         int nPoints = 6 + nWest + nSouth + nEast + nNorth;
01165         rc = new CElevationLookup;
01166         rc->glType = GL_TRIANGLE_FAN;
01167         rc->u.fanData.nPoints = nPoints;
01168         rc->points = new ulList(nPoints);
01169 
01170         SElevationLookupPoint *p;
01171 
01172         // Add center
01173         p = new SElevationLookupPoint;
01174         p->x = 0.5f;
01175         p->z = 0.5f;
01176         p->elevation = centerElev;
01177         rc->points->addEntity(p);
01178 
01179         // Add NW corner
01180         p = new SElevationLookupPoint;
01181         p->x = 0.0f;
01182         p->z = 0.0f;
01183         p->elevation = nwElev;
01184         rc->points->addEntity(p);
01185 
01186         // Add W intermediate points, from N->S
01187         dz = 1.0f / (nWest + 1);
01188         for (i=0; i<nWest; i++) {
01189           p = new SElevationLookupPoint;
01190           p->x = 0.0f;
01191           p->z = (float)(i+1) * dz;
01192           p->elevation = westEdge[i];
01193           rc->points->addEntity(p);
01194         }
01195 
01196         // Add SW corner
01197         p = new SElevationLookupPoint;
01198         p->x = 0.0f;
01199         p->z = 1.0f;
01200         p->elevation = swElev;
01201         rc->points->addEntity(p);
01202 
01203         // Add S intermediate points, from W->E
01204         dx = 1.0f / (nSouth + 1);
01205         for (i=0; i<nSouth; i++) {
01206           p = new SElevationLookupPoint;
01207           p->x = (float)(i+1) * dx;
01208           p->z = 1.0f;
01209           p->elevation = southEdge[i];
01210           rc->points->addEntity(p);
01211         }
01212 
01213         // Add SE corner
01214         p = new SElevationLookupPoint;
01215         p->x = 1.0f;
01216         p->z = 1.0f;
01217         p->elevation = seElev;
01218         rc->points->addEntity(p);
01219 
01220         // Add E intermediate points, S->N
01221         dz = 1.0f / (nEast + 1);
01222         for (i=0; i<nEast; i++) {
01223           p = new SElevationLookupPoint;
01224           p->x = 1.0f;
01225           p->z = 1.0f - ((float)(i+1) * dz);
01226           p->elevation = eastEdge[i];
01227           rc->points->addEntity(p);
01228         }
01229 
01230         // Add NE corner
01231         p = new SElevationLookupPoint;
01232         p->x = 1.0f;
01233         p->z = 0.0f;
01234         p->elevation = neElev;
01235         rc->points->addEntity(p);
01236 
01237         // Add N intermediate points, from E->W
01238         dx = 1.0f / (nNorth + 1);
01239         for (i=0; i<nNorth; i++) {
01240           p = new SElevationLookupPoint;
01241           p->x = 1.0f - ((float)(i+1) * dx);
01242           p->z = 0.0f;
01243           p->elevation = northEdge[i];
01244           rc->points->addEntity(p);
01245         }
01246 
01247         // Add NW corner again to close the fan
01248         p = new SElevationLookupPoint;
01249         p->x = 0.0f;
01250         p->z = 0.0f;
01251         p->elevation = nwElev;
01252         rc->points->addEntity(p);
01253       }
01254       break;
01255 
01256     case ELEVATION_TYPE_CORNER:
01257       {
01258         // Determine overall resolution required to hold all elevation samples
01259         //   for this tile.  In each direction, the dimension of the array
01260         //   is the maximum of this tile's resolution and those of the adjoining
01261         //   tiles.
01262 
01263         int tileResolution = thisBlock->GetDetailTileResolution();
01264 
01265         int northResolution = 0;
01266         CElevationBlock *northBlock = Search (x, z+1);
01267         if (northBlock->GetElevationType() == ELEVATION_TYPE_CORNER) {
01268           northResolution = northBlock->GetDetailTileResolution();
01269         }
01270 
01271         int southResolution = 0;
01272         CElevationBlock *southBlock = Search (x, z-1);
01273         if (southBlock->GetElevationType() == ELEVATION_TYPE_CORNER) {
01274           southResolution = southBlock->GetDetailTileResolution();
01275         }
01276 
01277         int westResolution = 0;
01278         CElevationBlock *westBlock = Search (x-1, z);
01279         if (westBlock->GetElevationType() == ELEVATION_TYPE_CORNER) {
01280           westResolution = westBlock->GetDetailTileResolution();
01281         }
01282 
01283         int eastResolution = 0;
01284         CElevationBlock *eastBlock = Search (x+1, z);
01285         if (eastBlock->GetElevationType() == ELEVATION_TYPE_CORNER) {
01286           eastResolution = eastBlock->GetDetailTileResolution();
01287         }
01288 
01289         // Allocate overall elevation array for this tile
01290         int xTile = max3 (tileResolution, northResolution, southResolution);
01291         int zTile = max3 (tileResolution, westResolution, eastResolution);
01292         float **overallData;
01293         overallData = new float*[zTile];
01294         for (i=0; i<zTile; i++) {
01295           overallData[i] = new float[xTile];
01296         }
01297 
01298         // Get detail tile elevations and copy to overall array
01299         if ((xTile > tileResolution) || (zTile > tileResolution)) {
01300           // Overall array is larger than tile array; initialize the overall array
01301           //   with elevations interpolated from the tile's elevations
01302           float **tileData;
01303           AllocateElevationArray (tileResolution, &tileData);
01304           thisBlock->GetDetailTileElevations (x, z, tileData);
01305           float dx = 1.0f / (float)(xTile - 1);
01306           float dz = 1.0f / (float)(zTile - 1);
01307           for (i=0; i<zTile; i++) {
01308             for (j=0; j<xTile; j++) {
01309               float xInt = j * dx;
01310               float zInt = i * dz;
01311               overallData[i][j] = InterpolatedData (xInt, zInt, tileResolution, tileData);
01312             }
01313           }
01314           FreeElevationArray (tileResolution, tileData);
01315 
01316           // Override N border if required
01317           if (northResolution > tileResolution) {
01318             // North tile is higher resolution than this tile, so the border
01319             //   must be overridden
01320             float **northData;
01321             AllocateElevationArray (northResolution, &northData);
01322             northBlock->GetDetailTileElevations(x, z+1, northData);
01323             if (xTile > northResolution) {
01324               // North tile is lower resolution than overall data; interpolate
01325               //   elevations from southern edge of the north tile
01326               for (j=0; j<xTile; j++) {
01327                 overallData[zTile-1][j] = InterpolatedData (0.0f, (float)j * dx,
01328                                                             northResolution, northData);
01329               }
01330             } else {
01331               // North tile is same resolution as overall data, simply copy
01332               //   southern elevations to northern border of overall data
01333               for (j=0; j<xTile; j++) {
01334                 overallData[zTile-1][j] = northData[0][j];
01335               }
01336             }
01337             FreeElevationArray (northResolution, northData);
01338           }
01339 
01340           // Override S border if required
01341           if (southResolution > tileResolution) {
01342             // South tile is higher resolution than this tile, so the border
01343             //   must be overridden
01344             float **southData;
01345             AllocateElevationArray (southResolution, &southData);
01346             southBlock->GetDetailTileElevations(x, z-1, southData);
01347             if (xTile > southResolution) {
01348               // South tile is lower resolution than overall data; interpolate
01349               //   elevations from northern edge of the south tile
01350               for (j=0; j<xTile; j++) {
01351                 overallData[0][j] = InterpolatedData (1.0f, (float)j * dx,
01352                                                       southResolution, southData);
01353               }
01354             } else {
01355               // South tile is same resolution as overall data, simply copy
01356               //   northern elevations to southern border of overall data
01357               for (j=0; j<xTile; j++) {
01358                 overallData[0][j] = southData[southResolution-1][j];
01359               }
01360             }
01361             FreeElevationArray (southResolution, southData);
01362           }
01363 
01364           // Override W border if required
01365           if (westResolution > tileResolution) {
01366             // West tile is higher resolution than this tile, so the border
01367             //   must be overridden
01368             float **westData;
01369             AllocateElevationArray (westResolution, &westData);
01370             westBlock->GetDetailTileElevations(x-1, z, westData);
01371             if (zTile > westResolution) {
01372               // West tile is lower resolution than overall data; interpolate
01373               //   elevations from eastern edge of the west tile
01374               for (i=0; i<zTile; i++) {
01375                 overallData[i][0] = InterpolatedData ((float)i * dz, 1.0f,
01376                                                             westResolution, westData);
01377               }
01378             } else {
01379               // West tile is same resolution as overall data, simply copy
01380               //   eastern elevations to western border of overall data
01381               for (i=0; i<zTile; i++) {
01382                 overallData[i][0] = westData[i][westResolution-1];
01383               }
01384             }
01385             FreeElevationArray (westResolution, westData);
01386           }
01387 
01388           // Override E border if required
01389           if (eastResolution > tileResolution) {
01390             // East tile is higher resolution than this tile, so the border
01391             //   must be overridden
01392             float **eastData;
01393             AllocateElevationArray (eastResolution, &eastData);
01394             eastBlock->GetDetailTileElevations(x+1, z, eastData);
01395             if (zTile > eastResolution) {
01396               // East tile is lower resolution than overall data; interpolate
01397               //   elevations from eastern edge of the west tile
01398               for (i=0; i<zTile; i++) {
01399                 overallData[i][xTile-1] = InterpolatedData ((float)i * dz, 0.0f,
01400                                                             eastResolution, eastData);
01401               }
01402             } else {
01403               // East tile is same resolution as overall data, simply copy
01404               //   western elevations to eastern border of overall data
01405               for (i=0; i<zTile; i++) {
01406                 overallData[i][xTile-1] = eastData[i][0];
01407               }
01408             }
01409             FreeElevationArray (eastResolution, eastData);
01410           }
01411         } else {
01412           // Overall array is same size as tile array; simply populate the
01413           //   overall array with this tile's elevations
01414           thisBlock->GetDetailTileElevations (x, z, overallData);
01415         }
01416 
01417         // Instantiate database lookup results
01418         rc = new CElevationLookup;
01419         rc->glType = GL_TRIANGLE_STRIP;
01420         int nStrips = zTile - 1;
01421         int stripSize = 2 * xTile;
01422         rc->u.stripData.nStrips = nStrips;
01423         rc->u.stripData.stripSize = stripSize;
01424         rc->points = new ulList(nStrips * stripSize);
01425 
01426         float dx = 1.0f / (float)(xTile - 1);
01427         float dz = 1.0f / (float)(zTile - 1);
01428         SElevationLookupPoint *p;
01429         for (i=0; i<nStrips; i++) {
01430           for (j=0; j<xTile; j++) {
01431             // Add northern point
01432             p = new SElevationLookupPoint;
01433             p->x = (float)j * dx;
01434             p->z = (float)(nStrips-i-1) * dz;
01435             p->elevation = overallData[i+1][j];
01436             rc->points->addEntity(p);
01437 
01438             // Add southern point
01439             p = new SElevationLookupPoint;
01440             p->x = (float)j * dx;
01441             p->z = (float)(nStrips-i) * dz;
01442             p->elevation = overallData[i][j];
01443             rc->points->addEntity(p);
01444           }
01445         }
01446 
01447         // Free overall elevation data for tile
01448         for (i=0; i<zTile; i++) {
01449           delete[] overallData[i];
01450         }
01451         delete[] overallData;
01452       }
01453       break;
01454     }
01455   } else {
01456     globals->logWarning->Write ("TEDB : Could not find elevations for DT %d,%d", x, z);
01457   }
01458 
01459   // Return pointer to CElevationLookup; this must be deleted by the application
01460   return rc;
01461 }
01462 
01463 // Declare tile elevation database (extern in Terrain.h)
01464 CTileElevationDatabase *tedb = NULL;
SourceForge.net Logo Documentation generated by doxygen