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