LandVisibilityPatch.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <land/LandVisibilityPatch.h>
00022 #include <land/VisibilityPatchGrid.h>
00023 #include <landscapemap/LandscapeMaps.h>
00024 #include <landscapemap/GraphicalHeightMap.h>
00025 #include <landscape/GraphicalLandscapeMap.h>
00026 #include <graph/OptionsDisplay.h>
00027 #include <graph/MainCamera.h>
00028 #include <client/ScorchedClient.h>
00029 #include <common/Logger.h>
00030 #include <GLEXT/GLStateExtension.h>
00031 #include <GLEXT/GLInfo.h>
00032 #include <GLW/GLWFont.h>
00033 
00034 LandVisibilityPatch::LandVisibilityPatch() : 
00035         visible_(false), recalculateErrors_(false),
00036         leftPatch_(0), rightPatch_(0),
00037         topPatch_(0), bottomPatch_(0),
00038         visibilityIndex_(-1),
00039         dataSize_(0)
00040 {
00041 }
00042 
00043 LandVisibilityPatch::~LandVisibilityPatch()
00044 {
00045 }
00046 
00047 static float getHeight(int x, int y)
00048 {
00049         int mapWidth = ScorchedClient::instance()->getLandscapeMaps().
00050                 getGroundMaps().getLandscapeWidth();
00051 
00052         GraphicalLandscapeMap *landscapeMap = (GraphicalLandscapeMap *)
00053                 ScorchedClient::instance()->getLandscapeMaps().
00054                         getGroundMaps().getHeightMap().getGraphicalMap();
00055         return landscapeMap->getHeightData()[x + (y * (mapWidth + 1))].floatPosition[2];
00056 }
00057 
00058 static float calculateError(int x1, int x2, int y1, int y2,
00059         float x1y1, float x2y2, float x1y2, float x2y1)
00060 {
00061         if (x2 - x1 <= 1) return 0.0f;
00062 
00063         int midx = (x1 + x2) / 2;
00064         int midy = (y1 + y2) / 2;
00065         float actualheight = getHeight(midx, midy);
00066 
00067         float approxheight1 = (x1y1 + x2y2) / 2.0f;
00068         float approxheight2 = (x1y2 + x2y1) / 2.0f;
00069         float approxheight3 = (x1y1 + x1y2) / 2.0f;
00070         float approxheight4 = (x1y1 + x2y1) / 2.0f;
00071         float approxheight5 = (x1y2 + x2y2) / 2.0f;
00072         float approxheight6 = (x2y1 + x2y2) / 2.0f;
00073 
00074         float heightdiff1 = fabs(approxheight1 - actualheight);
00075         float heightdiff2 = fabs(approxheight2 - actualheight);
00076         
00077         float errorChild1 = calculateError(x1, midx, y1, midy,
00078                 x1y1, approxheight1, approxheight3, approxheight4);
00079         float errorChild2 = calculateError(midx, x2, y1, midy,
00080                 approxheight4, approxheight6, approxheight1, x2y1);
00081         float errorChild3 = calculateError(x1, midx, midy, y2,
00082                 approxheight3, approxheight5, x1y2, approxheight2);
00083         float errorChild4 = calculateError(midx, x2, midy, y2,
00084                 approxheight2, x2y2, approxheight5, approxheight6);
00085 
00086         float errorChildren = MAX(errorChild1, MAX(errorChild2, MAX(errorChild3, errorChild4)));
00087         float totalError = MAX(errorChildren, MAX(heightdiff1, heightdiff2));
00088         return totalError;
00089 }
00090 
00091 void LandVisibilityPatch::setLocation(int x, int y,
00092         LandVisibilityPatch *leftPatch, 
00093         LandVisibilityPatch *rightPatch, 
00094         LandVisibilityPatch *topPatch, 
00095         LandVisibilityPatch *bottomPatch)
00096 {
00097         int mapWidth = ScorchedClient::instance()->getLandscapeMaps().
00098                 getGroundMaps().getLandscapeWidth();
00099         int mapHeight = ScorchedClient::instance()->getLandscapeMaps().
00100                 getGroundMaps().getLandscapeHeight();
00101 
00102         DIALOG_ASSERT(x >= 0 && y >= 0 &&
00103                 x < mapWidth && y < mapHeight);
00104 
00105         // Set location and neighbors
00106         x_ = x; y_ = y;
00107         leftPatch_ = leftPatch;
00108         rightPatch_ = rightPatch;
00109         topPatch_ = topPatch;
00110         bottomPatch_ = bottomPatch;
00111 
00112         // Set pointers to heightmap
00113         dataSize_ = (mapWidth + 1) * (mapHeight + 1);
00114 
00115         GraphicalLandscapeMap *landscapeMap = (GraphicalLandscapeMap *)
00116                 ScorchedClient::instance()->getLandscapeMaps().
00117                         getGroundMaps().getHeightMap().getGraphicalMap();
00118         dataOffSet_ = (x + (y * (mapWidth + 1))) * 
00119                 sizeof(GraphicalLandscapeMap::HeightData) / sizeof(float);
00120 
00121         calculateErrors();
00122 }
00123 
00124 void LandVisibilityPatch::calculateErrors()
00125 {
00126         maxHeight_ = 0.0f;
00127         minHeight_ = 100000.0f;
00128         for (int i=0; i<=5; i++)
00129         {
00130                 float error = 0.0f;
00131                 if (i>0)
00132                 {
00133                         int skip = 1 << i;
00134                         for (int y1=y_; y1<y_+32; y1+=skip)
00135                         {
00136                                 for (int x1=x_; x1<x_+32; x1+=skip)
00137                                 {
00138                                         int x2 = x1 + skip;
00139                                         int y2 = y1 + skip;
00140 
00141                                         float x1y1 = getHeight(x1, y1);
00142                                         float x2y2 = getHeight(x2, y2);
00143                                         float x1y2 = getHeight(x1, y2);
00144                                         float x2y1 = getHeight(x2, y1);
00145 
00146                                         float thisError = calculateError(x1, x2, y1, y2,
00147                                                 x1y1, x2y2, x1y2, x2y1);
00148                                         error = MAX(error, thisError);          
00149 
00150                                         if (x1y1 > maxHeight_) maxHeight_ = x1y1;
00151                                         if (x1y1 < minHeight_) minHeight_ = x1y1;
00152                                 }
00153                         }
00154                 }
00155 
00156                 indexErrors_[i] = error;
00157         }
00158 
00159         float heightRange = maxHeight_ - minHeight_;
00160         boundingSize_ = MAX(32.0f, heightRange) * 1.25f;
00161         position_ = Vector(float(x_ + 16), float(y_ + 16), 
00162                 heightRange / 2.0f + minHeight_);
00163 }
00164 
00165 bool LandVisibilityPatch::setVisible(float distance)
00166 { 
00167         visible_ = true;
00168 
00169         if (recalculateErrors_) 
00170         {
00171                 calculateErrors();
00172                 recalculateErrors_ = false;
00173         }
00174 
00175         float landDetailLevelRamp = (float) 
00176                 OptionsDisplay::instance()->getLandDetailLevelRamp();
00177         float maxError = ((distance - 32.0f) / landDetailLevelRamp) + 1.0f;
00178         if (maxError < 1.0f) maxError = 1.0f;
00179         else if (maxError > 5.0f) maxError = 5.0f;
00180 
00181         visibilityIndex_ = 0;
00182         if (!OptionsDisplay::instance()->getNoLandLOD())
00183         {
00184                 for (int i=0; i<=5; i++)
00185                 {
00186                         if (indexErrors_[i] > maxError) break;
00187                         visibilityIndex_ = i;
00188                 }
00189         }
00190 
00191         return true;
00192 }
00193 
00194 void LandVisibilityPatch::setNotVisible()
00195 {
00196         visible_ = false;
00197 }
00198 
00199 void LandVisibilityPatch::draw(MipMapPatchIndex &index, bool simple)
00200 {
00201         GraphicalLandscapeMap *landscapeMap = (GraphicalLandscapeMap *)
00202                 ScorchedClient::instance()->getLandscapeMaps().
00203                         getGroundMaps().getHeightMap().getGraphicalMap();
00204         float *heightMapData = &landscapeMap->getHeightData()->floatPosition[0];
00205 
00206         // Number triangles
00207         GLInfo::addNoTriangles(index.getSize() - 2);
00208 
00209         if (!OptionsDisplay::instance()->getNoGLDrawElements() &&
00210                 GLStateExtension::hasDrawRangeElements())
00211         {
00212                 // Map data to draw
00213                 float *data = 0;
00214                 if (landscapeMap->getBufferObject())
00215                 {
00216                         data = (float*) NULL + dataOffSet_;
00217                 }
00218                 else
00219                 {
00220                         data = &heightMapData[dataOffSet_];
00221                 }
00222 
00223                 // Vertices On
00224                 glVertexPointer(3, GL_FLOAT, sizeof(GraphicalLandscapeMap::HeightData), data);
00225 
00226                 if (!simple)
00227                 {
00228                         // Normals On
00229                         glNormalPointer(GL_FLOAT, sizeof(GraphicalLandscapeMap::HeightData), data + 3);
00230 
00231                         // Tex Coords
00232                         if (GLStateExtension::hasMultiTex())
00233                         {
00234                                 glClientActiveTextureARB(GL_TEXTURE1_ARB);
00235                                 glTexCoordPointer(2, GL_FLOAT, sizeof(GraphicalLandscapeMap::HeightData), data + 6);
00236                                 if (GLStateExtension::getTextureUnits() > 2)
00237                                 {
00238                                         glClientActiveTextureARB(GL_TEXTURE2_ARB);
00239                                         glTexCoordPointer(2, GL_FLOAT, sizeof(GraphicalLandscapeMap::HeightData), data + 8);
00240                                 }
00241                         }
00242                         glClientActiveTextureARB(GL_TEXTURE0_ARB);
00243                         glTexCoordPointer(2, GL_FLOAT, sizeof(GraphicalLandscapeMap::HeightData), data + 6);
00244                 }
00245 
00246                 // Map indices to draw
00247                 unsigned short *indices = 0;
00248                 if (index.getBufferOffSet() != -1)
00249                 {
00250                         indices = (unsigned short *) NULL + (index.getBufferOffSet() / sizeof(unsigned short));
00251                 }
00252                 else
00253                 {
00254                         indices = index.getIndices();
00255                 }
00256 
00257                 // Draw elements
00258                 glDrawRangeElements(GL_TRIANGLE_STRIP, 
00259                         index.getMinIndex(), 
00260                         index.getMaxIndex(),
00261                         index.getSize(), 
00262                         GL_UNSIGNED_SHORT, 
00263                         indices);
00264                 DIALOG_ASSERT((index.getMaxIndex()-index.getMinIndex()+1) < 
00265                         GLStateExtension::getMaxElementVertices());
00266                 DIALOG_ASSERT(index.getSize() < 
00267                         GLStateExtension::getMaxElementIndices());
00268         }
00269         else
00270         {
00271                 glBegin(GL_TRIANGLE_STRIP);
00272                         for (int i=0; i<index.getSize(); i++)
00273                         {
00274                                 float *data = &heightMapData[dataOffSet_] + 
00275                                         (sizeof(GraphicalLandscapeMap::HeightData) / 4 * index.getIndices()[i]);
00276                                 if (!simple)
00277                                 {
00278                                         glNormal3fv(data + 3);
00279                                         glTexCoord2fv(data + 6);
00280                                         if (GLStateExtension::hasMultiTex())
00281                                         {
00282                                                 glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, data + 6);
00283                                                 if (GLStateExtension::getTextureUnits() > 2)
00284                                                 {
00285                                                         glMultiTexCoord2fvARB(GL_TEXTURE2_ARB, data + 8);
00286                                                 }
00287                                         }
00288                                 }
00289 
00290                                 glVertex3fv(data);
00291                         }
00292                 glEnd();
00293         }
00294 }
00295 
00296 void LandVisibilityPatch::drawLODLevel(MipMapPatchIndex &index)
00297 {
00298         if (OptionsDisplay::instance()->getDrawLines()) glPolygonMode(GL_FRONT, GL_FILL);
00299 
00300         GraphicalLandscapeMap *landscapeMap = (GraphicalLandscapeMap *)
00301                 ScorchedClient::instance()->getLandscapeMaps().
00302                         getGroundMaps().getHeightMap().getGraphicalMap();
00303         float *heightMapData = &landscapeMap->getHeightData()->floatPosition[0];
00304 
00305         Vector red(1.0f, 0.0f, 0.0f);
00306         Vector yellow(1.0f, 1.0f, 0.0f);
00307         GLWFont::instance()->getGameFont()->drawBilboard(red, 1.0f, 3.0f, 
00308                 position_[0], position_[1], position_[2], 
00309                 S3D::formatStringBuffer("%i", visibilityIndex_));
00310 
00311         if ((MainCamera::instance()->getCamera().getLookAt() - position_).Magnitude() < 20.0f)
00312         {
00313                 for (int i=0; i<index.getSize(); i++)
00314                 {
00315                         float *data = &heightMapData[dataOffSet_] + 
00316                                 (sizeof(GraphicalLandscapeMap::HeightData) / 4 * index.getIndices()[i]);
00317 
00318                         GLWFont::instance()->getGameFont()->drawBilboard(yellow, 1.0f, 1.0f, 
00319                                 data[0], data[1], data[2] + i * 1.5f, 
00320                                 S3D::formatStringBuffer("%i", i));
00321                 }
00322         }
00323 
00324         if (OptionsDisplay::instance()->getDrawLines()) glPolygonMode(GL_FRONT, GL_LINE);
00325 }

Generated on Mon Feb 16 15:14:47 2009 for Scorched3D by  doxygen 1.5.3