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

DetailTile.cpp

Go to the documentation of this file.
00001 /*
00002  * DetailTile.cpp
00003  *
00004  * Part of Fly! Legacy project
00005  *
00006  * Copyright 2003-2004 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 
00034 #include "../Include/Globals.h"
00035 #include "../Include/Terrain.h"
00036 #include "../Include/Utility.h"
00037 #include "../Include/Ui.h"
00038 
00039 
00040 //
00041 // CDetailTile
00042 //
00043 
00044 CDetailTile::CDetailTile (unsigned int x, unsigned int z)
00045 {
00046   level = TERRAIN_SUBDIVISION_DETAIL_TILE; 
00047   this->x = x;
00048   this->z = z;
00049 
00050   // Initialize texture info
00051   STileTextureInfo info;
00052   info.texid = 0;
00053   info.lls = info.llt = 0.0f;
00054   info.urs = info.urt = 1.0f;
00055   memcpy (&texinfo[TILE_DETAIL_LOW], &info, sizeof(STileTextureInfo));
00056   memcpy (&texinfo[TILE_DETAIL_MEDIUM], &info, sizeof(STileTextureInfo));
00057   memcpy (&texinfo[TILE_DETAIL_HIGH], &info, sizeof(STileTextureInfo));
00058   detail = TILE_DETAIL_MEDIUM;
00059 
00060   // Get the default composite texture name for this tile
00061   dtdb->GetCompositeTextureName (x, z, defaultTextureName);
00062 
00063   elevLookup = NULL;
00064 
00065   //
00066   // Compute lat/lon boundaries for the tile
00067   //
00068 
00069   // First calculate parent globe tile indices
00070   int n = 64;   // Dimension of these tiles per globe tile
00071   globe_x = x / n;
00072   globe_z = z / n;
00073 
00074   // Get lat/lon boundaries for the globe tile, and convert to arcsec
00075   double globe_sw_lon, globe_ne_lon, globe_sw_lat, globe_ne_lat;
00076   globe_tile_lon_bounds (globe_x, globe_sw_lon, globe_ne_lon);
00077   globe_tile_lat_bounds (globe_z, globe_sw_lat, globe_ne_lat);
00078   globe_sw_lon *= 3600;
00079   globe_sw_lat *= 3600;
00080   globe_ne_lon *= 3600;
00081   globe_ne_lat *= 3600;
00082 
00083   // Calculate per-super tile offset
00084   double dlat = (globe_ne_lat - globe_sw_lat) / n;
00085   double dlon = (globe_ne_lon - globe_sw_lon) / n;
00086 
00087   // Calculate tile corners
00088   double sw_lat = globe_sw_lat + (dlat * (z % n));
00089   double sw_lon = globe_sw_lon + (dlon * (x % n));
00090   double ne_lat = sw_lat + dlat;
00091   double ne_lon = sw_lon + dlon;
00092   SetCorners (sw_lat, sw_lon, ne_lat, ne_lon);
00093 
00094   // Initialize top-level SSG entity
00095   top = new ssgBranch;
00096   char name[64];
00097   sprintf (name, "DT %d,%d", x, z);
00098   top->setName (name);
00099 }
00100 
00101 
00102 CDetailTile::~CDetailTile (void)
00103 {
00104   // Delete all textures
00105   for (int i=0; i<3; i++) {
00106     STileTextureInfo &info = texinfo[i];
00107     if (info.texid != 0) {
00108       glDeleteTextures (1, &info.texid);
00109     }
00110   }
00111 
00112   // Delete top-level branch if it was not added to the scene graph
00113 //  if (top->getRef() == 0) delete top;
00114 
00115   // Delete elevation lookup results
00116   if (elevLookup != NULL) delete elevLookup;
00117 }
00118 
00119 //
00120 // Assign the default terrain texture name, in the form:
00121 //   AAXXBBYYmn
00122 //
00123 void CDetailTile::AssignDefaultTextureName (const char* name)
00124 {
00125   strcpy (defaultTextureName, name);
00126 }
00127 
00128 void CDetailTile::AssignTexture (ETileDetail detail, STileTextureInfo &info)
00129 {
00130   // Store texturing information
00131   memcpy (&texinfo[detail], &info, sizeof(STileTextureInfo));
00132 
00133   // Update texturing of leaf nodes if necessary
00134   if (IsCreated() && (this->detail == detail)) {
00135     switch (elevLookup->glType) {
00136     case GL_TRIANGLE_FAN:
00137       break;
00138 
00139     case GL_TRIANGLE_STRIP:
00140       UpdateStripTexCoords (info);
00141       break;
00142     }
00143   }
00144 }
00145 
00146 //
00147 // Load default terrain texture into the appropriate texinfo array member
00148 //
00149 void CDetailTile::LoadDefaultTexture (ETileDetail detail)
00150 {
00151   texid = 0;
00152 
00153   if (!globals->settings->terrainReliefShaded) {
00154     // Get the fully transitioned detail tile texture.  This function
00155     //   allocates a new CRawImage* object which must be freed when
00156     //   it is no longer needed
00157     CRawImage *raw = dtdb->GetCompositeTexture (defaultTextureName, detail);
00158 
00159     if (raw != NULL) {
00160       // Convert the final A-tile raw image to an OpenGL texture name
00161       // Low-detail textures should be mipmapped; medium- and high-detail not
00162       bool mipmap = false;
00163       switch (detail) {
00164       case TILE_DETAIL_LOW:
00165         mipmap = true;
00166         break;
00167 
00168       case TILE_DETAIL_MEDIUM:
00169         mipmap = true;
00170         break;
00171 
00172       case TILE_DETAIL_HIGH:
00173         mipmap = false;
00174         break;
00175 
00176       default:
00177         gtfo ("Invalid texture detail level!");
00178       }
00179       texid = raw->GetTexture (mipmap);
00180 
00181       // Delete temporary raw image for A tile
00182       delete raw;
00183 
00184       // Update texture coordinates.  Low-detail textures are not overlapped;
00185       //   Medium and high detail textures are overlapped by 16 and 8 pixels
00186       //   respectively
00187       float offset = 0.0;
00188       switch (detail) {
00189       case TILE_DETAIL_MEDIUM:
00190         offset = 16.0 / 256.0;
00191         break;
00192       case TILE_DETAIL_HIGH:
00193         offset = 8.0 / 256.0;
00194         break;
00195       }
00196 
00197       // Update texture info structure with texture name and coordinates
00198       STileTextureInfo info;
00199       info.texid = texid;
00200       info.lls = info.llt = offset;
00201       info.urs = info.urt = 1.0f - offset;
00202       AssignTexture (detail, info);
00203     }
00204   }
00205 }
00206 
00207 
00208 void CDetailTile::SetDetail (ETileDetail detail)
00209 {
00210   this->detail = detail;
00211 /*
00212   if (globals->terrainmgr->debugLevel != DETAIL_TILES) {
00213 
00215 
00216     // Apply the texture to the detail tile's state
00217     for (int i=0; i<top->getNumKids(); i++) {
00218       ssgLeaf *leaf = (ssgLeaf *)top->getKid(i);
00219       ssgSimpleState *state = (ssgSimpleState*) leaf->getState ();
00220       state->setTexture (texID[detail]);
00221     }
00222   }
00223 */
00224 }
00225 
00226 
00227 //
00228 // Create tile geometry based on the elevation database returning a set of
00229 //   data points in a triangle fan
00230 //
00231 void CDetailTile::CreateFanGeometry (CElevationLookup *elev)
00232 {
00233   // Find cartesian coordinates of tile corners
00234   SVector vsw, vnw, vse, vne;
00235   vnw = PosToFlatCartesian (nw, globe_x, globe_z);
00236   vne = PosToFlatCartesian (ne, globe_x, globe_z);
00237   vse = PosToFlatCartesian (se, globe_x, globe_z);
00238   vsw = PosToFlatCartesian (sw, globe_x, globe_z);
00239 
00240   // NW corner is the base point for the E/W and N/S distances
00241   float ewDistance = vne.x - vnw.x;
00242   float nsDistance = vsw.y - vnw.y;
00243 
00244   ssgVertexArray *va = NULL;
00245   ssgColourArray *rgba = NULL;
00246   ssgTexCoordArray *ta = NULL;
00247 
00248   // Create vertex array
00249   int nPoints = elev->u.fanData.nPoints;
00250   va = new ssgVertexArray(nPoints);
00251   for (int i=0; i<nPoints; i++) {
00252     SElevationLookupPoint *p = (SElevationLookupPoint *)(elev->points->getEntity(i));
00253     sgVec3 v;
00254     sgSetVec3 (v,
00255                vsw.x + (p->x * ewDistance),
00256                vsw.y + (p->z * nsDistance),
00257                p->elevation);
00258     va->add (v);
00259   }
00260 
00261   // Initialize state information for the detail tile
00262   ssgSimpleState *state = new ssgSimpleState ();
00263   state->setShadeModel (GL_SMOOTH);
00264   state->disable (GL_LIGHTING);
00265   state->enable (GL_CULL_FACE);
00266   state->enable (GL_BLEND);
00267   state->disable (GL_ALPHA_TEST);
00268 
00269   // Check .ini setting to determine whether tiles are relief shaded or textured
00270   if (globals->settings->terrainReliefShaded) {
00271     // Terrain is relief-shaded
00272     state->disable (GL_TEXTURE_2D);
00273     state->enable (GL_COLOR_MATERIAL);
00274     state->setColourMaterial (GL_AMBIENT_AND_DIFFUSE);
00275     state->setMaterial (GL_EMISSION, 0, 0, 0, 1);
00276     state->setMaterial (GL_SPECULAR, 0, 0, 0, 1);
00277 
00278     rgba = new ssgColourArray (nPoints);
00279     for (int i=0; i<nPoints; i++) {
00280       SElevationLookupPoint *p = (SElevationLookupPoint *)(elev->points->getEntity(i));
00281       float r, g, b;
00282       dtdb->GetReliefShadingRGB (p->elevation, r, g, b);
00283       sgVec4 c;
00284       sgSetVec4 (c, r, g, b, 1.0);
00285       rgba->add (c);
00286     }
00287   } else {
00288     // Terrain is textured normally
00289     state->enable (GL_TEXTURE_2D);
00290     state->disable (GL_COLOR_MATERIAL);
00291 
00292     if (globals->terrainmgr->debugLevel == DETAIL_TILES) {
00293 
00294       // Create default tile debugging texture 
00295       SSurface *surface = CreateSurface (64, 64);
00296       unsigned int bg = MakeRGB (128, 128, 128);    // Medium grey
00297       unsigned int fg = MakeRGB (255, 255, 255);    // White
00298       unsigned int dot = MakeRGB (255, 0, 0);       // Red
00299       surface->xScreen = surface->yScreen = 0;
00300       EraseSurfaceRGB (surface, bg);
00301       DrawLine (surface, 0, 0, 63, 0, fg);
00302       DrawLine (surface, 63, 0, 63, 63, fg);
00303       DrawLine (surface, 63, 63, 0, 63, fg);
00304       DrawLine (surface, 63, 0, 0, 0, fg);
00305       char label[16];
00306       sprintf (label, "%03d,%03d", globe_x, globe_z);
00307       DrawTextC (surface, &globals->fonts.ftasci10, 32, 1, fg, label);
00308       int qx = (x / 32) % 2;
00309       int qz = (z / 32) % 2;
00310       sprintf (label, "Q%1d%1d", qx, qz);
00311       DrawTextC (surface, &globals->fonts.ftasci10, 32, 13, fg, label);
00312       int sx = (x / 4) % 8;
00313       int sz = (z / 4) % 8;
00314       sprintf (label, "S%1d%1d", sx, sz);
00315       DrawTextC (surface, &globals->fonts.ftasci10, 32, 25, fg, label);
00316       int dx = x % 4;
00317       int dz = z % 4;
00318       sprintf (label, "D%02d", (dx * 4) + dz);
00319       DrawTextC (surface, &globals->fonts.ftasci10, 32, 37, fg, label);
00320       DrawDot (surface, 31, 31, dot);
00321       DrawDot (surface, 32, 31, dot);
00322       DrawDot (surface, 31, 32, dot);
00323       DrawDot (surface, 32, 32, dot);
00324       texid = TextureFromSurface (surface, true);
00325       FreeSurface (surface);
00326       state->setTexture (texid);
00327     } else {
00328 
00330       state->setTexture ((GLuint) 0);
00331 
00332     }
00333 
00334     // Allocate texture coordinates
00335     ta = new ssgTexCoordArray (nPoints);
00336     for (int i=0; i<nPoints; i++) {
00337       SElevationLookupPoint *p = (SElevationLookupPoint *)(elev->points->getEntity(i));
00338       sgVec2 t;
00339       sgSetVec2 (t, p->x, p->z);
00340       ta->add (t);
00341     }
00342   }
00343 
00344   // Create leaf node
00345   ssgVtxTable *vtab = new ssgVtxTable (GL_TRIANGLE_FAN, va, NULL, ta, rgba);
00346   vtab->setState (state);
00347   top->addKid (vtab);
00348 }
00349 
00350 
00351 void CDetailTile::UpdateFanTexCoords (STileTextureInfo &info)
00352 {
00353   // Get leaf node
00354   ssgVtxTable *vtab = (ssgVtxTable *)top->getKid(0);
00355   ssgSimpleState *state = (ssgSimpleState *)vtab->getState ();
00356   ssgTexCoordArray *ta = vtab->getTexCoords ();
00357 
00358   // Update state with new texture ID
00359   state->setTexture (info.texid);
00360 
00361   // Update texcoord array
00362   float sDelta = info.urs - info.lls;
00363   float tDelta = info.urt - info.llt;
00364 
00365   int fanSize = elevLookup->u.fanData.nPoints;
00366   for (int i=0; i<fanSize; i++) {
00367     SElevationLookupPoint *p =
00368       (SElevationLookupPoint *)elevLookup->points->getEntity(i);
00369     sgVec2 t;
00370     sgSetVec2 (t, info.lls + (p->x * sDelta), info.llt + (p->z * tDelta));
00371     ta->set (t, i);
00372   }
00373 }
00374 
00375 
00376 //
00377 // Create tile geometry based on the elevation database returning a set of
00378 //   data points in a series of triangle strips
00379 //
00380 void CDetailTile::CreateStripGeometry (CElevationLookup *elev)
00381 {
00382   // Find cartesian coordinates of tile corners
00383   SVector vsw, vnw, vse, vne;
00384   vnw = PosToFlatCartesian (nw, globe_x, globe_z);
00385   vne = PosToFlatCartesian (ne, globe_x, globe_z);
00386   vse = PosToFlatCartesian (se, globe_x, globe_z);
00387   vsw = PosToFlatCartesian (sw, globe_x, globe_z);
00388 
00389   // NW corner is the base point for the E/W and N/S distances
00390   float ewDistance = vne.x - vnw.x;
00391   float nsDistance = vsw.y - vnw.y;
00392 
00393   ssgVertexArray *va = NULL;
00394   ssgColourArray *rgba = NULL;
00395   ssgTexCoordArray *ta = NULL;
00396   ssgSimpleState *state = NULL;
00397 
00398   SElevationLookupPoint *p = NULL;
00399 
00400   // Create triangle strip leaf nodes
00401   for (int i=0; i<elev->u.stripData.nStrips; i++) {
00402     // Create vertex array
00403     int nPoints = elev->u.stripData.stripSize;
00404 
00405     // Populate vertex array
00406     va = new ssgVertexArray(nPoints);
00407     p = (SElevationLookupPoint *)(elev->points->getEntity(i * nPoints));
00408     for (int j=0; j<nPoints; j++) {
00409       sgVec3 v;
00410       sgSetVec3 (v,
00411                  vsw.x + (p->x * ewDistance),
00412                  vsw.y + (p->z * nsDistance),
00413                  p->elevation);
00414       va->add (v);
00415 
00416       // Get next point from list
00417       p = (SElevationLookupPoint *)(elev->points->getNextEntity());
00418     }
00419 
00420     // Initialize state information for the detail tile
00421     state = new ssgSimpleState ();
00422     state->setShadeModel (GL_SMOOTH);
00423     state->disable (GL_LIGHTING);
00424     state->enable (GL_CULL_FACE);
00425     state->enable (GL_BLEND);
00426     state->disable (GL_ALPHA_TEST);
00427 
00428     // Check .ini setting to determine whether tiles are relief shaded or textured
00429     if (globals->settings->terrainReliefShaded) {
00430       // Terrain is relief-shaded
00431       state->disable (GL_TEXTURE_2D);
00432       state->enable (GL_COLOR_MATERIAL);
00433       state->setColourMaterial (GL_AMBIENT_AND_DIFFUSE);
00434       state->setMaterial (GL_EMISSION, 0, 0, 0, 1);
00435       state->setMaterial (GL_SPECULAR, 0, 0, 0, 1);
00436 
00437       // Populate colour array
00438       rgba = new ssgColourArray (nPoints);
00439       p = (SElevationLookupPoint *)(elev->points->getEntity(i * nPoints));
00440       for (int j=0; j<nPoints; j++) {
00441         float r, g, b;
00442         dtdb->GetReliefShadingRGB (p->elevation, r, g, b);
00443         sgVec4 c;
00444         sgSetVec4 (c, r, g, b, 1.0);
00445         rgba->add (c);
00446 
00447         // Get next point from list
00448         p = (SElevationLookupPoint *)(elev->points->getNextEntity());
00449       }
00450     } else {
00451       // Terrain is textured normally
00452       state->enable (GL_TEXTURE_2D);
00453       state->disable (GL_COLOR_MATERIAL);
00454 
00455       if (globals->terrainmgr->debugLevel == DETAIL_TILES) {
00456 
00457         // Create default tile debugging texture 
00458         SSurface *surface = CreateSurface (64, 64);
00459         unsigned int bg = MakeRGB (128, 128, 128);    // Medium grey
00460         unsigned int fg = MakeRGB (255, 255, 255);    // White
00461         unsigned int dot = MakeRGB (255, 0, 0);       // Red
00462         surface->xScreen = surface->yScreen = 0;
00463         EraseSurfaceRGB (surface, bg);
00464         DrawLine (surface, 0, 0, 63, 0, fg);
00465         DrawLine (surface, 63, 0, 63, 63, fg);
00466         DrawLine (surface, 63, 63, 0, 63, fg);
00467         DrawLine (surface, 63, 0, 0, 0, fg);
00468         char label[16];
00469         sprintf (label, "%03d,%03d", globe_x, globe_z);
00470         DrawTextC (surface, &globals->fonts.ftasci10, 32, 1, fg, label);
00471         int qx = (x / 32) % 2;
00472         int qz = (z / 32) % 2;
00473         sprintf (label, "Q%1d%1d", qx, qz);
00474         DrawTextC (surface, &globals->fonts.ftasci10, 32, 13, fg, label);
00475         int sx = (x / 4) % 8;
00476         int sz = (z / 4) % 8;
00477         sprintf (label, "S%1d%1d", sx, sz);
00478         DrawTextC (surface, &globals->fonts.ftasci10, 32, 25, fg, label);
00479         int dx = x % 4;
00480         int dz = z % 4;
00481         sprintf (label, "D%02d", (dx * 4) + dz);
00482         DrawTextC (surface, &globals->fonts.ftasci10, 32, 37, fg, label);
00483         DrawDot (surface, 31, 31, dot);
00484         DrawDot (surface, 32, 31, dot);
00485         DrawDot (surface, 31, 32, dot);
00486         DrawDot (surface, 32, 32, dot);
00487         texid = TextureFromSurface (surface, true);
00488         FreeSurface (surface);
00489         state->setTexture (texid);
00490       } else {
00492         state->setTexture ((GLuint) 0);
00493       }
00494 
00495       // Get the composite texture name for this tile
00496       dtdb->GetCompositeTextureName (x, z, defaultTextureName);
00497 
00498       // Allocate texture coordinates
00499       ta = new ssgTexCoordArray (nPoints);
00500       p = (SElevationLookupPoint *)(elev->points->getEntity(i * nPoints));
00501       for (int j=0; j<nPoints; j++) {
00502         sgVec2 t;
00503         sgSetVec2 (t, p->x, p->z);
00504         ta->add (t);
00505 
00506         // Get next point from list
00507         p = (SElevationLookupPoint *)(elev->points->getNextEntity());
00508       }
00509     }
00510 
00511     // Create leaf node
00512     ssgVtxTable *vtab = new ssgVtxTable (GL_TRIANGLE_STRIP, va, NULL, ta, rgba);
00513     vtab->setState (state);
00514     top->addKid (vtab);
00515   }
00516 }
00517 
00518 void CDetailTile::UpdateStripTexCoords (STileTextureInfo &info)
00519 {
00520   int n = elevLookup->u.stripData.nStrips;
00521   for (int i=0; i<n; i++) {
00522     // Get leaf node
00523     ssgVtxTable *vtab = (ssgVtxTable *)top->getKid(i);
00524     ssgSimpleState *state = (ssgSimpleState *)vtab->getState ();
00525     ssgTexCoordArray *ta = vtab->getTexCoords ();
00526 
00527     // Update state with new texture ID
00528     state->setTexture (info.texid);
00529 
00530     // Update texcoord array
00531     float sDelta = info.urs - info.lls;
00532     float tDelta = info.urt - info.llt;
00533 
00534     int stripSize = elevLookup->u.stripData.stripSize;
00535     for (int j=0; j<stripSize; j++) {
00536       SElevationLookupPoint *p =
00537         (SElevationLookupPoint *)elevLookup->points->getEntity(i * stripSize + j);
00538       sgVec2 t;
00539       sgSetVec2 (t, info.lls + (p->x * sDelta), info.llt + (p->z * tDelta));
00540       ta->set (t, j);
00541     }
00542   }
00543 }
00544 
00545 void CDetailTile::Create (void)
00546 {
00547   // Ensure there is valid low-resolution texture info.  If a fulltex image
00548   //   was found for the QGT then it should have been supplied through a call
00549   //   to AssignTexture.  If not then the texture info will be default, and
00550   //   the default terrain texture should be used
00551   STileTextureInfo &info = texinfo[detail];
00552   if (info.texid == 0) {
00553     LoadDefaultTexture (detail);
00554   }
00555 
00556   // Lookup elevations for this detail tile from the database.  The elevation
00557   //   points determine the geometry of the mesh for this tile
00558   elevLookup = tedb->GetDetailTileElevations (x, z);
00559   if (elevLookup == NULL) {
00560     gtfo ("CDetailTile : Could not get elevations for DT %d,%d", x, z);
00561   }
00562 
00563   switch (elevLookup->glType) {
00564   case GL_TRIANGLE_FAN:
00565     CreateFanGeometry (elevLookup);
00566     UpdateFanTexCoords (info);
00567     break;
00568 
00569   case GL_TRIANGLE_STRIP:
00570     CreateStripGeometry (elevLookup);
00571     UpdateStripTexCoords (info);
00572     break;
00573   }
00574 
00575   CTerrainTile::Create ();
00576 }
00577 
00578 void CDetailTile::Destroy (void)
00579 {
00580   if (elevLookup != NULL) {
00581     delete elevLookup;
00582     elevLookup = NULL;
00583   }
00584 
00585   CTerrainTile::Destroy ();
00586 }
00587 
00588 
SourceForge.net Logo Documentation generated by doxygen