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

Terrain.cpp

Go to the documentation of this file.
00001 /*
00002  * Terrain.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 
00028 #include "../Include/Globals.h"
00029 #include "../Include/Terrain.h"
00030 #include "../Include/Utility.h"
00031 #include "../Include/Ui.h"
00032 #include "../Include/Endian.h"
00033 
00034 
00035 //
00036 // CGenericTileType
00037 //
00038 CGenericTileType::CGenericTileType (void)
00039 {
00040   pixl = 0;
00041   txti = 0;
00042   tilc = 0;
00043 
00044   strcpy (texture, "");
00045 }
00046 
00047 int CGenericTileType::Read (SStream *stream, Tag tag)
00048 {
00049   int rc = TAG_IGNORED;
00050 
00051   switch (tag) {
00052   case 'pixl':
00053     ReadInt (&pixl, stream);
00054     rc = TAG_READ;
00055     break;
00056 
00057   case 'txti':
00058     ReadInt (&txti, stream);
00059     rc = TAG_READ;
00060     break;
00061 
00062   case 'tilc':
00063     ReadInt (&tilc, stream);
00064     rc = TAG_READ;
00065     break;
00066   }
00067 
00068   return rc;
00069 }
00070 
00071 void CGenericTileType::ReadFinished (void)
00072 {
00073 }
00074 
00075 
00076 //
00077 // CGenericTileDatabase
00078 //
00079 CGenericTileDatabase::CGenericTileDatabase (const char* gentiles)
00080 {
00081   strcpy (schm, "");
00082 
00083   // Open stream
00084   SStream s;
00085   strcpy (s.filename, "Data\\");
00086   strcat (s.filename, gentiles);
00087   strcpy (s.mode, "r");
00088   if (OpenStream (&s)) {
00089     ReadFrom (this, &s);
00090   } else {
00091     // Could not open generic tile database
00092     globals->logWarning->Write ("CGenericTileDatabase : Could not open file %s", gentiles);
00093   }
00094 
00095 }
00096 
00097 int CGenericTileDatabase::Read (SStream *stream, Tag tag)
00098 {
00099   int rc = TAG_IGNORED;
00100 
00101   switch (tag) {
00102   case 'schm':
00103     // Texture file naming scheme template
00104     ReadString (schm, 64, stream);
00105     rc = TAG_READ;
00106     break;
00107 
00108   case 'tile':
00109     // Generic tile type
00110     {
00111       CGenericTileType* newtile = new CGenericTileType;
00112       ReadFrom (newtile, stream);
00113       tile.addEntity (newtile);
00114     }
00115     rc = TAG_READ;
00116     break;
00117   }
00118 
00119   return rc;
00120 }
00121 
00122 
00123 
00124 //
00125 // CTerrainTypeDatabase
00126 //
00127 // This class implements an interface to the terrain type database encoded in the
00128 //   file tiletype.img.  The database is a 16K x 16K grid of 8-bit ground type
00129 //   values, one for each default detail tile
00130 
00131 CTerrainTypeDatabase::CTerrainTypeDatabase (void)
00132 : img(NULL)
00133 {
00134   // Open tiletype.img
00135   img = popen (&globals->pfs, "DATA\\TILETYPE.IMG");
00136   if (img == NULL) {
00137     gtfo ("CTerrainTypeDatabase : Cannot open TILETYPE.IMG");
00138   }
00139 }
00140 
00141 CTerrainTypeDatabase::~CTerrainTypeDatabase ()
00142 {
00143   // Close tiletype.img
00144   if (img != NULL) {
00145     pclose (img);
00146   }
00147 }
00148 
00149 ETerrainType CTerrainTypeDatabase::GetTerrainType (int x, int z)
00150 {
00151   // Calculate offset in tiletype.img for this tile.
00152   // The top-left entry in the image is x=0, z=16383
00153   long offset = ((16383 - z) * 16384) + x;
00154 
00155   pseek (img, offset, SEEK_SET);
00156   unsigned char c;
00157   pread (&c, 1, 1, img);
00158 
00159   ETerrainType t = (ETerrainType) c;
00160 
00161   // DEBUG : Set all tiles to use the same terrain type to test tiling
00162 //  t = TERRAIN_CITY_USA;
00163 
00164   return t;
00165 }
00166 
00167 
00168 // Declare terrain type database, extern in Terrain.h
00169 CTerrainTypeDatabase *ttdb = NULL;
00170 
00171 
00172 //
00173 // CDefaultTextureDatabase
00174 //
00175 // This class implements an interface to the set of detail tile textures for
00176 //   default terrain
00177 //
00178 CDefaultTextureDatabase::CDefaultTextureDatabase (void)
00179 {
00180   Init ();
00181 
00182   // Load .act (palette) for relief shading
00183   PODFILE *pAct = popen (&globals->pfs, "Art\\Topographic.act");
00184   if (pAct != NULL) {
00185     // Read palette data and close the POD file
00186     unsigned char data[256][3];
00187     pread (data, 256 * 3, 1, pAct);
00188     pclose (pAct);
00189 
00190     // Convert to float and copy to relief array
00191     for (int i=0; i<256; i++) {
00192       for (int j=0; j<3; j++) {
00193         relief[i][j] = (float)(data[i][j]) / 256;
00194       }
00195     }
00196 
00197     // Initialize relief mapping controls
00198     negativeIndex = 0;      // Palette index for negative elevations
00199     zeroIndex = 1;          // Palette index corresponding to zero elev
00200     maxElevation = 15000;   // Maximum positive elevation in feet
00201     baseIndex = 48;         // Palette index of lowest positive elevation
00202     maxIndex = 256;         // Palette index of highest elevation
00203   } else {
00204     gtfo ("DTDB : Cannot load relief shading texture");
00205   }
00206 }
00207 
00208 CDefaultTextureDatabase::~CDefaultTextureDatabase ()
00209 {
00210   // Delete any cached base textures
00211   CRawImage *raw;
00212   for (int type=0; type<256; type++) {
00213     raw = low[type];
00214     if (raw != NULL) delete raw;
00215 
00216     for (int j=0; j<4; j++) {
00217       for (int k=0; k<4; k++) {
00218         raw = med[type][j][k];
00219         if (raw != NULL) delete raw;
00220 
00221         raw = high[type][j][k];
00222         if (raw != NULL) delete raw;
00223       }
00224     }
00225   }
00226 
00227   // Clean up any cached composite textures
00228   int n = composite.getNumEntities();
00229   for (int i=0; i<n; i++) {
00230     CRawImage *raw = (CRawImage *)composite.getEntity(i);
00231     delete raw;
00232   }
00233   composite.removeAllEntities();
00234 }
00235 
00236 void CDefaultTextureDatabase::Init (void)
00237 {
00238   for (int type=0; type<256; type++) {
00239     // Preload all low-detail textures
00240     low[type] = NULL;
00241 
00242     /*  Low resolution textures should not even be used.  Comment out until
00243         until optimizations enable use of medium detail without constraints
00244 
00245     char raw[64];
00246     sprintf (raw, "SYSTEM\\GLOBE\\%02XFF1.RAW", type);
00247     char act[64];
00248     sprintf (act, "SYSTEM\\GLOBE\\%02XFF1.ACT", type);
00249     if (pexists (&globals->pfs, raw)) {
00250       low[type] = NULL;
00251     }
00252     */
00253 
00254     for (int j=0; j<4; j++) {
00255       for (int k=0; k<4; k++) {
00256         med[type][j][k] = NULL;
00257         high[type][j][k] = NULL;
00258       }
00259     }
00260   }
00261 
00262   // Initialize relief shading array
00263   memset (relief, 0, 256 * 3);
00264 }
00265 
00266 
00267 //
00268 // Purge all medium- and high-detail textures to recover memory
00269 //
00270 void CDefaultTextureDatabase::Purge (void)
00271 {
00272   for (int i=0; i<256; i++) {
00273     for (int j=0; j<4; j++) {
00274       for (int k=0; k<4; k++) {
00275         if (med[i][j][k] != NULL) {
00276           delete med[i][j][k];
00277         }
00278         med[i][j][k] = NULL;
00279 
00280         if (high[i][j][k] != NULL) {
00281           delete high[i][j][k];
00282         }
00283         high[i][j][k] = NULL;
00284       }
00285     }
00286   }
00287 }
00288 
00289 
00290 //
00291 // Return a pointer to the base texture for the given subtile, terrain type
00292 //   and resolution (tile detail level).  If the base texture is not already
00293 //   cached then it will be loaded into the cache.  Calling applications should
00294 //   not delete the returned object.
00295 //
00296 CRawImage* CDefaultTextureDatabase::GetBaseTexture (int x, int z,
00297                                                     ETerrainType type,
00298                                                     ETileDetail level)
00299 {
00300   CRawImage *image = NULL;
00301 
00302   // Invert order of z subtiles
00303   z = 3 - z;
00304 
00305   switch (level) {
00306   case TILE_DETAIL_LOW:
00307     {
00308       // All low-detail textures should always be loaded
00309       if (low[type] == NULL) {
00310         char raw[64];
00311         sprintf (raw, "SYSTEM\\GLOBE\\%02XFF1.RAW", type);
00312         char act[64];
00313         sprintf (act, "SYSTEM\\GLOBE\\%02XFF1.ACT", type);
00314         if (pexists (&globals->pfs, raw) && pexists (&globals->pfs, act)) {
00315           low[type] = new CRawImage (64, 64, raw, act);
00316           image = low[type];
00317         }
00318       } else {
00319         // Texture has already been loaded
00320         image = low[type];
00321       }
00322     }
00323     break;
00324 
00325   case TILE_DETAIL_MEDIUM:
00326     {
00327       // Check to see if this texture has already been loaded
00328       if (med[type][x][z] == NULL) {
00329         // No, it has not been loaded yet
00330         char raw[64];
00331         sprintf (raw, "SYSTEM\\GLOBE\\%02X%d%d4D.RAW", type, x, z);
00332         char act[64];
00333         sprintf (act, "SYSTEM\\GLOBE\\%02X%d%d4D.ACT", type, x, z);
00334         if (pexists (&globals->pfs, raw) && pexists (&globals->pfs, act)) {
00335           image = new CRawImage (128, 128, raw, act);
00336           med[type][x][z] = image;
00337         } else {
00338           gtfo ("Cannot open medium-detail texture for terrain type 0x%02X", type);
00339         }
00340       } else {
00341         // Texture has already been loaded
00342         image = med[type][x][z];
00343       }
00344     }
00345     break;
00346 
00347   case TILE_DETAIL_HIGH:
00348     {
00349       // Check to see if this texture has already been loaded
00350       if (high[type][x][z] == NULL) {
00351         // No, it has not been loaded yet
00352         char raw[64];
00353         sprintf (raw, "SYSTEM\\GLOBE\\%02X%d%d5D.RAW", type, x, z);
00354         char act[64];
00355         sprintf (act, "SYSTEM\\GLOBE\\%02X%d%d5D.ACT", type, x, z);
00356 
00357         if (pexists (&globals->pfs, raw) && pexists (&globals->pfs, act)) {
00358           image = new CRawImage (256, 256, raw, act);
00359           high[type][x][z] = image;
00360         } else {
00361           gtfo ("Cannot open high-detail texture for terrain type 0x%02X", type);
00362         }
00363       } else {
00364         // Texture has already been loaded
00365         image = high[type][x][z];
00366       }
00367     }
00368     break;
00369   }
00370 
00371   return image;
00372 }
00373 
00374 //
00375 // This function creates the generic texture name for a given detail tile.
00376 //   The texture name identifies the unique combination of default terrain
00377 //   types that are merged to form the texture for the tile.
00378 //
00379 void CDefaultTextureDatabase::GetCompositeTextureName (unsigned int x,
00380                                                        unsigned int z,
00381                                                        char *textureName)
00382 {
00383   if (ttdb == NULL) return;
00384 
00385   // Calculate tile indices for all relevant tiles:
00386   //   A = Tile being looked up
00387   //   B = South bordering tile
00388   //   X = East bordering tile
00389   //   Y = South-East bordering tile
00390 
00391   unsigned int Xx = (x + 1) % 16384;
00392   unsigned int Xz = z;
00393 
00394   unsigned int Bx = x;
00395   unsigned int Bz = z - 1;   if (Bz < 0) Bz = 0;
00396 
00397   unsigned int Yx = (x + 1) % 16384;
00398   unsigned int Yz = z - 1;   if (Yz < 0) Yz = 0;
00399 
00400   // Get terrain types for all tiles
00401   ETerrainType Atype = ttdb->GetTerrainType (x, z);
00402   ETerrainType Xtype = ttdb->GetTerrainType (Xx, Xz);
00403   ETerrainType Btype = ttdb->GetTerrainType (Bx, Bz);
00404   ETerrainType Ytype = ttdb->GetTerrainType (Yx, Yz);
00405 
00406   // Calculate medium- and high-detail tile offset
00407   unsigned int xSubtile = x % 4;
00408   unsigned int zSubtile = z % 4;
00409 
00410   // Format texture name
00411   sprintf (textureName, "%02X%02X%02X%02X%1d%1d",
00412     Atype, Xtype, Btype, Ytype, xSubtile, zSubtile);
00413 }
00414 
00415 //
00416 // This function compiles a customized generic detail tile texture.
00417 //   The composite texture is composed of up to four generic detail
00418 //   tile textures, properly transitioned based on the terrain type
00419 //   of the tile in question, and the terrain types of the tiles to
00420 //   the east, south and south-east.
00421 //
00422 // Composite textures are cached in case of re-use
00423 //
00424 CRawImage* CDefaultTextureDatabase::GetCompositeTexture (const char *textureName,
00425                                                          ETileDetail level)
00426 {
00427   CRawImage *aRaw = NULL;
00428 
00429   // Parse texture name into base texture types
00430   ETerrainType Atype, Btype, Xtype, Ytype;
00431   unsigned int xSubtile, zSubtile;
00432   if (sscanf (textureName, "%02X%02X%02X%02X%1d%1d",
00433               &Atype, &Xtype, &Btype, &Ytype, &xSubtile, &zSubtile) == 6)
00434   {
00435     // Create the composite texture as a copy of base texture A
00436     aRaw = new CRawImage (*(dtdb->GetBaseTexture (xSubtile, zSubtile, Atype, level)));
00437     aRaw->SetName (textureName);
00438 
00439     CRawImage *bRaw = NULL;
00440     CRawImage *xRaw = NULL;
00441     CRawImage *yRaw = NULL;
00442     CMaskImage *bMask = NULL;
00443     CMaskImage *xMask = NULL;
00444     CMaskImage *yMask = NULL;
00445 
00446 // Single preprocessor macro to enable/disable detail tile texture transitioning
00447 #define DO_TRANSITIONS
00448 #ifdef DO_TRANSITIONS
00449 
00450     // Don't transition to/from ocean tiles; these transitions are handled
00451     //   with the default water masks
00452     if (Atype != TERRAIN_WATER_OCEAN)
00453     {
00454       // Check for bottom-side transition first
00455 
00456       if ((Atype != Btype) && (Btype != TERRAIN_WATER_OCEAN)) {
00457         // Bottom-side transition applies
00458         bMask = tmdb->GetBottomTransition(level);
00459         bRaw = dtdb->GetBaseTexture (xSubtile, zSubtile, Btype, level);
00460       }
00461 
00462       // Check for right-side transition next
00463       if ((Atype != Xtype) && (Xtype != TERRAIN_WATER_OCEAN)) {
00464         // Right-side transition applies
00465         xMask = tmdb->GetRightTransition(level);
00466         xRaw = dtdb->GetBaseTexture (xSubtile, zSubtile, Xtype, level);
00467       }
00468 
00469       // Check for corner transition
00470       bool case1 = (Atype != Xtype) && (Atype == Ytype);
00471       bool case2 = (Atype == Xtype) && (Atype != Ytype);
00472       bool case3 = (Atype != Xtype) && (Atype != Ytype);
00473       if ((case1 || case2 || case3) && (Ytype != TERRAIN_WATER_OCEAN))
00474       {
00475         // Corner transition applies
00476         yMask = tmdb->GetCornerTransition(level);
00477         yRaw = dtdb->GetBaseTexture (xSubtile, zSubtile, Ytype, level);
00478       }
00479 
00480       // Merge all of the transition tiles together
00481       aRaw->MergeTransitions (bRaw, bMask,
00482                               xRaw, xMask,
00483                               yRaw, yMask);
00484     } else {
00485   /*
00486       // Check for watermask
00487       CMaskImage *wMask = wmdb->GetWaterMask (x, z, detail);
00488       if (wMask != NULL) {
00489         // Get water texture for this tile
00490         CRawImage *w = dtdb->GetRawImage (x, z, TERRAIN_WATER_OCEAN, detail);
00491       }
00492   */
00493     }
00494 #endif // DO_TRANSITIONS
00495   }
00496 
00497   return aRaw;
00498 }
00499 
00500 //
00501 // This function compiles a customized generic detail tile texture.
00502 //   The composite texture is composed of up to four generic detail
00503 //   tile textures, properly transitioned based on the terrain type
00504 //   of the tile in question, and the terrain types of the tiles to
00505 //   the east, south and south-east.
00506 //
00507 // Composite textures are cached in case of re-use
00508 //
00509 CRawImage* CDefaultTextureDatabase::GetCompositeTexture (unsigned int x,
00510                                                          unsigned int z,
00511                                                          ETileDetail level)
00512 {
00513   char textureName[64];
00514   GetCompositeTextureName (x, z, textureName);
00515 
00516   return GetCompositeTexture (textureName, level);
00517 }
00518 
00519 //
00520 // This function returns an RGB colour corresponding to the given elevation
00521 //   for terrain relief shading
00522 //
00523 void CDefaultTextureDatabase::GetReliefShadingRGB (const float elev,
00524                                                    float &r, float &g, float &b)
00525 {
00526   static const float zeroEpsilon = 3.0;
00527 
00528   // Calculate index
00529   int i = 0;
00530   if ((elev <= zeroEpsilon) && (elev >= -zeroEpsilon)) {
00531     // Elevation is considered to be zero
00532     i = zeroIndex;
00533   } else if (elev < 0) {
00534     // Negative elevations use a single colour
00535     i = negativeIndex;
00536   } else if (elev > maxElevation) {
00537     i = maxIndex;
00538   } else {
00539     // Positive elevation
00540     float d = 1 - ((maxElevation - elev) / maxElevation);
00541     int offset = (int)((float)(maxIndex - baseIndex) * d);
00542     i = baseIndex + offset;
00543   }
00544 
00545   // Assign colours
00546   r = relief[i][0];
00547   g = relief[i][1];
00548   b = relief[i][2];
00549 
00550   // DEBUG
00551 //  float x = elev / 10000;
00552 //  r = g = b = x;
00553 }
00554 
00555 
00556 // Declare default texture database, extern in Terrain.h
00557 CDefaultTextureDatabase *dtdb = NULL;
00558 
00559 
00560 
00561 //
00562 // Scenery Model Database
00563 //
00564 // This class implements a centralized database for scenery models (BIN and SMF formats).
00565 //
00566 
00567 CSceneryModelDatabase::~CSceneryModelDatabase ()
00568 {
00569   int n = model.getNumEntities();
00570   for (int i=0; i<n; i++) {
00571     SSceneryModel *m = (SSceneryModel *)model.getEntity(i);
00572     ssgEntity *ssge = m->smf->GetSSGEntity();
00573     ssge->deRef();
00574     delete m->smf;
00575     delete m;
00576   }
00577   model.removeAllEntities ();
00578 }
00579 
00580 
00581 ssgEntity* CSceneryModelDatabase::GetSceneryModel (const char* filename)
00582 {
00583   ssgEntity *rc = NULL;
00584 
00585   // Search models already loaded
00587   for (int i=0; i<model.getNumEntities (); i++) {
00588     SSceneryModel *s = (SSceneryModel *) model.getEntity (i);
00589     if (stricmp (s->filename, filename) == 0) {
00590       // Found a match!
00591       rc = s->smf->GetSSGEntity();
00592       break;
00593     }
00594   }
00595 
00596   // If model is not already in the list, then load it
00597   if (rc == NULL) {
00598     // Load the model
00599     SSceneryModel *s = new SSceneryModel;
00600     strcpy (s->filename, filename);
00601     s->smf = new CModelSMF (filename);
00602     rc = s->smf->GetSSGEntity();
00603 
00604     // Add a superfluous reference to the model so it isn't deleted automatically
00605     rc->ref();
00606 
00607     // Add the model to the database cache
00608     model.addEntity (s);
00609   }
00610 
00611   return rc;
00612 }
00613 
00614 
00615 // Declare scenery model database, extern in Terrain.h
00616 CSceneryModelDatabase *smdb = NULL;
00617 
00618 
00619 
00620 //
00621 // Transition Mask Database
00622 //
00623 
00624 CTransitionMaskDatabase::CTransitionMaskDatabase (void)
00625 {
00626   // Load right-side transition masks
00627   high_right = new CMaskImage (256, 256, "Art\\TransRightHigh.raw");
00628   med_right = new CMaskImage (128, 128, "Art\\TransRightMed.raw");
00629   low_right = new CMaskImage (64, 64, "Art\\TransRightLow.raw");
00630 
00631   // Load bottom-side transition masks
00632   high_bottom = new CMaskImage (256, 256, "Art\\TransBottomHigh.raw");
00633   med_bottom = new CMaskImage (128, 128, "Art\\TransBottomMed.raw");
00634   low_bottom = new CMaskImage (64, 64, "Art\\TransBottomLow.raw");
00635 
00636   // Load corner transition masks
00637   high_corner = new CMaskImage (256, 256, "Art\\TransCornerHigh.raw");
00638   med_corner = new CMaskImage (128, 128, "Art\\TransCornerMed.raw");
00639   low_corner = new CMaskImage (64, 64, "Art\\TransCornerLow.raw");
00640 }
00641 
00642 CTransitionMaskDatabase::~CTransitionMaskDatabase (void)
00643 {
00644   delete high_right;
00645   delete med_right;
00646   delete low_right;
00647   delete high_bottom;
00648   delete med_bottom;
00649   delete low_bottom;
00650   delete high_corner;
00651   delete med_corner;
00652   delete low_corner;
00653 }
00654 
00655 CMaskImage *CTransitionMaskDatabase::GetBottomTransition (ETileDetail detail)
00656 {
00657   CMaskImage *rc = NULL;
00658 
00659   switch (detail) {
00660   case TILE_DETAIL_LOW:
00661     rc = low_bottom;
00662     break;
00663 
00664   case TILE_DETAIL_MEDIUM:
00665     rc = med_bottom;
00666     break;
00667 
00668   case TILE_DETAIL_HIGH:
00669     rc = high_bottom;
00670     break;
00671   }
00672 
00673   return rc;
00674 }
00675 
00676 
00677 CMaskImage *CTransitionMaskDatabase::GetRightTransition (ETileDetail detail)
00678 {
00679   CMaskImage *rc = NULL;
00680 
00681   switch (detail) {
00682   case TILE_DETAIL_LOW:
00683     rc = low_right;
00684     break;
00685 
00686   case TILE_DETAIL_MEDIUM:
00687     rc = med_right;
00688     break;
00689 
00690   case TILE_DETAIL_HIGH:
00691     rc = high_right;
00692     break;
00693   }
00694 
00695   return rc;
00696 }
00697 
00698 
00699 CMaskImage *CTransitionMaskDatabase::GetCornerTransition (ETileDetail detail)
00700 {
00701   CMaskImage *rc = NULL;
00702 
00703   switch (detail) {
00704   case TILE_DETAIL_LOW:
00705     rc = low_corner;
00706     break;
00707 
00708   case TILE_DETAIL_MEDIUM:
00709     rc = med_corner;
00710     break;
00711 
00712   case TILE_DETAIL_HIGH:
00713     rc = high_corner;
00714     break;
00715   }
00716 
00717   return rc;
00718 }
00719 
00720 
00721 // Declare transition mask database (extern in Terrain.h)
00722 CTransitionMaskDatabase *tmdb = NULL;
00723 
00724 
00725 //
00726 // CGtpTile
00727 //
00728 void CGtpTile::Print (FILE *f)
00729 {
00730 }
00731 
00732 
00733 //
00734 // CGtpFile
00735 //
00736 CGtpFile::CGtpFile (void)
00737 {
00738   nTiles = 0;
00739 //  header = NULL;
00740 //  data = NULL;
00741 }
00742 
00743 CGtpFile::~CGtpFile (void)
00744 {
00745 //  if (header) {
00746 //    delete header;
00747 //  }
00748 
00749 //  if (data) {
00750 //    delete data;
00751 //  }
00752 }
00753 
00754 void CGtpFile::Print (FILE *f)
00755 {
00756   fprintf (f, "  Globe Tile : %d,%d\n", x, z);
00757   fprintf (f, "    nTiles = %d\n", nTiles);
00758   for (int i=0; i<nTiles; i++) {
00759     CGtpTile *t = &tile[i];
00760     t->Print (f);
00761   }
00762 }
00763 
00764 
00765 //
00766 // Water Mask Database
00767 //
00768 
00769 CWaterMaskDatabase::CWaterMaskDatabase (void)
00770 {
00771 }
00772 
00773 
00774 CWaterMaskDatabase::~CWaterMaskDatabase (void)
00775 {
00776 }
00777 
00778 
00779 void CWaterMaskDatabase::AddGlobeTile (int x, int z)
00780 {
00781   int i, j;
00782   
00783   // Instantiate a new structure representing the coastlines in this globe tile
00784   CGtpFile *gt = new CGtpFile;
00785   gt->nTiles = 0;
00786   gt->x = x;
00787   gt->z = z;
00788 
00789   // Attempt to open GTP file for this globe tile.  If the file does not exist
00790   //   then there are no coastline tiles in the globe tile, but the empty
00791   //   CGtpFile instance should still be added to the database
00792   char gtpFilename[64];
00793   sprintf (gtpFilename, "Coast\\V%03d%03d.GTP", x, z);
00794   PODFILE *pGtp = popen (&globals->pfs, gtpFilename);
00795   if (pGtp != NULL) {
00796     // Read the entire GTP file into memory for parsing
00797     int gtpSize = pGtp->size;
00798     char *data = new char[gtpSize];
00799     pread (data, gtpSize, 1, pGtp);
00800     pclose (pGtp);
00801 
00802     // Get number of ground tiles for which there is coastline data
00803     char *p = data;
00804     gt->nTiles = LittleEndian (*((short*)p));
00805     p += sizeof(short);
00806 
00807     // Parse the header data for each tile
00808     SGtpHeader *header = new SGtpHeader [gt->nTiles];
00809     for (i=0; i<gt->nTiles; i++) {
00810       SGtpHeader *h = &header[i];
00811       short index;
00812       index = LittleEndian (*((short*)p));    p += sizeof(short);
00813       h->z = index / 64;
00814       h->x = index % 64;
00815 
00816       unsigned long offset;
00817       offset = LittleEndian (*((long*)p));    p += sizeof(long);
00818       h->offset = offset;
00819     }
00820 
00821     // Parse vertex and polygon data for each tile
00822     gt->tile = new CGtpTile[gt->nTiles];
00823     for (i=0; i<gt->nTiles; i++) {
00824       SGtpHeader *h = &header[i];
00825 
00826       // Instantiate new SGtpTile
00827       CGtpTile *tile = &(gt->tile[i]);
00828       tile->x = h->x;
00829       tile->z = h->z;
00830 
00831       // Reset data pointer to beginning of this tile
00832       p = &(data[h->offset]);
00833 
00834       // Read vertex data
00835       tile->nVertices = LittleEndian (*((short*)p));    p += sizeof(short);
00836       tile->vlist = new SGtpVertex[tile->nVertices];
00837       for (j=0; j<tile->nVertices; j++) {
00838         SGtpVertex *v = &(tile->vlist[j]);
00839         v->x = LittleEndian (*((float*)p));     p += sizeof(float);
00840         v->z = LittleEndian (*((float*)p));     p += sizeof(float);
00841       }
00842 
00843       // Read polygon data
00844       tile->nPolygons = LittleEndian (*((short*)p));    p += sizeof(short);
00845       tile->plist = new SGtpPolygon[tile->nPolygons];
00846       for (i=0; i<tile->nPolygons; i++) {
00847         // Get polygon vertex indices
00848         SGtpPolygon *poly = &(tile->plist[i]);
00849         poly->nPolyVerts = LittleEndian (*((short*)p)); p += sizeof(short);
00850 
00851         poly->pvlist = new short[poly->nPolyVerts];
00852         for (int j=0; j<poly->nPolyVerts; j++) {
00853           poly->pvlist[j] = LittleEndian (*((short*)p));  p += sizeof(short);
00854         }
00855       }
00856     }
00857   } else {
00858     globals->logWarning->Write ("Could not open default coastline file %s", gtpFilename);
00859   }
00860 
00861   // Add the watermask struct to the list
00862   gtlist.addEntity (gt);
00863 }
00864 
00865 
00866 int CWaterMaskDatabase::FindGlobeTile (int x, int z)
00867 {
00868   int rc = -1;
00869 
00870   for (int i=0; i<gtlist.getNumEntities (); i++) {
00871     CGtpFile *gt = (CGtpFile*) gtlist.getEntity (i);
00872     if ((gt->x == x) && (gt->z == z)) {
00873       rc = i;
00874       break;
00875     }
00876   }
00877 
00878   return rc;
00879 }
00880 
00881 
00882 void CWaterMaskDatabase::DeleteGlobeTile (int x, int z)
00883 {
00884   int i = FindGlobeTile (x, z);
00885   if (i != -1) {
00886     // Globe tile exists, delete it from the list and destroy
00887     CGtpFile *gt = (CGtpFile*) gtlist.getEntity (i);
00888     gtlist.removeEntity (i);
00889     delete gt;
00890   }
00891 }
00892 
00893 /*
00894 //
00895 // Determine the offset of the start of GTP polygon data for the specified detail tile
00896 //
00897 // Inputs:
00898 //  dx      Detail tile x-index
00899 //  dz      Detail tile z-index
00900 //
00901 // Outputs:
00902 //  offset    Offset to start of polygon data for this detail tile
00903 //  index   Index into watermask database globe tile list
00904 //
00905 // Returns:
00906 //  bool    true if the offset is defined, i.e. watermask data exists for this tile
00907 //
00908 CGtpTile *CWaterMaskDatabase::FindDetailTile (int dx, int dz)
00909 //bool CWaterMaskDatabase::DetailTileOffset (int dx, int dz, unsigned long *offset, int *index)
00910 {
00911   CGtpTile *rc = NULL;
00912 
00913   // Convert absolute detail tile indices into globe tile and relative detail tile
00914   int x = dx / 64;
00915   int z = dz / 64;
00916   dx %= 64;
00917   dz %= 64;
00918 
00921 
00922   int index = FindGlobeTile (x, z);
00923   if (index != -1) {
00924     // The globe tile exists in the database
00925     CGtpFile *gt = (CGtpFile*) gtlist.getEntity (index);
00926 
00927     for (int i=0; i<gt->nTiles; i++) {
00928 //      SGtpHeader *header = &gt->header[i];
00929       CGtpTile *tile = &(gt->tile[i]);
00930 
00931 //      if ((header->x == dx) && (header->z == dz)) {
00932       if ((tile->x == dx) && (tile->z == dz)) {
00933         // Found a match
00934         rc = tile;
00935 //        *offset = header->offset;
00936         break;
00937       }
00938     }
00939   }
00940 
00941   return rc;
00942 }
00943 */
00944 
00945 CMaskImage *CWaterMaskDatabase::GetWaterMask (int dx, int dz, ETileDetail detail)
00946 {
00947   CMaskImage *rc = NULL;
00948 
00949   int x = dx / 64;
00950   int z = dz / 64;
00951   int i = FindGlobeTile (x, z);
00952   if (i != -1) {
00953     // Globe tile exists, search for detail tile
00954     CGtpFile *gt = (CGtpFile*) gtlist.getEntity (i);
00955     dx %= 64;
00956     dz %= 64;
00957     int nTiles = gt->nTiles;
00958     for (int j=0; j<nTiles; j++) {
00959       CGtpTile* tile = &(gt->tile[j]);
00960 
00961       if ((tile->x == dx) && (tile->z == dz)) {
00962 
00963         // Coastline data exists for this detail tile
00964         int mask_x = 0;
00965         int mask_z = 0;
00966 
00967         switch (detail) {
00968         case TILE_DETAIL_LOW:
00969           mask_x = mask_z = 64;
00970           break;
00971 
00972         case TILE_DETAIL_MEDIUM:
00973           mask_x = mask_z = 128;
00974           break;
00975 
00976         case TILE_DETAIL_HIGH:
00977           mask_x = mask_z = 256;
00978           break;
00979 
00980         default:
00981           gtfo ("CWaterMaskDatabase::GetWaterMask() : Invalid detail level");
00982         }
00983 
00984         // TEMP : Fill mask image with dummy checkerboard pattern
00985         GLubyte *data = new GLubyte[mask_x * mask_z];
00986         for (int m=0; m<mask_z; m++) {
00987           for (int n=0; n<mask_x; n++) {
00988             data[m * mask_x + n] = 0x80;
00989           }
00990         }
00991 
00992         // Create the watermask image
00993         char name[64];
00994         sprintf (name, "WaterMask %d,%d", dx, dz);
00995         rc = new CMaskImage (mask_x, mask_z, name);
00996       }
00997     }
00998 
00999     // "Draw" polygons in mask image bitmap
01000   }
01001   return rc;
01002 }
01003 
01004 void CWaterMaskDatabase::Print (FILE *f)
01005 {
01006   fprintf (f, "Water Mask Database :\n");
01007   for (int i=0; i<gtlist.getNumEntities(); i++) {
01008     CGtpFile *g = (CGtpFile *)gtlist.getEntity (i);
01009     g->Print (f);
01010   }
01011 }
01012 
01013 
01014 // Declare watermask database (extern in Terrain.h)
01015 CWaterMaskDatabase *wmdb = NULL;
01016 
SourceForge.net Logo Documentation generated by doxygen