aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llvovolume.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/llvovolume.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/llvovolume.cpp')
-rw-r--r--linden/indra/newview/llvovolume.cpp2046
1 files changed, 2046 insertions, 0 deletions
diff --git a/linden/indra/newview/llvovolume.cpp b/linden/indra/newview/llvovolume.cpp
new file mode 100644
index 0000000..6791acd
--- /dev/null
+++ b/linden/indra/newview/llvovolume.cpp
@@ -0,0 +1,2046 @@
1/**
2 * @file llvovolume.cpp
3 * @brief LLVOVolume class implementation
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// A "volume" is a box, cylinder, sphere, or other primitive shape.
29
30#include "llviewerprecompiledheaders.h"
31
32#include "llvovolume.h"
33
34#include "llviewercontrol.h"
35#include "lldir.h"
36#include "llflexibleobject.h"
37#include "llmaterialtable.h"
38#include "llprimitive.h"
39#include "llvolume.h"
40#include "llvolumemgr.h"
41#include "llvolumemessage.h"
42#include "material_codes.h"
43#include "message.h"
44#include "object_flags.h"
45
46#include "llagent.h"
47#include "lldrawable.h"
48#include "lldrawpoolsimple.h"
49#include "lldrawpoolbump.h"
50#include "llface.h"
51
52// TEMP HACK ventrella
53#include "llhudmanager.h"
54#include "llflexibleobject.h"
55#include "llanimalcontrols.h"
56
57#include "llsky.h"
58#include "llviewercamera.h"
59#include "llviewerimagelist.h"
60#include "llviewerregion.h"
61#include "llviewertextureanim.h"
62#include "llworld.h"
63#include "llselectmgr.h"
64#include "pipeline.h"
65
66const S32 MIN_QUIET_FRAMES_COALESCE = 30;
67
68//#define LLDEBUG_DISPLAY_LODS 1
69
70BOOL gAnimateTextures = TRUE;
71
72F32 LLVOVolume::sLODFactor = 1.f;
73F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop
74F32 LLVOVolume::sLODComplexityDistanceBias = 0.0f;//Changing this to zero makes all prims LOD equally regardless of complexity
75F32 LLVOVolume::sDistanceFactor = 1.0f;
76S32 LLVOVolume::sNumLODChanges = 0;
77
78LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
79 : LLViewerObject(id, pcode, regionp),
80 mVolumeImpl(NULL)
81{
82 mRelativeXform.identity();
83 mRelativeXformInvTrans.identity();
84
85 mLOD = MIN_LOD;
86 mInited = FALSE;
87 mAllTEsSame = FALSE;
88 mTextureAnimp = NULL;
89 mGlobalVolume = FALSE;
90
91 mTextureAnimp = NULL;
92 mAllTEsSame = FALSE;
93 mVObjRadius = LLVector3(1,1,0.5f).magVec();
94 mNumFaces = 0;
95}
96
97LLVOVolume::~LLVOVolume()
98{
99 delete mTextureAnimp;
100 mTextureAnimp = NULL;
101 delete mVolumeImpl;
102 mVolumeImpl = NULL;
103}
104
105
106// static
107void LLVOVolume::initClass()
108{
109}
110
111
112U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
113 void **user_data,
114 U32 block_num, EObjectUpdateType update_type,
115 LLDataPacker *dp)
116{
117 LLColor4U color;
118
119 // Do base class updates...
120 U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
121
122 if (!dp)
123 {
124 if (update_type == OUT_FULL)
125 {
126 ////////////////////////////////
127 //
128 // Unpack texture animation data
129 //
130 //
131
132 if (mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureAnim))
133 {
134 if (!mTextureAnimp)
135 {
136 mTextureAnimp = new LLViewerTextureAnim();
137 }
138 else
139 {
140 if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH))
141 {
142 mTextureAnimp->reset();
143 }
144 }
145 mTextureAnimp->unpackTAMessage(mesgsys, block_num);
146 }
147 else
148 {
149 delete mTextureAnimp;
150 mTextureAnimp = NULL;
151 }
152
153 // Unpack volume data
154 LLVolumeParams volume_params;
155 LLVolumeMessage::unpackVolumeParams(&volume_params, mesgsys, _PREHASH_ObjectData, block_num);
156
157 if (setVolume(volume_params, 0))
158 {
159 markForUpdate(TRUE);
160 }
161 }
162
163 // Sigh, this needs to be done AFTER the volume is set as well, otherwise bad stuff happens...
164 ////////////////////////////
165 //
166 // Unpack texture entry data
167 //
168 if (unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num) & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR))
169 {
170 updateTEData();
171 }
172 }
173 else
174 {
175 // CORY TO DO: Figure out how to get the value here
176 if (update_type != OUT_TERSE_IMPROVED)
177 {
178 LLVolumeParams volume_params;
179 BOOL res = LLVolumeMessage::unpackVolumeParams(&volume_params, *dp);
180 if (!res)
181 {
182 llwarns << "Bogus volume parameters in object " << getID() << llendl;
183 llwarns << getRegion()->getOriginGlobal() << llendl;
184 }
185
186 if (setVolume(volume_params, 0))
187 {
188 markForUpdate(TRUE);
189 }
190 S32 res2 = unpackTEMessage(*dp);
191 if (TEM_INVALID == res2)
192 {
193 // Well, crap, there's something bogus in the data that we're unpacking.
194 dp->dumpBufferToLog();
195 llwarns << "Flushing cache files" << llendl;
196 char mask[LL_MAX_PATH];
197 sprintf(mask, "%s*.slc", gDirUtilp->getDirDelimiter().c_str());
198 gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"").c_str(),mask);
199// llerrs << "Bogus TE data in " << getID() << ", crashing!" << llendl;
200 llwarns << "Bogus TE data in " << getID() << llendl;
201 }
202 else if (res2 & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR))
203 {
204 updateTEData();
205 }
206
207 U32 value = dp->getPassFlags();
208
209 if (value & 0x40)
210 {
211 if (!mTextureAnimp)
212 {
213 mTextureAnimp = new LLViewerTextureAnim();
214 }
215 else
216 {
217 if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH))
218 {
219 mTextureAnimp->reset();
220 }
221 }
222 mTextureAnimp->unpackTAMessage(*dp);
223 }
224 else
225 {
226 delete mTextureAnimp;
227 mTextureAnimp = NULL;
228 }
229 }
230 else
231 {
232 S32 texture_length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureEntry);
233 if (texture_length)
234 {
235 U8 tdpbuffer[1024];
236 LLDataPackerBinaryBuffer tdp(tdpbuffer, 1024);
237 mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num);
238 if ( unpackTEMessage(tdp) & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR))
239 {
240 updateTEData();
241 }
242 }
243 }
244 }
245
246 return retval;
247}
248
249
250BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
251{
252 LLViewerObject::idleUpdate(agent, world, time);
253
254 ///////////////////////
255 //
256 // Do texture animation stuff
257 //
258
259 if (mTextureAnimp && gAnimateTextures)
260 {
261 F32 off_s, off_t, scale_s, scale_t, rot;
262 S32 result;
263 if ((result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot)))
264 {
265 U8 has_bump = 0;
266 if (mTextureAnimp->mFace <= -1)
267 {
268 S32 face;
269 for (face = 0; face < getNumTEs(); face++)
270 {
271 if (result & LLViewerTextureAnim::TRANSLATE)
272 {
273 setTEOffset(face, off_s, off_t);
274 }
275 if (result & LLViewerTextureAnim::SCALE)
276 {
277 setTEScale(face, scale_s, scale_t);
278 }
279 if (result & LLViewerTextureAnim::ROTATE)
280 {
281 setTERotation(face, rot);
282 }
283 has_bump |= getTE(face)->getBumpmap();
284 }
285 }
286 else if (mTextureAnimp->mFace < getNumTEs())
287 {
288 if (result & LLViewerTextureAnim::TRANSLATE)
289 {
290 setTEOffset(mTextureAnimp->mFace, off_s, off_t);
291 }
292 if (result & LLViewerTextureAnim::SCALE)
293 {
294 setTEScale(mTextureAnimp->mFace, scale_s, scale_t);
295 }
296 if (result & LLViewerTextureAnim::ROTATE)
297 {
298 setTERotation(mTextureAnimp->mFace, rot);
299 }
300 has_bump |= getTE(mTextureAnimp->mFace)->getBumpmap();
301 }
302// mFaceMappingChanged = TRUE;
303 if (mDrawable->isVisible())
304 {
305 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, TRUE);
306 }
307 }
308 }
309
310 // Dispatch to implementation
311 if (mVolumeImpl)
312 {
313 mVolumeImpl->doIdleUpdate(agent, world, time);
314 }
315
316 return TRUE;
317}
318
319void LLVOVolume::updateTextures(LLAgent &agent)
320{
321
322}
323
324//static
325F32 LLVOVolume::getTextureVirtualSize(const LLFace* face)
326{
327 //LLVector2 tdim = face->mTexExtents[1] - face->mTexExtents[0];
328 //F32 pixel_area = 1.f/llmin(llmax(tdim.mV[0] * tdim.mV[1], 1.f), 10.f);
329 LLVector3 cross_vec = (face->mExtents[1] - face->mExtents[0]);
330
331
332 LLVector3 lookAt = (face->getPositionAgent()-gCamera->getOrigin());
333 F32 dist = lookAt.normVec();
334
335 F32 face_area;
336
337 if (face->isState(LLFace::GLOBAL))
338 {
339 face_area = cross_vec.mV[0]*cross_vec.mV[1]*fabsf(lookAt.mV[2]) +
340 cross_vec.mV[1]*cross_vec.mV[2]*fabsf(lookAt.mV[0]) +
341 cross_vec.mV[0]*cross_vec.mV[2]*fabsf(lookAt.mV[1]);
342 }
343 else
344 {
345 face_area = cross_vec.mV[0]*cross_vec.mV[1] +
346 cross_vec.mV[1]*cross_vec.mV[2] +
347 cross_vec.mV[0]*cross_vec.mV[2];
348 }
349
350 if (face_area <= 0)
351 {
352 return 0.f;
353 }
354
355 F32 view = llmax(lookAt*gCamera->getAtAxis(), 0.5f);
356 F32 dist_ramp = dist * view/face_area;
357 //ramp down distance for things closer than 16 m * lookAt
358 dist /= dist_ramp;
359 dist *= dist;
360 dist *= dist_ramp;
361
362 F32 dist_ratio = face_area / llmax(dist, 0.1f);
363 F32 pixel_area = dist_ratio*gCamera->getScreenPixelArea();
364
365 return view*pixel_area;
366}
367
368void LLVOVolume::updateTextures(S32 lod)
369{
370 // Update the image levels of all textures...
371 // First we do some quick checks.
372
373 // This doesn't take into account whether the object is in front
374 // or behind...
375
376 if (LLViewerImage::sDontLoadVolumeTextures || mDrawable.isNull() || !mDrawable->isVisible())
377 {
378 return;
379 }
380
381 const S32 num_faces = mDrawable->getNumFaces();
382
383 for (S32 i = 0; i < num_faces; i++)
384 {
385 const LLFace* face = mDrawable->getFace(i);
386 const LLTextureEntry *te = face->getTextureEntry();
387 LLViewerImage *imagep = face->getTexture();
388
389 if (!imagep || !te)
390 {
391 continue;
392 }
393
394 F32 vsize;
395
396 if (isHUDAttachment())
397 {
398 vsize = (F32) (imagep->getWidth(0) * imagep->getHeight(0));
399 imagep->setBoostLevel(LLViewerImage::BOOST_HUD);
400 }
401 else
402 {
403 vsize = getTextureVirtualSize(face);
404 }
405
406 imagep->addTextureStats(vsize);
407
408
409 U8 bump = te->getBumpmap();
410 if( te && bump)
411 {
412 gBumpImageList.addTextureStats( bump, imagep->getID(), vsize, 1, 1);
413 }
414 }
415}
416
417BOOL LLVOVolume::isActive() const
418{
419 return !mStatic || mTextureAnimp || isAttachment() || (mVolumeImpl && mVolumeImpl->isActive());
420}
421
422BOOL LLVOVolume::setMaterial(const U8 material)
423{
424 BOOL res = LLViewerObject::setMaterial(material);
425 if (res)
426 {
427 // for deprecated LL_MCODE_LIGHT
428 if (mDrawable.notNull())
429 {
430 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_LIGHTING, TRUE);
431 }
432 }
433 return res;
434}
435
436void LLVOVolume::setTexture(const S32 face)
437{
438 llassert(face < getNumTEs());
439 LLViewerImage::bindTexture(getTEImage(face));
440}
441
442void LLVOVolume::setScale(const LLVector3 &scale, BOOL damped)
443{
444 if (scale != getScale())
445 {
446 // store local radius
447 LLViewerObject::setScale(scale);
448
449 if (mVolumeImpl)
450 {
451 mVolumeImpl->onSetScale(scale, damped);
452 }
453
454 updateRadius();
455
456 //since drawable transforms do not include scale, changing volume scale
457 //requires an immediate rebuild of volume verts.
458 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
459 }
460}
461
462LLFace* LLVOVolume::addFace(S32 f)
463{
464 const LLTextureEntry* te = getTE(f);
465 LLViewerImage* imagep = getTEImage(f);
466 LLDrawPool* poolp;
467 if (isHUDAttachment())
468 {
469 poolp = gPipeline.getPool(LLDrawPool::POOL_HUD);
470 }
471 else
472 {
473 poolp = LLPipeline::getPoolFromTE(te, imagep);
474 }
475 return mDrawable->addFace(poolp, imagep);
476}
477
478LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
479{
480 pipeline->allocDrawable(this);
481 mDrawable->setRenderType(LLPipeline::RENDER_TYPE_VOLUME);
482
483 S32 max_tes_to_set = calcAllTEsSame() ? 1 : getNumTEs();
484 for (S32 i = 0; i < max_tes_to_set; i++)
485 {
486 LLFace* face = addFace(i);
487 // JC - should there be a setViewerObject(this) call here?
488 face->setTEOffset(i);
489 }
490 mNumFaces = max_tes_to_set;
491
492 if (isAttachment())
493 {
494 mDrawable->makeActive();
495 }
496
497 if (getIsLight())
498 {
499 // Add it to the pipeline mLightSet
500 gPipeline.setLight(mDrawable, TRUE);
501 }
502
503 updateRadius();
504 mDrawable->updateDistance(*gCamera);
505
506 return mDrawable;
507}
508
509
510BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume)
511{
512 // Check if we need to change implementations
513 bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE);
514 if (is_flexible)
515 {
516 setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, false);
517 if (!mVolumeImpl)
518 {
519 LLFlexibleObjectData* data = (LLFlexibleObjectData*)getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
520 mVolumeImpl = new LLVolumeImplFlexible(this, data);
521 }
522 }
523 else
524 {
525 // Mark the parameter not in use
526 setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, false);
527 if (mVolumeImpl)
528 {
529 delete mVolumeImpl;
530 mVolumeImpl = NULL;
531 if (mDrawable.notNull())
532 {
533 // Undo the damage we did to this matrix
534 mDrawable->updateXform(FALSE);
535 }
536 }
537 }
538 mGlobalVolume = (mVolumeImpl && mVolumeImpl->isVolumeGlobal());
539
540 //MSMSM Recompute LOD here in case the object was just created,
541 // its LOD might be incorrectly set to minumum detail...
542 calcLOD();
543
544 if (LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique())))
545 {
546 mFaceMappingChanged = TRUE;
547
548 if (mVolumeImpl)
549 {
550 mVolumeImpl->onSetVolume(volume_params, detail);
551 }
552
553 return TRUE;
554 }
555 return FALSE;
556}
557
558
559F32 LLVOVolume::computeLODProfilePathComplexityBias(){
560 //compute a complexity cost from 0 to 1.0 where the 'simplest' prim has a cost of 0.0
561 // and the 'heaviest' prim has a cost of 1.0
562// LLVolume* volume = getVolume();
563 F32 complexity = 0.0f;
564// const LLVolumeParams& params = volume->getParams();
565// U8 type = volume->getPathType();
566// U8 pcode = this->getPCode();
567// U8 proftype = volume->getProfileType();
568
569 //if(params.getHollow()>0.0f){// || (proftype == 1) || (proftype == 0)){
570 //If it is hollow, or a cube/pyramid(subdivided), the complexity is roughly doubled
571 // complexity+=0.5f;
572 //}
573
574 if(this->getVolume()->getProfile().mParams.getCurveType()==LL_PCODE_PROFILE_SQUARE &&
575 this->getVolume()->getPath().mParams.getCurveType()==LL_PCODE_PATH_LINE)
576 {
577 //Object is a cube so bias it heavily since cubes are subdivided alot.
578// this->setDebugText("CUBE");
579 complexity += 1.0f;
580 }
581
582// if(params.getTwist() != params.getTwistBegin()){
583 //if there is twist.. the complexity is bumped
584// complexity+=0.25f;
585// }
586// if(type != LL_PCODE_PATH_LINE)//If the path is not a line it is more complex
587// complexity+=0.2f;
588 return complexity * sLODComplexityDistanceBias;
589}
590
591S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius)
592{
593 S32 cur_detail;
594 // We've got LOD in the profile, and in the twist. Use radius.
595 F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
596 cur_detail = LLVolumeLODGroup::getDetailFromTan(tan_angle);
597 return cur_detail;
598}
599
600BOOL LLVOVolume::calcLOD()
601{
602 if (mDrawable.isNull())
603 {
604 return FALSE;
605 }
606 S32 cur_detail = 0;
607 /*if (isHUDAttachment())
608 {
609 cur_detail = LLVolumeLODGroup::NUM_LODS-1; // max detail
610 }
611 else*/
612 {
613 F32 radius = (mVolumep->mLODScaleBias.scaledVec(getScale())).magVec();
614 F32 distance = mDrawable->mDistanceWRTCamera;
615 distance *= sDistanceFactor;
616
617 F32 rampDist = LLVOVolume::sLODFactor * 2;
618
619 if (distance < rampDist)
620 {
621 // Boost LOD when you're REALLY close
622 distance *= 1.0f/rampDist;
623 distance *= distance;
624 distance *= rampDist;
625 }
626 else
627 {
628 //Now adjust the computed distance by some factor based on the geometric complexity of the primitive
629 distance += computeLODProfilePathComplexityBias();
630 }
631 // Compensate for field of view changing on FOV zoom.
632 distance *= gCamera->getView();
633
634 cur_detail = computeLODDetail(distance, radius);
635
636 //update textures with what the real LOD is
637 updateTextures(cur_detail);
638
639 if(cur_detail != mLOD)
640 {
641 // Here we test whether the LOD is increasing or decreasing to introduce a slop factor
642 if(cur_detail < mLOD)
643 {
644 // Viewer is moving away from the object
645 // so bias our LOD by adding a fixed amount to the distance.
646 // This will reduce the problem of LOD twitching when the
647 // user makes slight movements near the LOD transition threshhold.
648 F32 test_distance = distance - (distance*sLODSlopDistanceFactor/(1.0f+sLODFactor));
649 if(test_distance < 0.0f) test_distance = 0.0f;
650 S32 potential_detail = computeLODDetail( test_distance, radius );
651 if(potential_detail >= mLOD )
652 { //The LOD has truly not changed
653 cur_detail = mLOD;
654 }
655 }
656 }
657 }
658
659 if (cur_detail != mLOD)
660 {
661 mAppAngle = (F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG;
662 mLOD = cur_detail;
663 return TRUE;
664 }
665 else
666 {
667 return FALSE;
668 }
669}
670
671BOOL LLVOVolume::updateLOD()
672{
673 if (mDrawable.isNull())
674 {
675 return FALSE;
676 }
677
678 BOOL lod_changed = calcLOD();
679
680#if LLDEBUG_DISPLAY_LODS
681 //MS Enable this to display LOD numbers on objects
682 std::ostringstream msg;
683 msg << cur_detail;//((cur_detail<mLOD)?"-":cur_detail==mLOD?"=":"+") << (int)cur_detail << " , " << mDrawable->mDistanceWRTCamera << " , " << ((LLVOVolume::sLODFactor*mVObjRadius)/mDrawable->mDistanceWRTCamera);
684 this->setDebugText(msg.str());
685#endif
686
687 if (lod_changed)
688 {
689 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, FALSE);
690 mLODChanged = TRUE;
691 }
692
693 return lod_changed;
694}
695
696BOOL LLVOVolume::setDrawableParent(LLDrawable* parentp)
697{
698 if (!LLViewerObject::setDrawableParent(parentp))
699 {
700 // no change in drawable parent
701 return FALSE;
702 }
703
704 if (!mDrawable->isRoot())
705 {
706 // parent is dynamic, so I'll need to share its drawable, must rebuild to share drawables
707 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
708
709 if (mDrawable->isActive() && !parentp->isActive())
710 {
711 parentp->makeActive();
712 }
713 else if (mDrawable->isStatic() && parentp->isActive())
714 {
715 mDrawable->makeActive();
716 }
717 }
718
719 return TRUE;
720}
721
722void LLVOVolume::updateFaceFlags()
723{
724 for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
725 {
726 LLFace *face = mDrawable->getFace(i + mFaceIndexOffset);
727 BOOL fullbright = getTE(i)->getFullbright();
728 face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT);
729
730 if (fullbright || (mMaterial == LL_MCODE_LIGHT))
731 {
732 face->setState(LLFace::FULLBRIGHT);
733 }
734 if (mDrawable->isLight())
735 {
736 face->setState(LLFace::LIGHT);
737 }
738 if (isHUDAttachment())
739 {
740 face->setState(LLFace::HUD_RENDER);
741 }
742 if (getAllTEsSame())
743 {
744 break; // only 1 face
745 }
746 }
747}
748
749// NOTE: regenFaces() MUST be followed by genTriangles()!
750void LLVOVolume::regenFaces()
751{
752 // remove existing faces
753 // use mDrawable->getVOVolume() in case of shared drawables
754 mDrawable->getVOVolume()->deleteFaces(this);
755 mFaceIndexOffset = mDrawable->getNumFaces();
756 // add new faces
757 mNumFaces = getAllTEsSame() ? 1 : getNumTEs();
758 for (S32 i = 0; i < mNumFaces; i++)
759 {
760 LLFace* facep = addFace(i);
761 facep->setViewerObject(this);
762 facep->setTEOffset(i);
763 }
764 // Need to do this as texture entries may not correspond to faces any more!
765 mDrawable->updateTexture();
766 gPipeline.markMaterialed(mDrawable);
767}
768
769BOOL LLVOVolume::genTriangles(BOOL force_global)
770{
771 BOOL res = TRUE;
772
773 LLVector3 min,max;
774
775 if (getAllTEsSame())
776 {
777 setupSingleFace(mFaceIndexOffset);
778 LLFace *face = mDrawable->getFace(mFaceIndexOffset);
779 S32 num_faces = getVolume()->getNumFaces();
780 res = face->genVolumeTriangles(*getVolume(), 0, num_faces-1,
781 mRelativeXform, mRelativeXformInvTrans,
782 mGlobalVolume | force_global);
783
784 if (mDrawable->isState(LLDrawable::REBUILD_VOLUME))
785 {
786 min = face->mExtents[0];
787 max = face->mExtents[1];
788 }
789 mWereAllTEsSame = TRUE;
790 }
791 else
792 {
793 for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
794 {
795 LLFace *face = mDrawable->getFace(i + mFaceIndexOffset);
796 res &= face->genVolumeTriangles(*getVolume(), i,
797 mRelativeXform, mRelativeXformInvTrans,
798 mGlobalVolume | force_global);
799
800 if (mDrawable->isState(LLDrawable::REBUILD_VOLUME))
801 {
802 if (i == 0)
803 {
804 min = face->mExtents[0];
805 max = face->mExtents[1];
806 }
807 else
808 {
809 for (U32 i = 0; i < 3; i++)
810 {
811 if (face->mExtents[0].mV[i] < min.mV[i])
812 {
813 min.mV[i] = face->mExtents[0].mV[i];
814 }
815 if (face->mExtents[1].mV[i] > max.mV[i])
816 {
817 max.mV[i] = face->mExtents[1].mV[i];
818 }
819 }
820 }
821 }
822 }
823 mWereAllTEsSame = FALSE;
824 }
825
826 if (mDrawable->isState(LLDrawable::REBUILD_VOLUME))
827 {
828 mDrawable->setSpatialExtents(min,max);
829 if (!isVolumeGlobal())
830 {
831 mDrawable->setPositionGroup((min+max)*0.5f);
832 }
833 else
834 {
835 mDrawable->setPositionGroup(getPosition());
836 }
837
838 updateRadius();
839 mDrawable->updateBinRadius();
840 mDrawable->movePartition();
841 }
842
843 return res;
844}
845
846void LLVOVolume::updateRelativeXform(BOOL global_volume)
847{
848 if (mVolumeImpl)
849 {
850 mVolumeImpl->updateRelativeXform(global_volume);
851 return;
852 }
853
854 LLDrawable* drawable = mDrawable;
855
856 if (drawable->isActive())
857 {
858 // setup relative transforms
859 LLQuaternion delta_rot;
860 LLVector3 delta_pos, delta_scale;
861
862 //matrix from local space to parent relative/global space
863 delta_rot = drawable->isSpatialRoot() ? LLQuaternion() : mDrawable->getRotation();
864 delta_pos = drawable->isSpatialRoot() ? LLVector3(0,0,0) : mDrawable->getPosition();
865 delta_scale = mDrawable->getScale();
866
867 // Vertex transform (4x4)
868 LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot;
869 LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot;
870 LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot;
871
872 mRelativeXform.initRows(LLVector4(x_axis, 0.f),
873 LLVector4(y_axis, 0.f),
874 LLVector4(z_axis, 0.f),
875 LLVector4(delta_pos, 1.f));
876
877 x_axis.normVec();
878 y_axis.normVec();
879 z_axis.normVec();
880
881 mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis);
882 }
883 else
884 {
885 LLVector3 pos = getPosition();
886 LLVector3 scale = getScale();
887 LLQuaternion rot = getRotation();
888
889 if (mParent)
890 {
891 pos *= mParent->getRotation();
892 pos += mParent->getPosition();
893 rot *= mParent->getRotation();
894 }
895
896 LLViewerRegion* region = getRegion();
897 pos += region->getOriginAgent();
898
899 LLVector3 x_axis = LLVector3(scale.mV[VX], 0.f, 0.f) * rot;
900 LLVector3 y_axis = LLVector3(0.f, scale.mV[VY], 0.f) * rot;
901 LLVector3 z_axis = LLVector3(0.f, 0.f, scale.mV[VZ]) * rot;
902
903 mRelativeXform.initRows(LLVector4(x_axis, 0.f),
904 LLVector4(y_axis, 0.f),
905 LLVector4(z_axis, 0.f),
906 LLVector4(pos, 1.f));
907
908 x_axis.normVec();
909 y_axis.normVec();
910 z_axis.normVec();
911
912 mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis);
913 }
914}
915
916BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
917{
918 LLFastTimer t(LLFastTimer::FTM_UPDATE_PRIMITIVES);
919
920 if (mVolumeImpl != NULL)
921 {
922 LLFastTimer t(LLFastTimer::FTM_GEN_FLEX);
923 BOOL res = mVolumeImpl->doUpdateGeometry(drawable);
924 updateFaceFlags();
925 if (res)
926 {
927 drawable->clearState(LLDrawable::REBUILD_GEOMETRY);
928 }
929
930 return res;
931 }
932
933 BOOL compiled = FALSE;
934 BOOL change_shared = FALSE;
935
936 updateRelativeXform();
937
938 if (mDrawable.isNull()) // Not sure why this is happening, but it is...
939 {
940 return TRUE; // No update to complete
941 }
942
943 calcAllTEsSame();
944
945 if (mVolumeChanged || mFaceMappingChanged || change_shared)
946 {
947 compiled = TRUE;
948 mInited = TRUE;
949
950 {
951 LLFastTimer ftm(LLFastTimer::FTM_GEN_VOLUME);
952 LLVolumeParams volume_params = getVolume()->getParams();
953 setVolume(volume_params, 0);
954 }
955 drawable->setState(LLDrawable::REBUILD_GEOMETRY);
956 if (mVolumeChanged || change_shared)
957 {
958 drawable->setState(LLDrawable::REBUILD_LIGHTING);
959 }
960
961 {
962 LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES);
963 regenFaces();
964 genTriangles(FALSE);
965 }
966 }
967 else if (mLODChanged)
968 {
969 LLPointer<LLVolume> old_volumep, new_volumep;
970 F32 old_lod, new_lod;
971
972 old_volumep = getVolume();
973 old_lod = old_volumep->getDetail();
974
975 {
976 LLFastTimer ftm(LLFastTimer::FTM_GEN_VOLUME);
977 LLVolumeParams volume_params = getVolume()->getParams();
978 setVolume(volume_params, 0);
979 }
980 new_volumep = getVolume();
981 new_lod = new_volumep->getDetail();
982
983 if (new_lod != old_lod)
984 {
985 compiled = TRUE;
986 sNumLODChanges += (getAllTEsSame() ? 1 : getVolume()->getNumFaces());
987
988 drawable->setState(LLDrawable::REBUILD_ALL); // for face->genVolumeTriangles()
989
990 {
991 LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES);
992 if (new_volumep->getNumFaces() != old_volumep->getNumFaces())
993 {
994 regenFaces();
995 }
996 genTriangles(FALSE);
997 }
998 }
999 }
1000 // it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
1001 else
1002 {
1003 compiled = TRUE;
1004 // All it did was move or we changed the texture coordinate offset
1005 LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES);
1006 genTriangles(FALSE);
1007 }
1008
1009 // Update face flags
1010 updateFaceFlags();
1011
1012 if(compiled)
1013 {
1014 LLPipeline::sCompiles++;
1015 }
1016
1017 mVolumeChanged = FALSE;
1018 mLODChanged = FALSE;
1019 mFaceMappingChanged = FALSE;
1020
1021 drawable->clearState(LLDrawable::REBUILD_GEOMETRY);
1022
1023 return TRUE;
1024}
1025
1026BOOL LLVOVolume::isRootEdit() const
1027{
1028 if (mParent && !((LLViewerObject*)mParent)->isAvatar())
1029 {
1030 return FALSE;
1031 }
1032 return TRUE;
1033}
1034
1035void LLVOVolume::setTEImage(const U8 te, LLViewerImage *imagep)
1036{
1037// llinfos << "SetTEImage:" << llendl;
1038 BOOL changed = (mTEImages[te] != imagep);
1039 LLViewerObject::setTEImage(te, imagep);
1040 if (mDrawable.notNull())
1041 {
1042 if (changed)
1043 {
1044 calcAllTEsSame();
1045 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
1046 mFaceMappingChanged = TRUE;
1047 }
1048 }
1049}
1050
1051S32 LLVOVolume::setTETexture(const U8 te, const LLUUID &uuid)
1052{
1053 BOOL changed = (uuid != getTE(te)->getID() || (uuid == LLUUID::null));
1054
1055 S32 res = LLViewerObject::setTETexture(te, uuid);
1056 if (mDrawable.notNull())
1057 {
1058 if (changed)
1059 {
1060 calcAllTEsSame();
1061 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
1062 mFaceMappingChanged = TRUE;
1063 }
1064 }
1065 return res;
1066}
1067
1068S32 LLVOVolume::setTEColor(const U8 te, const LLColor4 &color)
1069{
1070 BOOL changed = (color != getTE(te)->getColor());
1071 S32 res = LLViewerObject::setTEColor(te, color);
1072 if (mDrawable.notNull())
1073 {
1074 if (changed)
1075 {
1076 calcAllTEsSame();
1077// mFaceMappingChanged = TRUE;
1078 }
1079 }
1080 return res;
1081}
1082
1083S32 LLVOVolume::setTEBumpmap(const U8 te, const U8 bumpmap)
1084{
1085 BOOL changed = (bumpmap != getTE(te)->getBumpmap());
1086 S32 res = LLViewerObject::setTEBumpmap(te, bumpmap);
1087 if (mDrawable.notNull())
1088 {
1089 if (changed)
1090 {
1091 calcAllTEsSame();
1092 mFaceMappingChanged = TRUE;
1093 }
1094 }
1095 return res;
1096}
1097
1098S32 LLVOVolume::setTETexGen(const U8 te, const U8 texgen)
1099{
1100 BOOL changed = (texgen != getTE(te)->getTexGen());
1101 S32 res = LLViewerObject::setTETexGen(te, texgen);
1102 if (mDrawable.notNull())
1103 {
1104 if (changed)
1105 {
1106 calcAllTEsSame();
1107 mFaceMappingChanged = TRUE;
1108 }
1109 }
1110 return res;
1111}
1112
1113S32 LLVOVolume::setTEShiny(const U8 te, const U8 shiny)
1114{
1115 BOOL changed = (shiny != getTE(te)->getShiny());
1116 S32 res = LLViewerObject::setTEShiny(te, shiny);
1117 if (mDrawable.notNull())
1118 {
1119 if (changed)
1120 {
1121 calcAllTEsSame();
1122 mFaceMappingChanged = TRUE;
1123 }
1124 }
1125 return res;
1126}
1127
1128S32 LLVOVolume::setTEFullbright(const U8 te, const U8 fullbright)
1129{
1130 BOOL changed = (fullbright != getTE(te)->getFullbright());
1131 S32 res = LLViewerObject::setTEFullbright(te, fullbright);
1132 if (mDrawable.notNull())
1133 {
1134 if (changed)
1135 {
1136 calcAllTEsSame();
1137 if (!mDrawable->isState(LLDrawable::REBUILD_VOLUME))
1138 {
1139 updateFaceFlags();
1140 }
1141 mFaceMappingChanged = TRUE;
1142 }
1143 }
1144 return res;
1145}
1146
1147S32 LLVOVolume::setTEMediaFlags(const U8 te, const U8 media_flags)
1148{
1149 bool changed = (media_flags != getTE(te)->getMediaFlags());
1150 S32 res = LLViewerObject::setTEMediaFlags(te, media_flags);
1151 if (mDrawable.notNull())
1152 {
1153 if (changed)
1154 {
1155 calcAllTEsSame();
1156 mFaceMappingChanged = TRUE;
1157 }
1158 }
1159 return res;
1160}
1161
1162S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t)
1163{
1164 F32 olds,oldt;
1165 getTE(te)->getScale(&olds, &oldt);
1166 bool changed = (s != olds || t != oldt);
1167 S32 res = LLViewerObject::setTEScale(te, s, t);
1168 if (mDrawable.notNull())
1169 {
1170 if (changed)
1171 {
1172 calcAllTEsSame();
1173 mFaceMappingChanged = TRUE;
1174 }
1175 }
1176 return res;
1177}
1178
1179S32 LLVOVolume::setTEScaleS(const U8 te, const F32 s)
1180{
1181 F32 olds,oldt;
1182 getTE(te)->getScale(&olds, &oldt);
1183 bool changed = (s != olds);
1184 S32 res = LLViewerObject::setTEScaleS(te, s);
1185 if (mDrawable.notNull())
1186 {
1187 if (changed)
1188 {
1189 calcAllTEsSame();
1190 mFaceMappingChanged = TRUE;
1191 }
1192 }
1193 return res;
1194}
1195
1196S32 LLVOVolume::setTEScaleT(const U8 te, const F32 t)
1197{
1198 F32 olds,oldt;
1199 getTE(te)->getScale(&olds, &oldt);
1200 bool changed = (t != oldt);
1201 S32 res = LLViewerObject::setTEScaleT(te, t);
1202 if (mDrawable.notNull())
1203 {
1204 if (changed)
1205 {
1206 calcAllTEsSame();
1207 mFaceMappingChanged = TRUE;
1208 }
1209 }
1210 return res;
1211}
1212
1213void LLVOVolume::updateTEData()
1214{
1215 if (mDrawable.notNull())
1216 {
1217 calcAllTEsSame();
1218 mFaceMappingChanged = TRUE;
1219 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
1220 }
1221}
1222
1223BOOL LLVOVolume::calcAllTEsSame()
1224{
1225 BOOL is_alpha = FALSE;
1226 BOOL was_same = mAllTEsSame;
1227 BOOL all_same = TRUE;
1228 S32 num_tes = getNumTEs();
1229
1230 LLViewerImage *first_texturep = getTEImage(0);
1231 if (!first_texturep)
1232 {
1233 return FALSE;
1234 }
1235
1236 const LLTextureEntry *tep = getTE(0);
1237 if (!tep)
1238 {
1239 llwarns << "Volume with zero textures!" << llendl;
1240 return FALSE;
1241 }
1242
1243 if (tep->getColor().mV[3] != 1.f)
1244 {
1245 is_alpha = TRUE;
1246 }
1247 const LLColor4 first_color = tep->getColor();
1248 const U8 first_bump = tep->getBumpShinyFullbright();
1249 const U8 first_media_flags = tep->getMediaTexGen();
1250
1251 if (first_texturep->getComponents() == 4)
1252 {
1253 is_alpha = TRUE;
1254 }
1255
1256 F32 s_scale, t_scale;
1257 tep->getScale(&s_scale, &t_scale);
1258
1259 for (S32 f = 1; f < num_tes; f++)
1260 {
1261 LLViewerImage *texturep = getTEImage(f);
1262 if (texturep != first_texturep)
1263 {
1264 all_same = FALSE;
1265 break;
1266 }
1267
1268 tep = getTE(f);
1269
1270 if( tep->getBumpShinyFullbright() != first_bump )
1271 {
1272 all_same = FALSE;
1273 break;
1274 }
1275
1276 if (first_bump)
1277 {
1278 F32 cur_s, cur_t;
1279 tep->getScale(&cur_s, &cur_t);
1280 if ((cur_s != s_scale) || (cur_t != t_scale))
1281 {
1282 all_same = FALSE;
1283 break;
1284 }
1285 }
1286
1287 if ((texturep->getComponents() == 4) || (tep->getColor().mV[3] != 1.f))
1288 {
1289 if (!is_alpha)
1290 {
1291 all_same = FALSE;
1292 break;
1293 }
1294 }
1295 else if (is_alpha)
1296 {
1297 all_same = FALSE;
1298 break;
1299 }
1300
1301 if (tep->getColor() != first_color)
1302 {
1303 all_same = FALSE;
1304 break;
1305 }
1306
1307 if (tep->getMediaTexGen() != first_media_flags)
1308 {
1309 all_same = FALSE;
1310 break;
1311 }
1312 }
1313
1314 mAllTEsSame = all_same;
1315 if (was_same != all_same)
1316 {
1317 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); // rebuild NOW
1318 mFaceMappingChanged = TRUE;
1319 }
1320 return mAllTEsSame;
1321}
1322
1323void LLVOVolume::setupSingleFace(S32 face_offset)
1324{
1325 S32 num_indices = 0;
1326 S32 num_vertices = 0;
1327
1328 if (mDrawable.isNull())
1329 {
1330 llerrs << "setupSingleFace called with NULL mDrawable" << llendl;
1331 }
1332 if (face_offset >= mDrawable->getNumFaces())
1333 {
1334 llerrs << "setupSingleFace called with invalid face_offset" << llendl;
1335 }
1336
1337 const S32 num_faces = getVolume()->getNumFaces();
1338 for (S32 i = 0; i < num_faces; i++)
1339 {
1340 const LLVolumeFace &vf = getVolume()->getVolumeFace(i);
1341 num_vertices += vf.mVertices.size();
1342 num_indices += vf.mIndices.size();
1343 }
1344 LLFace *facep = mDrawable->getFace(face_offset);
1345 facep->setSize(num_vertices, num_indices);
1346}
1347
1348//----------------------------------------------------------------------------
1349
1350void LLVOVolume::setIsLight(BOOL is_light)
1351{
1352 if (is_light != getIsLight())
1353 {
1354 if (is_light)
1355 {
1356 setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, TRUE, true);
1357 }
1358 else
1359 {
1360 setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, FALSE, true);
1361 }
1362
1363 if (is_light)
1364 {
1365 // Add it to the pipeline mLightSet
1366 gPipeline.setLight(mDrawable, TRUE);
1367 }
1368 else
1369 {
1370 // Not a light. Remove it from the pipeline's light set.
1371 gPipeline.setLight(mDrawable, FALSE);
1372
1373 // Remove this object from any object which has it as a light
1374 if (mDrawable)
1375 {
1376 mDrawable->clearLightSet();
1377 }
1378 }
1379 }
1380}
1381
1382void LLVOVolume::setLightColor(const LLColor3& color)
1383{
1384 LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
1385 if (param_block)
1386 {
1387 if (param_block->getColor() != color)
1388 {
1389 param_block->setColor(LLColor4(color, param_block->getColor().mV[3]));
1390 parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
1391 }
1392 }
1393}
1394
1395void LLVOVolume::setLightIntensity(F32 intensity)
1396{
1397 LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
1398 if (param_block)
1399 {
1400 if (param_block->getColor().mV[3] != intensity)
1401 {
1402 param_block->setColor(LLColor4(LLColor3(param_block->getColor()), intensity));
1403 parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
1404 }
1405 }
1406}
1407
1408void LLVOVolume::setLightRadius(F32 radius)
1409{
1410 LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
1411 if (param_block)
1412 {
1413 if (param_block->getRadius() != radius)
1414 {
1415 param_block->setRadius(radius);
1416 parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
1417 }
1418 }
1419}
1420
1421void LLVOVolume::setLightFalloff(F32 falloff)
1422{
1423 LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
1424 if (param_block)
1425 {
1426 if (param_block->getFalloff() != falloff)
1427 {
1428 param_block->setFalloff(falloff);
1429 parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
1430 }
1431 }
1432}
1433
1434void LLVOVolume::setLightCutoff(F32 cutoff)
1435{
1436 LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
1437 if (param_block)
1438 {
1439 if (param_block->getCutoff() != cutoff)
1440 {
1441 param_block->setCutoff(cutoff);
1442 parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
1443 }
1444 }
1445}
1446
1447//----------------------------------------------------------------------------
1448
1449BOOL LLVOVolume::getIsLight() const
1450{
1451 return getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT);
1452}
1453
1454LLColor3 LLVOVolume::getLightBaseColor() const
1455{
1456 const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
1457 if (param_block)
1458 {
1459 return LLColor3(param_block->getColor());
1460 }
1461 else
1462 {
1463 return LLColor3(1,1,1);
1464 }
1465}
1466
1467LLColor3 LLVOVolume::getLightColor() const
1468{
1469 const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
1470 if (param_block)
1471 {
1472 return LLColor3(param_block->getColor()) * param_block->getColor().mV[3];
1473 }
1474 else
1475 {
1476 return LLColor3(1,1,1);
1477 }
1478}
1479
1480F32 LLVOVolume::getLightIntensity() const
1481{
1482 const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
1483 if (param_block)
1484 {
1485 return param_block->getColor().mV[3];
1486 }
1487 else
1488 {
1489 return 1.f;
1490 }
1491}
1492
1493F32 LLVOVolume::getLightRadius() const
1494{
1495 const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
1496 if (param_block)
1497 {
1498 return param_block->getRadius();
1499 }
1500 else
1501 {
1502 return 0.f;
1503 }
1504}
1505
1506F32 LLVOVolume::getLightFalloff() const
1507{
1508 const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
1509 if (param_block)
1510 {
1511 return param_block->getFalloff();
1512 }
1513 else
1514 {
1515 return 0.f;
1516 }
1517}
1518
1519F32 LLVOVolume::getLightCutoff() const
1520{
1521 const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
1522 if (param_block)
1523 {
1524 return param_block->getCutoff();
1525 }
1526 else
1527 {
1528 return 0.f;
1529 }
1530}
1531
1532//----------------------------------------------------------------------------
1533
1534// returns < 0 if inside radius
1535F32 LLVOVolume::getLightDistance(const LLVector3& pos) const
1536{
1537 LLVector3 dpos = getRenderPosition() - pos;
1538 F32 dist = dpos.magVec() - getLightRadius();
1539 return dist;
1540}
1541
1542// returns intensity, modifies color in result
1543F32 LLVOVolume::calcLightAtPoint(const LLVector3& pos, const LLVector3& norm, LLColor4& result)
1544{
1545 if (!getIsLight())
1546 {
1547 return 0.0f;
1548 }
1549 F32 light_radius = getLightRadius();
1550 LLVector3 light_pos = getRenderPosition();
1551 LLVector3 light_dir = light_pos - pos;
1552 F32 dist = light_dir.normVec();
1553 F32 dp = norm * light_dir;
1554 if ((gPipeline.getVertexShaderLevel(LLPipeline::SHADER_OBJECT) >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS))
1555 {
1556 if (dp <= 0)
1557 {
1558 result *= 0;
1559 return 0;
1560 }
1561
1562 if (dist >= light_radius)
1563 {
1564 result *= 0;
1565 return 0;
1566 }
1567
1568 F32 mag = 1.0f-(dist/light_radius);
1569 mag = powf(mag, 0.75f);
1570 mag *= dp;
1571 result = getLightColor() * mag;
1572 return mag;
1573 }
1574 else
1575 {
1576 F32 light_radius = getLightRadius();
1577 LLVector3 light_pos = getRenderPosition();
1578 LLVector3 light_dir = light_pos - pos;
1579 F32 dist = light_dir.normVec();
1580 F32 dp = norm * light_dir;
1581 F32 atten = (1.f/.2f) / (light_radius); // 20% of brightness at radius
1582 F32 falloff = 1.f / (dist * atten);
1583 F32 mag = falloff * dp;
1584 mag = llmax(mag, 0.0f);
1585 result = getLightColor() * mag;
1586 return mag;
1587 }
1588}
1589
1590BOOL LLVOVolume::updateLighting(BOOL do_lighting)
1591{
1592 LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
1593
1594 if (mDrawable->isStatic())
1595 {
1596 do_lighting = FALSE;
1597 }
1598
1599 const LLMatrix4& mat_vert = mDrawable->getWorldMatrix();
1600 const LLMatrix3& mat_normal = LLMatrix3(mDrawable->getWorldRotation());
1601
1602 LLVolume* volume = getVolume();
1603 if (getAllTEsSame())
1604 {
1605 LLFace *face = mDrawable->getFace(mFaceIndexOffset);
1606 S32 num_faces = volume->getNumFaces();
1607 if (face && face->getGeomCount())
1608 {
1609 face->genLighting(volume, mDrawable, 0, num_faces-1, mat_vert, mat_normal, do_lighting);
1610 }
1611 }
1612 else
1613 {
1614 for (S32 i = 0; i < volume->getNumFaces(); i++)
1615 {
1616 LLFace *face = mDrawable->getFace(i + mFaceIndexOffset);
1617 if (face && face->getGeomCount())
1618 {
1619 face->genLighting(volume, mDrawable, i, i, mat_vert, mat_normal, do_lighting);
1620 }
1621 }
1622 }
1623 return TRUE;
1624}
1625
1626//----------------------------------------------------------------------------
1627
1628BOOL LLVOVolume::isFlexible() const
1629{
1630 if (getParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE))
1631 {
1632 if (getVolume()->getParams().getPathParams().getCurveType() != LL_PCODE_PATH_FLEXIBLE)
1633 {
1634 llwarns << "wtf" << llendl;
1635 LLVolumeParams volume_params = getVolume()->getParams();
1636 U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
1637 volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE);
1638 }
1639 return TRUE;
1640 }
1641 else
1642 {
1643 return FALSE;
1644 }
1645}
1646
1647BOOL LLVOVolume::isVolumeGlobal() const
1648{
1649 if (mVolumeImpl)
1650 {
1651 return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE;
1652 }
1653 return FALSE;
1654}
1655
1656BOOL LLVOVolume::canBeFlexible() const
1657{
1658 U8 path = getVolume()->getParams().getPathParams().getCurveType();
1659 return (path == LL_PCODE_PATH_FLEXIBLE || path == LL_PCODE_PATH_LINE);
1660}
1661
1662BOOL LLVOVolume::setIsFlexible(BOOL is_flexible)
1663{
1664 BOOL res = FALSE;
1665 BOOL was_flexible = isFlexible();
1666 LLVolumeParams volume_params;
1667 if (is_flexible)
1668 {
1669 if (!was_flexible)
1670 {
1671 volume_params = getVolume()->getParams();
1672 U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
1673 volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE);
1674 res = TRUE;
1675 setFlags(FLAGS_USE_PHYSICS, FALSE);
1676 setFlags(FLAGS_PHANTOM, TRUE);
1677 setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, true);
1678 if (mDrawable)
1679 {
1680 mDrawable->makeActive();
1681 }
1682 }
1683 }
1684 else
1685 {
1686 if (was_flexible)
1687 {
1688 volume_params = getVolume()->getParams();
1689 U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
1690 volume_params.setType(profile_and_hole, LL_PCODE_PATH_LINE);
1691 res = TRUE;
1692 setFlags(FLAGS_PHANTOM, FALSE);
1693 setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, true);
1694 }
1695 }
1696 if (res)
1697 {
1698 res = setVolume(volume_params, 1);
1699 if (res)
1700 {
1701 markForUpdate(TRUE);
1702 }
1703 }
1704 return res;
1705}
1706
1707//----------------------------------------------------------------------------
1708
1709void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point)
1710{
1711 LLVolume *volume = getVolume();
1712
1713 if (volume)
1714 {
1715 LLVector3 view_vector;
1716 view_vector = view_point;
1717
1718 if (!isVolumeGlobal())
1719 { //transform view vector into volume space
1720 view_vector -= getRenderPosition();
1721 LLQuaternion worldRot = getRenderRotation();
1722 view_vector = view_vector * ~worldRot;
1723 LLVector3 objScale = getScale();
1724 LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
1725 view_vector.scaleVec(invObjScale);
1726 }
1727
1728 updateRelativeXform();
1729 volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, mRelativeXform, mRelativeXformInvTrans);
1730
1731 nodep->mSilhouetteExists = TRUE;
1732 }
1733}
1734
1735void LLVOVolume::deleteFaces(LLVOVolume* childp)
1736{
1737 S32 face_count = childp->mNumFaces;
1738 S32 start_index = childp->mFaceIndexOffset;
1739 if (mDrawable.notNull())
1740 {
1741 mDrawable->deleteFaces(start_index, face_count);
1742 }
1743 if (mFaceIndexOffset > start_index)
1744 {
1745 mFaceIndexOffset -= face_count;
1746 }
1747
1748 for (U32 i = 0; i < mChildList.size(); i++)
1749 {
1750 LLViewerObject* siblingp = mChildList[i];
1751 if (siblingp != childp)
1752 {
1753 if (siblingp->getPCode() == LL_PCODE_VOLUME &&
1754 ((LLVOVolume*)siblingp)->mFaceIndexOffset > start_index)
1755 {
1756 ((LLVOVolume*)siblingp)->mFaceIndexOffset -= face_count;
1757 }
1758 }
1759 }
1760 childp->mFaceIndexOffset = 0;
1761 childp->mNumFaces = 0;
1762}
1763
1764void LLVOVolume::updateRadius()
1765{
1766 if (mDrawable.isNull())
1767 {
1768 return;
1769 }
1770
1771 mVObjRadius = getScale().magVec();
1772 mDrawable->setRadius(mVObjRadius);
1773}
1774
1775
1776BOOL LLVOVolume::isAttachment() const
1777{
1778 if (mState == 0)
1779 {
1780 return FALSE;
1781 }
1782 else
1783 {
1784 return TRUE;
1785 }
1786}
1787
1788BOOL LLVOVolume::isHUDAttachment() const
1789{
1790 // *NOTE: we assume hud attachment points are in defined range
1791 // since this range is constant for backwards compatibility
1792 // reasons this is probably a reasonable assumption to make
1793 S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState);
1794 return ( attachment_id >= 31 && attachment_id <= 38 );
1795}
1796
1797
1798const LLMatrix4 LLVOVolume::getRenderMatrix() const
1799{
1800 if (mDrawable->isActive() && !mDrawable->isRoot())
1801 {
1802 return mDrawable->getParent()->getWorldMatrix();
1803 }
1804 return mDrawable->getWorldMatrix();
1805}
1806
1807void LLVOVolume::writeCAL3D(apr_file_t* fp, std::string& path, std::string& file_base, S32 joint_num, LLVector3& pos, LLQuaternion& rot, S32& material_index, S32& texture_index, std::multimap<LLUUID, LLMaterialExportInfo*>& material_map)
1808{
1809 LLPointer<LLImageTGA> tga_image = new LLImageTGA;
1810
1811 if (mDrawable.isNull())
1812 {
1813 return;
1814 }
1815
1816 LLVector3 final_pos = getPosition();
1817 final_pos *= 100.f;
1818
1819 final_pos = final_pos * rot;
1820 final_pos += pos;
1821 LLQuaternion final_rot;
1822 final_rot = getRotation() * rot;
1823 LLMatrix4 transform;
1824 transform.initAll(getScale(), final_rot, final_pos);
1825
1826 LLMatrix4 int_transpose_transform;
1827 int_transpose_transform.initAll(LLVector3(1.f / getScale().mV[VX], 1.f / getScale().mV[VY], 1.f / getScale().mV[VZ]), final_rot, LLVector3::zero);
1828
1829 for (S32 i = 0; i < mDrawable->getNumFaces(); i++)
1830 {
1831 S32 vert_num = 0;
1832 LLFace* facep = mDrawable->getFace(i);
1833 LLDrawPool* poolp = facep->getPool();
1834
1835 const LLTextureEntry* tep = facep->getTextureEntry();
1836 if (!tep)
1837 {
1838 continue;
1839 }
1840
1841 S32 my_material = -1;
1842 S32 my_texture = -1;
1843 LLColor4 face_color = tep->getColor();
1844
1845 typedef std::multimap<LLUUID, LLMaterialExportInfo*>::iterator material_it_t;
1846 std::pair<material_it_t, material_it_t> found_range = material_map.equal_range(tep->getID());
1847 material_it_t material_it = found_range.first;
1848
1849 LLMaterialExportInfo* material_info = NULL;
1850
1851 while(material_it != material_map.end() && material_it != found_range.second)
1852 {
1853 // we've at least found a matching texture, so reuse it
1854 my_texture = material_it->second->mTextureIndex;
1855 if (material_it->second->mColor == face_color)
1856 {
1857 // we've found a matching material
1858 material_info = material_it->second;
1859 }
1860 ++material_it;
1861 }
1862
1863 if (material_info)
1864 {
1865 // material already exported, just reuse it
1866 my_material = material_info->mMaterialIndex;
1867 my_texture = material_info->mTextureIndex;
1868 }
1869 else
1870 {
1871 // reserve new material number
1872 my_material = material_index++;
1873
1874 // if we didn't already find a matching texture...
1875 if (my_texture == -1)
1876 {
1877 //...use the next available slot...
1878 my_texture = texture_index++;
1879
1880 //...and export texture as image file
1881 char filename[MAX_PATH];
1882 sprintf(filename, "%s\\%s_material_tex_%d.tga", path.c_str(), file_base.c_str(), my_texture);
1883
1884 LLViewerImage* imagep = facep->getTexture();
1885 if (imagep->getTexName() == 0)
1886 {
1887 llinfos << "No image data available for " << filename << llendl;
1888 continue;
1889 }
1890 LLPointer<LLImageRaw> raw_image = new LLImageRaw;
1891 imagep->readBackRaw(-1, raw_image);
1892 BOOL success = tga_image->encode(raw_image);
1893 success = tga_image->save(filename);
1894 }
1895
1896 material_info = new LLMaterialExportInfo(my_material, my_texture, face_color);
1897 material_map.insert(std::make_pair<LLUUID, LLMaterialExportInfo*>(tep->getID(), material_info));
1898 }
1899
1900 apr_file_printf(fp, "\t<SUBMESH NUMVERTICES=\"%d\" NUMFACES=\"%d\" MATERIAL=\"%d\" NUMLODSTEPS=\"0\" NUMSPRINGS=\"0\" NUMTEXCOORDS=\"1\">\n",
1901 facep->getGeomCount(), facep->getIndicesCount() / 3, my_material);
1902
1903 for (S32 vert_index = 0; vert_index < facep->getGeomCount(); vert_index++)
1904 {
1905 LLVector3 vert_pos = poolp->getVertex(facep->getGeomStart() + vert_index);
1906 vert_pos *= 100.f;
1907 vert_pos = vert_pos * transform;
1908 LLVector3 vert_norm = poolp->getNormal(facep->getGeomStart() + vert_index);
1909 vert_norm = vert_norm * int_transpose_transform;
1910 LLVector2 vert_tc = poolp->getTexCoord(facep->getGeomStart() + vert_index, 0);
1911 apr_file_printf(fp, " <VERTEX ID=\"%d\" NUMINFLUENCES=\"1\">\n", vert_num++);
1912 apr_file_printf(fp, " <POS>%.4f %.4f %.4f</POS>\n", vert_pos.mV[VX], vert_pos.mV[VY], vert_pos.mV[VZ]);
1913 apr_file_printf(fp, " <NORM>%.6f %.6f %.6f</NORM>\n", vert_norm.mV[VX], vert_norm.mV[VY], vert_norm.mV[VZ]);
1914 apr_file_printf(fp, " <TEXCOORD>%.6f %.6f</TEXCOORD>\n", vert_tc.mV[VX], 1.f - vert_tc.mV[VY]);
1915 apr_file_printf(fp, " <INFLUENCE ID=\"%d\">1.0</INFLUENCE>\n", joint_num + 1);
1916 apr_file_printf(fp, " </VERTEX>\n");
1917 }
1918
1919 for (U32 index_i = 0; index_i < facep->getIndicesCount(); index_i += 3)
1920 {
1921 U32 index_a = poolp->getIndex(facep->getIndicesStart() + index_i) - facep->getGeomStart();
1922 U32 index_b = poolp->getIndex(facep->getIndicesStart() + index_i + 1) - facep->getGeomStart();
1923 U32 index_c = poolp->getIndex(facep->getIndicesStart() + index_i + 2) - facep->getGeomStart();
1924 apr_file_printf(fp, " <FACE VERTEXID=\"%d %d %d\" />\n", index_a, index_b, index_c);
1925 }
1926
1927 apr_file_printf(fp, " </SUBMESH>\n");
1928 }
1929
1930 for (U32 i = 0; i < mChildList.size(); i++)
1931 {
1932 ((LLVOVolume*)(LLViewerObject*)mChildList[i])->writeCAL3D(fp, path, file_base, joint_num, final_pos, final_rot, material_index, texture_index, material_map);
1933 }
1934}
1935
1936//static
1937void LLVOVolume::preUpdateGeom()
1938{
1939 sNumLODChanges = 0;
1940}
1941
1942void LLVOVolume::parameterChanged(U16 param_type, bool local_origin)
1943{
1944 LLViewerObject::parameterChanged(param_type, local_origin);
1945}
1946
1947void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin)
1948{
1949 LLViewerObject::parameterChanged(param_type, data, in_use, local_origin);
1950 if (mVolumeImpl)
1951 {
1952 mVolumeImpl->onParameterChanged(param_type, data, in_use, local_origin);
1953 }
1954 if (mDrawable.notNull())
1955 {
1956 BOOL is_light = getIsLight();
1957 if (is_light != mDrawable->isState(LLDrawable::LIGHT))
1958 {
1959 gPipeline.setLight(mDrawable, is_light);
1960 }
1961 }
1962}
1963
1964void LLVOVolume::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
1965{
1966}
1967
1968const LLVector3 LLVOVolume::getPivotPositionAgent() const
1969{
1970 if (mVolumeImpl)
1971 {
1972 return mVolumeImpl->getPivotPosition();
1973 }
1974 return LLViewerObject::getPivotPositionAgent();
1975}
1976
1977void LLVOVolume::onShift(const LLVector3 &shift_vector)
1978{
1979 if (mVolumeImpl)
1980 {
1981 mVolumeImpl->onShift(shift_vector);
1982 }
1983}
1984
1985const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const
1986{
1987 if (mVolumeImpl)
1988 {
1989 return mVolumeImpl->getWorldMatrix(xform);
1990 }
1991 return xform->getWorldMatrix();
1992}
1993
1994LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const
1995{
1996 if (isVolumeGlobal())
1997 {
1998 return pos;
1999 }
2000
2001 LLVector3 ret = pos - getRenderPosition();
2002 ret = ret * ~getRenderRotation();
2003 LLVector3 objScale = getScale();
2004 LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
2005 ret.scaleVec(invObjScale);
2006
2007 return ret;
2008}
2009
2010LLVector3 LLVOVolume::agentDirectionToVolume(const LLVector3& dir) const
2011{
2012 return isVolumeGlobal() ? dir : (dir * ~getRenderRotation());
2013}
2014
2015LLVector3 LLVOVolume::volumePositionToAgent(const LLVector3& dir) const
2016{
2017 LLVector3 ret = dir;
2018 ret.scaleVec(getScale());
2019 ret = ret * getRenderRotation();
2020 ret += getRenderPosition();
2021
2022 return ret;
2023}
2024
2025BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, LLVector3& end) const
2026{
2027 LLVolume* volume = getVolume();
2028 BOOL ret = FALSE;
2029 if (volume)
2030 {
2031 LLVector3 v_start, v_end, v_dir;
2032
2033 v_start = agentPositionToVolume(start);
2034 v_end = agentPositionToVolume(end);
2035
2036 if (LLLineSegmentAABB(v_start, v_end, volume->mBounds[0], volume->mBounds[1]))
2037 {
2038 if (volume->lineSegmentIntersect(v_start, v_end) >= 0)
2039 {
2040 end = volumePositionToAgent(v_end);
2041 ret = TRUE;
2042 }
2043 }
2044 }
2045 return ret;
2046}