mod_sim_terrain_heightmap.hh

Go to the documentation of this file.
00001 /*
00008  * LEGAL:   COPYRIGHT (C) 2007 JIM E. BROOKS
00009  *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
00010  *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
00011  *****************************************************************************/
00012 
00013 #if COMPILING_MODULE
00014 #ifndef MOD_SIM_TERRAIN_HEIGHTMAP_HH
00015 #define MOD_SIM_TERRAIN_HEIGHTMAP_HH 1
00016 
00017 #include "eng_task.hh"
00018 
00019 namespace mod_sim {
00020 
00034 class Heightmap : public Shared
00035 {
00036   // way too big to copy
00037 friend class Terrain;
00038 friend class TileFactory;
00039 public:
00040     typedef uint8 Height;
00041     CLASS_CONST uint HEIGHT_INVALID = 0xff;
00042     CLASS_CONST uint HEIGHT_LIMIT   = 0xfe;
00043 
00044 public:
00050     class Elem
00051     {
00052     public:
00053         // Uninitialized for speed, Heightmap() ctor can clear optionally.
00054         Elem( void )
00055         {
00056             
00057         }
00058 
00059         ~Elem( void ) { }
00060 
00062         fp GetHeight( void ) const
00063         {
00064             ASSERT( mHeight != Heightmap::HEIGHT_INVALID );  // was element computed?
00065 
00066             return fp(mHeight) / fp(Heightmap::HEIGHT_LIMIT);
00067         }
00068 
00069         Heightmap::Height GetHeightDirect( void ) const
00070         {
00071             ASSERT( mHeight != Heightmap::HEIGHT_INVALID );  // was element computed?
00072 
00073             return mHeight;
00074         }
00075 
00076         void SetHeight( Heightmap::Height height )
00077         {
00078             // Change height in case value has the reserved invalid value.
00079             
00080 
00081             mHeight = height;
00082         }
00083 
00084     private:
00085         Heightmap::Height   mHeight;  
00086     };
00087 
00088 //------------------------------------------------------------------------------
00089 // Parameters for initializing a Heightmap.
00090 public:
00091     struct InitArgs
00092     {
00093         InitArgs( const BoxVolume& boxVolume,
00094                   const int        heightmapWidth,
00095                   const fp         heightScale );
00096         #if DEBUG
00097         void Check( void ) const;
00098         #endif
00099 
00100         // See Heightmap data members for desc.
00101         BoxVolume   mBoxVolume;         // passed
00102         int         mHeightmapWidth;    // passed
00103         fp          mHeightScale;       // passed
00104         fp          mWidthInWorld;      // computed
00105     };
00106 
00107 //------------------------------------------------------------------------------
00108 // Noise args:
00109 public:
00110     struct NoiseArgs
00111     {
00112         NoiseArgs( fp inc, fp z ) : mInc(inc), mZ(z) { }
00113         fp      mInc;   // increment across coordinates in Noise Space
00114         fp      mZ;     // Z in 3D Noise Space
00115     };
00116 
00117 //------------------------------------------------------------------------------
00118 // Graphic task:
00119 private:
00120     class TextureTask : public Task::TaskFunctor
00121     {
00122     public:
00123         TextureTask( Heightmap& heightmap, Array2D<Texture::Texel32>& colormap )
00124         : mHeightmap(heightmap), mColormap(colormap)
00125         {
00126         }
00127         void operator()( void );
00128 
00129         Heightmap&                  mHeightmap;
00130         Array2D<Texture::Texel32>&  mColormap;
00131     };
00132     friend class TextureTask;
00133 
00134 //------------------------------------------------------------------------------
00135 // Heightmap methods:
00136 //
00137 // Note: There are two (lat,lon) coordinate spaces:
00138 // (hmLat,hmLon) and (worldLat,worldLon).
00139 
00140 public:
00141             Heightmap( void );
00142             Heightmap( const InitArgs& initArgs );
00143             Heightmap( const InitArgs& initArgs, const NoiseArgs& noiseArgs );
00144             ~Heightmap();
00145 
00146 private:
00147     void    Init( const InitArgs& initArgs );
00148     void    InitRandomNumbers( const InitArgs& initArgs );
00149     void    ComputePalette( void );
00150 
00151 public:
00152     void SetHeight( const int hmLat, const int hmLon, const Height height )
00153     {
00154     ASSERT2( mValid );
00155 
00156         return mHeightmap.Get(hmLat,hmLon).SetHeight( height );  // Elem::GetHeight()
00157     }
00158 
00160     fp GetHeight( const int hmLat, const int hmLon ) const
00161     {
00162     ASSERT2( mValid );
00163   //ASSERT2( (hmLat < mHeightmapWidth) && (hmLon < mHeightmapWidth) );  // let Array2D clamp
00164 
00165         return mHeightmap.Get(hmLat,hmLon).GetHeight();  // Elem::GetHeight()
00166     }
00167 
00168     Heightmap::Height GetHeightDirect( const int hmLat, const int hmLon ) const
00169     {
00170     ASSERT2( mValid );
00171   //ASSERT2( (hmLat < mHeightmapWidth) && (hmLon < mHeightmapWidth) );  // let Array2D clamp
00172 
00173         return mHeightmap.Get(hmLat,hmLon).GetHeightDirect();
00174     }
00175 
00177     fp GetHeightScaled( const int hmLat, const int hmLon ) const
00178     {
00179     ASSERT2( mValid );
00180     ASSERT2( mHeightScale > 0.0 );
00181 
00182         return GetHeight(hmLat,hmLon) * mHeightScale;
00183     }
00184 
00186     fp GetHeightScaledInterpolated( const fp worldLat, const fp worldLon ) const
00187     {
00188     ASSERT2( mValid );
00189     ASSERT2( mHeightmapWorldRatio != 0.0 );
00190     ASSERT2( IfInsideApprox(worldLat,worldLon) );
00191 
00192         // (worldCoord-worldCoord) * (mapCoord/worldCoord) = worldCoord * (mapCoord/worldCood) = mapCoord
00193         int hmLat = int((worldLat - mBoxVolume.mMin.LAT_) * mHeightmapWorldRatio);
00194         int hmLon = int((worldLon - mBoxVolume.mMin.LON_) * mHeightmapWorldRatio);
00195         // TODO: Interpolation formula.
00196         return GetHeightScaled( hmLat, hmLon );
00197     }
00198 
00199     // Get an average height value.
00200     CLASS_METHOD Heightmap::Height
00201     GetHeightMedian( void );
00202 
00203     // Convert height into a world coordinate.
00204     fp ScaleHeight( const Height height )
00205     {
00206     ASSERT2( mHeightScale > 0.0 );
00207         return fp(height) / fp(HEIGHT_LIMIT) * mHeightScale;
00208     }
00209 
00211     WorldVertex GetPosition( const int hmLat, const int hmLon ) const
00212     {
00213     ASSERT2( mValid );
00214     ASSERT2( mWorldHeightmapRatio > 0.0 );
00215     ASSERT2( IfInsideApprox( hmLat * mWorldHeightmapRatio,
00216                              hmLon * mWorldHeightmapRatio ) );
00217 
00218         // mapCoord * (worldCoord/mapCoord) = worldCoord
00219         return WorldVertex( LAT_LON_ALT( mBoxVolume.mMin.LAT_ + hmLat * mWorldHeightmapRatio,
00220                                          mBoxVolume.mMin.LON_ + hmLon * mWorldHeightmapRatio,
00221                                          GetHeightScaled(hmLat,hmLon) ) );
00222     }
00223 
00225     uint GetIdx( const int hmLat, const int hmLon ) const
00226     {
00227     ASSERT2( mValid );
00228   //ASSERT2( (hmLat < mHeightmapWidth) && (hmLon < mHeightmapWidth) );  // let Array2D clamp
00229 
00230         return mHeightmap.GetIdx( hmLat, hmLon );
00231     }
00232 
00233     SharedPtr<Texture> GetColormapTexture( void ) const
00234     {
00235         return mColormapTexture;
00236     }
00237 
00238     TexCoord GetColormapTexCoord( const fp worldLat, const fp worldLon ) const
00239     {
00240         // Clamp tex coords.
00241         const fp tx = Clamp1( (worldLat - mBoxVolume.mMin.LAT_) / mWidthInWorld );
00242         const fp ty = Clamp1( (worldLon - mBoxVolume.mMin.LON_) / mWidthInWorld );
00243       //return TexCoord( tx, ty );
00244         return TexCoord( ty, tx );  // transpose
00245     }
00246 
00247 #if DEBUG
00248     bool IfInsideApprox( const fp worldLat, const fp worldLon ) const;
00249 #endif
00250 
00251     // Directly access element by flat index.
00252     Elem&       operator[]( uint i )       { return mHeightmap[i]; }  // Array2D[i]
00253     const Elem& operator[]( uint i ) const { return mHeightmap[i]; }
00254 
00255 //------------------------------------------------------------------------------
00256 // Water texture:
00257     class WaterTexture
00258     {
00259     public:
00260                 WaterTexture( const uint heightmapWidth );
00261                 ~WaterTexture();
00262 
00266         inline uint
00267         CLAMP_WATER_COLOR( uint in )
00268         {
00269             if ( in < 0 )
00270                 return 0;
00271             else if ( in > 150 )
00272                 return 150;
00273             else
00274                 return in;
00275         }
00276 
00281         inline Texture::Texel32
00282         GetTexel( const uint lat, const uint lon )
00283         {
00284             uint bufIdx = uint((lat * mIdxRatio) + (lon * mIdxRatio * mBufWidth)) << 2;
00285             ASSERT( bufIdx+3 < mBufLen );
00286             const uint8* c = reinterpret_cast<const uint8*>( &mBuf[bufIdx] );
00287             return ( CLAMP_WATER_COLOR(c[BB]- 70) << TexelDefs::TEXEL32_BB_BIT_SHIFT )
00288                  | ( CLAMP_WATER_COLOR(c[GG]-180) << TexelDefs::TEXEL32_GG_BIT_SHIFT )
00289                  | ( CLAMP_WATER_COLOR(c[RR]-180) << TexelDefs::TEXEL32_RR_BIT_SHIFT )
00290                  | (                   c[AA]      << TexelDefs::TEXEL32_AA_BIT_SHIFT );
00291 
00292         }
00293 
00294     private:
00295         Targa*          mTarga;
00296         const uint8*    mBuf;           // see Targa
00297         uint            mBufLen;
00298         uint            mBufWidth;
00299         fp              mIdxRatio;      // maps heightmap (lat,lon) to waterTexture (tx,ty)
00300     };
00301 
00302 //------------------------------------------------------------------------------
00303 // Heightmap data:
00304 //
00305 // BoxVolume:
00306 // Part of the World this Heightmap occupies.
00307 //
00308 // HeightmapWidth:
00309 // Determines the size of the Heightmap 2D array.
00310 // Width is in terms of height values.
00311 // This width is allowed to differ from the width of the texture image.
00312 // If heightmapWidth is smaller than the texture width, resolution will be lost.
00313 //
00314 // HeightScale:
00315 // Multiplies a Height value.
00316 // Equivalent to the altitude limit in World Space.
00317 
00318 private:
00319     CLASS_VAR int           msHeightmapWidthMinus1;  // tweak
00320     CLASS_VAR Array2D<fp>   msRandomHeight;  
00321     CLASS_VAR Array2D<uint> msRandomColor;   
00322     CLASS_VAR vector<RGBA>  msPalette;       
00323     CLASS_VAR WaterTexture* msWaterTexture;
00324 
00325     bool            mValid;
00326 
00327     // Spatial:
00328     BoxVolume       mBoxVolume;             
00329     fp              mWidthInWorld;          
00330     fp              mHeightScale;           
00331     fp              mHeightScaleHalf;
00332     fp              mWorldHeightmapRatio;   
00333     fp              mHeightmapWorldRatio;   
00334 
00335     // Heightmap:
00336     typedef Array2D<Elem,Shared> HeightmapArray2D;
00337     HeightmapArray2D mHeightmap;            
00338     int             mHeightmapWidth;        
00339 
00340     // Colormap:
00341     shptr<Texture>  mColormapTexture;       
00342 
00343 #if DEBUG
00344 public:
00345     CLASS_VAR bool msDisableIfInsideApprox;  // some cases do produce (lat,lon) outside a volume
00346 #endif
00347 };
00348 
00349 } // namespace mod_sim
00350 
00351 #endif // MOD_SIM_TERRAIN_HEIGHTMAP_HH
00352 #endif // COMPILING_MODULE
Palomino 3D Engine documents generated by doxygen 1.5.3 on Fri Nov 23 11:26:13 2007