WaterWaves.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 <water/WaterWaves.h>
00022 #include <water/WaterWaveDistance.h>
00023 #include <water/Water2Patches.h>
00024 #include <landscapemap/LandscapeMaps.h>
00025 #include <lang/LangResource.h>
00026 #include <client/ScorchedClient.h>
00027 #include <graph/OptionsDisplay.h>
00028 #include <common/OptionsTransient.h>
00029 #include <common/Defines.h>
00030 #include <GLEXT/GLStateExtension.h>
00031 #include <GLEXT/GLInfo.h>
00032 #include <image/ImageFactory.h>
00033 #include <math.h>
00034 
00035 WaterWaves::WaterWaves() : 
00036         totalTime_(0.0f), 
00037         wavesColor_(1.0f, 1.0f, 1.0f)
00038 {
00039 
00040 }
00041 
00042 WaterWaves::~WaterWaves()
00043 {
00044 }
00045 
00046 void WaterWaves::generateWaves(float waterHeight, ProgressCounter *counter)
00047 {
00048         paths1_.clear();
00049         paths2_.clear();
00050 
00051         //if (OptionsDisplay::instance()->getNoWaves()) return;
00052         if (!OptionsDisplay::instance()->getDrawWater()) return;
00053 
00054         int mapWidth = ScorchedClient::instance()->getLandscapeMaps().
00055                 getGroundMaps().getLandscapeWidth();
00056         int mapHeight = ScorchedClient::instance()->getLandscapeMaps().
00057                 getGroundMaps().getLandscapeHeight();
00058 
00059         // Wave points
00060         WaterWaveContext context;
00061         context.pointCount = 0;
00062         context.removedCount = 0;
00063         context.pointsMult = 1;
00064         context.mapWidth = mapWidth;
00065         context.mapHeight = mapHeight;
00066         context.pointsWidth = mapWidth / context.pointsMult;
00067         context.pointsHeight = mapHeight / context.pointsMult;
00068         context.wavePoints = new bool[context.pointsWidth * context.pointsHeight];
00069         memset(context.wavePoints, 0, 
00070                 context.pointsWidth * context.pointsHeight * sizeof(bool));
00071 
00072         // Find all of the points that are equal to a certain height (the water height)
00073         if (counter) counter->setNewOp(LANG_RESOURCE("CREATING_BREAKERS_1", "Creating Breakers 1"));
00074         findPoints(&context, waterHeight, counter);
00075 
00076         // Find the list of points that are next to eachother
00077         if (counter) counter->setNewOp(LANG_RESOURCE("CREATING_BREAKERS_2", "Creating Breakers 2"));
00078         while (findNextPath(&context, waterHeight, counter)) {}
00079 
00080         ImageHandle waves1 = ImageFactory::loadAlphaImageHandle(
00081                 S3D::getDataFile("data/textures/waves.bmp"));
00082         ImageHandle waves2 = ImageFactory::loadAlphaImageHandle(
00083                 S3D::getDataFile("data/textures/waves2.bmp"));
00084         wavesTexture1_.create(waves1);
00085         wavesTexture2_.create(waves2);
00086 
00087         delete [] context.wavePoints;
00088 }
00089 
00090 void WaterWaves::findPoints(WaterWaveContext *context,
00091         float waterHeight, ProgressCounter *counter)
00092 {
00093         int distanceCount = 0;
00094         for (int y=context->pointsMult; 
00095                 y<context->mapHeight - context->pointsMult; 
00096                 y+=context->pointsMult)
00097         {
00098                 if (counter) counter->setNewPercentage(float(y)/
00099                         float(context->pointsHeight)*100.0f);
00100                 for (int x=context->pointsMult; 
00101                         x<context->mapWidth - context->pointsMult; 
00102                         x+=context->pointsMult)
00103                 {
00104                         float height =
00105                                 ScorchedClient::instance()->getLandscapeMaps().
00106                                         getGroundMaps().getHeight(x, y).asFloat();
00107                         if (height > waterHeight - 4.0f && height < waterHeight)
00108                         {
00109                                 float height2=
00110                                         ScorchedClient::instance()->getLandscapeMaps().
00111                                         getGroundMaps().getHeight(x+context->pointsMult, y).asFloat();
00112                                 float height3=
00113                                         ScorchedClient::instance()->getLandscapeMaps().
00114                                         getGroundMaps().getHeight(x-context->pointsMult, y).asFloat();
00115                                 float height4=
00116                                         ScorchedClient::instance()->getLandscapeMaps().
00117                                         getGroundMaps().getHeight(x, y+context->pointsMult).asFloat();
00118                                 float height5=
00119                                         ScorchedClient::instance()->getLandscapeMaps().
00120                                         getGroundMaps().getHeight(x, y-context->pointsMult).asFloat();
00121 
00122                                 if (height2 > waterHeight || height3 > waterHeight ||
00123                                         height4 > waterHeight || height5 > waterHeight)
00124                                 {
00125                                         {
00126                                                 int a = x / context->pointsMult;
00127                                                 int b = y / context->pointsMult;
00128                                                 bool &pts = context->wavePoints[
00129                                                         a + b * context->pointsWidth];
00130                                                 if (!pts)
00131                                                 {
00132                                                         context->pointCount ++;
00133                                                         pts = true;
00134                                                 }
00135                                         }
00136                                 }
00137                         }
00138                 }
00139         }
00140 }
00141 
00142 bool WaterWaves::findNextPath(WaterWaveContext *context,
00143         float waterHeight, ProgressCounter *counter)
00144 {
00145         std::vector<Vector> points;
00146 
00147         for (int y=1; y<context->pointsHeight; y++)
00148         {
00149                 for (int x=1; x<context->pointsWidth; x++)
00150                 {
00151                         if (context->wavePoints[x + y * context->pointsWidth]) 
00152                         {
00153                                 findPath(context, points, x, y, counter);
00154                                 constructLines(context, waterHeight, points);
00155                                 return true;                    
00156                         }
00157                 }
00158         }
00159 
00160         return false;
00161 }
00162 
00163 void WaterWaves::findPath(WaterWaveContext *context,
00164         std::vector<Vector> &points, 
00165         int x, int y, ProgressCounter *counter)
00166 {
00167         if (x < 0 || x >= context->pointsWidth ||
00168                 y < 0 || y >= context->pointsHeight)
00169         {
00170                 return;
00171         }
00172 
00173         context->removedCount ++;
00174         points.push_back(
00175                 Vector(
00176                         float(x * context->pointsMult), 
00177                         float(y * context->pointsMult), 
00178                         0.0f));
00179         
00180         if (counter && context->removedCount % 50 == 0) 
00181                 counter->setNewPercentage(
00182                         float(context->removedCount)/float(context->pointCount)*100.0f);
00183 
00184         context->wavePoints[x + y * context->pointsWidth] = false;
00185         if (context->wavePoints[(x+1) + y * context->pointsWidth]) 
00186                 findPath(context, points, x+1, y, counter);
00187         else if (context->wavePoints[(x-1) + y * context->pointsWidth]) 
00188                 findPath(context, points, x-1, y, counter);
00189         else if (context->wavePoints[x + (y-1) * context->pointsWidth]) 
00190                 findPath(context, points, x, y-1, counter);
00191         else if (context->wavePoints[x + (y+1) * context->pointsWidth]) 
00192                 findPath(context, points, x, y+1, counter);
00193         else if (context->wavePoints[(x-1) + (y-1) * context->pointsWidth]) 
00194                 findPath(context, points, x-1, y-1, counter);
00195         else if (context->wavePoints[(x-1) + (y+1) * context->pointsWidth]) 
00196                 findPath(context, points, x-1, y+1, counter);
00197         else if (context->wavePoints[(x+1) + (y+1) * context->pointsWidth]) 
00198                 findPath(context, points, x+1, y+1, counter);
00199         else if (context->wavePoints[(x+1) + (y-1) * context->pointsWidth]) 
00200                 findPath(context, points, x+1, y-1, counter);
00201 }
00202 
00203 void WaterWaves::constructLines(WaterWaveContext *context,
00204         float waterHeight, std::vector<Vector> &points)
00205 {
00206         Vector ptA;
00207         Vector ptB;
00208         Vector point = points.front();
00209         int dist = int(RAND * 10.0f + 1.0f);
00210         for (int i=0; i<(int)points.size(); i++)
00211         {
00212                 Vector &current = points[i];
00213                 int diffX = int(current[0]) - int(point[0]);
00214                 int diffY = int(current[1]) - int(point[1]);
00215                 int actualdist = diffX * diffX + diffY * diffY;
00216                 if (actualdist  >= dist)
00217                 {
00218                         WaterWaveEntry entry;
00219                         Vector grad = point-current;
00220                         Vector perp = grad.get2DPerp().Normalize2D();
00221 
00222                         int newx = int(current[0] + perp[0] * 3.0f);
00223                         int newy = int(current[1] + perp[1] * 3.0f);
00224                         if (newx <= 0 || newy <= 0 ||
00225                                 newx >= context->mapWidth || newy >= context->mapHeight)
00226                         {
00227                         }
00228                         else
00229                         {
00230                                 if (ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getHeight(
00231                                         newx, newy).asFloat() > waterHeight)
00232                                 {
00233                                         perp =- perp;
00234                                         entry.ptA = current - perp / 3.0f;
00235                                         entry.ptB = point - perp / 3.0f;
00236                                         entry.perp = perp;
00237                                         entry.ptC = point + perp * 6.0f;
00238                                         entry.ptD = current + perp * 6.0f;
00239                                 }
00240                                 else
00241                                 {
00242                                         entry.ptA = point - perp / 3.0f;
00243                                         entry.ptB = current - perp / 3.0f;
00244                                         entry.perp = perp;
00245                                         entry.ptC = current + perp * 6.0f;
00246                                         entry.ptD = point + perp * 6.0f;
00247                                 }
00248 
00249                                 if (RAND > 0.5f) paths1_.push_back(entry);
00250                                 else paths2_.push_back(entry);
00251                         }
00252 
00253                         if (i > 1)
00254                         {
00255                                 i-= 1;
00256                                 point = points[i];
00257                         }
00258                         else point = current;
00259                         
00260                         dist = int(RAND * 10.0f + 1.0f);
00261                 }
00262         }
00263 }
00264 
00265 void WaterWaves::simulate(float frameTime)
00266 {
00267         totalTime_ += frameTime / 2.0f;
00268         if (totalTime_ > 6.0f) totalTime_ = 0.0f;
00269 }
00270 
00271 void WaterWaves::draw(Water2Patches &currentPatch)
00272 {
00273         //if (OptionsDisplay::instance()->getNoWaves()) return;
00274 
00275         Vector windDir = 
00276                 ScorchedClient::instance()->getOptionsTransient().getWindDirection().asVector();
00277         Vector windDirPerp = windDir.Normalize();
00278 
00279         GLState state(GLState::TEXTURE_ON | GLState::BLEND_ON); 
00280         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
00281         glDepthMask(GL_FALSE);
00282 
00283         wavesTexture1_.draw(true);
00284         drawBoxes(currentPatch, totalTime_ + 0.0f, windDirPerp, paths1_);
00285         drawBoxes(currentPatch, totalTime_ + 2.0f, windDirPerp, paths1_);
00286         drawBoxes(currentPatch, totalTime_ + 4.0f, windDirPerp, paths1_);
00287 
00288         wavesTexture2_.draw(true);
00289         drawBoxes(currentPatch, totalTime_ + 1.0f, windDirPerp, paths2_);
00290         drawBoxes(currentPatch, totalTime_ + 3.0f, windDirPerp, paths2_);
00291         drawBoxes(currentPatch, totalTime_ + 5.0f, windDirPerp, paths2_);
00292 
00293         glDepthMask(GL_TRUE);
00294         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00295 }
00296 
00297 void WaterWaves::drawBoxes(Water2Patches &currentPatch,
00298                                                    float totalTime, Vector &windDirPerp, 
00299                                                    std::vector<WaterWaveEntry> &paths)
00300 {
00301         float newTime = totalTime;
00302         if (newTime > 6.0f) newTime -= 6.0f;
00303 
00304         // First set of boxes
00305         // Some set of magic to try to get it look kind of ok!
00306         float alpha = 1.0f;
00307         float frontlen = newTime + 0.2f;
00308         float endlen = newTime / 2.0f;
00309         if (newTime < 1.0f)
00310         {
00311                 alpha = newTime;
00312         }
00313         if (newTime > 4.0f)
00314         {
00315                 frontlen = 4.2f - (newTime - 4.0f) / 3.0f;
00316                 endlen = 2.0f - (newTime - 4.0f) / 3.0f;
00317 
00318                 alpha = (2.0f - (newTime - 4.0f)) / 2.0f;
00319         }
00320         frontlen *= 2.0f;
00321         endlen *= 2.0f;
00322 
00323         // Draw the actual texture boxes
00324         glColor4f(wavesColor_[0], wavesColor_[1], wavesColor_[2], alpha * 0.3f);
00325         glBegin(GL_QUADS);
00326                 Vector ptA, ptB, ptC, ptD;
00327                 std::vector<WaterWaveEntry>::iterator itor = paths.begin();
00328                 std::vector<WaterWaveEntry>::iterator enditor = paths.end();
00329                 for (; itor != enditor; itor++)
00330                 {
00331                         WaterWaveEntry &p = *itor;
00332                                 
00333                         if (((p.perp[0] * windDirPerp[0]) + (p.perp[1] * windDirPerp[1])) > 0.0f) 
00334                                 continue;
00335 
00336                         ptA = p.ptD - p.perp * frontlen;
00337                         ptA[2] = currentPatch.getPoint(int(ptA[0]/2), int(ptA[1]/2))->z + 0.05f;
00338                         ptB = p.ptC - p.perp * frontlen;
00339                         ptB[2] = currentPatch.getPoint(int(ptB[0]/2), int(ptB[1]/2))->z + 0.05f;
00340 
00341                         ptC = p.ptC - p.perp * endlen;
00342                         ptC[2] = currentPatch.getPoint(int(ptC[0]/2), int(ptC[1]/2))->z + 0.05f;
00343                         ptD = p.ptD - p.perp * endlen;
00344                         ptD[2] = currentPatch.getPoint(int(ptD[0]/2), int(ptD[1]/2))->z + 0.05f;
00345                         
00346                         glTexCoord2f(1.0f, 1.0f);
00347                         glVertex3fv(ptA);
00348                         glTexCoord2f(0.0f, 1.0f);
00349                         glVertex3fv(ptB);
00350                         glTexCoord2f(0.0f, 0.0f);
00351                         glVertex3fv(ptC);
00352                         glTexCoord2f(1.0f, 0.0f);
00353                         glVertex3fv(ptD);
00354                 }
00355         glEnd();
00356         GLInfo::addNoTriangles(paths.size() - 2);
00357 }

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