00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llvlcomposition.h"
00035 #include "llerror.h"
00036 #include "v3math.h"
00037 #include "llsurface.h"
00038 #include "lltextureview.h"
00039 #include "llviewerimage.h"
00040 #include "llviewerimagelist.h"
00041 #include "llviewerregion.h"
00042 #include "noise.h"
00043 #include "llregionhandle.h"
00044 #include "llviewercontrol.h"
00045
00046
00047
00048 F32 bilinear(const F32 v00, const F32 v01, const F32 v10, const F32 v11, const F32 x_frac, const F32 y_frac)
00049 {
00050
00051
00052 F32 result;
00053
00054 const F32 inv_x_frac = 1.f - x_frac;
00055 const F32 inv_y_frac = 1.f - y_frac;
00056 result = inv_x_frac*inv_y_frac*v00
00057 + x_frac*inv_y_frac*v10
00058 + inv_x_frac*y_frac*v01
00059 + x_frac*y_frac*v11;
00060
00061 return result;
00062 }
00063
00064
00065 LLVLComposition::LLVLComposition(LLSurface *surfacep, const U32 width, const F32 scale) :
00066 LLViewerLayer(width, scale),
00067 mParamsReady(FALSE)
00068 {
00069 mSurfacep = surfacep;
00070
00071
00072 LLUUID id;
00073
00074 id.set( gViewerArt.getString("terrain_dirt_detail.tga") );
00075 setDetailTextureID(0, id);
00076
00077
00078 id.set( gViewerArt.getString("terrain_grass_detail.tga") );
00079 setDetailTextureID(1, id);
00080
00081
00082 id.set( gViewerArt.getString("terrain_mountain_detail.tga") );
00083 setDetailTextureID(2, id);
00084
00085
00086 id.set( gViewerArt.getString("terrain_rock_detail.tga") );
00087 setDetailTextureID(3, id);
00088
00089
00090 for (S32 i = 0; i < CORNER_COUNT; ++i)
00091 {
00092 mStartHeight[i] = gSavedSettings.getF32("TerrainColorStartHeight");
00093 mHeightRange[i] = gSavedSettings.getF32("TerrainColorHeightRange");
00094 }
00095 mTexScaleX = 16.f;
00096 mTexScaleY = 16.f;
00097 mTexturesLoaded = FALSE;
00098 }
00099
00100
00101 LLVLComposition::~LLVLComposition()
00102 {
00103 }
00104
00105
00106 void LLVLComposition::setSurface(LLSurface *surfacep)
00107 {
00108 mSurfacep = surfacep;
00109 }
00110
00111
00112 void LLVLComposition::setDetailTextureID(S32 corner, const LLUUID& id)
00113 {
00114 if(id.isNull())
00115 {
00116 return;
00117 }
00118 mDetailTextures[corner] = gImageList.getImage(id);
00119 mRawImages[corner] = NULL;
00120 }
00121
00122 BOOL LLVLComposition::generateHeights(const F32 x, const F32 y,
00123 const F32 width, const F32 height)
00124 {
00125 if (!mParamsReady)
00126 {
00127
00128 return FALSE;
00129 }
00130
00131 llassert(mSurfacep);
00132
00133 if (!mSurfacep || !mSurfacep->getRegion())
00134 {
00135
00136 return FALSE;
00137 }
00138
00139 S32 x_begin, y_begin, x_end, y_end;
00140
00141 x_begin = llround( x * mScaleInv );
00142 y_begin = llround( y * mScaleInv );
00143 x_end = llround( (x + width) * mScaleInv );
00144 y_end = llround( (y + width) * mScaleInv );
00145
00146 if (x_end > mWidth)
00147 {
00148 x_end = mWidth;
00149 }
00150 if (y_end > mWidth)
00151 {
00152 y_end = mWidth;
00153 }
00154
00155 LLVector3d origin_global = from_region_handle(mSurfacep->getRegion()->getHandle());
00156
00157
00158 const F32 slope_squared = 1.5f*1.5f;
00159 const F32 xyScale = 4.9215f;
00160 const F32 zScale = 4;
00161 const F32 z_offset = 0.f;
00162 const F32 noise_magnitude = 2.f;
00163
00164
00165
00166
00167 const S32 NUM_TEXTURES = 4;
00168
00169 const F32 xyScaleInv = (1.f / xyScale);
00170 const F32 zScaleInv = (1.f / zScale);
00171
00172 const F32 inv_width = 1.f/mWidth;
00173
00174
00175 for (S32 j = y_begin; j < y_end; j++)
00176 {
00177 for (S32 i = x_begin; i < x_end; i++)
00178 {
00179
00180 F32 vec[3];
00181 F32 vec1[3];
00182 F32 twiddle;
00183
00184
00185 F32 start_height = bilinear(mStartHeight[SOUTHWEST],
00186 mStartHeight[SOUTHEAST],
00187 mStartHeight[NORTHWEST],
00188 mStartHeight[NORTHEAST],
00189 i*inv_width, j*inv_width);
00190 F32 height_range = bilinear(mHeightRange[SOUTHWEST],
00191 mHeightRange[SOUTHEAST],
00192 mHeightRange[NORTHWEST],
00193 mHeightRange[NORTHEAST],
00194 i*inv_width, j*inv_width);
00195
00196 LLVector3 location(i*mScale, j*mScale, 0.f);
00197
00198 F32 height = mSurfacep->resolveHeightRegion(location) + z_offset;
00199
00200
00201 vec[0] = (F32)(origin_global.mdV[VX]+location.mV[VX])*xyScaleInv;
00202 vec[1] = (F32)(origin_global.mdV[VY]+location.mV[VY])*xyScaleInv;
00203 vec[2] = height*zScaleInv;
00204
00205
00206
00207 vec1[0] = vec[0]*(0.2222222222f);
00208 vec1[1] = vec[1]*(0.2222222222f);
00209 vec1[2] = vec[2]*(0.2222222222f);
00210 twiddle = noise2(vec1)*6.5f;
00211
00212 twiddle += turbulence2(vec, 2)*slope_squared;
00213 twiddle *= noise_magnitude;
00214
00215 F32 scaled_noisy_height = (height + twiddle - start_height) * F32(NUM_TEXTURES) / height_range;
00216
00217 scaled_noisy_height = llmax(0.f, scaled_noisy_height);
00218 scaled_noisy_height = llmin(3.f, scaled_noisy_height);
00219 *(mDatap + i + j*mWidth) = scaled_noisy_height;
00220 }
00221 }
00222 return TRUE;
00223 }
00224
00225 static const S32 BASE_SIZE = 128;
00226
00227 BOOL LLVLComposition::generateComposition()
00228 {
00229
00230 if (!mParamsReady)
00231 {
00232
00233 return FALSE;
00234 }
00235
00236 for (S32 i = 0; i < 4; i++)
00237 {
00238 if (mDetailTextures[i]->getDiscardLevel() < 0)
00239 {
00240 mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN);
00241 mDetailTextures[i]->addTextureStats(BASE_SIZE*BASE_SIZE);
00242 return FALSE;
00243 }
00244 if ((mDetailTextures[i]->getDiscardLevel() != 0 &&
00245 (mDetailTextures[i]->getWidth() < BASE_SIZE ||
00246 mDetailTextures[i]->getHeight() < BASE_SIZE)))
00247 {
00248 S32 width = mDetailTextures[i]->getWidth(0);
00249 S32 height = mDetailTextures[i]->getHeight(0);
00250 S32 min_dim = llmin(width, height);
00251 S32 ddiscard = 0;
00252 while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL)
00253 {
00254 ddiscard++;
00255 min_dim /= 2;
00256 }
00257 mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN);
00258 mDetailTextures[i]->setMinDiscardLevel(ddiscard);
00259 return FALSE;
00260 }
00261 }
00262
00263 return TRUE;
00264 }
00265
00266 BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
00267 const F32 width, const F32 height)
00268 {
00269 llassert(mSurfacep);
00270 llassert(x >= 0.f);
00271 llassert(y >= 0.f);
00272
00273 LLTimer gen_timer;
00274
00276
00277
00278
00279
00280
00281
00282 U8* st_data[4];
00283 S32 st_data_size[4];
00284
00285 for (S32 i = 0; i < 4; i++)
00286 {
00287 if (mRawImages[i].isNull())
00288 {
00289
00290 mRawImages[i] = new LLImageRaw;
00291 S32 min_dim = llmin(mDetailTextures[i]->getWidth(0), mDetailTextures[i]->getHeight(0));
00292 S32 ddiscard = 0;
00293 while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL)
00294 {
00295 ddiscard++;
00296 min_dim /= 2;
00297 }
00298 if (!mDetailTextures[i]->readBackRaw(ddiscard, mRawImages[i], false))
00299 {
00300 llwarns << "Unable to read raw data for terrain detail texture: " << mDetailTextures[i]->getID() << llendl;
00301 mRawImages[i] = NULL;
00302 return FALSE;
00303 }
00304 if (mDetailTextures[i]->getWidth(ddiscard) != BASE_SIZE ||
00305 mDetailTextures[i]->getHeight(ddiscard) != BASE_SIZE ||
00306 mDetailTextures[i]->getComponents() != 3)
00307 {
00308 LLPointer<LLImageRaw> newraw = new LLImageRaw(BASE_SIZE, BASE_SIZE, 3);
00309 newraw->composite(mRawImages[i]);
00310 mRawImages[i] = newraw;
00311 }
00312 }
00313 st_data[i] = mRawImages[i]->getData();
00314 st_data_size[i] = mRawImages[i]->getDataSize();
00315 }
00316
00318
00319
00320
00321
00322
00323 S32 x_begin, y_begin, x_end, y_end;
00324 x_begin = (S32)(x * mScaleInv);
00325 y_begin = (S32)(y * mScaleInv);
00326 x_end = llround( (x + width) * mScaleInv );
00327 y_end = llround( (y + width) * mScaleInv );
00328
00329 if (x_end > mWidth)
00330 {
00331 llwarns << "x end > width" << llendl;
00332 x_end = mWidth;
00333 }
00334 if (y_end > mWidth)
00335 {
00336 llwarns << "y end > width" << llendl;
00337 y_end = mWidth;
00338 }
00339
00340
00342
00343
00344
00345
00346
00347 LLViewerImage *texturep;
00348 U32 tex_width, tex_height, tex_comps;
00349 U32 tex_stride;
00350 F32 tex_x_scalef, tex_y_scalef;
00351 S32 tex_x_begin, tex_y_begin, tex_x_end, tex_y_end;
00352 F32 tex_x_ratiof, tex_y_ratiof;
00353
00354 texturep = mSurfacep->getSTexture();
00355 tex_width = texturep->getWidth();
00356 tex_height = texturep->getHeight();
00357 tex_comps = texturep->getComponents();
00358 tex_stride = tex_width * tex_comps;
00359
00360 S32 st_comps = 3;
00361 S32 st_width = BASE_SIZE;
00362 S32 st_height = BASE_SIZE;
00363
00364 if (tex_comps != st_comps)
00365 {
00366 llwarns << "Base texture comps != input texture comps" << llendl;
00367 return FALSE;
00368 }
00369
00370 tex_x_scalef = (F32)tex_width / (F32)mWidth;
00371 tex_y_scalef = (F32)tex_height / (F32)mWidth;
00372 tex_x_begin = (S32)((F32)x_begin * tex_x_scalef);
00373 tex_y_begin = (S32)((F32)y_begin * tex_y_scalef);
00374 tex_x_end = (S32)((F32)x_end * tex_x_scalef);
00375 tex_y_end = (S32)((F32)y_end * tex_y_scalef);
00376
00377 tex_x_ratiof = (F32)mWidth*mScale / (F32)tex_width;
00378 tex_y_ratiof = (F32)mWidth*mScale / (F32)tex_height;
00379
00380 LLPointer<LLImageRaw> raw = new LLImageRaw(tex_width, tex_height, tex_comps);
00381 U8 *rawp = raw->getData();
00382
00383 F32 tex_width_inv = 1.f/tex_width;
00384 F32 tex_height_inv = 1.f/tex_height;
00385
00386 F32 st_x_stride, st_y_stride;
00387 st_x_stride = ((F32)st_width / (F32)mTexScaleX)*((F32)mWidth / (F32)tex_width);
00388 st_y_stride = ((F32)st_height / (F32)mTexScaleY)*((F32)mWidth / (F32)tex_height);
00389
00390 llassert(st_x_stride > 0.f);
00391 llassert(st_y_stride > 0.f);
00393
00394
00395
00396
00397
00398
00399 F32 sti, stj;
00400 S32 st_offset;
00401 sti = (tex_x_begin * st_x_stride) - st_width*(llfloor((tex_x_begin * st_x_stride)/st_width));
00402 stj = (tex_y_begin * st_y_stride) - st_height*(llfloor((tex_y_begin * st_y_stride)/st_height));
00403
00404 st_offset = (llfloor(stj * st_width) + llfloor(sti)) * st_comps;
00405 for (S32 j = tex_y_begin; j < tex_y_end; j++)
00406 {
00407 U32 offset = j * tex_stride + tex_x_begin * tex_comps;
00408 sti = (tex_x_begin * st_x_stride) - st_width*((U32)(tex_x_begin * st_x_stride)/st_width);
00409 for (S32 i = tex_x_begin; i < tex_x_end; i++)
00410 {
00411 S32 tex0, tex1;
00412 F32 composition = getValueScaled(i*tex_x_ratiof, j*tex_y_ratiof);
00413
00414 tex0 = llfloor( composition );
00415 tex0 = llclamp(tex0, 0, 3);
00416 composition -= tex0;
00417 tex1 = tex0 + 1;
00418 tex1 = llclamp(tex1, 0, 3);
00419
00420 F32 xy_int_i, xy_int_j;
00421
00422 xy_int_i = i * tex_width_inv;
00423 xy_int_j = j * tex_height_inv;
00424
00425 st_offset = (lltrunc(sti) + lltrunc(stj)*st_width) * st_comps;
00426 for (U32 k = 0; k < tex_comps; k++)
00427 {
00428
00429 if (st_offset >= st_data_size[tex0] || st_offset >= st_data_size[tex1])
00430 {
00431
00432
00433
00434 }
00435 else
00436 {
00437 F32 a = *(st_data[tex0] + st_offset);
00438 F32 b = *(st_data[tex1] + st_offset);
00439 rawp[ offset ] = (U8)lltrunc( a + composition * (b - a) );
00440 }
00441 offset++;
00442 st_offset++;
00443 }
00444
00445 sti += st_x_stride;
00446 if (sti >= st_width)
00447 {
00448 sti -= st_width;
00449 }
00450 }
00451
00452 stj += st_y_stride;
00453 if (stj >= st_height)
00454 {
00455 stj -= st_height;
00456 }
00457 }
00458
00459 texturep->setSubImage(raw, tex_x_begin, tex_y_begin, tex_x_end - tex_x_begin, tex_y_end - tex_y_begin);
00460 LLSurface::sTextureUpdateTime += gen_timer.getElapsedTimeF32();
00461 LLSurface::sTexelsUpdated += (tex_x_end - tex_x_begin) * (tex_y_end - tex_y_begin);
00462
00463 for (S32 i = 0; i < 4; i++)
00464 {
00465
00466 mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_NONE);
00467 mDetailTextures[i]->setMinDiscardLevel(MAX_DISCARD_LEVEL + 1);
00468 }
00469
00470 return TRUE;
00471 }
00472
00473 LLUUID LLVLComposition::getDetailTextureID(S32 corner)
00474 {
00475 return mDetailTextures[corner]->getID();
00476 }
00477
00478 LLViewerImage* LLVLComposition::getDetailTexture(S32 corner)
00479 {
00480 return mDetailTextures[corner];
00481 }
00482
00483 F32 LLVLComposition::getStartHeight(S32 corner)
00484 {
00485 return mStartHeight[corner];
00486 }
00487
00488 void LLVLComposition::setStartHeight(S32 corner, const F32 start_height)
00489 {
00490 mStartHeight[corner] = start_height;
00491 }
00492
00493 F32 LLVLComposition::getHeightRange(S32 corner)
00494 {
00495 return mHeightRange[corner];
00496 }
00497
00498 void LLVLComposition::setHeightRange(S32 corner, const F32 range)
00499 {
00500 mHeightRange[corner] = range;
00501 }