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

Generated on Fri May 16 08:34:21 2008 for SecondLife by  doxygen 1.5.5