llvovolume.cpp

Go to the documentation of this file.
00001 
00032 // A "volume" is a box, cylinder, sphere, or other primitive shape.
00033 
00034 #include "llviewerprecompiledheaders.h"
00035 
00036 #include "llvovolume.h"
00037 
00038 #include "llviewercontrol.h"
00039 #include "lldir.h"
00040 #include "llflexibleobject.h"
00041 #include "llmaterialtable.h"
00042 #include "llprimitive.h"
00043 #include "llvolume.h"
00044 #include "llvolumemgr.h"
00045 #include "llvolumemessage.h"
00046 #include "material_codes.h"
00047 #include "message.h"
00048 #include "object_flags.h"
00049 #include "llagent.h"
00050 #include "lldrawable.h"
00051 #include "lldrawpoolsimple.h"
00052 #include "lldrawpoolbump.h"
00053 #include "llface.h"
00054 
00055 // TEMP HACK ventrella
00056 #include "llhudmanager.h"
00057 #include "llflexibleobject.h"
00058 #include "llanimalcontrols.h"
00059 
00060 #include "llsky.h"
00061 #include "llviewercamera.h"
00062 #include "llviewerimagelist.h"
00063 #include "llviewerregion.h"
00064 #include "llviewertextureanim.h"
00065 #include "llworld.h"
00066 #include "llselectmgr.h"
00067 #include "pipeline.h"
00068 
00069 const S32 MIN_QUIET_FRAMES_COALESCE = 30;
00070 const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
00071 const F32 FORCE_CULL_AREA = 8.f;
00072 const S32 SCULPT_REZ = 128;
00073 
00074 BOOL gAnimateTextures = TRUE;
00075 extern BOOL gHideSelectedObjects;
00076 
00077 F32 LLVOVolume::sLODFactor = 1.f;
00078 F32     LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop 
00079 F32 LLVOVolume::sDistanceFactor = 1.0f;
00080 S32 LLVOVolume::sNumLODChanges = 0;
00081 
00082 LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
00083         : LLViewerObject(id, pcode, regionp),
00084           mVolumeImpl(NULL)
00085 {
00086         mTexAnimMode = 0;
00087         mRelativeXform.identity();
00088         mRelativeXformInvTrans.identity();
00089 
00090         mLOD = MIN_LOD;
00091         mInited = FALSE;
00092         mTextureAnimp = NULL;
00093         mGlobalVolume = FALSE;
00094         mVObjRadius = LLVector3(1,1,0.5f).magVec();
00095         mNumFaces = 0;
00096         mLODChanged = FALSE;
00097         mSculptChanged = FALSE;
00098 }
00099 
00100 LLVOVolume::~LLVOVolume()
00101 {
00102         delete mTextureAnimp;
00103         mTextureAnimp = NULL;
00104         delete mVolumeImpl;
00105         mVolumeImpl = NULL;
00106 }
00107 
00108 
00109 // static
00110 void LLVOVolume::initClass()
00111 {
00112 }
00113 
00114 
00115 U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
00116                                                                                   void **user_data,
00117                                                                                   U32 block_num, EObjectUpdateType update_type,
00118                                                                                   LLDataPacker *dp)
00119 {
00120         LLColor4U color;
00121 
00122         // Do base class updates...
00123         U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
00124 
00125         LLUUID sculpt_id;
00126         U8 sculpt_type = 0;
00127         if (isSculpted())
00128         {
00129                 LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
00130                 sculpt_id = sculpt_params->getSculptTexture();
00131                 sculpt_type = sculpt_params->getSculptType();
00132         }
00133 
00134         if (!dp)
00135         {
00136                 if (update_type == OUT_FULL)
00137                 {
00139                         //
00140                         // Unpack texture animation data
00141                         //
00142                         //
00143 
00144                         if (mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureAnim))
00145                         {
00146                                 if (!mTextureAnimp)
00147                                 {
00148                                         mTextureAnimp = new LLViewerTextureAnim();
00149                                 }
00150                                 else
00151                                 {
00152                                         if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH))
00153                                         {
00154                                                 mTextureAnimp->reset();
00155                                         }
00156                                 }
00157                                 mTexAnimMode = 0;
00158                                 mTextureAnimp->unpackTAMessage(mesgsys, block_num);
00159                         }
00160                         else
00161                         {
00162                                 if (mTextureAnimp)
00163                                 {
00164                                         delete mTextureAnimp;
00165                                         mTextureAnimp = NULL;
00166                                         gPipeline.markTextured(mDrawable);
00167                                         mFaceMappingChanged = TRUE;
00168                                         mTexAnimMode = 0;
00169                                 }
00170                         }
00171 
00172                         // Unpack volume data
00173                         LLVolumeParams volume_params;
00174                         LLVolumeMessage::unpackVolumeParams(&volume_params, mesgsys, _PREHASH_ObjectData, block_num);
00175                         volume_params.setSculptID(sculpt_id, sculpt_type);
00176 
00177                         if (setVolume(volume_params, 0))
00178                         {
00179                                 markForUpdate(TRUE);
00180                         }
00181                 }
00182 
00183                 // Sigh, this needs to be done AFTER the volume is set as well, otherwise bad stuff happens...
00185                 //
00186                 // Unpack texture entry data
00187                 //
00188                 if (unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num) & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR))
00189                 {
00190                         updateTEData();
00191                 }
00192         }
00193         else
00194         {
00195                 // CORY TO DO: Figure out how to get the value here
00196                 if (update_type != OUT_TERSE_IMPROVED)
00197                 {
00198                         LLVolumeParams volume_params;
00199                         BOOL res = LLVolumeMessage::unpackVolumeParams(&volume_params, *dp);
00200                         if (!res)
00201                         {
00202                                 llwarns << "Bogus volume parameters in object " << getID() << llendl;
00203                                 llwarns << getRegion()->getOriginGlobal() << llendl;
00204                         }
00205 
00206                         volume_params.setSculptID(sculpt_id, sculpt_type);
00207 
00208                         if (setVolume(volume_params, 0))
00209                         {
00210                                 markForUpdate(TRUE);
00211                         }
00212                         S32 res2 = unpackTEMessage(*dp);
00213                         if (TEM_INVALID == res2)
00214                         {
00215                                 // Well, crap, there's something bogus in the data that we're unpacking.
00216                                 dp->dumpBufferToLog();
00217                                 llwarns << "Flushing cache files" << llendl;
00218                                 char mask[LL_MAX_PATH];         /* Flawfinder: ignore */
00219                                 snprintf(mask, LL_MAX_PATH, "%s*.slc", gDirUtilp->getDirDelimiter().c_str());           /* Flawfinder: ignore */
00220                                 gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"").c_str(),mask);
00221 //                              llerrs << "Bogus TE data in " << getID() << ", crashing!" << llendl;
00222                                 llwarns << "Bogus TE data in " << getID() << llendl;
00223                         }
00224                         else if (res2 & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR))
00225                         {
00226                                 updateTEData();
00227                         }
00228 
00229                         U32 value = dp->getPassFlags();
00230 
00231                         if (value & 0x40)
00232                         {
00233                                 if (!mTextureAnimp)
00234                                 {
00235                                         mTextureAnimp = new LLViewerTextureAnim();
00236                                 }
00237                                 else
00238                                 {
00239                                         if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH))
00240                                         {
00241                                                 mTextureAnimp->reset();
00242                                         }
00243                                 }
00244                                 mTexAnimMode = 0;
00245                                 mTextureAnimp->unpackTAMessage(*dp);
00246                         }
00247                         else if (mTextureAnimp)
00248                         {
00249                                 delete mTextureAnimp;
00250                                 mTextureAnimp = NULL;
00251                                 gPipeline.markTextured(mDrawable);
00252                                 mFaceMappingChanged = TRUE;
00253                                 mTexAnimMode = 0;
00254                         }
00255                 }
00256                 else
00257                 {
00258                         S32 texture_length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureEntry);
00259                         if (texture_length)
00260                         {
00261                                 U8                                                      tdpbuffer[1024];
00262                                 LLDataPackerBinaryBuffer        tdp(tdpbuffer, 1024);
00263                                 mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num);
00264                                 if ( unpackTEMessage(tdp) & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR))
00265                                 {
00266                                         updateTEData();
00267                                 }
00268                         }
00269                 }
00270         }
00271         
00272         return retval;
00273 }
00274 
00275 
00276 void LLVOVolume::animateTextures()
00277 {
00278         F32 off_s = 0.f, off_t = 0.f, scale_s = 1.f, scale_t = 1.f, rot = 0.f;
00279         S32 result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot);
00280         
00281         if (result)
00282         {
00283                 if (!mTexAnimMode)
00284                 {
00285                         mFaceMappingChanged = TRUE;
00286                         gPipeline.markTextured(mDrawable);
00287                 }
00288                 mTexAnimMode = result | mTextureAnimp->mMode;
00289                                 
00290                 S32 start=0, end=mDrawable->getNumFaces()-1;
00291                 if (mTextureAnimp->mFace >= 0 && mTextureAnimp->mFace <= end)
00292                 {
00293                         start = end = mTextureAnimp->mFace;
00294                 }
00295                 
00296                 for (S32 i = start; i <= end; i++)
00297                 {
00298                         LLFace* facep = mDrawable->getFace(i);
00299                         const LLTextureEntry* te = facep->getTextureEntry();
00300                         
00301                         if (!te)
00302                         {
00303                                 continue;
00304                         }
00305                 
00306                         if (!(result & LLViewerTextureAnim::ROTATE))
00307                         {
00308                                 te->getRotation(&rot);
00309                         }
00310                         if (!(result & LLViewerTextureAnim::TRANSLATE))
00311                         {
00312                                 te->getOffset(&off_s,&off_t);
00313                         }                       
00314                         if (!(result & LLViewerTextureAnim::SCALE))
00315                         {
00316                                 te->getScale(&scale_s, &scale_t);
00317                         }
00318 
00319                         LLVector3 scale(scale_s, scale_t, 1.f);
00320                         LLVector3 trans(off_s+0.5f, off_t+0.5f, 0.f);
00321                         LLQuaternion quat;
00322                         quat.setQuat(rot, 0, 0, -1.f);
00323                 
00324                         LLMatrix4& tex_mat = facep->mTextureMatrix;
00325                         tex_mat.identity();
00326                         tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f));
00327                         tex_mat.rotate(quat);                           
00328 
00329                         LLMatrix4 mat;
00330                         mat.initAll(scale, LLQuaternion(), LLVector3());
00331                         tex_mat *= mat;
00332                 
00333                         tex_mat.translate(trans);
00334                 }
00335         }
00336         else
00337         {
00338                 if (mTexAnimMode && mTextureAnimp->mRate == 0)
00339                 {
00340                         U8 start, count;
00341 
00342                         if (mTextureAnimp->mFace == -1)
00343                         {
00344                                 start = 0;
00345                                 count = getNumTEs();
00346                         }
00347                         else
00348                         {
00349                                 start = (U8) mTextureAnimp->mFace;
00350                                 count = 1;
00351                         }
00352 
00353                         for (S32 i = start; i < start + count; i++)
00354                         {
00355                                 if (mTexAnimMode & LLViewerTextureAnim::TRANSLATE)
00356                                 {
00357                                         setTEOffset(i, mTextureAnimp->mOffS, mTextureAnimp->mOffT);                             
00358                                 }
00359                                 if (mTexAnimMode & LLViewerTextureAnim::SCALE)
00360                                 {
00361                                         setTEScale(i, mTextureAnimp->mScaleS, mTextureAnimp->mScaleT);  
00362                                 }
00363                                 if (mTexAnimMode & LLViewerTextureAnim::ROTATE)
00364                                 {
00365                                         setTERotation(i, mTextureAnimp->mRot);
00366                                 }
00367                         }
00368 
00369                         gPipeline.markTextured(mDrawable);
00370                         mFaceMappingChanged = TRUE;
00371                         mTexAnimMode = 0;
00372                 }
00373         }
00374 }
00375 BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
00376 {
00377         LLViewerObject::idleUpdate(agent, world, time);
00378 
00379         if (mDead || mDrawable.isNull())
00380         {
00381                 return TRUE;
00382         }
00383         
00385         //
00386         // Do texture animation stuff
00387         //
00388 
00389         if (mTextureAnimp && gAnimateTextures)
00390         {
00391                 animateTextures();
00392         }
00393 
00394         // Dispatch to implementation
00395         if (mVolumeImpl)
00396         {
00397                 mVolumeImpl->doIdleUpdate(agent, world, time);
00398         }
00399 
00400         return TRUE;
00401 }
00402 
00403 void LLVOVolume::updateTextures(LLAgent &agent)
00404 {
00405 //      LLFastTimer t(LLFastTimer::FTM_TEMP6);
00406         const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds
00407         if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
00408         {
00409                 if (mDrawable->isVisible())
00410                 {
00411                         updateTextures();
00412                 }
00413         }
00414 }
00415 
00416 void LLVOVolume::updateTextures()
00417 {
00418         // Update the pixel area of all faces
00419 
00420         if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE))
00421         {
00422                 return;
00423         }
00424         
00425         if (LLViewerImage::sDontLoadVolumeTextures || mDrawable.isNull()) // || !mDrawable->isVisible())
00426         {
00427                 return;
00428         }
00429 
00430         mTextureUpdateTimer.reset();
00431         
00432         F32 old_area = mPixelArea;
00433         mPixelArea = 0.f;
00434 
00435         const S32 num_faces = mDrawable->getNumFaces();
00436         F32 min_vsize=999999999.f, max_vsize=0.f;
00437         for (S32 i = 0; i < num_faces; i++)
00438         {
00439                 LLFace* face = mDrawable->getFace(i);
00440                 const LLTextureEntry *te = face->getTextureEntry();
00441                 LLViewerImage *imagep = face->getTexture();
00442                 if (!imagep || !te ||
00443                         face->mExtents[0] == face->mExtents[1])
00444                 {
00445                         continue;
00446                 }
00447                 
00448                 F32 vsize;
00449                 
00450                 if (isHUDAttachment())
00451                 {
00452                         F32 area = (F32) gCamera->getScreenPixelArea();
00453                         vsize = area;
00454                         imagep->setBoostLevel(LLViewerImage::BOOST_HUD);
00455                         face->setPixelArea(area); // treat as full screen
00456                 }
00457                 else
00458                 {
00459                         vsize = getTextureVirtualSize(face);
00460                 }
00461 
00462                 mPixelArea = llmax(mPixelArea, face->getPixelArea());
00463                 face->setVirtualSize(vsize);
00464                 imagep->addTextureStats(vsize);
00465                 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
00466                 {
00467                         if (vsize < min_vsize) min_vsize = vsize;
00468                         if (vsize > max_vsize) max_vsize = vsize;
00469                 }
00470                 else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
00471                 {
00472                         F32 pri = imagep->getDecodePriority();
00473                         if (pri < min_vsize) min_vsize = pri;
00474                         if (pri > max_vsize) max_vsize = pri;
00475                 }
00476                 else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
00477                 {
00478                         F32 pri = mPixelArea;
00479                         if (pri < min_vsize) min_vsize = pri;
00480                         if (pri > max_vsize) max_vsize = pri;
00481                 }       
00482         }
00483         
00484         if (isSculpted())
00485         {
00486                 LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
00487                 LLUUID id =  sculpt_params->getSculptTexture(); 
00488                 mSculptTexture = gImageList.getImage(id);
00489                 if (mSculptTexture.notNull())
00490                 {
00491                         mSculptTexture->addTextureStats(SCULPT_REZ * SCULPT_REZ);
00492                         mSculptTexture->setBoostLevel(LLViewerImage::BOOST_SCULPTED);
00493                 }
00494 
00495                 S32 desired_discard = 0; // lower discard levels have MUCH less resolution - (old=MAX_LOD - mLOD)
00496                 S32 current_discard = getVolume()->getSculptLevel();
00497 
00498                 if (desired_discard != current_discard)
00499                 {
00500                         gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
00501                         mSculptChanged = TRUE;
00502                 }
00503                 
00504         }
00505 
00506 
00507         if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
00508         {
00509                 setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
00510         }
00511         else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
00512         {
00513                 setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
00514         }
00515         else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
00516         {
00517                 setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
00518         }
00519 
00520         if (mPixelArea == 0)
00521         { //flexi phasing issues make this happen
00522                 mPixelArea = old_area;
00523         }
00524 }
00525 
00526 F32 LLVOVolume::getTextureVirtualSize(LLFace* face)
00527 {
00528         //get area of circle around face
00529         LLVector3 center = face->getPositionAgent();
00530         LLVector3 size = (face->mExtents[1] - face->mExtents[0]) * 0.5f;
00531         
00532         F32 face_area = LLPipeline::calcPixelArea(center, size, *gCamera);
00533 
00534         face->setPixelArea(face_area);
00535 
00536         if (face_area <= 0)
00537         {
00538                 return 0.f;
00539         }
00540 
00541         //get area of circle in texture space
00542         LLVector2 tdim = face->mTexExtents[1] - face->mTexExtents[0];
00543         F32 texel_area = (tdim * 0.5f).magVecSquared()*3.14159f;
00544         if (texel_area <= 0)
00545         {
00546                 // Probably animated, use default
00547                 texel_area = 1.f;
00548         }
00549 
00550         //apply texel area to face area to get accurate ratio
00551         face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
00552 
00553         return face_area;
00554 }
00555 
00556 BOOL LLVOVolume::isActive() const
00557 {
00558         return !mStatic || mTextureAnimp || isAttachment() || (mVolumeImpl && mVolumeImpl->isActive());
00559 }
00560 
00561 BOOL LLVOVolume::setMaterial(const U8 material)
00562 {
00563         BOOL res = LLViewerObject::setMaterial(material);
00564         if (res)
00565         {
00566                 // for deprecated LL_MCODE_LIGHT
00567                 if (mDrawable.notNull())
00568                 {
00569                         gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_LIGHTING, TRUE);
00570                 }
00571         }
00572         return res;
00573 }
00574 
00575 void LLVOVolume::setTexture(const S32 face)
00576 {
00577         llassert(face < getNumTEs());
00578         LLViewerImage::bindTexture(getTEImage(face));
00579 }
00580 
00581 void LLVOVolume::setScale(const LLVector3 &scale, BOOL damped)
00582 {
00583         if (scale != getScale())
00584         {
00585                 // store local radius
00586                 LLViewerObject::setScale(scale);
00587 
00588                 if (mVolumeImpl)
00589                 {
00590                         mVolumeImpl->onSetScale(scale, damped);
00591                 }
00592                 
00593                 updateRadius();
00594 
00595                 //since drawable transforms do not include scale, changing volume scale
00596                 //requires an immediate rebuild of volume verts.
00597                 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION, TRUE);
00598         }
00599 }
00600 
00601 LLFace* LLVOVolume::addFace(S32 f)
00602 {
00603         const LLTextureEntry* te = getTE(f);
00604         LLViewerImage* imagep = getTEImage(f);
00605         return mDrawable->addFace(te, imagep);
00606 }
00607 
00608 LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
00609 {
00610         pipeline->allocDrawable(this);
00611         mDrawable->setRenderType(LLPipeline::RENDER_TYPE_VOLUME);
00612 
00613         S32 max_tes_to_set = getNumTEs();
00614         for (S32 i = 0; i < max_tes_to_set; i++)
00615         {
00616                 LLFace* face = addFace(i);
00617                 // JC - should there be a setViewerObject(this) call here?
00618                 face->setTEOffset(i);
00619         }
00620         mNumFaces = max_tes_to_set;
00621 
00622         if (isAttachment())
00623         {
00624                 mDrawable->makeActive();
00625         }
00626 
00627         if (getIsLight())
00628         {
00629                 // Add it to the pipeline mLightSet
00630                 gPipeline.setLight(mDrawable, TRUE);
00631         }
00632         
00633         updateRadius();
00634         mDrawable->updateDistance(*gCamera);
00635 
00636         return mDrawable;
00637 }
00638 
00639 
00640 BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume)
00641 {
00642         // Check if we need to change implementations
00643         bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE);
00644         if (is_flexible)
00645         {
00646                 setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, false);
00647                 if (!mVolumeImpl)
00648                 {
00649                         LLFlexibleObjectData* data = (LLFlexibleObjectData*)getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
00650                         mVolumeImpl = new LLVolumeImplFlexible(this, data);
00651                 }
00652         }
00653         else
00654         {
00655                 // Mark the parameter not in use
00656                 setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, false);
00657                 if (mVolumeImpl)
00658                 {
00659                         delete mVolumeImpl;
00660                         mVolumeImpl = NULL;
00661                         if (mDrawable.notNull())
00662                         {
00663                                 // Undo the damage we did to this matrix
00664                                 mDrawable->updateXform(FALSE);
00665                         }
00666                 }
00667         }
00668         
00669         mGlobalVolume = (mVolumeImpl && mVolumeImpl->isVolumeGlobal());
00670         
00671         if ((LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
00672         {
00673                 mFaceMappingChanged = TRUE;
00674                 
00675                 if (mVolumeImpl)
00676                 {
00677                         mVolumeImpl->onSetVolume(volume_params, detail);
00678                 }
00679                 
00680                 if (isSculpted())
00681                 {
00682                         mSculptTexture = gImageList.getImage(volume_params.getSculptID());
00683                         if (mSculptTexture.notNull())
00684                         {
00685                                 sculpt();
00686                         }
00687                 }
00688                 else
00689                 {
00690                         mSculptTexture = NULL;
00691                 }
00692 
00693                 return TRUE;
00694         }
00695         return FALSE;
00696 }
00697 
00698 // sculpt replaces generate() for sculpted surfaces
00699 void LLVOVolume::sculpt()
00700 {
00701         U16 sculpt_height = 0;
00702         U16 sculpt_width = 0;
00703         S8 sculpt_components = 0;
00704         const U8* sculpt_data = NULL;
00705 
00706         if (mSculptTexture.notNull())
00707         {
00708                 S32 discard_level;
00709                 S32 desired_discard = 0; // lower discard levels have MUCH less resolution 
00710 
00711                 discard_level = desired_discard;
00712                 
00713                 S32 max_discard = mSculptTexture->getMaxDiscardLevel();
00714                 if (discard_level > max_discard)
00715                         discard_level = max_discard;    // clamp to the best we can do
00716 
00717                 S32 best_discard = mSculptTexture->getDiscardLevel();
00718                 if (discard_level < best_discard)
00719                         discard_level = best_discard;   // clamp to what we have
00720 
00721                 if (best_discard == -1)
00722                         discard_level = -1;  // and if we have nothing, set to nothing
00723 
00724                 
00725                 S32 current_discard = getVolume()->getSculptLevel();
00726                 if (current_discard == discard_level)  // no work to do here
00727                         return;
00728                 
00729                 LLPointer<LLImageRaw> raw_image = new LLImageRaw();
00730                 mSculptTexture->readBackRaw(discard_level, raw_image, TRUE);
00731 
00732                 sculpt_height = raw_image->getHeight();
00733                 sculpt_width = raw_image->getWidth();
00734 
00735                 sculpt_components = raw_image->getComponents();
00736                 sculpt_data = raw_image->getData();
00737                 getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level);
00738         }
00739 }
00740 
00741 S32     LLVOVolume::computeLODDetail(F32 distance, F32 radius)
00742 {
00743         S32     cur_detail;
00744         // We've got LOD in the profile, and in the twist.  Use radius.
00745         F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
00746         cur_detail = LLVolumeLODGroup::getDetailFromTan(llround(tan_angle, 0.01f));
00747         return cur_detail;
00748 }
00749 
00750 BOOL LLVOVolume::calcLOD()
00751 {
00752         if (mDrawable.isNull())
00753         {
00754                 return FALSE;
00755         }
00756 
00757         S32 cur_detail = 0;
00758         
00759         F32 radius = mVolumep->mLODScaleBias.scaledVec(getScale()).magVec();
00760         F32 distance = mDrawable->mDistanceWRTCamera;
00761         distance *= sDistanceFactor;
00762                         
00763         F32 rampDist = LLVOVolume::sLODFactor * 2;
00764         
00765         if (distance < rampDist)
00766         {
00767                 // Boost LOD when you're REALLY close
00768                 distance *= 1.0f/rampDist;
00769                 distance *= distance;
00770                 distance *= rampDist;
00771         }
00772         
00773         // DON'T Compensate for field of view changing on FOV zoom.
00774         distance *= 3.14159f/3.f;
00775 
00776         cur_detail = computeLODDetail(llround(distance, 0.01f), 
00777                                                                         llround(radius, 0.01f));
00778 
00779         if (cur_detail != mLOD)
00780         {
00781                 mAppAngle = llround((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
00782                 mLOD = cur_detail;              
00783                 return TRUE;
00784         }
00785         else
00786         {
00787                 return FALSE;
00788         }
00789 }
00790 
00791 BOOL LLVOVolume::updateLOD()
00792 {
00793         if (mDrawable.isNull())
00794         {
00795                 return FALSE;
00796         }
00797         
00798         BOOL lod_changed = calcLOD();
00799 
00800         if (lod_changed)
00801         {
00802                 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
00803                 mLODChanged = TRUE;
00804         }
00805 
00806         lod_changed |= LLViewerObject::updateLOD();
00807         
00808         return lod_changed;
00809 }
00810 
00811 BOOL LLVOVolume::setDrawableParent(LLDrawable* parentp)
00812 {
00813         if (!LLViewerObject::setDrawableParent(parentp))
00814         {
00815                 // no change in drawable parent
00816                 return FALSE;
00817         }
00818 
00819         if (!mDrawable->isRoot())
00820         {
00821                 // rebuild vertices in parent relative space
00822                 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
00823 
00824                 if (mDrawable->isActive() && !parentp->isActive())
00825                 {
00826                         parentp->makeActive();
00827                 }
00828                 else if (mDrawable->isStatic() && parentp->isActive())
00829                 {
00830                         mDrawable->makeActive();
00831                 }
00832         }
00833         
00834         return TRUE;
00835 }
00836 
00837 void LLVOVolume::updateFaceFlags()
00838 {
00839         for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
00840         {
00841                 LLFace *face = mDrawable->getFace(i);
00842                 BOOL fullbright = getTE(i)->getFullbright();
00843                 face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT);
00844 
00845                 if (fullbright || (mMaterial == LL_MCODE_LIGHT))
00846                 {
00847                         face->setState(LLFace::FULLBRIGHT);
00848                 }
00849                 if (mDrawable->isLight())
00850                 {
00851                         face->setState(LLFace::LIGHT);
00852                 }
00853                 if (isHUDAttachment())
00854                 {
00855                         face->setState(LLFace::HUD_RENDER);
00856                 }
00857         }
00858 }
00859 
00860 void LLVOVolume::setParent(LLViewerObject* parent)
00861 {
00862         LLViewerObject::setParent(parent);
00863         if (mDrawable)
00864         {
00865                 gPipeline.markMoved(mDrawable);
00866                 mVolumeChanged = TRUE;
00867                 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
00868         }
00869 }
00870 
00871 // NOTE: regenFaces() MUST be followed by genTriangles()!
00872 void LLVOVolume::regenFaces()
00873 {
00874         // remove existing faces
00875         BOOL count_changed = mNumFaces != getNumTEs();
00876         
00877         if (count_changed)
00878         {
00879                 deleteFaces();          
00880                 // add new faces
00881                 mNumFaces = getNumTEs();
00882         }
00883                 
00884         for (S32 i = 0; i < mNumFaces; i++)
00885         {
00886                 LLFace* facep = count_changed ? addFace(i) : mDrawable->getFace(i);
00887                 facep->setTEOffset(i);
00888                 facep->setTexture(getTEImage(i));
00889                 facep->setViewerObject(this);
00890         }
00891         
00892         if (!count_changed)
00893         {
00894                 updateFaceFlags();
00895         }
00896 }
00897 
00898 BOOL LLVOVolume::genBBoxes(BOOL force_global)
00899 {
00900         BOOL res = TRUE;
00901 
00902         LLVector3 min,max;
00903 
00904         BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION);
00905 
00906         for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
00907         {
00908                 LLFace *face = mDrawable->getFace(i);
00909                 res &= face->genVolumeBBoxes(*getVolume(), i,
00910                                                                                 mRelativeXform, mRelativeXformInvTrans,
00911                                                                                 mGlobalVolume | force_global);
00912                 
00913                 if (rebuild)
00914                 {
00915                         if (i == 0)
00916                         {
00917                                 min = face->mExtents[0];
00918                                 max = face->mExtents[1];
00919                         }
00920                         else
00921                         {
00922                                 for (U32 i = 0; i < 3; i++)
00923                                 {
00924                                         if (face->mExtents[0].mV[i] < min.mV[i])
00925                                         {
00926                                                 min.mV[i] = face->mExtents[0].mV[i];
00927                                         }
00928                                         if (face->mExtents[1].mV[i] > max.mV[i])
00929                                         {
00930                                                 max.mV[i] = face->mExtents[1].mV[i];
00931                                         }
00932                                 }
00933                         }
00934                 }
00935         }
00936         
00937         if (rebuild)
00938         {
00939                 mDrawable->setSpatialExtents(min,max);
00940                 mDrawable->setPositionGroup((min+max)*0.5f);    
00941                 //bounding boxes changed, update texture priorities
00942                 updateTextures();
00943         }
00944 
00945         updateRadius();
00946         mDrawable->movePartition();
00947                         
00948         return res;
00949 }
00950 
00951 void LLVOVolume::updateRelativeXform()
00952 {
00953         if (mVolumeImpl)
00954         {
00955                 mVolumeImpl->updateRelativeXform();
00956                 return;
00957         }
00958         
00959         LLDrawable* drawable = mDrawable;
00960         
00961         if (drawable->isActive())
00962         {                               
00963                 // setup relative transforms
00964                 LLQuaternion delta_rot;
00965                 LLVector3 delta_pos, delta_scale;
00966                 
00967                 //matrix from local space to parent relative/global space
00968                 delta_rot = drawable->isSpatialRoot() ? LLQuaternion() : mDrawable->getRotation();
00969                 delta_pos = drawable->isSpatialRoot() ? LLVector3(0,0,0) : mDrawable->getPosition();
00970                 delta_scale = mDrawable->getScale();
00971 
00972                 // Vertex transform (4x4)
00973                 LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot;
00974                 LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot;
00975                 LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot;
00976 
00977                 mRelativeXform.initRows(LLVector4(x_axis, 0.f),
00978                                                                 LLVector4(y_axis, 0.f),
00979                                                                 LLVector4(z_axis, 0.f),
00980                                                                 LLVector4(delta_pos, 1.f));
00981 
00982                 
00983                 // compute inverse transpose for normals
00984                 // mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis);
00985                 // mRelativeXformInvTrans.invert(); 
00986                 // mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis);
00987                 // grumble - invert is NOT a matrix invert, so we do it by hand:
00988 
00989                 LLMatrix3 rot_inverse = LLMatrix3(~delta_rot);
00990 
00991                 LLMatrix3 scale_inverse;
00992                 scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / delta_scale.mV[VX],
00993                                                           LLVector3(0.0, 1.0, 0.0) / delta_scale.mV[VY],
00994                                                           LLVector3(0.0, 0.0, 1.0) / delta_scale.mV[VZ]);
00995                                                            
00996                 
00997                 mRelativeXformInvTrans = rot_inverse * scale_inverse;
00998 
00999                 mRelativeXformInvTrans.transpose();
01000         }
01001         else
01002         {
01003                 LLVector3 pos = getPosition();
01004                 LLVector3 scale = getScale();
01005                 LLQuaternion rot = getRotation();
01006         
01007                 if (mParent)
01008                 {
01009                         pos *= mParent->getRotation();
01010                         pos += mParent->getPosition();
01011                         rot *= mParent->getRotation();
01012                 }
01013                 
01014                 LLViewerRegion* region = getRegion();
01015                 pos += region->getOriginAgent();
01016                 
01017                 LLVector3 x_axis = LLVector3(scale.mV[VX], 0.f, 0.f) * rot;
01018                 LLVector3 y_axis = LLVector3(0.f, scale.mV[VY], 0.f) * rot;
01019                 LLVector3 z_axis = LLVector3(0.f, 0.f, scale.mV[VZ]) * rot;
01020 
01021                 mRelativeXform.initRows(LLVector4(x_axis, 0.f),
01022                                                                 LLVector4(y_axis, 0.f),
01023                                                                 LLVector4(z_axis, 0.f),
01024                                                                 LLVector4(pos, 1.f));
01025 
01026                 // compute inverse transpose for normals
01027                 LLMatrix3 rot_inverse = LLMatrix3(~rot);
01028 
01029                 LLMatrix3 scale_inverse;
01030                 scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / scale.mV[VX],
01031                                                           LLVector3(0.0, 1.0, 0.0) / scale.mV[VY],
01032                                                           LLVector3(0.0, 0.0, 1.0) / scale.mV[VZ]);
01033                                                            
01034                 
01035                 mRelativeXformInvTrans = rot_inverse * scale_inverse;
01036 
01037                 mRelativeXformInvTrans.transpose();
01038         }
01039 }
01040 
01041 BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
01042 {
01043         LLFastTimer t(LLFastTimer::FTM_UPDATE_PRIMITIVES);
01044         
01045         if (mVolumeImpl != NULL)
01046         {
01047                 LLFastTimer t(LLFastTimer::FTM_GEN_FLEX);
01048                 BOOL res = mVolumeImpl->doUpdateGeometry(drawable);
01049                 updateFaceFlags();
01050                 return res;
01051         }
01052         
01053         BOOL compiled = FALSE;
01054                         
01055         updateRelativeXform();
01056         
01057         if (mDrawable.isNull()) // Not sure why this is happening, but it is...
01058         {
01059                 return TRUE; // No update to complete
01060         }
01061 
01062         if (mVolumeChanged || mFaceMappingChanged )
01063         {
01064                 compiled = TRUE;
01065                 mInited = TRUE;
01066 
01067                 if (mVolumeChanged)
01068                 {
01069                         LLFastTimer ftm(LLFastTimer::FTM_GEN_VOLUME);
01070                         LLVolumeParams volume_params = getVolume()->getParams();
01071                         setVolume(volume_params, 0);
01072                         drawable->setState(LLDrawable::REBUILD_VOLUME);
01073                 }
01074 
01075                 {
01076                         LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES);
01077                         regenFaces();
01078                         genBBoxes(FALSE);
01079                 }
01080         }
01081         else if ((mLODChanged) || (mSculptChanged))
01082         {
01083                 LLPointer<LLVolume> old_volumep, new_volumep;
01084                 F32 old_lod, new_lod;
01085 
01086                 old_volumep = getVolume();
01087                 old_lod = old_volumep->getDetail();
01088 
01089                 {
01090                         LLFastTimer ftm(LLFastTimer::FTM_GEN_VOLUME);
01091                         LLVolumeParams volume_params = getVolume()->getParams();
01092                         setVolume(volume_params, 0);
01093                 }
01094                 new_volumep = getVolume();
01095                 new_lod = new_volumep->getDetail();
01096 
01097                 if ((new_lod != old_lod) || mSculptChanged)
01098                 {
01099                         compiled = TRUE;
01100                         sNumLODChanges += getVolume()->getNumFaces();
01101         
01102                         drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
01103 
01104                         {
01105                                 LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES);
01106                                 if (new_volumep->getNumFaces() != old_volumep->getNumFaces())
01107                                 {
01108                                         regenFaces();
01109                                 }
01110                                 genBBoxes(FALSE);
01111                         }
01112                 }
01113         }
01114         // it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
01115         else
01116         {
01117                 compiled = TRUE;
01118                 // All it did was move or we changed the texture coordinate offset
01119                 LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES);
01120                 genBBoxes(FALSE);
01121         }
01122 
01123         // Update face flags
01124         updateFaceFlags();
01125         
01126         if(compiled)
01127         {
01128                 LLPipeline::sCompiles++;
01129         }
01130         
01131         mVolumeChanged = FALSE;
01132         mLODChanged = FALSE;
01133         mSculptChanged = FALSE;
01134         mFaceMappingChanged = FALSE;
01135 
01136         return LLViewerObject::updateGeometry(drawable);
01137 }
01138 
01139 void LLVOVolume::updateFaceSize(S32 idx)
01140 {
01141         LLFace* facep = mDrawable->getFace(idx);
01142         if (idx >= getVolume()->getNumVolumeFaces())
01143         {
01144                 facep->setSize(0,0);
01145         }
01146         else
01147         {
01148                 const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
01149                 facep->setSize(vol_face.mVertices.size(), vol_face.mIndices.size());
01150         }
01151 }
01152 
01153 BOOL LLVOVolume::isRootEdit() const
01154 {
01155         if (mParent && !((LLViewerObject*)mParent)->isAvatar())
01156         {
01157                 return FALSE;
01158         }
01159         return TRUE;
01160 }
01161 
01162 void LLVOVolume::setTEImage(const U8 te, LLViewerImage *imagep)
01163 {
01164         BOOL changed = (mTEImages[te] != imagep);
01165         LLViewerObject::setTEImage(te, imagep);
01166         if (changed)
01167         {
01168                 gPipeline.markTextured(mDrawable);
01169                 mFaceMappingChanged = TRUE;
01170         }
01171 }
01172 
01173 S32 LLVOVolume::setTETexture(const U8 te, const LLUUID &uuid)
01174 {
01175         S32 res = LLViewerObject::setTETexture(te, uuid);
01176         if (res)
01177         {
01178                 gPipeline.markTextured(mDrawable);
01179                 mFaceMappingChanged = TRUE;
01180         }
01181         return res;
01182 }
01183 
01184 S32 LLVOVolume::setTEColor(const U8 te, const LLColor4 &color)
01185 {
01186         S32 res = LLViewerObject::setTEColor(te, color);
01187         if (res)
01188         {
01189                 gPipeline.markTextured(mDrawable);
01190                 mFaceMappingChanged = TRUE;
01191         }
01192         return  res;
01193 }
01194 
01195 S32 LLVOVolume::setTEBumpmap(const U8 te, const U8 bumpmap)
01196 {
01197         S32 res = LLViewerObject::setTEBumpmap(te, bumpmap);
01198         if (res)
01199         {
01200                 gPipeline.markTextured(mDrawable);
01201                 mFaceMappingChanged = TRUE;
01202         }
01203         return  res;
01204 }
01205 
01206 S32 LLVOVolume::setTETexGen(const U8 te, const U8 texgen)
01207 {
01208         S32 res = LLViewerObject::setTETexGen(te, texgen);
01209         if (res)
01210         {
01211                 gPipeline.markTextured(mDrawable);
01212                 mFaceMappingChanged = TRUE;
01213         }
01214         return  res;
01215 }
01216 
01217 S32 LLVOVolume::setTEShiny(const U8 te, const U8 shiny)
01218 {
01219         S32 res = LLViewerObject::setTEShiny(te, shiny);
01220         if (res)
01221         {
01222                 gPipeline.markTextured(mDrawable);
01223                 mFaceMappingChanged = TRUE;
01224         }
01225         return  res;
01226 }
01227 
01228 S32 LLVOVolume::setTEFullbright(const U8 te, const U8 fullbright)
01229 {
01230         S32 res = LLViewerObject::setTEFullbright(te, fullbright);
01231         if (res)
01232         {
01233                 gPipeline.markTextured(mDrawable);
01234                 mFaceMappingChanged = TRUE;
01235         }
01236         return  res;
01237 }
01238 
01239 S32 LLVOVolume::setTEMediaFlags(const U8 te, const U8 media_flags)
01240 {
01241         S32 res = LLViewerObject::setTEMediaFlags(te, media_flags);
01242         if (res)
01243         {
01244                 gPipeline.markTextured(mDrawable);
01245                 mFaceMappingChanged = TRUE;
01246         }
01247         return  res;
01248 }
01249 
01250 S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t)
01251 {
01252         S32 res = LLViewerObject::setTEScale(te, s, t);
01253         if (res)
01254         {
01255                 gPipeline.markTextured(mDrawable);
01256                 mFaceMappingChanged = TRUE;
01257         }
01258         return res;
01259 }
01260 
01261 S32 LLVOVolume::setTEScaleS(const U8 te, const F32 s)
01262 {
01263         S32 res = LLViewerObject::setTEScaleS(te, s);
01264         if (res)
01265         {
01266                 gPipeline.markTextured(mDrawable);
01267                 mFaceMappingChanged = TRUE;
01268         }
01269         return res;
01270 }
01271 
01272 S32 LLVOVolume::setTEScaleT(const U8 te, const F32 t)
01273 {
01274         S32 res = LLViewerObject::setTEScaleT(te, t);
01275         if (res)
01276         {
01277                 gPipeline.markTextured(mDrawable);
01278                 mFaceMappingChanged = TRUE;
01279         }
01280         return res;
01281 }
01282 
01283 void LLVOVolume::updateTEData()
01284 {
01285         if (mDrawable.notNull())
01286         {
01287                 mFaceMappingChanged = TRUE;
01288                 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_MATERIAL, TRUE);
01289         }
01290 }
01291 
01292 //----------------------------------------------------------------------------
01293 
01294 void LLVOVolume::setIsLight(BOOL is_light)
01295 {
01296         if (is_light != getIsLight())
01297         {
01298                 if (is_light)
01299                 {
01300                         setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, TRUE, true);
01301                 }
01302                 else
01303                 {
01304                         setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, FALSE, true);
01305                 }
01306 
01307                 if (is_light)
01308                 {
01309                         // Add it to the pipeline mLightSet
01310                         gPipeline.setLight(mDrawable, TRUE);
01311                 }
01312                 else
01313                 {
01314                         // Not a light.  Remove it from the pipeline's light set.
01315                         gPipeline.setLight(mDrawable, FALSE);
01316                         
01317                         // Remove this object from any object which has it as a light
01318                         if (mDrawable)
01319                         {
01320                                 mDrawable->clearLightSet();
01321                         }
01322                 }
01323         }
01324 }
01325 
01326 void LLVOVolume::setLightColor(const LLColor3& color)
01327 {
01328         LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
01329         if (param_block)
01330         {
01331                 if (param_block->getColor() != color)
01332                 {
01333                         param_block->setColor(LLColor4(color, param_block->getColor().mV[3]));
01334                         parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
01335                         gPipeline.markTextured(mDrawable);
01336                         mFaceMappingChanged = TRUE;
01337                 }
01338         }
01339 }
01340 
01341 void LLVOVolume::setLightIntensity(F32 intensity)
01342 {
01343         LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
01344         if (param_block)
01345         {
01346                 if (param_block->getColor().mV[3] != intensity)
01347                 {
01348                         param_block->setColor(LLColor4(LLColor3(param_block->getColor()), intensity));
01349                         parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
01350                 }
01351         }
01352 }
01353 
01354 void LLVOVolume::setLightRadius(F32 radius)
01355 {
01356         LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
01357         if (param_block)
01358         {
01359                 if (param_block->getRadius() != radius)
01360                 {
01361                         param_block->setRadius(radius);
01362                         parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
01363                 }
01364         }
01365 }
01366 
01367 void LLVOVolume::setLightFalloff(F32 falloff)
01368 {
01369         LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
01370         if (param_block)
01371         {
01372                 if (param_block->getFalloff() != falloff)
01373                 {
01374                         param_block->setFalloff(falloff);
01375                         parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
01376                 }
01377         }
01378 }
01379 
01380 void LLVOVolume::setLightCutoff(F32 cutoff)
01381 {
01382         LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
01383         if (param_block)
01384         {
01385                 if (param_block->getCutoff() != cutoff)
01386                 {
01387                         param_block->setCutoff(cutoff);
01388                         parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
01389                 }
01390         }
01391 }
01392 
01393 //----------------------------------------------------------------------------
01394 
01395 BOOL LLVOVolume::getIsLight() const
01396 {
01397         return getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT);
01398 }
01399 
01400 LLColor3 LLVOVolume::getLightBaseColor() const
01401 {
01402         const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
01403         if (param_block)
01404         {
01405                 return LLColor3(param_block->getColor());
01406         }
01407         else
01408         {
01409                 return LLColor3(1,1,1);
01410         }
01411 }
01412 
01413 LLColor3 LLVOVolume::getLightColor() const
01414 {
01415         const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
01416         if (param_block)
01417         {
01418                 return LLColor3(param_block->getColor()) * param_block->getColor().mV[3];
01419         }
01420         else
01421         {
01422                 return LLColor3(1,1,1);
01423         }
01424 }
01425 
01426 F32 LLVOVolume::getLightIntensity() const
01427 {
01428         const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
01429         if (param_block)
01430         {
01431                 return param_block->getColor().mV[3];
01432         }
01433         else
01434         {
01435                 return 1.f;
01436         }
01437 }
01438 
01439 F32 LLVOVolume::getLightRadius() const
01440 {
01441         const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
01442         if (param_block)
01443         {
01444                 return param_block->getRadius();
01445         }
01446         else
01447         {
01448                 return 0.f;
01449         }
01450 }
01451 
01452 F32 LLVOVolume::getLightFalloff() const
01453 {
01454         const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
01455         if (param_block)
01456         {
01457                 return param_block->getFalloff();
01458         }
01459         else
01460         {
01461                 return 0.f;
01462         }
01463 }
01464 
01465 F32 LLVOVolume::getLightCutoff() const
01466 {
01467         const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
01468         if (param_block)
01469         {
01470                 return param_block->getCutoff();
01471         }
01472         else
01473         {
01474                 return 0.f;
01475         }
01476 }
01477 
01478 //----------------------------------------------------------------------------
01479 
01480 // returns < 0 if inside radius
01481 F32 LLVOVolume::getLightDistance(const LLVector3& pos) const
01482 {
01483         LLVector3 dpos = getRenderPosition() - pos;
01484         F32 dist = dpos.magVec() - getLightRadius();
01485         return dist;
01486 }
01487 
01488 // returns intensity, modifies color in result
01489 F32 LLVOVolume::calcLightAtPoint(const LLVector3& pos, const LLVector3& norm, LLColor4& result)
01490 {
01491         if (!getIsLight())
01492         {
01493                 return 0.0f;
01494         }
01495         F32 light_radius = getLightRadius();
01496         LLVector3 light_pos = getRenderPosition();
01497         LLVector3 light_dir = light_pos - pos;
01498         F32 dist = light_dir.normVec();
01499         F32 dp = norm * light_dir;
01500         if ((gPipeline.getLightingDetail() > 2))
01501         {
01502                 if (dp <= 0)
01503                 {
01504                         result *= 0;
01505                         return 0;
01506                 }
01507 
01508                 if (dist >= light_radius)
01509                 {
01510                         result *= 0;
01511                         return 0;
01512                 }
01513 
01514                 F32 mag = 1.0f-(dist/light_radius);
01515                 mag = powf(mag, 0.75f);
01516                 mag *= dp;
01517                 result = getLightColor() * mag;
01518                 return mag;
01519         }
01520         else
01521         {
01522                 F32 light_radius = getLightRadius();
01523                 LLVector3 light_pos = getRenderPosition();
01524                 LLVector3 light_dir = light_pos - pos;
01525                 F32 dist = light_dir.normVec();
01526                 F32 dp = norm * light_dir;
01527                 F32 atten = (1.f/.2f) / (light_radius); // 20% of brightness at radius
01528                 F32 falloff = 1.f / (dist * atten);
01529                 F32 mag = falloff * dp;
01530                 mag = llmax(mag, 0.0f);
01531                 result = getLightColor() * mag;
01532                 return mag;
01533         }
01534 }
01535 
01536 BOOL LLVOVolume::updateLighting(BOOL do_lighting)
01537 {
01538         LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
01539 #if 0
01540         if (mDrawable->isStatic())
01541         {
01542                 do_lighting = FALSE;
01543         }
01544 
01545         const LLMatrix4& mat_vert  = mDrawable->getWorldMatrix();
01546         const LLMatrix3& mat_normal = LLMatrix3(mDrawable->getWorldRotation());
01547         
01548         LLVolume* volume = getVolume();
01549 
01550         for (S32 i = 0; i < volume->getNumFaces(); i++)
01551         {
01552                 LLFace *face = mDrawable->getFace(i);
01553                 if (face && face->getGeomCount())
01554                 {
01555                         face->genLighting(volume, mDrawable, i, i, mat_vert, mat_normal, do_lighting);
01556                 }
01557         }               
01558 #endif
01559         return TRUE;
01560 }
01561 
01562 //----------------------------------------------------------------------------
01563 
01564 U32 LLVOVolume::getVolumeInterfaceID() const
01565 {
01566         if (mVolumeImpl)
01567         {
01568                 return mVolumeImpl->getID();
01569         }
01570 
01571         return 0;
01572 }
01573 
01574 BOOL LLVOVolume::isFlexible() const
01575 {
01576         if (getParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE))
01577         {
01578                 if (getVolume()->getParams().getPathParams().getCurveType() != LL_PCODE_PATH_FLEXIBLE)
01579                 {
01580                         LLVolumeParams volume_params = getVolume()->getParams();
01581                         U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
01582                         volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE);
01583                 }
01584                 return TRUE;
01585         }
01586         else
01587         {
01588                 return FALSE;
01589         }
01590 }
01591 
01592 BOOL LLVOVolume::isSculpted() const
01593 {
01594         if (getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT))
01595         {
01596                 return TRUE;
01597         }
01598         
01599         return FALSE;
01600 }
01601 
01602 BOOL LLVOVolume::isVolumeGlobal() const
01603 {
01604         if (mVolumeImpl)
01605         {
01606                 return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE;
01607         }
01608         return FALSE;
01609 }
01610 
01611 BOOL LLVOVolume::canBeFlexible() const
01612 {
01613         U8 path = getVolume()->getParams().getPathParams().getCurveType();
01614         return (path == LL_PCODE_PATH_FLEXIBLE || path == LL_PCODE_PATH_LINE);
01615 }
01616 
01617 BOOL LLVOVolume::setIsFlexible(BOOL is_flexible)
01618 {
01619         BOOL res = FALSE;
01620         BOOL was_flexible = isFlexible();
01621         LLVolumeParams volume_params;
01622         if (is_flexible)
01623         {
01624                 if (!was_flexible)
01625                 {
01626                         volume_params = getVolume()->getParams();
01627                         U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
01628                         volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE);
01629                         res = TRUE;
01630                         setFlags(FLAGS_USE_PHYSICS, FALSE);
01631                         setFlags(FLAGS_PHANTOM, TRUE);
01632                         setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, true);
01633                         if (mDrawable)
01634                         {
01635                                 mDrawable->makeActive();
01636                         }
01637                 }
01638         }
01639         else
01640         {
01641                 if (was_flexible)
01642                 {
01643                         volume_params = getVolume()->getParams();
01644                         U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
01645                         volume_params.setType(profile_and_hole, LL_PCODE_PATH_LINE);
01646                         res = TRUE;
01647                         setFlags(FLAGS_PHANTOM, FALSE);
01648                         setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, true);
01649                 }
01650         }
01651         if (res)
01652         {
01653                 res = setVolume(volume_params, 1);
01654                 if (res)
01655                 {
01656                         markForUpdate(TRUE);
01657                 }
01658         }
01659         return res;
01660 }
01661 
01662 //----------------------------------------------------------------------------
01663 
01664 void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point)
01665 {
01666         LLVolume *volume = getVolume();
01667 
01668         if (volume)
01669         {
01670                 LLVector3 view_vector;
01671                 view_vector = view_point; 
01672 
01673                 //transform view vector into volume space
01674                 view_vector -= getRenderPosition();
01675                 mDrawable->mDistanceWRTCamera = view_vector.magVec();
01676                 LLQuaternion worldRot = getRenderRotation();
01677                 view_vector = view_vector * ~worldRot;
01678                 if (!isVolumeGlobal())
01679                 {
01680                         LLVector3 objScale = getScale();
01681                         LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
01682                         view_vector.scaleVec(invObjScale);
01683                 }
01684                 
01685                 updateRelativeXform();
01686                 volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, mRelativeXform, mRelativeXformInvTrans);
01687 
01688                 nodep->mSilhouetteExists = TRUE;
01689         }
01690 }
01691 
01692 void LLVOVolume::deleteFaces()
01693 {
01694         S32 face_count = mNumFaces;
01695         if (mDrawable.notNull())
01696         {
01697                 mDrawable->deleteFaces(0, face_count);
01698         }
01699 
01700         mNumFaces = 0;
01701 }
01702 
01703 void LLVOVolume::updateRadius()
01704 {
01705         if (mDrawable.isNull())
01706         {
01707                 return;
01708         }
01709         
01710         mVObjRadius = getScale().magVec();
01711         mDrawable->setRadius(mVObjRadius);
01712 }
01713 
01714 
01715 BOOL LLVOVolume::isAttachment() const
01716 {
01717         if (mState == 0)
01718         {
01719                 return FALSE;
01720         }
01721         else
01722         {
01723                 return TRUE;
01724         }
01725 }
01726 
01727 BOOL LLVOVolume::isHUDAttachment() const
01728 {
01729         // *NOTE: we assume hud attachment points are in defined range
01730         // since this range is constant for backwards compatibility
01731         // reasons this is probably a reasonable assumption to make
01732         S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState);
01733         return ( attachment_id >= 31 && attachment_id <= 38 );
01734 }
01735 
01736 
01737 const LLMatrix4 LLVOVolume::getRenderMatrix() const
01738 {
01739         if (mDrawable->isActive() && !mDrawable->isRoot())
01740         {
01741                 return mDrawable->getParent()->getWorldMatrix();
01742         }
01743         return mDrawable->getWorldMatrix();
01744 }
01745 
01746 void 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)
01747 {
01748 #if 0
01749         LLImageTGA tga_image;
01750 
01751         if (mDrawable.isNull())
01752         {
01753                 return;
01754         }
01755 
01756         LLVector3 final_pos = getPosition();
01757         final_pos *= 100.f;
01758 
01759         final_pos = final_pos * rot;
01760         final_pos += pos;
01761         LLQuaternion final_rot;
01762         final_rot = getRotation() * rot;
01763         LLMatrix4 transform;
01764         transform.initAll(getScale(), final_rot, final_pos);
01765 
01766         LLMatrix4 int_transpose_transform;
01767         int_transpose_transform.initAll(LLVector3(1.f / getScale().mV[VX], 1.f / getScale().mV[VY], 1.f / getScale().mV[VZ]), final_rot, LLVector3::zero);
01768 
01769         for (S32 i = 0; i < mDrawable->getNumFaces(); i++)
01770         {
01771                 S32 vert_num = 0;
01772                 LLFace* facep = mDrawable->getFace(i);
01773                 LLDrawPool* poolp = facep->getPool();
01774 
01775                 const LLTextureEntry* tep = facep->getTextureEntry();
01776                 if (!tep)
01777                 {
01778                         continue;
01779                 }
01780 
01781                 S32 my_material = -1;
01782                 S32 my_texture = -1;
01783                 LLColor4 face_color = tep->getColor();
01784 
01785                 typedef std::multimap<LLUUID, LLMaterialExportInfo*>::iterator material_it_t;
01786                 std::pair<material_it_t, material_it_t> found_range = material_map.equal_range(tep->getID());
01787                 material_it_t material_it = found_range.first;
01788 
01789                 LLMaterialExportInfo* material_info = NULL;
01790 
01791                 while(material_it != material_map.end() && material_it != found_range.second)
01792                 {
01793                         // we've at least found a matching texture, so reuse it
01794                         my_texture = material_it->second->mTextureIndex;
01795                         if (material_it->second->mColor == face_color)
01796                         {
01797                                 // we've found a matching material
01798                                 material_info = material_it->second;
01799                         }
01800                         ++material_it;
01801                 }
01802 
01803                 if (material_info)
01804                 {
01805                         // material already exported, just reuse it
01806                         my_material = material_info->mMaterialIndex;
01807                         my_texture = material_info->mTextureIndex;
01808                 }
01809                 else
01810                 {
01811                         // reserve new material number
01812                         my_material = material_index++;
01813 
01814                         // if we didn't already find a matching texture...
01815                         if (my_texture == -1)
01816                         {
01817                                 //...use the next available slot...
01818                                 my_texture = texture_index++;
01819 
01820                                 //...and export texture as image file
01821                                 char filename[MAX_PATH];                /* Flawfinder: ignore */
01822                                 snprintf(filename, MAX_PATH, "%s\\%s_material_tex_%d.tga", path.c_str(), file_base.c_str(), my_texture);                /* Flawfinder: ignore */
01823 
01824                                 LLViewerImage* imagep = facep->getTexture();
01825                                 if (imagep->getTexName() == 0)
01826                                 {
01827                                         llinfos << "No image data available for " << filename << llendl;
01828                                         continue;
01829                                 }
01830                                 LLImageRaw raw_image;
01831                                 imagep->readBackRaw(-1, raw_image);
01832                                 BOOL success = tga_image.encode(raw_image);
01833                                 success = tga_image.save(filename);
01834                         }
01835 
01836                         material_info = new LLMaterialExportInfo(my_material, my_texture, face_color);
01837                         material_map.insert(std::make_pair<LLUUID, LLMaterialExportInfo*>(tep->getID(), material_info));
01838                 }
01839 
01840                 apr_file_printf(fp, "\t<SUBMESH NUMVERTICES=\"%d\" NUMFACES=\"%d\" MATERIAL=\"%d\" NUMLODSTEPS=\"0\" NUMSPRINGS=\"0\" NUMTEXCOORDS=\"1\">\n", 
01841                         facep->getGeomCount(), facep->getIndicesCount() / 3, my_material);
01842 
01843                 for (S32 vert_index = 0; vert_index < facep->getGeomCount(); vert_index++)
01844                 {
01845                         LLVector3 vert_pos = poolp->getVertex(facep->getGeomStart() + vert_index);
01846                         vert_pos *= 100.f;
01847                         vert_pos = vert_pos * transform;
01848                         LLVector3 vert_norm = poolp->getNormal(facep->getGeomStart() + vert_index);
01849                         vert_norm = vert_norm * int_transpose_transform;
01850                         LLVector2 vert_tc = poolp->getTexCoord(facep->getGeomStart() + vert_index, 0);
01851                         apr_file_printf(fp, "           <VERTEX ID=\"%d\" NUMINFLUENCES=\"1\">\n", vert_num++);
01852                         apr_file_printf(fp, "                   <POS>%.4f %.4f %.4f</POS>\n", vert_pos.mV[VX], vert_pos.mV[VY], vert_pos.mV[VZ]);
01853                         apr_file_printf(fp, "                   <NORM>%.6f %.6f %.6f</NORM>\n", vert_norm.mV[VX], vert_norm.mV[VY], vert_norm.mV[VZ]);
01854                         apr_file_printf(fp, "                   <TEXCOORD>%.6f %.6f</TEXCOORD>\n", vert_tc.mV[VX], 1.f - vert_tc.mV[VY]);
01855                         apr_file_printf(fp, "                   <INFLUENCE ID=\"%d\">1.0</INFLUENCE>\n", joint_num + 1);
01856                         apr_file_printf(fp, "           </VERTEX>\n");
01857                 }
01858 
01859                 for (U32 index_i = 0; index_i < facep->getIndicesCount(); index_i += 3)
01860                 {
01861                         U32 index_a = poolp->getIndex(facep->getIndicesStart() + index_i) - facep->getGeomStart();
01862                         U32 index_b = poolp->getIndex(facep->getIndicesStart() + index_i + 1) - facep->getGeomStart();
01863                         U32 index_c = poolp->getIndex(facep->getIndicesStart() + index_i + 2) - facep->getGeomStart();
01864                         apr_file_printf(fp, "           <FACE VERTEXID=\"%d %d %d\" />\n", index_a, index_b, index_c);
01865                 }
01866 
01867                 apr_file_printf(fp, "   </SUBMESH>\n");
01868         }
01869         
01870         for (U32 i = 0; i < mChildList.size(); i++)
01871         {
01872                 ((LLVOVolume*)(LLViewerObject*)mChildList[i])->writeCAL3D(fp, path, file_base, joint_num, final_pos, final_rot, material_index, texture_index, material_map);
01873         }
01874 #endif
01875 }
01876 
01877 //static
01878 void LLVOVolume::preUpdateGeom()
01879 {
01880         sNumLODChanges = 0;
01881 }
01882 
01883 void LLVOVolume::parameterChanged(U16 param_type, bool local_origin)
01884 {
01885         LLViewerObject::parameterChanged(param_type, local_origin);
01886 }
01887 
01888 void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin)
01889 {
01890         LLViewerObject::parameterChanged(param_type, data, in_use, local_origin);
01891         if (mVolumeImpl)
01892         {
01893                 mVolumeImpl->onParameterChanged(param_type, data, in_use, local_origin);
01894         }
01895         if (mDrawable.notNull())
01896         {
01897                 BOOL is_light = getIsLight();
01898                 if (is_light != mDrawable->isState(LLDrawable::LIGHT))
01899                 {
01900                         gPipeline.setLight(mDrawable, is_light);
01901                 }
01902         }
01903 }
01904 
01905 void LLVOVolume::setSelected(BOOL sel)
01906 {
01907         LLViewerObject::setSelected(sel);
01908         if (mDrawable.notNull())
01909         {
01910                 mDrawable->movePartition();
01911         }
01912 }
01913 
01914 void LLVOVolume::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
01915 {               
01916 }
01917 
01918 F32 LLVOVolume::getBinRadius()
01919 {
01920         F32 radius;
01921         
01922         const LLVector3* ext = mDrawable->getSpatialExtents();
01923         
01924         BOOL shrink_wrap = mDrawable->isAnimating();
01925         BOOL alpha_wrap = FALSE;
01926 
01927         if (!isHUDAttachment())
01928         {
01929                 for (S32 i = 0; i < mDrawable->getNumFaces(); i++)
01930                 {
01931                         if (mDrawable->getFace(i)->getPoolType() == LLDrawPool::POOL_ALPHA)
01932                         {
01933                                 alpha_wrap = TRUE;
01934                                 break;
01935                         }
01936                 }
01937         }
01938         else
01939         {
01940                 shrink_wrap = FALSE;
01941         }
01942 
01943         if (alpha_wrap)
01944         {
01945                 LLVector3 bounds = getScale();
01946                 radius = llmin(bounds.mV[1], bounds.mV[2]);
01947                 radius = llmin(radius, bounds.mV[0]);
01948                 radius *= 0.5f;
01949         }
01950         else if (shrink_wrap)
01951         {
01952                 radius = (ext[1]-ext[0]).magVec()*0.5f;
01953         }
01954         else if (mDrawable->isStatic())
01955         {
01956                 radius = 32.f;
01957         }
01958         else
01959         {
01960                 radius = 8.f;
01961         }
01962 
01963         return llclamp(radius, 0.5f, 256.f);
01964 }
01965 
01966 const LLVector3 LLVOVolume::getPivotPositionAgent() const
01967 {
01968         if (mVolumeImpl)
01969         {
01970                 return mVolumeImpl->getPivotPosition();
01971         }
01972         return LLViewerObject::getPivotPositionAgent();
01973 }
01974 
01975 void LLVOVolume::onShift(const LLVector3 &shift_vector)
01976 {
01977         if (mVolumeImpl)
01978         {
01979                 mVolumeImpl->onShift(shift_vector);
01980         }
01981 
01982         updateRelativeXform();
01983 }
01984 
01985 const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const
01986 {
01987         if (mVolumeImpl)
01988         {
01989                 return mVolumeImpl->getWorldMatrix(xform);
01990         }
01991         return xform->getWorldMatrix();
01992 }
01993 
01994 LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const
01995 {
01996         LLVector3 ret = pos - getRenderPosition();
01997         ret = ret * ~getRenderRotation();
01998         LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale();
01999         LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
02000         ret.scaleVec(invObjScale);
02001         
02002         return ret;
02003 }
02004 
02005 LLVector3 LLVOVolume::agentDirectionToVolume(const LLVector3& dir) const
02006 {
02007         return dir * ~getRenderRotation();
02008 }
02009 
02010 LLVector3 LLVOVolume::volumePositionToAgent(const LLVector3& dir) const
02011 {
02012         LLVector3 ret = dir;
02013         ret.scaleVec(getScale());
02014         ret = ret * getRenderRotation();
02015         ret += getRenderPosition();
02016         
02017         return ret;
02018 }
02019 
02020 BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, LLVector3& end) const
02021 {
02022         return FALSE;
02023         
02024 #if 0 // needs to be rewritten to use face extents instead of volume bounds
02025         LLVolume* volume = getVolume();
02026         BOOL ret = FALSE;
02027         if (volume)
02028         {       
02029                 LLVector3 v_start, v_end, v_dir;
02030         
02031                 v_start = agentPositionToVolume(start);
02032                 v_end = agentPositionToVolume(end);
02033                 
02034                 if (LLLineSegmentAABB(v_start, v_end, volume->mBounds[0], volume->mBounds[1]))
02035                 {
02036                         if (volume->lineSegmentIntersect(v_start, v_end) >= 0)
02037                         {
02038                                 end = volumePositionToAgent(v_end);
02039                                 ret = TRUE;
02040                         }
02041                 }
02042         }
02043         return ret;
02044 #endif
02045 }
02046 
02047 U32 LLVOVolume::getPartitionType() const
02048 {
02049         if (isHUDAttachment())
02050         {
02051                 return LLPipeline::PARTITION_HUD;
02052         }
02053 
02054         return LLPipeline::PARTITION_VOLUME;
02055 }
02056 
02057 LLVolumePartition::LLVolumePartition()
02058 : LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, FALSE)
02059 {
02060         mLODPeriod = 16;
02061         mDepthMask = FALSE;
02062         mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
02063         mPartitionType = LLPipeline::PARTITION_VOLUME;
02064         mSlopRatio = 0.25f;
02065         mBufferUsage = GL_DYNAMIC_DRAW_ARB;
02066         mImageEnabled = TRUE;
02067 }
02068 
02069 LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep)
02070 : LLSpatialBridge(drawablep, LLVOVolume::VERTEX_DATA_MASK)
02071 {
02072         mDepthMask = FALSE;
02073         mLODPeriod = 16;
02074         mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
02075         mPartitionType = LLPipeline::PARTITION_BRIDGE;
02076         
02077         mBufferUsage = GL_DYNAMIC_DRAW_ARB;
02078 
02079         mSlopRatio = 0.25f;
02080 }
02081 
02082 void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
02083 {
02084         LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
02085 
02086         if (facep->getViewerObject()->isSelected() && gHideSelectedObjects)
02087         {
02088                 return;
02089         }
02090 
02091         //add face to drawmap
02092         LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[type];       
02093 
02094         S32 idx = draw_vec.size()-1;
02095 
02096 
02097         BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT ||
02098                                           type == LLRenderPass::PASS_ALPHA) ? facep->isState(LLFace::FULLBRIGHT) : FALSE;
02099 
02100         const LLMatrix4* tex_mat = NULL;
02101         if (type != LLRenderPass::PASS_SHINY && facep->isState(LLFace::TEXTURE_ANIM))
02102         {
02103                 tex_mat = &(facep->mTextureMatrix);     
02104         }
02105 
02106         U8 bump = (type == LLRenderPass::PASS_BUMP ? facep->getTextureEntry()->getBumpmap() : 0);
02107         
02108         //LLViewerImage* tex = facep->mAppAngle < FORCE_SIMPLE_RENDER_ANGLE ? NULL : facep->getTexture();
02109         LLViewerImage* tex = facep->getTexture();
02110 
02111         if (type == LLRenderPass::PASS_GLOW)
02112         {
02113                 U32 start = facep->getGeomIndex();
02114                 U32 end = start + facep->getGeomCount()-1;
02115                 U32 offset = facep->getIndicesStart();
02116                 U32 count = facep->getIndicesCount();
02117                 LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset,tex, 
02118                         facep->mVertexBuffer, fullbright, bump); 
02119                 draw_info->mVSize = facep->getVirtualSize();
02120                 draw_vec.push_back(draw_info);
02121                 LLVOVolume* volume = (LLVOVolume*) facep->getViewerObject();
02122                 BOOL is_light = volume->mDrawable->isLight();
02123 
02124                 U8 alpha = is_light ? 196 : 160;
02125                 LLColor3 col = is_light ? volume->getLightColor() : LLColor3(0,0,0);
02126                 LLColor4 col2 = facep->getRenderColor();
02127                 draw_info->mGlowColor.setVec((U8) (col.mV[0]*col2.mV[0]*255),
02128                                                                         (U8) (col.mV[1]*col2.mV[1]*255),
02129                                                                         (U8) (col.mV[2]*col2.mV[2]*255),
02130                                                                         alpha);                                 
02131                 draw_info->mTextureMatrix = tex_mat;
02132                 validate_draw_info(*draw_info);
02133         }
02134         else if (idx >= 0 && 
02135                 draw_vec[idx]->mVertexBuffer == facep->mVertexBuffer &&
02136                 draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
02137                 draw_vec[idx]->mTexture == tex &&
02138 #if LL_DARWIN
02139                 draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
02140                 draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
02141 #endif
02142                 draw_vec[idx]->mFullbright == fullbright &&
02143                 draw_vec[idx]->mBump == bump &&
02144                 draw_vec[idx]->mTextureMatrix == tex_mat)
02145         {
02146                 draw_vec[idx]->mCount += facep->getIndicesCount();
02147                 draw_vec[idx]->mEnd += facep->getGeomCount();
02148                 draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
02149                 validate_draw_info(*draw_vec[idx]);
02150         }
02151         else
02152         {
02153                 U32 start = facep->getGeomIndex();
02154                 U32 end = start + facep->getGeomCount()-1;
02155                 U32 offset = facep->getIndicesStart();
02156                 U32 count = facep->getIndicesCount();
02157                 LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset,tex, 
02158                         facep->mVertexBuffer, fullbright, bump); 
02159                 draw_info->mVSize = facep->getVirtualSize();
02160                 draw_vec.push_back(draw_info);
02161                 draw_info->mReflectionMap = group->mReflectionMap;
02162                 draw_info->mTextureMatrix = tex_mat;
02163                 validate_draw_info(*draw_info);
02164         }
02165 }
02166 
02167 void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
02168 {
02169 
02170 }
02171 
02172 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
02173 {
02174         if (group->changeLOD())
02175         {
02176                 group->mLastUpdateDistance = group->mDistance;
02177         }
02178 
02179         group->mLastUpdateViewAngle = group->mViewAngle;
02180 
02181         if (!group->isState(LLSpatialGroup::GEOM_DIRTY |
02182                                                 LLSpatialGroup::ALPHA_DIRTY))
02183         {
02184                 return;
02185         }
02186 
02187         group->mBuilt = 1.f;
02188         LLFastTimer ftm(LLFastTimer::FTM_REBUILD_VBO);  
02189 
02190         LLFastTimer ftm2(LLFastTimer::FTM_REBUILD_VOLUME_VB);
02191 
02192         //find reflection map
02193         if (group->mSpatialPartition->mImageEnabled)
02194         {
02195                 if (group->mReflectionMap.isNull())
02196                 {
02197                         LLSpatialGroup* parent = group->getParent();
02198                         while (parent && group->mReflectionMap.isNull())
02199                         {
02200                                 group->mReflectionMap = parent->mReflectionMap;
02201                                 parent = parent->getParent();
02202                         }
02203                 }
02204         }
02205 
02206         group->clearDrawMap();
02207 
02208         mFaceList.clear();
02209 
02210         std::vector<LLFace*> alpha_faces;
02211         U32 vertex_count = 0;
02212         U32 index_count = 0;
02213         U32 useage = group->mSpatialPartition->mBufferUsage;
02214 
02215         //get all the faces into a list, putting alpha faces in their own list
02216         for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
02217         {
02218                 LLDrawable* drawablep = *drawable_iter;
02219                 
02220                 if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
02221                 {
02222                         continue;
02223                 }
02224         
02225                 if (drawablep->isAnimating())
02226                 { //fall back to stream draw for animating verts
02227                         useage = GL_STREAM_DRAW_ARB;
02228                 }
02229 
02230                 LLVOVolume* vobj = drawablep->getVOVolume();
02231 
02232                 //for each face
02233                 for (S32 i = 0; i < drawablep->getNumFaces(); i++)
02234                 {
02235                         //sum up face verts and indices
02236                         drawablep->updateFaceSize(i);
02237                         LLFace* facep = drawablep->getFace(i);
02238                         if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA)
02239                         {
02240                                 const LLTextureEntry* te = facep->getTextureEntry();
02241                                 LLViewerImage* tex = facep->getTexture();
02242 
02243                                 BOOL force_simple = (facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA);
02244                                 U32 type = gPipeline.getPoolTypeFromTE(te, tex);
02245                                 if (type != LLDrawPool::POOL_ALPHA && force_simple)
02246                                 {
02247                                         type = LLDrawPool::POOL_SIMPLE;
02248                                 }
02249                                 facep->setPoolType(type);
02250 
02251                                 if (vobj->isHUDAttachment())
02252                                 {
02253                                         facep->setState(LLFace::FULLBRIGHT);
02254                                 }
02255 
02256                                 if (vobj->mTextureAnimp && vobj->mTexAnimMode)
02257                                 {
02258                                         if (vobj->mTextureAnimp->mFace <= -1)
02259                                         {
02260                                                 S32 face;
02261                                                 for (face = 0; face < vobj->getNumTEs(); face++)
02262                                                 {
02263                                                         drawablep->getFace(face)->setState(LLFace::TEXTURE_ANIM);
02264                                                 }
02265                                         }
02266                                         else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs())
02267                                         {
02268                                                 drawablep->getFace(vobj->mTextureAnimp->mFace)->setState(LLFace::TEXTURE_ANIM);
02269                                         }
02270                                 }
02271 
02272                                 if (type == LLDrawPool::POOL_ALPHA)
02273                                 {
02274                                         vertex_count += facep->getGeomCount();
02275                                         index_count += facep->getIndicesCount();
02276                                         alpha_faces.push_back(facep);
02277                                 }
02278                                 else
02279                                 {
02280                                         if (drawablep->isState(LLDrawable::REBUILD_VOLUME))
02281                                         {
02282                                                 facep->mLastUpdateTime = gFrameTimeSeconds;
02283                                         }
02284                                         mFaceList.push_back(facep);
02285                                 }
02286                         }
02287                         else
02288                         {       //face has no renderable geometry
02289                                 facep->mVertexBuffer = NULL;
02290                                 facep->mLastVertexBuffer = NULL;
02291                                 //don't alpha wrap drawables that have only tiny tiny alpha faces
02292                                 facep->setPoolType(LLDrawPool::POOL_SIMPLE);
02293                         }
02294 
02295                         vobj->updateTextures();
02296                 }
02297         }
02298 
02299         group->mVertexCount = vertex_count;
02300         group->mIndexCount = index_count;
02301         group->mBufferUsage = useage;
02302 
02303         LLStrider<LLVector3> vertices;
02304         LLStrider<LLVector3> normals;
02305         LLStrider<LLVector2> texcoords2;
02306         LLStrider<LLVector2> texcoords;
02307         LLStrider<LLColor4U> colors;
02308         LLStrider<U32> indices;
02309 
02310         //PROCESS NON-ALPHA FACES
02311         {
02312                 //sort faces by texture
02313                 std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareTextureAndTime());
02314                 
02315                 std::vector<LLFace*>::iterator face_iter = mFaceList.begin();
02316                 
02317                 LLSpatialGroup::buffer_map_t buffer_map;
02318 
02319                 while (face_iter != mFaceList.end())
02320                 {
02321                         //pull off next face
02322                         LLFace* facep = *face_iter;
02323                         LLViewerImage* tex = facep->getTexture();
02324 
02325                         U32 index_count = facep->getIndicesCount();
02326                         U32 geom_count = facep->getGeomCount();
02327 
02328                         //sum up vertices needed for this texture
02329                         std::vector<LLFace*>::iterator i = face_iter;
02330                         ++i;
02331                         while (i != mFaceList.end() && (*i)->getTexture() == tex)
02332                         {
02333                                 facep = *i;
02334                                 ++i;
02335                                 index_count += facep->getIndicesCount();
02336                                 geom_count += facep->getGeomCount();
02337                         }
02338                 
02339                         //create/delete/resize vertex buffer if needed
02340                         LLVertexBuffer* buffer = NULL;
02341                         LLSpatialGroup::buffer_map_t::iterator found_iter = group->mBufferMap.find(tex);
02342                         if (found_iter != group->mBufferMap.end())
02343                         {
02344                                 buffer = found_iter->second;
02345                         }
02346                                                 
02347                         if (!buffer)
02348                         { //create new buffer if needed
02349                                 buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, 
02350                                                                                                 group->mBufferUsage);
02351                                 buffer->allocateBuffer(geom_count, index_count, TRUE);
02352                         }
02353                         else 
02354                         {
02355                                 if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage)
02356                                 {
02357                                         buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, 
02358                                                                                                 group->mBufferUsage);
02359                                         buffer->allocateBuffer(geom_count, index_count, TRUE);
02360                                 }
02361                                 else
02362                                 {
02363                                         buffer->resizeBuffer(geom_count, index_count);
02364                                 }
02365                         }
02366 
02367                         BOOL clean = TRUE;
02368                         buffer_map[tex] = buffer;
02369 
02370                         //add face geometry
02371                 
02372                         //get vertex buffer striders
02373                         buffer->getVertexStrider(vertices);
02374                         buffer->getNormalStrider(normals);
02375                         buffer->getTexCoordStrider(texcoords);
02376                         buffer->getTexCoord2Strider(texcoords2);
02377                         buffer->getColorStrider(colors);
02378                         buffer->getIndexStrider(indices);
02379 
02380                         U32 indices_index = 0;
02381                         U32 index_offset = 0;
02382 
02383                         while (face_iter < i)
02384                         {
02385                                 facep = *face_iter;
02386                                 LLDrawable* drawablep = facep->getDrawable();
02387                                 LLVOVolume* vobj = drawablep->getVOVolume();
02388                                 LLVolume* volume = vobj->getVolume();
02389 
02390                                 U32 te_idx = facep->getTEOffset();
02391                                 facep->mIndicesIndex = indices_index;
02392                                 facep->mGeomIndex = index_offset;
02393                                 facep->mVertexBuffer = buffer;
02394                                 {
02395                                         if (facep->getGeometryVolume(*volume, te_idx, vertices, normals, texcoords, texcoords2, colors, indices, 
02396                                                 vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset))
02397                                         {
02398                                                 clean = FALSE;
02399                                                 buffer->markDirty(facep->getGeomIndex(), facep->getGeomCount(), 
02400                                                         facep->getIndicesStart(), facep->getIndicesCount());
02401                                         }
02402                                 }
02403 
02404                                 indices_index += facep->mIndicesCount;
02405 
02406                                 BOOL force_simple = facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA;
02407                                 BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
02408                                 const LLTextureEntry* te = facep->getTextureEntry();
02409 
02410                                 if (tex->getPrimaryFormat() == GL_ALPHA)
02411                                 {
02412                                         registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
02413                                 }
02414                                 else if (fullbright)
02415                                 {
02416                                         registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
02417                                 }
02418                                 else
02419                                 {
02420                                         registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
02421                                 }
02422 
02423                                 facep->setPoolType(LLDrawPool::POOL_SIMPLE);
02424 
02425                                 if (te->getShiny())
02426                                 {
02427                                         registerFace(group, facep, LLRenderPass::PASS_SHINY);
02428                                 }
02429 
02430                                 if (!force_simple && te->getBumpmap())
02431                                 {
02432                                         registerFace(group, facep, LLRenderPass::PASS_BUMP);
02433                                 }
02434 
02435                                 if (vobj->getIsLight() ||
02436                                         (LLPipeline::sRenderGlow && facep->isState(LLFace::FULLBRIGHT)))
02437                                 {
02438                                         registerFace(group, facep, LLRenderPass::PASS_GLOW);
02439                                 }
02440                                 
02441 
02442                                 ++face_iter;
02443                         }
02444 
02445                         if (clean)
02446                         {
02447                                 buffer->markClean();
02448                         }
02449                 }
02450 
02451                 group->mBufferMap.clear();
02452                 for (LLSpatialGroup::buffer_map_t::iterator i = buffer_map.begin(); i != buffer_map.end(); ++i)
02453                 {
02454                         group->mBufferMap[i->first] = i->second;
02455                 }
02456         }
02457 
02458         //PROCESS ALPHA FACES
02459         if (!alpha_faces.empty())
02460         {
02461                 //sort alpha faces by distance
02462                 std::sort(alpha_faces.begin(), alpha_faces.end(), LLFace::CompareDistanceGreater());
02463 
02464                 //store alpha faces in root vertex buffer
02465                 if (group->mVertexBuffer.isNull() || (LLVertexBuffer::sEnableVBOs && group->mBufferUsage != group->mVertexBuffer->getUsage()))
02466                 {
02467                         group->mVertexBuffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, 
02468                                                                                                           group->mBufferUsage);
02469                         group->mVertexBuffer->allocateBuffer(group->mVertexCount, group->mIndexCount, true);
02470                         stop_glerror();
02471                 }
02472                 else
02473                 {
02474                         group->mVertexBuffer->resizeBuffer(group->mVertexCount, group->mIndexCount);
02475                         stop_glerror();
02476                 }
02477 
02478                 //get vertex buffer striders
02479                 LLVertexBuffer* buffer = group->mVertexBuffer;
02480 
02481                 BOOL clean = TRUE;
02482 
02483                 buffer->getVertexStrider(vertices);
02484                 buffer->getNormalStrider(normals);
02485                 buffer->getTexCoordStrider(texcoords);
02486                 buffer->getTexCoord2Strider(texcoords2);
02487                 buffer->getColorStrider(colors);
02488                 buffer->getIndexStrider(indices);
02489 
02490                 U32 index_offset = 0;
02491                 U32 indices_index = 0;
02492 
02493                 for (std::vector<LLFace*>::iterator i = alpha_faces.begin(); i != alpha_faces.end(); ++i)
02494                 {
02495                         LLFace* facep = *i;
02496                         LLDrawable* drawablep = facep->getDrawable();
02497                         LLVOVolume* vobj = drawablep->getVOVolume();
02498                         LLVolume* volume = vobj->getVolume();
02499 
02500                         U32 te_idx = facep->getTEOffset();
02501                         facep->mIndicesIndex = indices_index;
02502                         facep->mGeomIndex = index_offset;
02503                         facep->mVertexBuffer = group->mVertexBuffer;
02504                         if (facep->getGeometryVolume(*volume, te_idx, vertices, normals, texcoords, texcoords2, colors, indices, 
02505                                 vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset))
02506                         {
02507                                 clean = FALSE;
02508                                 buffer->markDirty(facep->getGeomIndex(), facep->getGeomCount(), 
02509                                         facep->getIndicesStart(), facep->getIndicesCount());
02510                         }
02511 
02512                         indices_index += facep->mIndicesCount;
02513 
02514                         registerFace(group, facep, LLRenderPass::PASS_ALPHA);
02515                 }
02516 
02517                 if (clean)
02518                 {
02519                         buffer->markClean();
02520                 }
02521         }
02522         else
02523         {
02524                 group->mVertexBuffer = NULL;
02525         }
02526 
02527         //get all the faces into a list, putting alpha faces in their own list
02528         for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
02529         {
02530                 LLDrawable* drawablep = *drawable_iter;
02531                 drawablep->clearState(LLDrawable::REBUILD_ALL);
02532         }
02533 
02534         group->mLastUpdateTime = gFrameTimeSeconds;
02535         group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::MATRIX_DIRTY |
02536                                                 LLSpatialGroup::ALPHA_DIRTY);
02537 
02538         mFaceList.clear();
02539 }
02540 
02541 void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count)
02542 {       
02543         //initialize to default usage for this partition
02544         U32 usage = group->mSpatialPartition->mBufferUsage;
02545         
02546         //clear off any old faces
02547         mFaceList.clear();
02548 
02549         //for each drawable
02550         for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
02551         {
02552                 LLDrawable* drawablep = *drawable_iter;
02553                 
02554                 if (drawablep->isDead())
02555                 {
02556                         continue;
02557                 }
02558         
02559                 if (drawablep->isAnimating())
02560                 { //fall back to stream draw for animating verts
02561                         usage = GL_STREAM_DRAW_ARB;
02562                 }
02563 
02564                 //for each face
02565                 for (S32 i = 0; i < drawablep->getNumFaces(); i++)
02566                 {
02567                         //sum up face verts and indices
02568                         drawablep->updateFaceSize(i);
02569                         LLFace* facep = drawablep->getFace(i);
02570                         if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA)
02571                         {
02572                                 vertex_count += facep->getGeomCount();
02573                                 index_count += facep->getIndicesCount();
02574 
02575                                 //remember face (for sorting)
02576                                 mFaceList.push_back(facep);
02577                         }
02578                         else
02579                         {
02580                                 facep->mVertexBuffer = NULL;
02581                                 facep->mLastVertexBuffer = NULL;
02582                         }
02583                 }
02584         }
02585         
02586         group->mBufferUsage = usage;
02587 }
02588 
02589 LLHUDPartition::LLHUDPartition()
02590 {
02591         mPartitionType = LLPipeline::PARTITION_HUD;
02592         mDrawableType = LLPipeline::RENDER_TYPE_HUD;
02593         mSlopRatio = 0.f;
02594         mLODPeriod = 16;
02595 }
02596 
02597 void LLHUDPartition::shift(const LLVector3 &offset)
02598 {
02599         //HUD objects don't shift with region crossing.  That would be silly.
02600 }
02601 
02602 

Generated on Thu Jul 1 06:09:44 2010 for Second Life Viewer by  doxygen 1.4.7