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;
00058 const F32 GRASS_BLADE_TOP = 0.25f;
00059 const F32 GRASS_BLADE_HEIGHT = 0.5f;
00060 const F32 GRASS_DISTRIBUTION_SD = 0.15f;
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];
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
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];
00216
00217 for (S32 i=0;i<sMaxGrassSpecies;++i)
00218 {
00219 if (!sSpeciesTable.count(i))
00220 {
00221 snprintf(buffer,10," %d",i);
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)
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();
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
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
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
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
00334 F32 pixels_per_meter = LLViewerCamera::getInstance()->getViewHeightInPixels() / (tan(LLViewerCamera::getInstance()->getView()) * range);
00335
00336
00337 mPixelArea = (pixels_per_meter) * (pixels_per_meter) * 25.f;
00338 }
00339
00340
00341
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
00413
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
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
00573 void LLVOGrass::updateDrawable(BOOL force_damped)
00574 {
00575
00576 if (mDrawable.notNull())
00577 {
00578 mDrawable->updateXform(TRUE);
00579 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
00580 }
00581 clearChanged(SHIFTED);
00582 }