aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llvograss.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llvograss.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llvograss.cpp')
-rw-r--r--linden/indra/newview/llvograss.cpp518
1 files changed, 518 insertions, 0 deletions
diff --git a/linden/indra/newview/llvograss.cpp b/linden/indra/newview/llvograss.cpp
new file mode 100644
index 0000000..048ae61
--- /dev/null
+++ b/linden/indra/newview/llvograss.cpp
@@ -0,0 +1,518 @@
1/**
2 * @file llvograss.cpp
3 * @brief Not a blade, but a clump of grass
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "llvograss.h"
31
32#include "imageids.h"
33#include "llviewercontrol.h"
34
35#include "llagent.h"
36#include "llviewerwindow.h"
37#include "lldrawable.h"
38#include "llface.h"
39#include "llsky.h"
40#include "llsurface.h"
41#include "llsurfacepatch.h"
42#include "llvosky.h"
43#include "llviewercamera.h"
44#include "llviewerimagelist.h"
45#include "llviewerregion.h"
46#include "pipeline.h"
47#include "llworld.h"
48#include "lldir.h"
49#include "llxmltree.h"
50
51const S32 GRASS_MAX_BLADES = 32;
52const F32 GRASS_BLADE_BASE = 0.25f; // Width of grass at base
53const F32 GRASS_BLADE_TOP = 0.25f; // Width of grass at top
54const F32 GRASS_BLADE_HEIGHT = 0.5f; // meters
55const F32 GRASS_DISTRIBUTION_SD = 0.15f; // empirically defined
56
57F32 exp_x[GRASS_MAX_BLADES];
58F32 exp_y[GRASS_MAX_BLADES];
59F32 rot_x[GRASS_MAX_BLADES];
60F32 rot_y[GRASS_MAX_BLADES];
61F32 dz_x [GRASS_MAX_BLADES];
62F32 dz_y [GRASS_MAX_BLADES];
63
64F32 w_mod[GRASS_MAX_BLADES]; // Factor to modulate wind movement by to randomize appearance
65
66LLVOGrass::SpeciesMap LLVOGrass::sSpeciesTable;
67S32 LLVOGrass::sMaxGrassSpecies = 0;
68
69
70LLVOGrass::LLVOGrass(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
71: LLViewerObject(id, pcode, regionp)
72{
73 mPatch = NULL;
74 mLastPatchUpdateTime = 0;
75 mGrassVel.clearVec();
76 mGrassBend.clearVec();
77 mbCanSelect = TRUE;
78
79 mBladeWindAngle = 35.f;
80 mBWAOverlap = 2.f;
81
82 setNumTEs(1);
83
84 setTEColor(0, LLColor4(1.0f, 1.0f, 1.0f, 1.f));
85 mNumBlades = GRASS_MAX_BLADES;
86}
87
88LLVOGrass::~LLVOGrass()
89{
90}
91
92
93void LLVOGrass::updateSpecies()
94{
95 mSpecies = mState;
96
97 if (!sSpeciesTable.count(mSpecies))
98 {
99 llinfos << "Unknown grass type, substituting grass type." << llendl;
100 SpeciesMap::const_iterator it = sSpeciesTable.begin();
101 mSpecies = (*it).first;
102 }
103 setTEImage(0, gImageList.getImage(sSpeciesTable[mSpecies]->mTextureID));
104}
105
106
107void alert_done(S32 option, void* user_data)
108{
109 return;
110}
111
112
113void LLVOGrass::initClass()
114{
115 LLVector3 pos(0.0f, 0.0f, 0.0f);
116 // Create nifty list of exponential distribution 0-1
117 F32 x = 0.f;
118 F32 y = 0.f;
119 F32 rot;
120
121 std::string xml_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"grass.xml");
122
123 LLXmlTree grass_def_grass;
124
125 if (!grass_def_grass.parseFile(xml_filename))
126 {
127 llerrs << "Failed to parse grass file." << llendl;
128 return;
129 }
130
131 LLXmlTreeNode* rootp = grass_def_grass.getRoot();
132
133 for (LLXmlTreeNode* grass_def = rootp->getFirstChild();
134 grass_def;
135 grass_def = rootp->getNextChild())
136 {
137 if (!grass_def->hasName("grass"))
138 {
139 llwarns << "Invalid grass definition node " << grass_def->getName() << llendl;
140 continue;
141 }
142 F32 F32_val;
143 LLUUID id;
144
145 BOOL success = TRUE;
146
147 S32 species;
148 static LLStdStringHandle species_id_string = LLXmlTree::addAttributeString("species_id");
149 if (!grass_def->getFastAttributeS32(species_id_string, species))
150 {
151 llwarns << "No species id defined" << llendl;
152 continue;
153 }
154
155 if (species < 0)
156 {
157 llwarns << "Invalid species id " << species << llendl;
158 continue;
159 }
160
161 GrassSpeciesData* newGrass = new GrassSpeciesData();
162
163
164 static LLStdStringHandle texture_id_string = LLXmlTree::addAttributeString("texture_id");
165 grass_def->getFastAttributeUUID(texture_id_string, id);
166 newGrass->mTextureID = id;
167
168 if (newGrass->mTextureID.isNull())
169 {
170 LLString textureName;
171
172 static LLStdStringHandle texture_name_string = LLXmlTree::addAttributeString("texture_name");
173 success &= grass_def->getFastAttributeString(texture_name_string, textureName);
174 newGrass->mTextureID.set( gViewerArt.getString(textureName) );
175 }
176
177 static LLStdStringHandle blade_sizex_string = LLXmlTree::addAttributeString("blade_size_x");
178 success &= grass_def->getFastAttributeF32(blade_sizex_string, F32_val);
179 newGrass->mBladeSizeX = F32_val;
180
181 static LLStdStringHandle blade_sizey_string = LLXmlTree::addAttributeString("blade_size_y");
182 success &= grass_def->getFastAttributeF32(blade_sizey_string, F32_val);
183 newGrass->mBladeSizeY = F32_val;
184
185 if (sSpeciesTable.count(species))
186 {
187 llinfos << "Grass species " << species << " already defined! Duplicate discarded." << llendl;
188 delete newGrass;
189 continue;
190 }
191 else
192 {
193 sSpeciesTable[species] = newGrass;
194 }
195
196 if (species >= sMaxGrassSpecies) sMaxGrassSpecies = species + 1;
197
198 if (!success)
199 {
200 LLString name;
201 static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
202 grass_def->getFastAttributeString(name_string, name);
203 llwarns << "Incomplete definition of grass " << name << llendl;
204 }
205 }
206
207 BOOL have_all_grass = TRUE;
208 LLString err;
209 char buffer[10];
210
211 for (S32 i=0;i<sMaxGrassSpecies;++i)
212 {
213 if (!sSpeciesTable.count(i))
214 {
215 snprintf(buffer,10," %d",i);
216 err.append(buffer);
217 have_all_grass = FALSE;
218 }
219 }
220
221 if (!have_all_grass)
222 {
223 LLStringBase<char>::format_map_t args;
224 args["[SPECIES]"] = err;
225 gViewerWindow->alertXml("ErrorUndefinedGrasses", args, alert_done );
226 }
227
228 for (S32 i = 0; i < GRASS_MAX_BLADES; ++i)
229 {
230 if (1) //(i%2 == 0) Uncomment for X blading
231 {
232 F32 u = sqrt(-2.0f * log(frand(1.0)));
233 F32 v = 2.0f * F_PI * frand(1.0);
234
235 x = u * sin(v) * GRASS_DISTRIBUTION_SD;
236 y = u * cos(v) * GRASS_DISTRIBUTION_SD;
237
238 rot = frand(F_PI);
239 }
240 else
241 {
242 rot += (F_PI*0.4f + frand(0.2f*F_PI));
243 }
244
245 exp_x[i] = x;
246 exp_y[i] = y;
247 rot_x[i] = sin(rot);
248 rot_y[i] = cos(rot);
249 dz_x[i] = frand(GRASS_BLADE_BASE * 0.25f);
250 dz_y[i] = frand(GRASS_BLADE_BASE * 0.25f);
251 w_mod[i] = 0.5f + frand(1.f); // Degree to which blade is moved by wind
252
253 }
254}
255
256void LLVOGrass::cleanupClass()
257{
258 for_each(sSpeciesTable.begin(), sSpeciesTable.end(), DeletePairedPointer());
259}
260
261U32 LLVOGrass::processUpdateMessage(LLMessageSystem *mesgsys,
262 void **user_data,
263 U32 block_num,
264 const EObjectUpdateType update_type,
265 LLDataPacker *dp)
266{
267 // Do base class updates...
268 U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
269
270 updateSpecies();
271
272 if ( (getVelocity().magVecSquared() > 0.f)
273 ||(getAcceleration().magVecSquared() > 0.f)
274 ||(getAngularVelocity().magVecSquared() > 0.f))
275 {
276 llinfos << "ACK! Moving grass!" << llendl;
277 setVelocity(LLVector3::zero);
278 setAcceleration(LLVector3::zero);
279 setAngularVelocity(LLVector3::zero);
280 }
281
282 if (mDrawable)
283 {
284 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
285 }
286
287 return retval;
288}
289
290BOOL LLVOGrass::isActive() const
291{
292 return TRUE;
293}
294
295BOOL LLVOGrass::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
296{
297 if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_GRASS)))
298 {
299 return TRUE;
300 }
301
302 if (!mDrawable)
303 {
304 // So drones work.
305 return TRUE;
306 }
307
308 if (mPatch && (mLastPatchUpdateTime != mPatch->getLastUpdateTime()))
309 {
310 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
311 }
312
313 return TRUE;
314}
315
316
317void LLVOGrass::setPixelAreaAndAngle(LLAgent &agent)
318{
319 // This should be the camera's center, as soon as we move to all region-local.
320 LLVector3 relative_position = getPositionAgent() - agent.getCameraPositionAgent();
321 F32 range = relative_position.magVec(); // ugh, square root
322
323 F32 max_scale = getMaxScale();
324
325 mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG;
326
327 // Compute pixels per meter at the given range
328 F32 pixels_per_meter = gCamera->getViewHeightInPixels() /
329 (tan(gCamera->getView()) * range);
330
331 // Assume grass texture is a 1 meter by 1 meter sprite at the grass object's center
332 mPixelArea = (pixels_per_meter) * (pixels_per_meter);
333}
334
335
336// BUG could speed this up by caching the relative_position and range calculations
337void LLVOGrass::updateTextures(LLAgent &agent)
338{
339 // dot_product = A B cos T
340 // BUT at_axis is unit, so dot_product = B cos T
341 LLVector3 relative_position = getPositionAgent() - agent.getCameraPositionAgent();
342 F32 dot_product = relative_position * agent.getFrameAgent().getAtAxis();
343 F32 cos_angle = dot_product / relative_position.magVec();
344
345 if (getTEImage(0))
346 {
347 getTEImage(0)->addTextureStats(mPixelArea*20.f, 1.f, cos_angle);
348 }
349}
350
351BOOL LLVOGrass::updateLOD()
352{
353 F32 tan_angle = 0.f;
354 S32 num_blades = 0;
355
356 tan_angle = (mScale.mV[0]*mScale.mV[1])/mDrawable->mDistanceWRTCamera;
357 num_blades = llmin(GRASS_MAX_BLADES, lltrunc(tan_angle * 5));
358 num_blades = llmax(1, num_blades);
359 if (num_blades >= (mNumBlades << 1))
360 {
361 while (mNumBlades < num_blades)
362 {
363 mNumBlades <<= 1;
364 }
365
366 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
367 }
368 else if (num_blades <= (mNumBlades >> 1))
369 {
370 while (mNumBlades > num_blades)
371 {
372 mNumBlades >>=1;
373 }
374
375 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
376 return TRUE;
377 }
378
379 return FALSE;
380}
381
382LLDrawable* LLVOGrass::createDrawable(LLPipeline *pipeline)
383{
384 pipeline->allocDrawable(this);
385// mDrawable->setLit(FALSE);
386 mDrawable->setRenderType(LLPipeline::RENDER_TYPE_GRASS);
387
388 LLDrawPool *pool = gPipeline.getPool(LLDrawPool::POOL_ALPHA);
389
390 mDrawable->setNumFaces(1, pool, getTEImage(0));
391
392 return mDrawable;
393}
394
395BOOL LLVOGrass::updateGeometry(LLDrawable *drawable)
396{
397 plantBlades();
398 return TRUE;
399}
400
401void LLVOGrass::plantBlades()
402{
403 mPatch = mRegionp->getLand().resolvePatchRegion(getPositionRegion());
404 mLastPatchUpdateTime = mPatch->getLastUpdateTime();
405
406 LLVector3 position;
407 // Create random blades of grass with gaussian distribution
408 F32 x,y,xf,yf,dzx,dzy;
409
410 LLVector3 normal(0,0,1);
411 LLColor4U color(0,0,0,1);
412
413 LLFace *face = mDrawable->getFace(0);
414
415 LLStrider<LLVector3> verticesp;
416 LLStrider<LLVector3> normalsp;
417 LLStrider<LLVector2> texCoordsp;
418 LLStrider<LLColor4U> colorsp;
419
420 U32 *indicesp;
421
422 face->setPool(face->getPool(), getTEImage(0));
423 face->setState(LLFace::GLOBAL);
424 face->setSize(mNumBlades * 4, mNumBlades * 12);
425 face->setPrimType(LLTriangles);
426 S32 index_offset = face->getGeometryColors(verticesp,normalsp,texCoordsp,colorsp,indicesp);
427 if (-1 == index_offset)
428 {
429 return;
430 }
431
432 // It is possible that the species of a grass is not defined
433 // This is bad, but not the end of the world.
434 if (!sSpeciesTable.count(mSpecies))
435 {
436 llinfos << "Unknown grass species " << mSpecies << llendl;
437 return;
438 }
439
440 F32 width = sSpeciesTable[mSpecies]->mBladeSizeX;
441 F32 height = sSpeciesTable[mSpecies]->mBladeSizeY;
442
443 for (S32 i = 0; i < mNumBlades; i++)
444 {
445 x = exp_x[i] * mScale.mV[VX];
446 y = exp_y[i] * mScale.mV[VY];
447 xf = rot_x[i] * GRASS_BLADE_BASE * width * w_mod[i];
448 yf = rot_y[i] * GRASS_BLADE_BASE * width * w_mod[i];
449 dzx = dz_x [i];
450 dzy = dz_y [i];
451
452 F32 blade_height= GRASS_BLADE_HEIGHT * height * w_mod[i];
453
454 *texCoordsp++ = LLVector2(0, 0);
455 *texCoordsp++ = LLVector2(0, 0.98f);
456 *texCoordsp++ = LLVector2(1, 0);
457 *texCoordsp++ = LLVector2(1, 0.98f);
458
459 position.mV[0] = mPosition.mV[VX] + x + xf;
460 position.mV[1] = mPosition.mV[VY] + y + yf;
461 position.mV[2] = 0.f;
462 position.mV[2] = mRegionp->getLand().resolveHeightRegion(position);
463 *verticesp++ = position + mRegionp->getOriginAgent();
464
465 position.mV[0] += dzx;
466 position.mV[1] += dzy;
467 position.mV[2] += blade_height;
468 *verticesp++ = position + mRegionp->getOriginAgent();
469
470 position.mV[0] = mPosition.mV[VX] + x - xf;
471 position.mV[1] = mPosition.mV[VY] + y - xf;
472 position.mV[2] = 0.f;
473 position.mV[2] = mRegionp->getLand().resolveHeightRegion(position);
474 *verticesp++ = position + mRegionp->getOriginAgent();
475
476 position.mV[0] += dzx;
477 position.mV[1] += dzy;
478 position.mV[2] += blade_height;
479 *verticesp++ = position + mRegionp->getOriginAgent();
480
481 *(normalsp++) = normal;
482 *(normalsp++) = normal;
483 *(normalsp++) = normal;
484 *(normalsp++) = normal;
485
486 *(colorsp++) = color;
487 *(colorsp++) = color;
488 *(colorsp++) = color;
489 *(colorsp++) = color;
490
491 *indicesp++ = index_offset + 0;
492 *indicesp++ = index_offset + 1;
493 *indicesp++ = index_offset + 2;
494
495 *indicesp++ = index_offset + 1;
496 *indicesp++ = index_offset + 3;
497 *indicesp++ = index_offset + 2;
498
499 *indicesp++ = index_offset + 0;
500 *indicesp++ = index_offset + 2;
501 *indicesp++ = index_offset + 1;
502
503 *indicesp++ = index_offset + 1;
504 *indicesp++ = index_offset + 2;
505 *indicesp++ = index_offset + 3;
506 index_offset += 4;
507 }
508
509 LLPipeline::sCompiles++;
510
511 face->mCenterLocal = mPosition;
512
513}
514
515
516
517
518