summaryrefslogtreecommitdiff
path: root/indra/newview/llvograss.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llvograss.cpp')
-rw-r--r--indra/newview/llvograss.cpp499
1 files changed, 499 insertions, 0 deletions
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
new file mode 100644
index 0000000000..a1bfe31f1e
--- /dev/null
+++ b/indra/newview/llvograss.cpp
@@ -0,0 +1,499 @@
+/**
+ * @file llvograss.cpp
+ * @brief Not a blade, but a clump of grass
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llvograss.h"
+
+#include "imageids.h"
+#include "llviewercontrol.h"
+
+#include "llagent.h"
+#include "llviewerwindow.h"
+#include "lldrawable.h"
+#include "llface.h"
+#include "llsky.h"
+#include "llsurface.h"
+#include "llsurfacepatch.h"
+#include "llvosky.h"
+#include "llviewercamera.h"
+#include "llviewerimagelist.h"
+#include "llviewerregion.h"
+#include "pipeline.h"
+#include "llworld.h"
+#include "lldir.h"
+#include "llxmltree.h"
+
+const S32 GRASS_MAX_BLADES = 32;
+const F32 GRASS_BLADE_BASE = 0.25f; // Width of grass at base
+const F32 GRASS_BLADE_TOP = 0.25f; // Width of grass at top
+const F32 GRASS_BLADE_HEIGHT = 0.5f; // meters
+const F32 GRASS_DISTRIBUTION_SD = 0.15f; // empirically defined
+
+F32 exp_x[GRASS_MAX_BLADES];
+F32 exp_y[GRASS_MAX_BLADES];
+F32 rot_x[GRASS_MAX_BLADES];
+F32 rot_y[GRASS_MAX_BLADES];
+F32 dz_x [GRASS_MAX_BLADES];
+F32 dz_y [GRASS_MAX_BLADES];
+
+F32 w_mod[GRASS_MAX_BLADES]; // Factor to modulate wind movement by to randomize appearance
+
+LLVOGrass::SpeciesMap LLVOGrass::sSpeciesTable;
+S32 LLVOGrass::sMaxGrassSpecies = 0;
+
+
+LLVOGrass::LLVOGrass(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
+: LLViewerObject(id, pcode, regionp)
+{
+ mPatch = NULL;
+ mLastPatchUpdateTime = 0;
+ mGrassVel.clearVec();
+ mGrassBend.clearVec();
+ mbCanSelect = TRUE;
+
+ mBladeWindAngle = 35.f;
+ mBWAOverlap = 2.f;
+
+ setNumTEs(1);
+
+ setTEColor(0, LLColor4(1.0f, 1.0f, 1.0f, 1.f));
+ mNumBlades = GRASS_MAX_BLADES;
+}
+
+LLVOGrass::~LLVOGrass()
+{
+}
+
+
+void LLVOGrass::updateSpecies()
+{
+ mSpecies = mState;
+
+ if (!sSpeciesTable.count(mSpecies))
+ {
+ llinfos << "Unknown grass type, substituting grass type." << llendl;
+ SpeciesMap::const_iterator it = sSpeciesTable.begin();
+ mSpecies = (*it).first;
+ }
+ setTEImage(0, gImageList.getImage(sSpeciesTable[mSpecies]->mTextureID));
+}
+
+
+void alert_done(S32 option, void* user_data)
+{
+ return;
+}
+
+
+void LLVOGrass::initClass()
+{
+ LLVector3 pos(0.0f, 0.0f, 0.0f);
+ // Create nifty list of exponential distribution 0-1
+ F32 x = 0.f;
+ F32 y = 0.f;
+ F32 rot;
+
+ std::string xml_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"grass.xml");
+
+ LLXmlTree grass_def_grass;
+
+ if (!grass_def_grass.parseFile(xml_filename))
+ {
+ llerrs << "Failed to parse grass file." << llendl;
+ return;
+ }
+
+ LLXmlTreeNode* rootp = grass_def_grass.getRoot();
+
+ for (LLXmlTreeNode* grass_def = rootp->getFirstChild();
+ grass_def;
+ grass_def = rootp->getNextChild())
+ {
+ if (!grass_def->hasName("grass"))
+ {
+ llwarns << "Invalid grass definition node " << grass_def->getName() << llendl;
+ continue;
+ }
+ F32 F32_val;
+ LLUUID id;
+
+ BOOL success = TRUE;
+
+ S32 species;
+ static LLStdStringHandle species_id_string = LLXmlTree::addAttributeString("species_id");
+ if (!grass_def->getFastAttributeS32(species_id_string, species))
+ {
+ llwarns << "No species id defined" << llendl;
+ continue;
+ }
+
+ if (species < 0)
+ {
+ llwarns << "Invalid species id " << species << llendl;
+ continue;
+ }
+
+ GrassSpeciesData* newGrass = new GrassSpeciesData();
+
+
+ static LLStdStringHandle texture_id_string = LLXmlTree::addAttributeString("texture_id");
+ grass_def->getFastAttributeUUID(texture_id_string, id);
+ newGrass->mTextureID = id;
+
+ if (newGrass->mTextureID.isNull())
+ {
+ LLString textureName;
+
+ static LLStdStringHandle texture_name_string = LLXmlTree::addAttributeString("texture_name");
+ success &= grass_def->getFastAttributeString(texture_name_string, textureName);
+ newGrass->mTextureID.set( gViewerArt.getString(textureName) );
+ }
+
+ static LLStdStringHandle blade_sizex_string = LLXmlTree::addAttributeString("blade_size_x");
+ success &= grass_def->getFastAttributeF32(blade_sizex_string, F32_val);
+ newGrass->mBladeSizeX = F32_val;
+
+ static LLStdStringHandle blade_sizey_string = LLXmlTree::addAttributeString("blade_size_y");
+ success &= grass_def->getFastAttributeF32(blade_sizey_string, F32_val);
+ newGrass->mBladeSizeY = F32_val;
+
+ if (sSpeciesTable.count(species))
+ {
+ llinfos << "Grass species " << species << " already defined! Duplicate discarded." << llendl;
+ delete newGrass;
+ continue;
+ }
+ else
+ {
+ sSpeciesTable[species] = newGrass;
+ }
+
+ if (species >= sMaxGrassSpecies) sMaxGrassSpecies = species + 1;
+
+ if (!success)
+ {
+ LLString name;
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ grass_def->getFastAttributeString(name_string, name);
+ llwarns << "Incomplete definition of grass " << name << llendl;
+ }
+ }
+
+ BOOL have_all_grass = TRUE;
+ LLString err;
+ char buffer[10];
+
+ for (S32 i=0;i<sMaxGrassSpecies;++i)
+ {
+ if (!sSpeciesTable.count(i))
+ {
+ snprintf(buffer,10," %d",i);
+ err.append(buffer);
+ have_all_grass = FALSE;
+ }
+ }
+
+ if (!have_all_grass)
+ {
+ LLStringBase<char>::format_map_t args;
+ args["[SPECIES]"] = err;
+ gViewerWindow->alertXml("ErrorUndefinedGrasses", args, alert_done );
+ }
+
+ for (S32 i = 0; i < GRASS_MAX_BLADES; ++i)
+ {
+ if (1) //(i%2 == 0) Uncomment for X blading
+ {
+ F32 u = sqrt(-2.0f * log(frand(1.0)));
+ F32 v = 2.0f * F_PI * frand(1.0);
+
+ x = u * sin(v) * GRASS_DISTRIBUTION_SD;
+ y = u * cos(v) * GRASS_DISTRIBUTION_SD;
+
+ rot = frand(F_PI);
+ }
+ else
+ {
+ rot += (F_PI*0.4f + frand(0.2f*F_PI));
+ }
+
+ exp_x[i] = x;
+ exp_y[i] = y;
+ rot_x[i] = sin(rot);
+ rot_y[i] = cos(rot);
+ dz_x[i] = frand(GRASS_BLADE_BASE * 0.25f);
+ dz_y[i] = frand(GRASS_BLADE_BASE * 0.25f);
+ w_mod[i] = 0.5f + frand(1.f); // Degree to which blade is moved by wind
+
+ }
+}
+
+void LLVOGrass::cleanupClass()
+{
+ for_each(sSpeciesTable.begin(), sSpeciesTable.end(), DeletePairedPointer());
+}
+
+U32 LLVOGrass::processUpdateMessage(LLMessageSystem *mesgsys,
+ void **user_data,
+ U32 block_num,
+ const EObjectUpdateType update_type,
+ LLDataPacker *dp)
+{
+ // Do base class updates...
+ U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
+
+ updateSpecies();
+
+ if ( (getVelocity().magVecSquared() > 0.f)
+ ||(getAcceleration().magVecSquared() > 0.f)
+ ||(getAngularVelocity().magVecSquared() > 0.f))
+ {
+ llinfos << "ACK! Moving grass!" << llendl;
+ setVelocity(LLVector3::zero);
+ setAcceleration(LLVector3::zero);
+ setAngularVelocity(LLVector3::zero);
+ }
+
+ if (mDrawable)
+ {
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
+ }
+
+ return retval;
+}
+
+BOOL LLVOGrass::isActive() const
+{
+ return TRUE;
+}
+
+BOOL LLVOGrass::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
+{
+ if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_GRASS)))
+ {
+ return TRUE;
+ }
+
+ if (!mDrawable)
+ {
+ // So drones work.
+ return TRUE;
+ }
+
+ if (mPatch && (mLastPatchUpdateTime != mPatch->getLastUpdateTime()))
+ {
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
+ }
+
+ return TRUE;
+}
+
+
+void LLVOGrass::setPixelAreaAndAngle(LLAgent &agent)
+{
+ // This should be the camera's center, as soon as we move to all region-local.
+ LLVector3 relative_position = getPositionAgent() - agent.getCameraPositionAgent();
+ F32 range = relative_position.magVec(); // ugh, square root
+
+ F32 max_scale = getMaxScale();
+
+ mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG;
+
+ // Compute pixels per meter at the given range
+ F32 pixels_per_meter = gCamera->getViewHeightInPixels() /
+ (tan(gCamera->getView()) * range);
+
+ // Assume grass texture is a 1 meter by 1 meter sprite at the grass object's center
+ mPixelArea = (pixels_per_meter) * (pixels_per_meter);
+}
+
+
+// BUG could speed this up by caching the relative_position and range calculations
+void LLVOGrass::updateTextures(LLAgent &agent)
+{
+ // dot_product = A B cos T
+ // BUT at_axis is unit, so dot_product = B cos T
+ LLVector3 relative_position = getPositionAgent() - agent.getCameraPositionAgent();
+ F32 dot_product = relative_position * agent.getFrameAgent().getAtAxis();
+ F32 cos_angle = dot_product / relative_position.magVec();
+
+ if (getTEImage(0))
+ {
+ getTEImage(0)->addTextureStats(mPixelArea*20.f, 1.f, cos_angle);
+ }
+}
+
+BOOL LLVOGrass::updateLOD()
+{
+ F32 tan_angle = 0.f;
+ S32 num_blades = 0;
+
+ tan_angle = (mScale.mV[0]*mScale.mV[1])/mDrawable->mDistanceWRTCamera;
+ num_blades = llmin(GRASS_MAX_BLADES, lltrunc(tan_angle * 5));
+ num_blades = llmax(1, num_blades);
+ if (num_blades >= (mNumBlades << 1))
+ {
+ while (mNumBlades < num_blades)
+ {
+ mNumBlades <<= 1;
+ }
+
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+ }
+ else if (num_blades <= (mNumBlades >> 1))
+ {
+ while (mNumBlades > num_blades)
+ {
+ mNumBlades >>=1;
+ }
+
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+LLDrawable* LLVOGrass::createDrawable(LLPipeline *pipeline)
+{
+ pipeline->allocDrawable(this);
+// mDrawable->setLit(FALSE);
+ mDrawable->setRenderType(LLPipeline::RENDER_TYPE_GRASS);
+
+ LLDrawPool *pool = gPipeline.getPool(LLDrawPool::POOL_ALPHA);
+
+ mDrawable->setNumFaces(1, pool, getTEImage(0));
+
+ return mDrawable;
+}
+
+BOOL LLVOGrass::updateGeometry(LLDrawable *drawable)
+{
+ plantBlades();
+ return TRUE;
+}
+
+void LLVOGrass::plantBlades()
+{
+ mPatch = mRegionp->getLand().resolvePatchRegion(getPositionRegion());
+ mLastPatchUpdateTime = mPatch->getLastUpdateTime();
+
+ LLVector3 position;
+ // Create random blades of grass with gaussian distribution
+ F32 x,y,xf,yf,dzx,dzy;
+
+ LLVector3 normal(0,0,1);
+ LLColor4U color(0,0,0,1);
+
+ LLFace *face = mDrawable->getFace(0);
+
+ LLStrider<LLVector3> verticesp;
+ LLStrider<LLVector3> normalsp;
+ LLStrider<LLVector2> texCoordsp;
+ LLStrider<LLColor4U> colorsp;
+
+ U32 *indicesp;
+
+ face->setPool(face->getPool(), getTEImage(0));
+ face->setState(LLFace::GLOBAL);
+ face->setSize(mNumBlades * 4, mNumBlades * 12);
+ face->setPrimType(LLTriangles);
+ S32 index_offset = face->getGeometryColors(verticesp,normalsp,texCoordsp,colorsp,indicesp);
+ if (-1 == index_offset)
+ {
+ return;
+ }
+
+ // It is possible that the species of a grass is not defined
+ // This is bad, but not the end of the world.
+ if (!sSpeciesTable.count(mSpecies))
+ {
+ llinfos << "Unknown grass species " << mSpecies << llendl;
+ return;
+ }
+
+ F32 width = sSpeciesTable[mSpecies]->mBladeSizeX;
+ F32 height = sSpeciesTable[mSpecies]->mBladeSizeY;
+
+ for (S32 i = 0; i < mNumBlades; i++)
+ {
+ x = exp_x[i] * mScale.mV[VX];
+ y = exp_y[i] * mScale.mV[VY];
+ xf = rot_x[i] * GRASS_BLADE_BASE * width * w_mod[i];
+ yf = rot_y[i] * GRASS_BLADE_BASE * width * w_mod[i];
+ dzx = dz_x [i];
+ dzy = dz_y [i];
+
+ F32 blade_height= GRASS_BLADE_HEIGHT * height * w_mod[i];
+
+ *texCoordsp++ = LLVector2(0, 0);
+ *texCoordsp++ = LLVector2(0, 0.98f);
+ *texCoordsp++ = LLVector2(1, 0);
+ *texCoordsp++ = LLVector2(1, 0.98f);
+
+ position.mV[0] = mPosition.mV[VX] + x + xf;
+ position.mV[1] = mPosition.mV[VY] + y + yf;
+ position.mV[2] = 0.f;
+ position.mV[2] = mRegionp->getLand().resolveHeightRegion(position);
+ *verticesp++ = position + mRegionp->getOriginAgent();
+
+ position.mV[0] += dzx;
+ position.mV[1] += dzy;
+ position.mV[2] += blade_height;
+ *verticesp++ = position + mRegionp->getOriginAgent();
+
+ position.mV[0] = mPosition.mV[VX] + x - xf;
+ position.mV[1] = mPosition.mV[VY] + y - xf;
+ position.mV[2] = 0.f;
+ position.mV[2] = mRegionp->getLand().resolveHeightRegion(position);
+ *verticesp++ = position + mRegionp->getOriginAgent();
+
+ position.mV[0] += dzx;
+ position.mV[1] += dzy;
+ position.mV[2] += blade_height;
+ *verticesp++ = position + mRegionp->getOriginAgent();
+
+ *(normalsp++) = normal;
+ *(normalsp++) = normal;
+ *(normalsp++) = normal;
+ *(normalsp++) = normal;
+
+ *(colorsp++) = color;
+ *(colorsp++) = color;
+ *(colorsp++) = color;
+ *(colorsp++) = color;
+
+ *indicesp++ = index_offset + 0;
+ *indicesp++ = index_offset + 1;
+ *indicesp++ = index_offset + 2;
+
+ *indicesp++ = index_offset + 1;
+ *indicesp++ = index_offset + 3;
+ *indicesp++ = index_offset + 2;
+
+ *indicesp++ = index_offset + 0;
+ *indicesp++ = index_offset + 2;
+ *indicesp++ = index_offset + 1;
+
+ *indicesp++ = index_offset + 1;
+ *indicesp++ = index_offset + 2;
+ *indicesp++ = index_offset + 3;
+ index_offset += 4;
+ }
+
+ LLPipeline::sCompiles++;
+
+ face->mCenterLocal = mPosition;
+
+}
+
+
+
+
+