VisibilityPatchGrid.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/VisibilityPatchGrid.h>
00022 #include <landscape/Landscape.h>
00023 #include <water/Water2Patches.h>
00024 #include <sky/Sky.h>
00025 #include <landscapemap/LandscapeMaps.h>
00026 #include <landscape/GraphicalLandscapeMap.h>
00027 #include <client/ScorchedClient.h>
00028 #include <engine/GameState.h>
00029 #include <GLEXT/GLStateExtension.h>
00030 #include <GLEXT/GLVertexBufferObject.h>
00031 #include <GLEXT/GLCamera.h>
00032 #include <GLSL/GLSLShaderSetup.h>
00033 #include <graph/OptionsDisplay.h>
00034 
00035 VisibilityPatchGrid *VisibilityPatchGrid::instance()
00036 {
00037         static VisibilityPatchGrid instance;
00038         return &instance;
00039 }
00040 
00041 VisibilityPatchGrid::VisibilityPatchGrid() : 
00042         landPatches_(0), targetPatches_(0), 
00043         waterPatches_(0), visibilityPatches_(0),
00044         epoc_(0)
00045 {
00046 }
00047 
00048 VisibilityPatchGrid::~VisibilityPatchGrid()
00049 {
00050 }
00051 
00052 void VisibilityPatchGrid::clear()
00053 {
00054         delete [] landPatches_;
00055         landPatches_ = 0;
00056 
00057         delete [] waterPatches_;
00058         waterPatches_ = 0;
00059 
00060         delete [] targetPatches_;
00061         targetPatches_ = 0;
00062 
00063         delete [] visibilityPatches_;
00064         visibilityPatches_ = 0;
00065 }
00066 
00067 void VisibilityPatchGrid::generate()
00068 {
00069         clear();
00070         epoc_++;
00071 
00072         // Figure out how large the visible area will be
00073         int mapWidth = ScorchedClient::instance()->getLandscapeMaps().
00074                 getGroundMaps().getLandscapeWidth();
00075         int mapHeight = ScorchedClient::instance()->getLandscapeMaps().
00076                 getGroundMaps().getLandscapeHeight();
00077         int actualWidth = mapWidth + 4096; // The map visible area is at least 4096*4096
00078         int actualHeight = mapHeight + 4096;
00079         actualWidth = (actualWidth / 512) * 512; // The actual width and height are multiples of 512
00080         actualHeight = (actualHeight / 512) * 512;
00081 
00082         // Generate land indices
00083         landIndexs_.generate(32, mapWidth);
00084 
00085         // Find the mid point
00086         midX_ = -actualWidth / 2 + mapWidth / 2;
00087         midY_ = -actualHeight / 2 + mapHeight / 2;
00088         midX_ = (midX_ / 32) * 32; // Move to the nearest 32 boundry
00089         midY_ = (midY_ / 32) * 32;
00090 
00091         {
00092                 // Devide this visible area into a set of patches
00093                 landWidth_ = mapWidth / 32;
00094                 landHeight_ = mapHeight / 32;
00095 
00096                 // Create the patches
00097                 landPatches_ = new LandVisibilityPatch[landWidth_ * landHeight_];
00098 
00099                 // For each patch set it's location
00100                 LandVisibilityPatch *currentPatch = landPatches_;
00101                 for (int y=0; y<landHeight_; y++)
00102                 {
00103                         for (int x=0; x<landWidth_; x++, currentPatch++)
00104                         {
00105                                 LandVisibilityPatch *leftPatch = (x==0?0:currentPatch-1);
00106                                 LandVisibilityPatch *rightPatch = (x==landWidth_-1?0:currentPatch+1);
00107                                 LandVisibilityPatch *topPatch = (y==0?0:currentPatch-landWidth_);
00108                                 LandVisibilityPatch *bottomPatch = (y==landHeight_-1?0:currentPatch+landWidth_);
00109 
00110                                 currentPatch->setLocation(x * 32, y * 32,
00111                                         leftPatch, rightPatch, topPatch, bottomPatch);
00112                         }
00113                 }
00114         }
00115 
00116         {
00117                 // Divide this visible area into a set of patches
00118                 targetWidth_ = actualWidth / 32;
00119                 targetHeight_ = actualHeight / 32;
00120 
00121                 // Create the patches
00122                 targetPatches_ = new TargetVisibilityPatch[targetWidth_ * targetHeight_];
00123 
00124                 // For each patch set it's location
00125                 TargetVisibilityPatch *currentPatch = targetPatches_;
00126                 for (int y=0; y<targetHeight_; y++)
00127                 {
00128                         for (int x=0; x<targetWidth_; x++, currentPatch++)
00129                         {
00130                                 currentPatch->setLocation(x * 32 + midX_, y * 32  + midY_);
00131                         }
00132                 }
00133         }
00134 
00135         {
00136                 // Divide this visible area into a set of patches
00137                 waterWidth_ = actualWidth / 128;
00138                 waterHeight_ = actualHeight / 128;
00139 
00140                 // Create the patches
00141                 waterPatches_ = new WaterVisibilityPatch[waterWidth_ * waterHeight_];
00142 
00143                 // For each patch set it's location
00144                 WaterVisibilityPatch *currentPatch = waterPatches_;
00145                 for (int y=0, py=0; y<waterHeight_; y++, py++)
00146                 {
00147                         for (int x=0, px=0; x<waterWidth_; x++, currentPatch++, px++)
00148                         {
00149                                 WaterVisibilityPatch *leftPatch = (x==0?0:currentPatch-1);
00150                                 WaterVisibilityPatch *rightPatch = (x==waterWidth_-1?0:currentPatch+1);
00151                                 WaterVisibilityPatch *topPatch = (y==0?0:currentPatch-waterWidth_);
00152                                 WaterVisibilityPatch *bottomPatch = (y==waterHeight_-1?0:currentPatch+waterWidth_);
00153 
00154                                 currentPatch->setLocation(x * 128 + midX_, y * 128 + midY_,
00155                                         px % 2, py % 2,
00156                                         leftPatch, rightPatch, topPatch, bottomPatch);
00157                         }
00158                 }
00159         }
00160 
00161         {
00162                 // Devide this visible area into a set of visibility test patches
00163                 visibilityWidth_ = actualWidth / 512;
00164                 visibilityHeight_ = actualHeight / 512;
00165 
00166                 // Create the set of visibility patches
00167                 visibilityPatches_ = new VisibilityPatchQuad[visibilityWidth_ * visibilityHeight_];
00168 
00169                 // Set the visibility location
00170                 VisibilityPatchQuad *currentPatch = visibilityPatches_;
00171                 for (int y=0; y<visibilityHeight_; y++)
00172                 {
00173                         for (int x=0; x<visibilityWidth_; x++, currentPatch++)
00174                         {
00175                                 currentPatch->setLocation(this, x * 512 + midX_, y * 512 + midY_, 512,
00176                                         mapWidth, mapHeight);
00177                         }
00178                 }
00179         }
00180 
00181         {
00182                 patchInfo_.generate(
00183                         landWidth_ * landHeight_, 
00184                         waterWidth_ * waterHeight_, 
00185                         targetWidth_ * targetHeight_);
00186         }
00187 
00188         surround_.generate();
00189 }
00190 
00191 void VisibilityPatchGrid::recalculateErrors(FixedVector &position, fixed size)
00192 {
00193         int sizei = size.asInt();
00194         int midX = position[0].asInt();
00195         int midY = position[1].asInt();
00196 
00197         int startX = midX - sizei;
00198         int startY = midY - sizei;
00199         int endX = midX + sizei;
00200         int endY = midY + sizei;
00201 
00202         startX /= 32;
00203         startY /= 32;
00204         endX /= 32;
00205         endY /= 32;
00206 
00207         if (endX < 0 || endY < 0) return;
00208         if (startX >= landWidth_ || startY >= landHeight_) return;
00209 
00210         startX = MAX(0, startX);
00211         startY = MAX(0, startY);
00212         endX = MIN(landWidth_ - 1, endX);
00213         endY = MIN(landHeight_ - 1, endY);
00214         
00215         for (int x=startX; x<=endX; x++)
00216         {
00217                 for (int y=startY; y<=endY; y++)
00218                 {
00219                         LandVisibilityPatch &patch = landPatches_[x + y * landWidth_];
00220                         patch.setRecalculateErrors();
00221                 }
00222         }
00223 }
00224 
00225 LandVisibilityPatch *VisibilityPatchGrid::getLandVisibilityPatch(int x, int y)
00226 {
00227         DIALOG_ASSERT(epoc_);
00228 
00229         int realX = x / 32;
00230         int realY = y / 32;
00231 
00232         if (realX < 0 || realY < 0 ||
00233                 realX >= landWidth_ || realY >= landHeight_) 
00234         {
00235                 return 0;
00236         }
00237 
00238         return &landPatches_[realX + realY * landWidth_];
00239 }
00240 
00241 TargetVisibilityPatch *VisibilityPatchGrid::getTargetVisibilityPatch(int x, int y)
00242 {
00243         DIALOG_ASSERT(epoc_);
00244 
00245         int realX = (x - midX_) / 32;
00246         int realY = (y - midY_) / 32;
00247 
00248         if (realX < 0 || realY < 0 ||
00249                 realX >= targetWidth_ || realY >= targetHeight_) 
00250         {
00251                 return 0;
00252         }
00253 
00254         return &targetPatches_[realX + realY * targetWidth_];
00255 }
00256 
00257 WaterVisibilityPatch *VisibilityPatchGrid::getWaterVisibilityPatch(int x, int y)
00258 {
00259         DIALOG_ASSERT(epoc_);
00260 
00261         int realX = (x - midX_) / 128;
00262         int realY = (y - midY_) / 128;
00263 
00264         if (realX < 0 || realY < 0 ||
00265                 realX >= waterWidth_ || realY >= waterHeight_) 
00266         {
00267                 return 0;
00268         }
00269 
00270         return &waterPatches_[realX + realY * waterWidth_];
00271 }
00272 
00273 void VisibilityPatchGrid::calculateVisibility()
00274 {
00275         Vector &cameraPos = GLCamera::getCurrentCamera()->getCurrentPos();
00276 
00277         patchInfo_.reset();
00278 
00279         // Calculate visibility
00280         VisibilityPatchQuad *currentPatch = visibilityPatches_;
00281         for (int y=0; y<visibilityHeight_; y++)
00282         {
00283                 for (int x=0; x<visibilityWidth_; x++, currentPatch++)
00284                 {
00285                         currentPatch->calculateVisibility(patchInfo_, cameraPos);
00286                 }
00287         }
00288 }
00289 
00290 void VisibilityPatchGrid::drawLand(int addIndex, bool simple)
00291 {
00292         GraphicalLandscapeMap *landscapeMap = (GraphicalLandscapeMap *)
00293                 ScorchedClient::instance()->getLandscapeMaps().
00294                         getGroundMaps().getHeightMap().getGraphicalMap();
00295 
00296         if (!OptionsDisplay::instance()->getNoGLDrawElements() &&
00297                 GLStateExtension::hasDrawRangeElements())
00298         {
00299                 // Map indices to draw
00300                 if (landIndexs_.getBufferObject())
00301                 {
00302                         landIndexs_.getBufferObject()->bind();
00303                 }
00304 
00305                 // Map the vertex VBO
00306                 if (landscapeMap->getBufferObject())
00307                 {
00308                         landscapeMap->getBufferObject()->bind();
00309                 }
00310 
00311                 glEnableClientState(GL_VERTEX_ARRAY);
00312                 if (!simple)
00313                 {
00314                         glEnableClientState(GL_NORMAL_ARRAY);
00315                         if (GLStateExtension::hasMultiTex())
00316                         {
00317                                 glClientActiveTextureARB(GL_TEXTURE1_ARB);
00318                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00319                                 if (GLStateExtension::getTextureUnits() > 2)
00320                                 {
00321                                         glClientActiveTextureARB(GL_TEXTURE2_ARB);
00322                                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00323                                 }
00324                         }
00325                         glClientActiveTextureARB(GL_TEXTURE0_ARB);
00326                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00327                 }
00328         }
00329 
00330         if (simple)
00331         {
00332                 LandVisibilityPatch *currentPatch = landPatches_;
00333                 for (int y=0; y<landHeight_; y++)
00334                 {
00335                         for (int x=0; x<landWidth_; x++, currentPatch++)
00336                         {
00337                                 MipMapPatchIndex *landIndex = landIndexs_.getIndex(4, 0);
00338                                 if (landIndex) currentPatch->draw(*landIndex, true);
00339                         }
00340                 }
00341         }
00342         else
00343         {
00344                 void *currentPatchPtr = 0;
00345                 TargetListIterator patchItor(patchInfo_.getLandVisibility());
00346                 while (currentPatchPtr = patchItor.getNext())
00347                 {
00348                         LandVisibilityPatch *currentPatch = (LandVisibilityPatch *) currentPatchPtr;
00349                         unsigned int index = currentPatch->getVisibilityIndex();
00350                         if (index == -1) 
00351                         {
00352                                 continue;
00353                         }
00354 
00355                         unsigned int borders = 0;
00356                         int leftIndex = currentPatch->getLeftPatch()?
00357                                 currentPatch->getLeftPatch()->getVisibilityIndex():-1;
00358                         int rightIndex = currentPatch->getRightPatch()?
00359                                 currentPatch->getRightPatch()->getVisibilityIndex():-1;
00360                         int topIndex = currentPatch->getTopPatch()?
00361                                 currentPatch->getTopPatch()->getVisibilityIndex():-1;
00362                         int bottomIndex = currentPatch->getBottomPatch()?
00363                                 currentPatch->getBottomPatch()->getVisibilityIndex():-1;
00364 
00365                         MipMapPatchIndex *landIndex = 
00366                                 landIndexs_.getIndex(index, leftIndex, rightIndex, topIndex, bottomIndex, addIndex);
00367                         if (landIndex) currentPatch->draw(*landIndex, false);
00368                 }
00369         }
00370 
00371         if (!OptionsDisplay::instance()->getNoGLDrawElements() &&
00372                 GLStateExtension::hasDrawRangeElements())
00373         {
00374                 glDisableClientState(GL_VERTEX_ARRAY);
00375                 if (!simple)
00376                 {
00377                         glDisableClientState(GL_NORMAL_ARRAY);
00378                         if (GLStateExtension::hasMultiTex())
00379                         {
00380                                 glClientActiveTextureARB(GL_TEXTURE1_ARB);
00381                                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
00382                                 if (GLStateExtension::getTextureUnits() > 2)
00383                                 {
00384                                         glClientActiveTextureARB(GL_TEXTURE2_ARB);
00385                                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
00386                                 }
00387                         }
00388                         glClientActiveTextureARB(GL_TEXTURE0_ARB);
00389                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
00390                 }
00391 
00392                 // Unmap indices to draw
00393                 if (landIndexs_.getBufferObject())
00394                 {
00395                         landIndexs_.getBufferObject()->unbind();
00396                 }
00397 
00398                 // Unmap the vertex VBO
00399                 if (landscapeMap->getBufferObject())
00400                 {
00401                         landscapeMap->getBufferObject()->unbind();
00402                 }
00403         }
00404 }
00405 
00406 void VisibilityPatchGrid::drawLandLODLevels()
00407 {
00408         {
00409                 void *currentPatchPtr = 0;
00410                 TargetListIterator patchItor(patchInfo_.getLandVisibility());
00411                 while (currentPatchPtr = patchItor.getNext())
00412                 {
00413                         LandVisibilityPatch *currentPatch = (LandVisibilityPatch *) currentPatchPtr;
00414                         unsigned int index = currentPatch->getVisibilityIndex();
00415                         if (index == -1) continue;
00416 
00417                         unsigned int borders = 0;
00418                         int leftIndex = currentPatch->getLeftPatch()?
00419                                 currentPatch->getLeftPatch()->getVisibilityIndex():-1;
00420                         int rightIndex = currentPatch->getRightPatch()?
00421                                 currentPatch->getRightPatch()->getVisibilityIndex():-1;
00422                         int topIndex = currentPatch->getTopPatch()?
00423                                 currentPatch->getTopPatch()->getVisibilityIndex():-1;
00424                         int bottomIndex = currentPatch->getBottomPatch()?
00425                                 currentPatch->getBottomPatch()->getVisibilityIndex():-1;
00426 
00427                         MipMapPatchIndex *landIndex = 
00428                                 landIndexs_.getIndex(index, leftIndex, rightIndex, topIndex, bottomIndex, 0);
00429                         if (landIndex) currentPatch->drawLODLevel(*landIndex);
00430                 }
00431         }
00432 }
00433 
00434 void VisibilityPatchGrid::drawSurround()
00435 {
00436         surround_.draw(ScorchedClient::instance()->getLandscapeMaps().
00437                 getGroundMaps().getHeightMap(), true, true);
00438 }
00439 
00440 void VisibilityPatchGrid::drawWater(Water2Patches &patches, 
00441                 MipMapPatchIndexs &indexes, Vector &cameraPosition, 
00442                 Vector landscapeSize,
00443                 GLSLShaderSetup *waterShader)
00444 {
00445         GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "WATER_DRAW");
00446 
00447         if (!OptionsDisplay::instance()->getNoGLDrawElements() &&
00448                 GLStateExtension::hasDrawRangeElements())
00449         {
00450                 glEnableClientState(GL_VERTEX_ARRAY);
00451                 glEnableClientState(GL_NORMAL_ARRAY);
00452 
00453                 // Map the vertex VBO
00454                 if (patches.getBufferObject())
00455                 {
00456                         patches.getBufferObject()->bind();
00457                 }
00458 
00459                 // Map indices to draw
00460                 if (indexes.getBufferObject())
00461                 {
00462                         indexes.getBufferObject()->bind();
00463                 }
00464         }
00465 
00466         for (int w=0; w<4; w++)
00467         {
00468                 Water2Patch *patch = patches.getPatch(w);
00469 
00470                 if (!OptionsDisplay::instance()->getNoGLDrawElements() &&
00471                         GLStateExtension::hasDrawRangeElements())
00472                 {
00473                         // Map data to draw
00474                         float *data = 0;
00475                         if (patch->getBufferOffSet() != -1)
00476                         {
00477                                 data = (float*) NULL + (patch->getBufferOffSet() / sizeof(unsigned int));
00478                         }
00479                         else
00480                         {
00481                                 data = &patch->getInternalData()->x;
00482                         }
00483 
00484                         // Vertices On
00485                         glVertexPointer(3, GL_FLOAT, sizeof(Water2Patch::Data), data);
00486 
00487                         // Normals On
00488                         glNormalPointer(GL_FLOAT, sizeof(Water2Patch::Data), data + 3);
00489                 }
00490 
00491                 static float startproj[16], startmodel[16];
00492                 glGetFloatv(GL_PROJECTION_MATRIX, startproj);
00493                 glGetFloatv(GL_MODELVIEW_MATRIX, startmodel);
00494 
00495                 // Draw all patches
00496                 void *currentPatchPtr = 0;
00497                 TargetListIterator patchItor(patchInfo_.getWaterVisibility(w));
00498                 while (currentPatchPtr = patchItor.getNext())
00499                 {
00500                         WaterVisibilityPatch *currentPatch = (WaterVisibilityPatch *) currentPatchPtr;
00501                         unsigned int index = currentPatch->getVisibilityIndex();
00502                         if (index == -1) continue;
00503 
00504                         unsigned int borders = 0;
00505                         int leftIndex = currentPatch->getLeftPatch()?
00506                                 currentPatch->getLeftPatch()->getVisibilityIndex():-1;
00507                         int rightIndex = currentPatch->getRightPatch()?
00508                                 currentPatch->getRightPatch()->getVisibilityIndex():-1;
00509                         int topIndex = currentPatch->getTopPatch()?
00510                                 currentPatch->getTopPatch()->getVisibilityIndex():-1;
00511                         int bottomIndex = currentPatch->getBottomPatch()?
00512                                 currentPatch->getBottomPatch()->getVisibilityIndex():-1;
00513 
00514                         glPushMatrix();
00515                         glTranslatef(
00516                                 currentPatch->getOffset()[0],
00517                                 currentPatch->getOffset()[1], 
00518                                 currentPatch->getOffset()[2]);
00519 
00520                         // Setup the texture matrix for texture 0
00521                         if (waterShader)
00522                         {
00523                                 if (!OptionsDisplay::instance()->getSimpleWaterShaders())
00524                                 {
00525                                         Vector landfoam;
00526                                         landfoam[0] = currentPatch->getOffset()[0];
00527                                         landfoam[1] = currentPatch->getOffset()[1];
00528                                         landfoam[2] = ((currentPatch->getPosition()[0] >= 0.0f && 
00529                                                 currentPatch->getPosition()[1] >= 0.0f &&
00530                                                 currentPatch->getPosition()[0] <= landscapeSize[0] && 
00531                                                 currentPatch->getPosition()[1] <= landscapeSize[1])?1.0f:0.0f);
00532                                         waterShader->set_uniform("landfoam", landfoam);
00533                                 }
00534 
00535                                 // Set lighting position
00536                                 // done after the translation
00537                                 Landscape::instance()->getSky().getSun().setLightPosition(true);
00538 
00539                                 // Setup the texture matrix for texture 1
00540                                 glActiveTexture(GL_TEXTURE1);
00541                                 glMatrixMode(GL_TEXTURE);
00542                                 glLoadIdentity();
00543                                 glTranslatef(0.5f,0.5f,0.0f);
00544                                 glScalef(0.5f,0.5f,1.0f);
00545                                 glMultMatrixf(startproj);
00546                                 glMultMatrixf(startmodel);
00547                                 glTranslatef(
00548                                         currentPatch->getOffset()[0],
00549                                         currentPatch->getOffset()[1], 
00550                                         currentPatch->getOffset()[2]);
00551                                 glMatrixMode(GL_MODELVIEW);
00552 
00553                                 // Reset to texture 0
00554                                 glActiveTexture(GL_TEXTURE0);
00555                         }
00556 
00557                         MipMapPatchIndex *patchIndex = 
00558                                 indexes.getIndex(index, leftIndex, rightIndex, topIndex, bottomIndex, 0);
00559                         if (patchIndex) patch->draw(*patchIndex);
00560 
00561                         glPopMatrix();
00562                 }
00563         }
00564 
00565         if (!OptionsDisplay::instance()->getNoGLDrawElements() &&
00566                 GLStateExtension::hasDrawRangeElements())
00567         {
00568                 // Unmap data to draw
00569                 if (patches.getBufferObject())
00570                 {
00571                         patches.getBufferObject()->unbind();
00572                 }
00573 
00574                 // Unmap indices to draw
00575                 if (indexes.getBufferObject())
00576                 {
00577                         indexes.getBufferObject()->unbind();
00578                 }
00579 
00580                 glDisableClientState(GL_VERTEX_ARRAY);
00581                 glDisableClientState(GL_NORMAL_ARRAY);
00582         }
00583 
00584         GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "WATER_DRAW");
00585 }

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