llvlcomposition.cpp

Go to the documentation of this file.
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" // for from_region_handle
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         // Not sure if this is the right math...
00051         // Take weighted average of all four points (bilinear interpolation)
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         // Load Terrain Textures - Original ones
00072         LLUUID id;
00073         // Dirt
00074         id.set( gViewerArt.getString("terrain_dirt_detail.tga") );
00075         setDetailTextureID(0, id);
00076 
00077         // Grass
00078         id.set( gViewerArt.getString("terrain_grass_detail.tga") );
00079         setDetailTextureID(1, id);
00080 
00081         // Rock mountain
00082         id.set( gViewerArt.getString("terrain_mountain_detail.tga") );
00083         setDetailTextureID(2, id);
00084 
00085         // Rock face
00086         id.set( gViewerArt.getString("terrain_rock_detail.tga") );
00087         setDetailTextureID(3, id);
00088 
00089         // Initialize the texture matrix to defaults.
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                 // All the parameters haven't been set yet (we haven't gotten the message from the sim)
00128                 return FALSE;
00129         }
00130 
00131         llassert(mSurfacep);
00132 
00133         if (!mSurfacep || !mSurfacep->getRegion()) 
00134         {
00135                 // We don't always have the region yet here....
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         // For perlin noise generation...
00158         const F32 slope_squared = 1.5f*1.5f;
00159         const F32 xyScale = 4.9215f; //0.93284f;
00160         const F32 zScale = 4; //0.92165f;
00161         const F32 z_offset = 0.f;
00162         const F32 noise_magnitude = 2.f;                //  Degree to which noise modulates composition layer (versus
00163                                                                                         //  simple height)
00164 
00165         // Heights map into textures as 0-1 = first, 1-2 = second, etc.
00166         // So we need to compress heights into this range.
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         // OK, for now, just have the composition value equal the height at the point.
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                         // Bilinearly interpolate the start height and height range of the textures
00185                         F32 start_height = bilinear(mStartHeight[SOUTHWEST],
00186                                                                                 mStartHeight[SOUTHEAST],
00187                                                                                 mStartHeight[NORTHWEST],
00188                                                                                 mStartHeight[NORTHEAST],
00189                                                                                 i*inv_width, j*inv_width); // These will be bilinearly interpolated
00190                         F32 height_range = bilinear(mHeightRange[SOUTHWEST],
00191                                                                                 mHeightRange[SOUTHEAST],
00192                                                                                 mHeightRange[NORTHWEST],
00193                                                                                 mHeightRange[NORTHEAST],
00194                                                                                 i*inv_width, j*inv_width); // These will be bilinearly interpolated
00195 
00196                         LLVector3 location(i*mScale, j*mScale, 0.f);
00197 
00198                         F32 height = mSurfacep->resolveHeightRegion(location) + z_offset;
00199 
00200                         // Step 0: Measure the exact height at this texel
00201                         vec[0] = (F32)(origin_global.mdV[VX]+location.mV[VX])*xyScaleInv;       //  Adjust to non-integer lattice
00202                         vec[1] = (F32)(origin_global.mdV[VY]+location.mV[VY])*xyScaleInv;
00203                         vec[2] = height*zScaleInv;
00204                         //
00205                         //  Choose material value by adding to the exact height a random value 
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;                                    //  Low freq component for large divisions
00211 
00212                         twiddle += turbulence2(vec, 2)*slope_squared;   //  High frequency component
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                 // All the parameters haven't been set yet (we haven't gotten the message from the sim)
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); // in case we are at low detail
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); // in case we are at low detail
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         // Generate raw data arrays for surface textures
00278         //
00279         //
00280 
00281         // These have already been validated by generateComposition.
00282         U8* st_data[4];
00283         S32 st_data_size[4]; // for debugging
00284 
00285         for (S32 i = 0; i < 4; i++)
00286         {
00287                 if (mRawImages[i].isNull())
00288                 {
00289                         // Read back a raw image for this discard level, if it exists
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; // deletes old
00311                         }
00312                 }
00313                 st_data[i] = mRawImages[i]->getData();
00314                 st_data_size[i] = mRawImages[i]->getDataSize();
00315         }
00316 
00318         //
00319         // Generate and clamp x/y bounding box.
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         // Generate target texture information, stride ratios.
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         // Iterate through the target texture, striding through the
00395         // subtextures and interpolating appropriately.
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                                 // Linearly interpolate based on composition.
00429                                 if (st_offset >= st_data_size[tex0] || st_offset >= st_data_size[tex1])
00430                                 {
00431                                         // SJB: This shouldn't be happening, but does... Rounding error?
00432                                         //llwarns << "offset 0 [" << tex0 << "] =" << st_offset << " >= size=" << st_data_size[tex0] << llendl;
00433                                         //llwarns << "offset 1 [" << tex1 << "] =" << st_offset << " >= size=" << st_data_size[tex1] << llendl;
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                 // Un-boost detatil textures (will get re-boosted if rendering in high detail)
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 }

Generated on Thu Jul 1 06:09:35 2010 for Second Life Viewer by  doxygen 1.4.7