llvograss.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llvograss.h"
00035 
00036 #include "imageids.h"
00037 #include "llviewercontrol.h"
00038 
00039 #include "llagent.h"
00040 #include "llviewerwindow.h"
00041 #include "lldrawable.h"
00042 #include "llface.h"
00043 #include "llsky.h"
00044 #include "llsurface.h"
00045 #include "llsurfacepatch.h"
00046 #include "llvosky.h"
00047 #include "llviewercamera.h"
00048 #include "llviewerimagelist.h"
00049 #include "llviewerregion.h"
00050 #include "pipeline.h"
00051 #include "llworld.h"
00052 #include "lldir.h"
00053 #include "llxmltree.h"
00054 
00055 const S32 GRASS_MAX_BLADES =    32;
00056 const F32 GRASS_BLADE_BASE =    0.25f;                  //  Width of grass at base
00057 const F32 GRASS_BLADE_TOP =             0.25f;                  //  Width of grass at top
00058 const F32 GRASS_BLADE_HEIGHT =  0.5f;                   // meters
00059 const F32 GRASS_DISTRIBUTION_SD = 0.15f;                // empirically defined
00060 
00061 F32 exp_x[GRASS_MAX_BLADES];
00062 F32 exp_y[GRASS_MAX_BLADES];
00063 F32 rot_x[GRASS_MAX_BLADES];
00064 F32 rot_y[GRASS_MAX_BLADES];
00065 F32 dz_x [GRASS_MAX_BLADES];
00066 F32 dz_y [GRASS_MAX_BLADES];
00067 
00068 F32 w_mod[GRASS_MAX_BLADES];                                    //  Factor to modulate wind movement by to randomize appearance
00069 
00070 LLVOGrass::SpeciesMap LLVOGrass::sSpeciesTable;
00071 S32 LLVOGrass::sMaxGrassSpecies = 0;
00072 
00073 
00074 LLVOGrass::LLVOGrass(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
00075 :       LLAlphaObject(id, pcode, regionp)
00076 {
00077         mPatch               = NULL;
00078         mLastPatchUpdateTime = 0;
00079         mGrassVel.clearVec();
00080         mGrassBend.clearVec();
00081         mbCanSelect          = TRUE;
00082 
00083         mBladeWindAngle      = 35.f;
00084         mBWAOverlap          = 2.f;
00085 
00086         setNumTEs(1);
00087 
00088         setTEColor(0, LLColor4(1.0f, 1.0f, 1.0f, 1.f));
00089         mNumBlades = GRASS_MAX_BLADES;
00090 }
00091 
00092 LLVOGrass::~LLVOGrass()
00093 {
00094 }
00095 
00096 
00097 void LLVOGrass::updateSpecies()
00098 {
00099         mSpecies = mState;
00100         
00101         if (!sSpeciesTable.count(mSpecies))
00102         {
00103                 llinfos << "Unknown grass type, substituting grass type." << llendl;
00104                 SpeciesMap::const_iterator it = sSpeciesTable.begin();
00105                 mSpecies = (*it).first;
00106         }
00107         setTEImage(0, gImageList.getImage(sSpeciesTable[mSpecies]->mTextureID));
00108 }
00109 
00110 
00111 void alert_done(S32 option, void* user_data)
00112 {
00113         return;
00114 }
00115 
00116 
00117 void LLVOGrass::initClass()
00118 {
00119         LLVector3 pos(0.0f, 0.0f, 0.0f);
00120         //  Create nifty list of exponential distribution 0-1
00121         F32 x = 0.f;
00122         F32 y = 0.f;
00123         F32 rot;
00124         
00125         std::string xml_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"grass.xml");
00126         
00127         LLXmlTree grass_def_grass;
00128 
00129         if (!grass_def_grass.parseFile(xml_filename))
00130         {
00131                 llerrs << "Failed to parse grass file." << llendl;
00132                 return;
00133         }
00134 
00135         LLXmlTreeNode* rootp = grass_def_grass.getRoot();
00136 
00137         for (LLXmlTreeNode* grass_def = rootp->getFirstChild();
00138                 grass_def;
00139                 grass_def = rootp->getNextChild())
00140         {
00141                 if (!grass_def->hasName("grass"))
00142                 {
00143                         llwarns << "Invalid grass definition node " << grass_def->getName() << llendl;
00144                         continue;
00145                 }
00146                 F32 F32_val;
00147                 LLUUID id;
00148 
00149                 BOOL success = TRUE;
00150 
00151                 S32 species;
00152                 static LLStdStringHandle species_id_string = LLXmlTree::addAttributeString("species_id");
00153                 if (!grass_def->getFastAttributeS32(species_id_string, species))
00154                 {
00155                         llwarns << "No species id defined" << llendl;
00156                         continue;
00157                 }
00158 
00159                 if (species < 0)
00160                 {
00161                         llwarns << "Invalid species id " << species << llendl;
00162                         continue;
00163                 }
00164 
00165                 GrassSpeciesData* newGrass = new GrassSpeciesData();
00166 
00167 
00168                 static LLStdStringHandle texture_id_string = LLXmlTree::addAttributeString("texture_id");
00169                 grass_def->getFastAttributeUUID(texture_id_string, id);
00170                 newGrass->mTextureID = id;
00171 
00172                 if (newGrass->mTextureID.isNull())
00173                 {
00174                         LLString textureName;
00175 
00176                         static LLStdStringHandle texture_name_string = LLXmlTree::addAttributeString("texture_name");
00177                         success &= grass_def->getFastAttributeString(texture_name_string, textureName);
00178                         newGrass->mTextureID.set( gViewerArt.getString(textureName) );
00179                 }
00180 
00181                 static LLStdStringHandle blade_sizex_string = LLXmlTree::addAttributeString("blade_size_x");
00182                 success &= grass_def->getFastAttributeF32(blade_sizex_string, F32_val);
00183                 newGrass->mBladeSizeX = F32_val;
00184 
00185                 static LLStdStringHandle blade_sizey_string = LLXmlTree::addAttributeString("blade_size_y");
00186                 success &= grass_def->getFastAttributeF32(blade_sizey_string, F32_val);
00187                 newGrass->mBladeSizeY = F32_val;
00188 
00189                 if (sSpeciesTable.count(species))
00190                 {
00191                         llinfos << "Grass species " << species << " already defined! Duplicate discarded." << llendl;
00192                         delete newGrass;
00193                         continue;
00194                 }
00195                 else
00196                 {
00197                         sSpeciesTable[species] = newGrass;
00198                 }
00199 
00200                 if (species >= sMaxGrassSpecies) sMaxGrassSpecies = species + 1;
00201 
00202                 if (!success)
00203                 {
00204                         LLString name;
00205                         static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
00206                         grass_def->getFastAttributeString(name_string, name);
00207                         llwarns << "Incomplete definition of grass " << name << llendl;
00208                 }
00209         }
00210 
00211         BOOL have_all_grass = TRUE;
00212         LLString err;
00213         char buffer[10];                /* Flawfinder: ignore */
00214 
00215         for (S32 i=0;i<sMaxGrassSpecies;++i)
00216         {
00217                 if (!sSpeciesTable.count(i))
00218                 {
00219                         snprintf(buffer,10," %d",i);            /* Flawfinder: ignore */
00220                         err.append(buffer);
00221                         have_all_grass = FALSE;
00222                 }
00223         }
00224 
00225         if (!have_all_grass) 
00226         {
00227                 LLStringBase<char>::format_map_t args;
00228                 args["[SPECIES]"] = err;
00229                 gViewerWindow->alertXml("ErrorUndefinedGrasses", args, alert_done );
00230         }
00231 
00232         for (S32 i = 0; i < GRASS_MAX_BLADES; ++i)
00233         {
00234                 if (1)   //(i%2 == 0)                   Uncomment for X blading
00235                 {
00236                         F32 u = sqrt(-2.0f * log(ll_frand()));
00237                         F32 v = 2.0f * F_PI * ll_frand();
00238                         
00239                         x = u * sin(v) * GRASS_DISTRIBUTION_SD;
00240                         y = u * cos(v) * GRASS_DISTRIBUTION_SD;
00241 
00242                         rot = ll_frand(F_PI);
00243                 }
00244                 else
00245                 {
00246                         rot += (F_PI*0.4f + ll_frand(0.2f*F_PI));
00247                 }
00248 
00249                 exp_x[i] = x;
00250                 exp_y[i] = y;
00251                 rot_x[i] = sin(rot);
00252                 rot_y[i] = cos(rot);
00253                 dz_x[i] = ll_frand(GRASS_BLADE_BASE * 0.25f);
00254                 dz_y[i] = ll_frand(GRASS_BLADE_BASE * 0.25f);
00255                 w_mod[i] = 0.5f + ll_frand();                                           //  Degree to which blade is moved by wind
00256 
00257         }
00258 }
00259 
00260 void LLVOGrass::cleanupClass()
00261 {
00262         for_each(sSpeciesTable.begin(), sSpeciesTable.end(), DeletePairedPointer());
00263 }
00264 
00265 U32 LLVOGrass::processUpdateMessage(LLMessageSystem *mesgsys,
00266                                                                                   void **user_data,
00267                                                                                   U32 block_num,
00268                                                                                   const EObjectUpdateType update_type,
00269                                                                                   LLDataPacker *dp)
00270 {
00271         // Do base class updates...
00272         U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
00273 
00274         updateSpecies();
00275 
00276         if (  (getVelocity().magVecSquared() > 0.f)
00277                 ||(getAcceleration().magVecSquared() > 0.f)
00278                 ||(getAngularVelocity().magVecSquared() > 0.f))
00279         {
00280                 llinfos << "ACK! Moving grass!" << llendl;
00281                 setVelocity(LLVector3::zero);
00282                 setAcceleration(LLVector3::zero);
00283                 setAngularVelocity(LLVector3::zero);
00284         }
00285 
00286         if (mDrawable)
00287         {
00288                 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
00289         }
00290 
00291         return retval;
00292 }
00293 
00294 BOOL LLVOGrass::isActive() const
00295 {
00296         return TRUE;
00297 }
00298 
00299 BOOL LLVOGrass::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
00300 {
00301         if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_GRASS)))
00302         {
00303                 return TRUE;
00304         }
00305         
00306         if (!mDrawable)
00307         {
00308                 // So drones work.
00309                 return TRUE;
00310         }
00311 
00312         if (mPatch && (mLastPatchUpdateTime != mPatch->getLastUpdateTime()))
00313         {
00314                 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
00315         }
00316 
00317         return TRUE;
00318 }
00319 
00320 
00321 void LLVOGrass::setPixelAreaAndAngle(LLAgent &agent)
00322 {
00323         // This should be the camera's center, as soon as we move to all region-local.
00324         LLVector3 relative_position = getPositionAgent() - agent.getCameraPositionAgent();
00325         F32 range = relative_position.magVec();
00326 
00327         F32 max_scale = getMaxScale();
00328 
00329         mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG;
00330 
00331         // Compute pixels per meter at the given range
00332         F32 pixels_per_meter = gCamera->getViewHeightInPixels() / (tan(gCamera->getView()) * range);
00333 
00334         // Assume grass texture is a 5 meter by 5 meter sprite at the grass object's center
00335         mPixelArea = (pixels_per_meter) * (pixels_per_meter) * 25.f;
00336 }
00337 
00338 
00339 // BUG could speed this up by caching the relative_position and range calculations
00340 void LLVOGrass::updateTextures(LLAgent &agent)
00341 {
00342         if (getTEImage(0))
00343         {
00344                 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
00345                 {
00346                         setDebugText(llformat("%4.0f", fsqrtf(mPixelArea)));
00347                 }
00348                 getTEImage(0)->addTextureStats(mPixelArea);
00349         }
00350 }
00351 
00352 BOOL LLVOGrass::updateLOD()
00353 {
00354         if (mDrawable->getNumFaces() <= 0)
00355         {
00356                 return FALSE;
00357         }
00358         
00359         LLFace* face = mDrawable->getFace(0);
00360 
00361         F32 tan_angle = 0.f;
00362         S32 num_blades = 0;
00363 
00364         tan_angle = (mScale.mV[0]*mScale.mV[1])/mDrawable->mDistanceWRTCamera;
00365         num_blades = llmin(GRASS_MAX_BLADES, lltrunc(tan_angle * 5));
00366         num_blades = llmax(1, num_blades);
00367         if (num_blades >= (mNumBlades << 1))
00368         {
00369                 while (mNumBlades < num_blades)
00370                 {
00371                         mNumBlades <<= 1;
00372                 }
00373 
00374                 face->setSize(mNumBlades*8, mNumBlades*12);
00375                 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
00376         }
00377         else if (num_blades <= (mNumBlades >> 1))
00378         {
00379                 while (mNumBlades > num_blades)
00380                 {
00381                         mNumBlades >>=1;
00382                 }
00383 
00384                 face->setSize(mNumBlades*8, mNumBlades*12);
00385                 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
00386                 return TRUE;
00387         }
00388 
00389         return FALSE;
00390 }
00391 
00392 LLDrawable* LLVOGrass::createDrawable(LLPipeline *pipeline)
00393 {
00394         pipeline->allocDrawable(this);
00395         mDrawable->setRenderType(LLPipeline::RENDER_TYPE_GRASS);
00396         
00397         return mDrawable;
00398 }
00399 
00400 BOOL LLVOGrass::updateGeometry(LLDrawable *drawable)
00401 {
00402         LLFastTimer ftm(LLFastTimer::FTM_UPDATE_GRASS);
00403         plantBlades();
00404         return TRUE;
00405 }
00406 
00407 void LLVOGrass::plantBlades()
00408 {
00409         // It is possible that the species of a grass is not defined
00410         // This is bad, but not the end of the world.
00411         if (!sSpeciesTable.count(mSpecies))
00412         {
00413                 llinfos << "Unknown grass species " << mSpecies << llendl;
00414                 return;
00415         }
00416         
00417         if (mDrawable->getNumFaces() < 1)
00418         {
00419                 mDrawable->setNumFaces(1, NULL, getTEImage(0));
00420         }
00421                 
00422         LLFace *face = mDrawable->getFace(0);
00423 
00424         face->setTexture(getTEImage(0));
00425         face->setState(LLFace::GLOBAL);
00426         face->setSize(mNumBlades * 8, mNumBlades * 12);
00427         face->mVertexBuffer = NULL;
00428         face->setTEOffset(0);
00429         face->mCenterLocal = mPosition + mRegionp->getOriginAgent();
00430         
00431         mDepth = (face->mCenterLocal - gCamera->getOrigin())*gCamera->getAtAxis();
00432         mDrawable->setPosition(face->mCenterLocal);
00433         mDrawable->movePartition();
00434         LLPipeline::sCompiles++;
00435 }
00436 
00437 void LLVOGrass::getGeometry(S32 idx,
00438                                                                 LLStrider<LLVector3>& verticesp,
00439                                                                 LLStrider<LLVector3>& normalsp, 
00440                                                                 LLStrider<LLVector2>& texcoordsp,
00441                                                                 LLStrider<LLColor4U>& colorsp, 
00442                                                                 LLStrider<U32>& indicesp)
00443 {
00444         mPatch = mRegionp->getLand().resolvePatchRegion(getPositionRegion());
00445         if (mPatch)
00446                 mLastPatchUpdateTime = mPatch->getLastUpdateTime();
00447         
00448         LLVector3 position;
00449         // Create random blades of grass with gaussian distribution
00450         F32 x,y,xf,yf,dzx,dzy;
00451 
00452         LLColor4U color(255,255,255,255);
00453 
00454         LLFace *face = mDrawable->getFace(idx);
00455 
00456         F32 width  = sSpeciesTable[mSpecies]->mBladeSizeX;
00457         F32 height = sSpeciesTable[mSpecies]->mBladeSizeY;
00458 
00459         U32 index_offset = face->getGeomIndex();
00460 
00461         for (S32 i = 0;  i < mNumBlades; i++)
00462         {
00463                 x   = exp_x[i] * mScale.mV[VX];
00464                 y   = exp_y[i] * mScale.mV[VY];
00465                 xf  = rot_x[i] * GRASS_BLADE_BASE * width * w_mod[i];
00466                 yf  = rot_y[i] * GRASS_BLADE_BASE * width * w_mod[i];
00467                 dzx = dz_x [i];
00468                 dzy = dz_y [i];
00469 
00470                 LLVector3 v1,v2,v3;
00471                 F32 blade_height= GRASS_BLADE_HEIGHT * height * w_mod[i];
00472 
00473                 *texcoordsp++   = LLVector2(0, 0);
00474                 *texcoordsp++   = LLVector2(0, 0);
00475                 *texcoordsp++   = LLVector2(0, 0.98f);
00476                 *texcoordsp++   = LLVector2(0, 0.98f);
00477                 *texcoordsp++   = LLVector2(1, 0);
00478                 *texcoordsp++   = LLVector2(1, 0);
00479                 *texcoordsp++   = LLVector2(1, 0.98f);
00480                 *texcoordsp++   = LLVector2(1, 0.98f);
00481 
00482                 position.mV[0]  = mPosition.mV[VX] + x + xf;
00483                 position.mV[1]  = mPosition.mV[VY] + y + yf;
00484                 position.mV[2]  = mRegionp->getLand().resolveHeightRegion(position);
00485                 *verticesp++    = v1 = position + mRegionp->getOriginAgent();
00486                 *verticesp++    = v1;
00487 
00488 
00489                 position.mV[0] += dzx;
00490                 position.mV[1] += dzy;
00491                 position.mV[2] += blade_height;
00492                 *verticesp++    = v2 = position + mRegionp->getOriginAgent();
00493                 *verticesp++    = v2;
00494 
00495                 position.mV[0]  = mPosition.mV[VX] + x - xf;
00496                 position.mV[1]  = mPosition.mV[VY] + y - xf;
00497                 position.mV[2]  = mRegionp->getLand().resolveHeightRegion(position);
00498                 *verticesp++    = v3 = position + mRegionp->getOriginAgent();
00499                 *verticesp++    = v3;
00500 
00501                 LLVector3 normal1 = (v1-v2) % (v2-v3);
00502                 normal1.mV[VZ] = 0.75f;
00503                 normal1.normVec();
00504                 LLVector3 normal2 = -normal1;
00505                 normal2.mV[VZ] = -normal2.mV[VZ];
00506 
00507                 position.mV[0] += dzx;
00508                 position.mV[1] += dzy;
00509                 position.mV[2] += blade_height;
00510                 *verticesp++    = v1 = position + mRegionp->getOriginAgent();
00511                 *verticesp++    = v1;
00512 
00513                 *(normalsp++)   = normal1;
00514                 *(normalsp++)   = normal2;
00515                 *(normalsp++)   = normal1;
00516                 *(normalsp++)   = normal2;
00517 
00518                 *(normalsp++)   = normal1;
00519                 *(normalsp++)   = normal2;
00520                 *(normalsp++)   = normal1;
00521                 *(normalsp++)   = normal2;
00522 
00523                 *(colorsp++)   = color;
00524                 *(colorsp++)   = color;
00525                 *(colorsp++)   = color;
00526                 *(colorsp++)   = color;
00527                 *(colorsp++)   = color;
00528                 *(colorsp++)   = color;
00529                 *(colorsp++)   = color;
00530                 *(colorsp++)   = color;
00531                 
00532                 *indicesp++     = index_offset + 0;
00533                 *indicesp++     = index_offset + 2;
00534                 *indicesp++     = index_offset + 4;
00535 
00536                 *indicesp++     = index_offset + 2;
00537                 *indicesp++     = index_offset + 6;
00538                 *indicesp++     = index_offset + 4;
00539 
00540                 *indicesp++     = index_offset + 1;
00541                 *indicesp++     = index_offset + 5;
00542                 *indicesp++     = index_offset + 3;
00543 
00544                 *indicesp++     = index_offset + 3;
00545                 *indicesp++     = index_offset + 5;
00546                 *indicesp++     = index_offset + 7;
00547                 index_offset   += 8;
00548         }
00549 
00550         LLPipeline::sCompiles++;
00551 }
00552 
00553 U32 LLVOGrass::getPartitionType() const
00554 {
00555         return LLPipeline::PARTITION_GRASS;
00556 }
00557 
00558 LLGrassPartition::LLGrassPartition()
00559 {
00560         mDrawableType = LLPipeline::RENDER_TYPE_GRASS;
00561         mPartitionType = LLPipeline::PARTITION_GRASS;
00562         mLODPeriod = 16;
00563         mDepthMask = TRUE;
00564         mSlopRatio = 0.1f;
00565         mRenderPass = LLRenderPass::PASS_GRASS;
00566         mBufferUsage = GL_DYNAMIC_DRAW_ARB;
00567 }
00568 
00569 // virtual
00570 void LLVOGrass::updateDrawable(BOOL force_damped)
00571 {
00572         // Force an immediate rebuild on any update
00573         if (mDrawable.notNull())
00574         {
00575                 mDrawable->updateXform(TRUE);
00576                 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
00577         }
00578         clearChanged(SHIFTED);
00579 }

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