diff options
Diffstat (limited to 'linden/indra/newview/llvograss.cpp')
-rw-r--r-- | linden/indra/newview/llvograss.cpp | 518 |
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 | |||
51 | const S32 GRASS_MAX_BLADES = 32; | ||
52 | const F32 GRASS_BLADE_BASE = 0.25f; // Width of grass at base | ||
53 | const F32 GRASS_BLADE_TOP = 0.25f; // Width of grass at top | ||
54 | const F32 GRASS_BLADE_HEIGHT = 0.5f; // meters | ||
55 | const F32 GRASS_DISTRIBUTION_SD = 0.15f; // empirically defined | ||
56 | |||
57 | F32 exp_x[GRASS_MAX_BLADES]; | ||
58 | F32 exp_y[GRASS_MAX_BLADES]; | ||
59 | F32 rot_x[GRASS_MAX_BLADES]; | ||
60 | F32 rot_y[GRASS_MAX_BLADES]; | ||
61 | F32 dz_x [GRASS_MAX_BLADES]; | ||
62 | F32 dz_y [GRASS_MAX_BLADES]; | ||
63 | |||
64 | F32 w_mod[GRASS_MAX_BLADES]; // Factor to modulate wind movement by to randomize appearance | ||
65 | |||
66 | LLVOGrass::SpeciesMap LLVOGrass::sSpeciesTable; | ||
67 | S32 LLVOGrass::sMaxGrassSpecies = 0; | ||
68 | |||
69 | |||
70 | LLVOGrass::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 | |||
88 | LLVOGrass::~LLVOGrass() | ||
89 | { | ||
90 | } | ||
91 | |||
92 | |||
93 | void 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 | |||
107 | void alert_done(S32 option, void* user_data) | ||
108 | { | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | |||
113 | void 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 | |||
256 | void LLVOGrass::cleanupClass() | ||
257 | { | ||
258 | for_each(sSpeciesTable.begin(), sSpeciesTable.end(), DeletePairedPointer()); | ||
259 | } | ||
260 | |||
261 | U32 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 | |||
290 | BOOL LLVOGrass::isActive() const | ||
291 | { | ||
292 | return TRUE; | ||
293 | } | ||
294 | |||
295 | BOOL 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 | |||
317 | void 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 | ||
337 | void 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 | |||
351 | BOOL 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 | |||
382 | LLDrawable* 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 | |||
395 | BOOL LLVOGrass::updateGeometry(LLDrawable *drawable) | ||
396 | { | ||
397 | plantBlades(); | ||
398 | return TRUE; | ||
399 | } | ||
400 | |||
401 | void 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 | |||