00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <water/Water2.h>
00022 #include <common/Vector.h>
00023 #include <common/Vector4.h>
00024 #include <common/Logger.h>
00025 #include <common/ProgressCounter.h>
00026 #include <common/OptionsTransient.h>
00027 #include <client/ScorchedClient.h>
00028 #include <landscapedef/LandscapeTex.h>
00029 #include <landscapedef/LandscapeDefn.h>
00030 #include <landscapemap/LandscapeMaps.h>
00031 #include <graph/OptionsDisplay.h>
00032 #include <GLEXT/GLState.h>
00033 #include <GLEXT/GLStateExtension.h>
00034 #include <image/ImageFactory.h>
00035 #include <lang/LangResource.h>
00036 #include "ocean_wave_generator.h"
00037
00038 #include <water/Water2Constants.h>
00039
00040 Water2::Water2()
00041 {
00042 }
00043
00044 Water2::~Water2()
00045 {
00046
00047 }
00048
00049 Water2Patches &Water2::getPatch(float time)
00050 {
00051 unsigned int index = ((unsigned int)(time)) % generatedPatches_;
00052 DIALOG_ASSERT(index < (unsigned int) generatedPatches_);
00053 return patches_[index];
00054 }
00055
00056 static float calculateError(Water2Points &displacement,
00057 int x1, int x2, int y1, int y2,
00058 float x1y1, float x2y2, float x1y2, float x2y1)
00059 {
00060 if (x2 - x1 <= 1) return 0.0f;
00061
00062 int midx = (x1 + x2) / 2;
00063 int midy = (y1 + y2) / 2;
00064 float actualheight = displacement.getPoint(midx, midy)[2];
00065
00066 float approxheight1 = (x1y1 + x2y2) / 2.0f;
00067 float approxheight2 = (x1y2 + x2y1) / 2.0f;
00068 float approxheight3 = (x1y1 + x1y2) / 2.0f;
00069 float approxheight4 = (x1y1 + x2y1) / 2.0f;
00070 float approxheight5 = (x1y2 + x2y2) / 2.0f;
00071 float approxheight6 = (x2y1 + x2y2) / 2.0f;
00072
00073 float heightdiff1 = fabs(approxheight1 - actualheight);
00074 float heightdiff2 = fabs(approxheight2 - actualheight);
00075
00076 float errorChild1 = calculateError(displacement,
00077 x1, midx, y1, midy,
00078 x1y1, approxheight1, approxheight3, approxheight4);
00079 float errorChild2 = calculateError(displacement,
00080 midx, x2, y1, midy,
00081 approxheight4, approxheight6, approxheight1, x2y1);
00082 float errorChild3 = calculateError(displacement,
00083 x1, midx, midy, y2,
00084 approxheight3, approxheight5, x1y2, approxheight2);
00085 float errorChild4 = calculateError(displacement,
00086 midx, x2, midy, y2,
00087 approxheight2, x2y2, approxheight5, approxheight6);
00088
00089 float errorChildren = MAX(errorChild1, MAX(errorChild2, MAX(errorChild3, errorChild4)));
00090 float totalError = MAX(errorChildren, MAX(heightdiff1, heightdiff2));
00091 return totalError;
00092 }
00093
00094 void Water2::generate(LandscapeTexBorderWater *water, ProgressCounter *counter)
00095 {
00096 if (counter) counter->setNewOp(LANG_RESOURCE("WATER_MOTION", "Water Motion"));
00097
00098
00099 float windSpeed = ScorchedClient::instance()->
00100 getOptionsTransient().getWindSpeed().asFloat() * 2.0f + 3.0f;
00101 Vector windDir = ScorchedClient::instance()->
00102 getOptionsTransient().getWindDirection().asVector();
00103 if (windDir == Vector::getNullVector())
00104 {
00105 windDir = Vector(0.8f, 0.8f);
00106 }
00107
00108 ocean_wave_generator<float>
00109 owg(wave_resolution,
00110 windDir,
00111 windSpeed,
00112 float(wave_resolution) * (1e-8f),
00113 float(wave_waterwidth),
00114 wave_tidecycle_time);
00115
00116
00117 generatedPatches_ = 0;
00118 static Water2Points displacements[256];
00119 for (unsigned i=0; i<wave_phases; i++)
00120 {
00121 if (counter) counter->setNewPercentage(float(i * 100) / float(wave_phases));
00122
00123
00124 float currentTime = wave_tidecycle_time * float(i) / float(wave_phases);
00125 float timeMod = myfmod(currentTime, wave_tidecycle_time);
00126 owg.set_time(timeMod);
00127
00128
00129 owg.compute_heights(displacements[i]);
00130
00131
00132 owg.compute_displacements(-2.0f, displacements[i]);
00133
00134
00135 for (int y=0; y<wave_resolution; y++)
00136 {
00137 for (int x=0; x<wave_resolution; x++)
00138 {
00139 Vector &point = displacements[i].getPoint(x, y);
00140 point[2] += water->height.asFloat();
00141 }
00142 }
00143
00144
00145 patches_[i].generate(displacements[i], wave_resolution,
00146 wave_patch_width, water->height.asFloat());
00147 generatedPatches_++;
00148
00149
00150
00151 if (i == 0)
00152 {
00153 for (int j=0; j<=6; j++)
00154 {
00155 float error = 0.0f;
00156 if (j>0)
00157 {
00158 int skip = 1 << j;
00159 for (int y1=0; y1<wave_patch_width; y1+=skip)
00160 {
00161 for (int x1=0; x1<wave_patch_width; x1+=skip)
00162 {
00163 int x2 = x1 + skip;
00164 int y2 = y1 + skip;
00165
00166 float x1y1 = displacements[i].getPoint(x1, y1)[2];
00167 float x2y2 = displacements[i].getPoint(x2, y2)[2];
00168 float x1y2 = displacements[i].getPoint(x1, y2)[2];
00169 float x2y1 = displacements[i].getPoint(x2, y1)[2];
00170
00171 float thisError = calculateError(displacements[i],
00172 x1, x2, y1, y2,
00173 x1y1, x2y2, x1y2, x2y1);
00174 error = MAX(error, thisError);
00175 }
00176 }
00177 }
00178
00179 indexErrors_[j] = error;
00180 }
00181 }
00182
00183
00184 if (OptionsDisplay::instance()->getNoWaterMovement() ||
00185 !OptionsDisplay::instance()->getDrawWater())
00186 {
00187 break;
00188 }
00189 }
00190
00191 if (indexs_.getNoLevels() == 0)
00192 {
00193
00194 indexs_.generate(wave_patch_width, wave_patch_width, 2);
00195 }
00196
00197
00198 LandscapeDefn &defn = *ScorchedClient::instance()->getLandscapeMaps().
00199 getDefinitions().getDefn();
00200 ImageHandle loadedFoam =
00201 ImageFactory::loadImageHandle(S3D::getDataFile(water->foam.c_str()));
00202 if (loadedFoam.getWidth() != wave_resolution ||
00203 loadedFoam.getHeight() != wave_resolution)
00204 {
00205 S3D::dialogExit("Water2",
00206 S3D::formatStringBuffer("Foam image size must be %ix%i",
00207 wave_resolution, wave_resolution));
00208 }
00209
00210 float aof[wave_resolution*wave_resolution];
00211 memset(aof, 0, sizeof(float) * wave_resolution * wave_resolution);
00212
00213 float rndtab[37];
00214 for (unsigned k = 0; k < 37; ++k) rndtab[k] = RAND;
00215
00216
00217 if (GLStateExtension::hasShaders() &&
00218 !OptionsDisplay::instance()->getNoWaterWaves() &&
00219 !OptionsDisplay::instance()->getSimpleWaterShaders())
00220 {
00221 counter->setNewOp(LANG_RESOURCE("WATER_WAVES", "Water Waves"));
00222 for (unsigned k = 0; k < wave_phases; ++k)
00223 {
00224 if (counter) counter->setNewPercentage(float(k * 50) / float(wave_phases));
00225 Water2Points &wd = displacements[k % wave_phases];
00226 generateAOF(wd, 0, rndtab, displacements, aof);
00227 if (generatedPatches_ == 1) break;
00228 }
00229 }
00230
00231
00232 counter->setNewOp(LANG_RESOURCE("WATER_EFFECTS", "Water Effects"));
00233 for (unsigned k = 0; k < wave_phases; ++k)
00234 {
00235 if (counter) counter->setNewPercentage(float(k * 50) / float(wave_phases));
00236 Water2Points &wd = displacements[k % wave_phases];
00237
00238 ImageHandle aofImage =
00239 ImageFactory::createBlank(wave_resolution, wave_resolution, false, 0);
00240 memcpy(aofImage.getBits(), loadedFoam.getBits(), wave_resolution * wave_resolution * 3);
00241
00242
00243 if (GLStateExtension::hasShaders() &&
00244 !OptionsDisplay::instance()->getNoWaterWaves() &&
00245 !OptionsDisplay::instance()->getSimpleWaterShaders())
00246 {
00247 generateAOF(wd, &aofImage, rndtab, displacements, aof);
00248 }
00249 else
00250 {
00251 unsigned char *bits = aofImage.getBits();
00252 for (unsigned y = 0; y<wave_resolution; ++y)
00253 {
00254 for (unsigned x = 0; x<wave_resolution; ++x, bits+=3)
00255 {
00256 bits[0] = 0;
00257 }
00258 }
00259 }
00260
00261
00262 generateTransparency(wd, aofImage, defn);
00263
00264
00265 Water2Patches &patches = patches_[k];
00266 patches.getAOF().create(aofImage);
00267
00268 if (generatedPatches_ == 1) break;
00269 }
00270 }
00271
00272 void Water2::generateAOF(Water2Points &wd, ImageHandle *aofImage, float *rndtab,
00273 Water2Points *displacements, float *aof)
00274 {
00275
00276 const float deriv_fac = wavetile_length_rcp * wave_resolution;
00277 const float lambda = 1.0;
00278 const float decay = 4.0/wave_phases;
00279 const float decay_rnd = 0.25/wave_phases;
00280 const float foam_spawn_fac = 0.25;
00281
00282
00283 for (unsigned y = 0; y < wave_resolution; ++y) {
00284 unsigned ym1 = (y + wave_resolution - 1) & (wave_resolution-1);
00285 unsigned yp1 = (y + 1) & (wave_resolution-1);
00286 for (unsigned x = 0; x < wave_resolution; ++x) {
00287 unsigned xm1 = (x + wave_resolution - 1) & (wave_resolution-1);
00288 unsigned xp1 = (x + 1) & (wave_resolution-1);
00289
00290 Vector &xp1y = wd.getPoint(xp1, y);
00291 Vector &xm1y = wd.getPoint(xm1, y);
00292 Vector &xyp1 = wd.getPoint(x, yp1);
00293 Vector &xym1 = wd.getPoint(x, ym1);
00294 float dispx_dx = (xp1y[0] - xm1y[0]) * deriv_fac;
00295 float dispx_dy = (xyp1[0] - xym1[0]) * deriv_fac;
00296 float dispy_dx = (xp1y[1] - xm1y[1]) * deriv_fac;
00297 float dispy_dy = (xyp1[1] - xym1[1]) * deriv_fac;
00298 float Jxx = 1.0f + lambda * dispx_dx;
00299 float Jyy = 1.0f + lambda * dispy_dy;
00300 float Jxy = lambda * dispy_dx;
00301 float Jyx = lambda * dispx_dy;
00302 float J = Jxx*Jyy - Jxy*Jyx;
00303
00304 float foam_add = (J < 0.0f) ? ((J < -1.0f) ? 1.0f : -J) : 0.0f;
00305
00306 aof[y*wave_resolution+x] += foam_add * foam_spawn_fac;
00307
00308
00309 aof[ym1*wave_resolution+x] += foam_add * foam_spawn_fac * 0.5f;
00310 aof[yp1*wave_resolution+x] += foam_add * foam_spawn_fac * 0.5f;
00311 aof[y*wave_resolution+xm1] += foam_add * foam_spawn_fac * 0.5f;
00312 aof[y*wave_resolution+xp1] += foam_add * foam_spawn_fac * 0.5f;
00313 }
00314 }
00315
00316
00317 unsigned ptr = 0;
00318 for (unsigned y = 0; y < wave_resolution; ++y)
00319 {
00320 for (unsigned x = 0; x < wave_resolution; ++x, ++ptr)
00321 {
00322 float aofVal = std::max(std::min(aof[ptr], 1.0f) -
00323 (decay + decay_rnd * rndtab[(3*x + 5*y) % 37]), 0.0f);
00324
00325 aof[ptr] = aofVal;
00326
00327 if (aofImage)
00328 {
00329 aofImage->getBits()[ptr * 3 + 0] = (unsigned char) (255.0f * aofVal);
00330 }
00331 }
00332 }
00333 }
00334
00335 void Water2::generateTransparency(Water2Points &wd,
00336 ImageHandle &aofImage, LandscapeDefn &defn)
00337 {
00338 unsigned ptr = 0;
00339 for (unsigned y = 0; y < wave_resolution; ++y)
00340 {
00341 for (unsigned x = 0; x < wave_resolution; ++x, ++ptr)
00342 {
00343
00344 Vector &points = wd.getPoint(x, y);
00345 float waterHeight = points[2];
00346
00347
00348 int lx = int(float(x) * float(defn.getLandscapeWidth()) / float(wave_resolution));
00349 int ly = int(float(y) * float(defn.getLandscapeHeight()) / float(wave_resolution));
00350 float groundHeight = ScorchedClient::instance()->getLandscapeMaps().
00351 getGroundMaps().getHeight(lx, ly).asFloat();
00352
00353
00354 float waterDepth = waterHeight - groundHeight;
00355 if (waterDepth < 0.0f) waterDepth = 0.0f;
00356 else if (waterDepth > 10.0f) waterDepth = 10.0f;
00357
00358
00359 unsigned char result = (unsigned char) (waterDepth * 25.0f);
00360 aofImage.getBits()[ptr * 3 + 1] = result;
00361 }
00362 }
00363 }