00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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
00073 if (counter) counter->setNewOp(LANG_RESOURCE("CREATING_BREAKERS_1", "Creating Breakers 1"));
00074 findPoints(&context, waterHeight, counter);
00075
00076
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 ¤t = 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 ¤tPatch)
00272 {
00273
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 ¤tPatch,
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
00305
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
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 }