diff --git a/indra/newview/llface.h b/indra/newview/llface.h index f8a3fa50d..716e608b3 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -106,6 +106,9 @@ public: F32 getVirtualSize() const { return mVSize; } F32 getPixelArea() const { return mPixelArea; } + S32 getIndexInTex() const {return mIndexInTex ;} + void setIndexInTex(S32 index) { mIndexInTex = index ;} + void renderSetColor() const; S32 renderElements(const U16 *index_array) const; S32 renderIndexed (); @@ -226,6 +229,7 @@ private: U16 mGeomIndex; // index into draw pool U32 mIndicesCount; U32 mIndicesIndex; // index into draw pool for indices (yeah, I know!) + S32 mIndexInTex ; //previous rebuild's geometry info U16 mLastGeomCount; diff --git a/indra/newview/llviewerimage.cpp b/indra/newview/llviewerimage.cpp index 227404e84..7978a9355 100644 --- a/indra/newview/llviewerimage.cpp +++ b/indra/newview/llviewerimage.cpp @@ -61,6 +61,7 @@ #include "llappviewer.h" #include "llface.h" #include "llviewercamera.h" +#include "llvovolume.h" // #include "llimagemetadatareader.h" @@ -357,6 +358,11 @@ void LLViewerImage::init(bool firstinit) mDesiredSavedRawDiscardLevel = -1 ; mCanUseHTTP = true; //default on if cap/settings allows us + + mNumFaces = 0 ; + mNumVolumes = 0; + mFaceList.clear() ; + mVolumeList.clear(); } // virtual @@ -393,6 +399,7 @@ LLViewerImage::~LLViewerImage() void LLViewerImage::cleanup() { mFaceList.clear() ; + mVolumeList.clear(); for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); iter != mLoadedCallbackList.end(); ) { @@ -753,19 +760,19 @@ void LLViewerImage::updateVirtualSize() { addTextureStats(0.f, FALSE) ;//reset } - if(mFaceList.size() > 0) + for(U32 i = 0 ; i < mNumFaces ; i++) { - for(std::list::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ++iter) + LLFace* facep = mFaceList[i] ; + if(facep->getDrawable()->isRecentlyVisible()) { - LLFace* facep = *iter ; - if(facep->getDrawable()->isRecentlyVisible()) - { - addTextureStats(facep->getVirtualSize()) ; - setAdditionalDecodePriority(facep->getImportanceToCamera()) ; - } - } + addTextureStats(facep->getVirtualSize()) ; + setAdditionalDecodePriority(facep->getImportanceToCamera()) ; + } } + mNeedsResetMaxVirtualSize = TRUE ; + reorganizeFaceList(); + reorganizeVolumeList(); #endif } void LLViewerImage::scaleDown() @@ -1755,13 +1762,19 @@ void LLViewerImage::setCachedRawImage() if(mForSculpt) { max_size = MAX_CACHED_RAW_SCULPT_IMAGE_AREA ; + // Even though we don't use the full pixel size, we want to decode up to discard 0, + // because some legacy sculpts are weird like that. + mCachedRawImageReady = !mRawDiscardLevel ; + } + else + { + mCachedRawImageReady = (!mRawDiscardLevel || ((w * h) >= max_size)) ; } while(((w >> i) * (h >> i)) > max_size) { ++i ; } - mCachedRawImageReady = (!mRawDiscardLevel || ((w * h) >= max_size)) ; if(i) { @@ -1772,7 +1785,8 @@ void LLViewerImage::setCachedRawImage() mRawImage->scale(w >> i, h >> i) ; } mCachedRawImage = mRawImage ; - mCachedRawDiscardLevel = mRawDiscardLevel + i ; + mRawDiscardLevel += i ; + mCachedRawDiscardLevel = mRawDiscardLevel ; } } @@ -1780,7 +1794,7 @@ void LLViewerImage::checkCachedRawSculptImage() { if(mCachedRawImageReady && mCachedRawDiscardLevel > 0) { - if(mCachedRawImage->getWidth() * mCachedRawImage->getHeight() < MAX_CACHED_RAW_SCULPT_IMAGE_AREA) + if(getDiscardLevel() != 0) { mCachedRawImageReady = FALSE ; } @@ -1806,11 +1820,111 @@ void LLViewerImage::setForSculpt() checkCachedRawSculptImage() ; } +//virtual void LLViewerImage::addFace(LLFace* facep) { - mFaceList.push_back(facep) ; + if(mNumFaces >= mFaceList.size()) + { + mFaceList.resize(2 * mNumFaces + 1) ; + } + mFaceList[mNumFaces] = facep ; + facep->setIndexInTex(mNumFaces) ; + mNumFaces++ ; + mLastFaceListUpdateTimer.reset() ; } -void LLViewerImage::removeFace(LLFace* facep) + +//virtual +void LLViewerImage::removeFace(LLFace* facep) { - mFaceList.remove(facep) ; + if(mNumFaces > 1) + { + S32 index = facep->getIndexInTex() ; + mFaceList[index] = mFaceList[--mNumFaces] ; + mFaceList[index]->setIndexInTex(index) ; + } + else + { + mFaceList.clear() ; + mNumFaces = 0 ; + } + mLastFaceListUpdateTimer.reset() ; +} + +S32 LLViewerImage::getNumFaces() const +{ + return mNumFaces ; +} + + +//virtual +void LLViewerImage::addVolume(LLVOVolume* volumep) +{ + if( mNumVolumes >= mVolumeList.size()) + { + mVolumeList.resize(2 * mNumVolumes + 1) ; + } + mVolumeList[mNumVolumes] = volumep ; + volumep->setIndexInTex(mNumVolumes) ; + mNumVolumes++ ; + mLastVolumeListUpdateTimer.reset() ; +} + +//virtual +void LLViewerImage::removeVolume(LLVOVolume* volumep) +{ + if(mNumVolumes > 1) + { + S32 index = volumep->getIndexInTex() ; + mVolumeList[index] = mVolumeList[--mNumVolumes] ; + mVolumeList[index]->setIndexInTex(index) ; + } + else + { + mVolumeList.clear() ; + mNumVolumes = 0 ; + } + mLastVolumeListUpdateTimer.reset() ; +} + +S32 LLViewerImage::getNumVolumes() const +{ + return mNumVolumes ; +} + +void LLViewerImage::reorganizeFaceList() +{ + static const F32 MAX_WAIT_TIME = 20.f; // seconds + static const U32 MAX_EXTRA_BUFFER_SIZE = 4 ; + + if(mNumFaces + MAX_EXTRA_BUFFER_SIZE > mFaceList.size()) + { + return ; + } + + if(mLastFaceListUpdateTimer.getElapsedTimeF32() < MAX_WAIT_TIME) + { + return ; + } + + mLastFaceListUpdateTimer.reset() ; + mFaceList.erase(mFaceList.begin() + mNumFaces, mFaceList.end()); +} + +void LLViewerImage::reorganizeVolumeList() +{ + static const F32 MAX_WAIT_TIME = 20.f; // seconds + static const U32 MAX_EXTRA_BUFFER_SIZE = 4 ; + + if(mNumVolumes + MAX_EXTRA_BUFFER_SIZE > mVolumeList.size()) + { + return ; + } + + if(mLastVolumeListUpdateTimer.getElapsedTimeF32() < MAX_WAIT_TIME) + { + return ; + } + + mLastVolumeListUpdateTimer.reset() ; + mVolumeList.erase(mVolumeList.begin() + mNumVolumes, mVolumeList.end()); } diff --git a/indra/newview/llviewerimage.h b/indra/newview/llviewerimage.h index 93c1ce151..58e596c85 100644 --- a/indra/newview/llviewerimage.h +++ b/indra/newview/llviewerimage.h @@ -51,6 +51,7 @@ typedef void (*loaded_callback_func)( BOOL success, LLViewerImage *src_vi, LLIma class LLVFile; class LLMessageSystem; +class LLVOVolume; class LLLoadedCallbackEntry { @@ -209,6 +210,9 @@ public: INVALID_DISCARD_LEVEL = 0x7fff }; + typedef std::vector ll_face_list_t; + typedef std::vector ll_volume_list_t; + protected: /*virtual*/ ~LLViewerImage(); @@ -317,8 +321,17 @@ public: BOOL isSameTexture(const LLViewerImage* tex) const ; - void addFace(LLFace* facep) ; - void removeFace(LLFace* facep) ; + virtual void addFace(LLFace* facep) ; + virtual void removeFace(LLFace* facep) ; + S32 getNumFaces() const; + const ll_face_list_t* getFaceList() const {return &mFaceList;} + void reorganizeFaceList() ; + + virtual void addVolume(LLVOVolume* volumep); + virtual void removeVolume(LLVOVolume* volumep); + S32 getNumVolumes() const; + const ll_volume_list_t* getVolumeList() const { return &mVolumeList; } + void reorganizeVolumeList() ; void setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;}; @@ -424,8 +437,13 @@ private: BOOL mForSculpt ; //a flag if the texture is used for a sculpt data. mutable BOOL mNeedsResetMaxVirtualSize ; - typedef std::list ll_face_list_t ; - ll_face_list_t mFaceList ; //reverse pointer pointing to the faces using this image as texture + ll_face_list_t mFaceList ; //reverse pointer pointing to the faces using this image as texture + U32 mNumFaces ; + LLFrameTimer mLastFaceListUpdateTimer ; + + ll_volume_list_t mVolumeList; + U32 mNumVolumes; + LLFrameTimer mLastVolumeListUpdateTimer; bool mCanUseHTTP; // can this image be fetched by http diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 6917ff5f3..f1603beef 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -88,12 +88,12 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mRelativeXformInvTrans.setIdentity(); mLOD = MIN_LOD; - mSculptLevel = -2; mTextureAnimp = NULL; mVObjRadius = LLVector3(1,1,0.5f).length(); mNumFaces = 0; mLODChanged = FALSE; mSculptChanged = FALSE; + mIndexInTex = 0; } LLVOVolume::~LLVOVolume() @@ -513,9 +513,8 @@ void LLVOVolume::updateTextureVirtualSize() if (isSculpted()) { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID id = sculpt_params->getSculptTexture(); - mSculptTexture = gImageList.getImage(id); + updateSculptTexture(); + if (mSculptTexture.notNull()) { mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(), @@ -538,8 +537,8 @@ void LLVOVolume::updateTextureVirtualSize() } } - S32 texture_discard = mSculptTexture->getCachedRawImageLevel(); //try to match the texture - S32 current_discard = mSculptLevel; + S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture + S32 current_discard = getVolume() ? getVolume()->getSculptLevel() : -2 ; if (texture_discard >= 0 && //texture has some data available (texture_discard < current_discard || //texture has more data than last rebuild @@ -692,25 +691,52 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail mVolumeImpl->onSetVolume(volume_params, detail); } + updateSculptTexture(); + if (isSculpted()) { - mSculptTexture = gImageList.getImage(volume_params.getSculptID()); if (mSculptTexture.notNull()) { sculpt(); - mSculptLevel = getVolume()->getSculptLevel(); } } - else - { - mSculptTexture = NULL; - } return TRUE; } return FALSE; } +void LLVOVolume::updateSculptTexture() +{ + LLPointer old_sculpt = mSculptTexture; + + if (isSculpted()) + { + LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLUUID id = sculpt_params->getSculptTexture(); + if (id.notNull()) + { + mSculptTexture = gImageList.getImage(id); + } + } + else + { + mSculptTexture = NULL; + } + + if (mSculptTexture != old_sculpt) + { + if (old_sculpt.notNull()) + { + old_sculpt->removeVolume(this); + } + if (mSculptTexture.notNull()) + { + mSculptTexture->addVolume(this); + } + } +} + // sculpt replaces generate() for sculpted surfaces void LLVOVolume::sculpt() { @@ -721,7 +747,7 @@ void LLVOVolume::sculpt() S8 sculpt_components = 0; const U8* sculpt_data = NULL; - S32 discard_level = mSculptTexture->getCachedRawImageLevel() ; + S32 discard_level = mSculptTexture->getDiscardLevel(); LLImageRaw* raw_image = mSculptTexture->getCachedRawImage() ; S32 max_discard = mSculptTexture->getMaxDiscardLevel(); @@ -764,6 +790,16 @@ void LLVOVolume::sculpt() sculpt_data = raw_image->getData(); } getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level); + + //notify rebuild any other VOVolumes that reference this sculpty volume + for (S32 i = 0; i < mSculptTexture->getNumVolumes(); ++i) + { + LLVOVolume* volume = (*(mSculptTexture->getVolumeList()))[i]; + if (volume != this && volume->getVolume() == getVolume()) + { + gPipeline.markRebuild(volume->mDrawable, LLDrawable::REBUILD_GEOMETRY, FALSE); + } + } } } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 8cfb9698b..8cc1331f5 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -169,8 +169,10 @@ public: /*virtual*/ BOOL setMaterial(const U8 material); void setTexture(const S32 face); - + S32 getIndexInTex() const {return mIndexInTex ;} /*virtual*/ BOOL setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false); + void updateSculptTexture(); + void setIndexInTex(S32 index) { mIndexInTex = index ;} void sculpt(); void updateRelativeXform(); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); @@ -228,7 +230,6 @@ private: LLFrameTimer mTextureUpdateTimer; S32 mLOD; BOOL mLODChanged; - S32 mSculptLevel; BOOL mSculptChanged; LLMatrix4 mRelativeXform; LLMatrix3 mRelativeXformInvTrans; @@ -236,6 +237,7 @@ private: F32 mVObjRadius; LLVolumeInterface *mVolumeImpl; LLPointer mSculptTexture; + S32 mIndexInTex; // statics public: